max / makenotwork
- Co-Authored-By
- Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 file changed,
+14 insertions,
-2 deletions
| @@ -652,7 +652,14 @@ | |||
| 652 | 652 | request: axum::http::Request<axum::body::Body>, | |
| 653 | 653 | next: middleware::Next, | |
| 654 | 654 | ) -> axum::response::Response { | |
| 655 | - | let is_embed = request.uri().path().starts_with("/embed/"); | |
| 655 | + | let path = request.uri().path(); | |
| 656 | + | let is_embed = path.starts_with("/embed/"); | |
| 657 | + | // OAuth PKCE consent posts redirect to the RP's registered redirect_uri, | |
| 658 | + | // which for native/desktop clients is a loopback callback per RFC 8252 §7.3. | |
| 659 | + | // form-action applies to redirect chains (CSP3 §5.1), so a bare 'self' blocks | |
| 660 | + | // the callback and the user sees the login form re-post with no visible | |
| 661 | + | // effect. Widen form-action on the authorize endpoints only. | |
| 662 | + | let is_oauth_authorize = path == "/oauth/authorize"; | |
| 656 | 663 | let mut response = next.run(request).await; | |
| 657 | 664 | let headers = response.headers_mut(); | |
| 658 | 665 | ||
| @@ -710,6 +717,11 @@ | |||
| 710 | 717 | "http" | |
| 711 | 718 | }; | |
| 712 | 719 | let user_pages_origin = format!("{scheme}://{}", state.config.user_pages_host); | |
| 720 | + | let form_action = if is_oauth_authorize { | |
| 721 | + | "'self' http://127.0.0.1:* http://[::1]:* http://localhost:*" | |
| 722 | + | } else { | |
| 723 | + | "'self'" | |
| 724 | + | }; | |
| 713 | 725 | // script-src is 'self' (+ Stripe) with NO 'unsafe-inline': all inline | |
| 714 | 726 | // on*/hx-on handlers were moved to delegated listeners in static/*.js | |
| 715 | 727 | // (the data-action / data-hx-* dispatchers in mnw.js), so any injected | |
| @@ -725,7 +737,7 @@ | |||
| 725 | 737 | media-src 'self'{storage_origins}; \ | |
| 726 | 738 | frame-src 'self' https://js.stripe.com {user_pages_origin}; \ | |
| 727 | 739 | base-uri 'self'; \ | |
| 728 | - | form-action 'self'; \ | |
| 740 | + | form-action {form_action}; \ | |
| 729 | 741 | frame-ancestors 'none'" | |
| 730 | 742 | ); | |
| 731 | 743 | if let Ok(value) = HeaderValue::from_str(&csp) { |