@fabrika/proxy-core 0.5.3 → 0.5.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +4 -4
- package/src/authorize.ts +21 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fabrika/proxy-core",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.5",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -37,9 +37,9 @@
|
|
|
37
37
|
},
|
|
38
38
|
"dependencies": {
|
|
39
39
|
"zod": "^3.25.76",
|
|
40
|
-
"@fabrika/auth-core": "0.5.
|
|
41
|
-
"@fabrika/jwks": "0.5.
|
|
40
|
+
"@fabrika/auth-core": "0.5.5",
|
|
41
|
+
"@fabrika/jwks": "0.5.5",
|
|
42
42
|
"jose": "^5.9.0",
|
|
43
|
-
"@fabrika/platform": "0.5.
|
|
43
|
+
"@fabrika/platform": "0.5.5"
|
|
44
44
|
}
|
|
45
45
|
}
|
package/src/authorize.ts
CHANGED
|
@@ -26,6 +26,7 @@ import {
|
|
|
26
26
|
callerAdmittedAt,
|
|
27
27
|
callerOf,
|
|
28
28
|
type CompiledEndpointTable,
|
|
29
|
+
FORM_MULTIPART_TYPE,
|
|
29
30
|
formatEndpointHeader,
|
|
30
31
|
planEndpoint,
|
|
31
32
|
satisfies,
|
|
@@ -77,7 +78,10 @@ export type DenyReason =
|
|
|
77
78
|
| 'cross_site'
|
|
78
79
|
/** The request's `Content-Type` is not one the endpoint admits. */
|
|
79
80
|
| 'content_type'
|
|
80
|
-
/**
|
|
81
|
+
/**
|
|
82
|
+
* A preflight for an endpoint the contract does not open to another origin, or from an origin it does not admit; or a
|
|
83
|
+
* multipart form's request from such an origin, which a browser sends without a preflight.
|
|
84
|
+
*/
|
|
81
85
|
| 'cross_origin'
|
|
82
86
|
/** IAM refused the delegation grant a membership or scope-creating endpoint needs. */
|
|
83
87
|
| 'delegation_refused'
|
|
@@ -301,7 +305,8 @@ export class Authorizer {
|
|
|
301
305
|
private async decideRow(app: ProxyApp, row: ManifestEndpointRow, request: ForwardedRequest, crossOrigin: string | null): Promise<Decision> {
|
|
302
306
|
const endpoint = formatEndpointHeader(row.id, row.digest)
|
|
303
307
|
if (row.requirement === null) {
|
|
304
|
-
return admitBody(row, request.headers) ??
|
|
308
|
+
return admitBody(row, request.headers) ?? admitFormOrigin(app, row, request, crossOrigin)
|
|
309
|
+
?? { outcome: 'allow', token: null, subject: null, endpoint, delegation: null, crossOrigin }
|
|
305
310
|
}
|
|
306
311
|
const oauth = oauthBindingOf(app, row)
|
|
307
312
|
if (oauth === 'unregistered') {
|
|
@@ -656,6 +661,20 @@ function withBearerChallenge(denial: Denial, oauth: OAuthBinding | null): Denial
|
|
|
656
661
|
return { ...denial, challenge: denial.status === 401 ? { ...challenge, error: 'invalid_token' } : challenge }
|
|
657
662
|
}
|
|
658
663
|
|
|
664
|
+
/**
|
|
665
|
+
* A multipart form admits a browser's request only from the application's own origin or one the row admits (ADR-0022
|
|
666
|
+
* "Cross-origin endpoints"). A page on any origin sends `multipart/form-data` without a preflight, so the proxy refuses
|
|
667
|
+
* at the request what it refuses at the preflight of a JSON form. A request without `Origin` is no browser's
|
|
668
|
+
* cross-origin request.
|
|
669
|
+
*/
|
|
670
|
+
function admitFormOrigin(app: ProxyApp, row: ManifestEndpointRow, request: ForwardedRequest, crossOrigin: string | null): Denial | null {
|
|
671
|
+
const origin = request.headers.get(ORIGIN_HEADER)
|
|
672
|
+
if (row.kind !== 'form' || origin === null || crossOrigin !== null || !(row.admission?.contentTypes.includes(FORM_MULTIPART_TYPE) ?? false)) {
|
|
673
|
+
return null
|
|
674
|
+
}
|
|
675
|
+
return origin === `${app.scheme}://${request.url.host}` ? null : { outcome: 'deny', status: 403, reason: 'cross_origin' }
|
|
676
|
+
}
|
|
677
|
+
|
|
659
678
|
/** An endpoint that admits a body admits only its declared media types (ADR-0022 rule 3, admission). */
|
|
660
679
|
function admitBody(row: ManifestEndpointRow, headers: Headers): Denial | null {
|
|
661
680
|
if (row.admission === null) {
|