@amalgm/core 0.4.3 → 0.4.4

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/PURPOSE.md CHANGED
@@ -127,6 +127,8 @@ that composes an exact Core release with the other product releases.
127
127
  credential may mint an audience- and scope-exact access token, but every
128
128
  resource request also proves possession of that machine's key; Core owns
129
129
  the claims and renewal law while hosts own keys, storage, signing, and HTTP.
130
+ Behind a proxy, the configured public origin is authority for the DPoP URL;
131
+ caller-controlled forwarding headers are not.
130
132
  23. **Machine key replacement is an explicit recovery, never startup repair.**
131
133
  Ordinary registration may pin an absent key or reuse the same key; replacing
132
134
  it requires fresh user approval, proof of the candidate private key, and a
@@ -17,4 +17,10 @@ export interface DpopSignerPort {
17
17
  /** RFC 9449 htu excludes query and fragment and uses an absolute URI. */
18
18
  export declare function normalizeDpopHtu(value: string): string;
19
19
  export declare function normalizeDpopMethod(value: string): string;
20
+ /**
21
+ * Reconstruct the public resource URL behind a reverse proxy without trusting
22
+ * caller-controlled forwarding headers. Deployment config owns the origin;
23
+ * the HTTP request contributes only its origin-form path and query.
24
+ */
25
+ export declare function publicResourceRequestUrl(publicOrigin: string, requestTarget: string): string;
20
26
  //# sourceMappingURL=dpop.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"dpop.d.ts","sourceRoot":"","sources":["../../../src/identity/authorization/dpop.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;CAC/B;AAED,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,SAAS,CAAC,KAAK,EAAE,cAAc,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;CACnD;AAED,yEAAyE;AACzE,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAUtD;AAED,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAIzD"}
1
+ {"version":3,"file":"dpop.d.ts","sourceRoot":"","sources":["../../../src/identity/authorization/dpop.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;CAC/B;AAED,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,SAAS,CAAC,KAAK,EAAE,cAAc,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;CACnD;AAED,yEAAyE;AACzE,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAUtD;AAED,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAIzD;AAED;;;;GAIG;AACH,wBAAgB,wBAAwB,CAAC,YAAY,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,GAAG,MAAM,CAe5F"}
@@ -16,4 +16,24 @@ export function normalizeDpopMethod(value) {
16
16
  throw new TypeError('DPoP method is invalid');
17
17
  return method;
18
18
  }
19
+ /**
20
+ * Reconstruct the public resource URL behind a reverse proxy without trusting
21
+ * caller-controlled forwarding headers. Deployment config owns the origin;
22
+ * the HTTP request contributes only its origin-form path and query.
23
+ */
24
+ export function publicResourceRequestUrl(publicOrigin, requestTarget) {
25
+ const origin = new URL(publicOrigin);
26
+ const loopback = origin.hostname === 'localhost' || origin.hostname === '127.0.0.1';
27
+ if ((origin.protocol !== 'https:' && !(loopback && origin.protocol === 'http:'))
28
+ || origin.username
29
+ || origin.password
30
+ || origin.pathname !== '/'
31
+ || origin.search
32
+ || origin.hash)
33
+ throw new TypeError('Public resource origin must be an HTTPS origin');
34
+ if (!requestTarget.startsWith('/') || requestTarget.startsWith('//')) {
35
+ throw new TypeError('Resource request target must use origin form');
36
+ }
37
+ return new URL(requestTarget, origin).toString();
38
+ }
19
39
  //# sourceMappingURL=dpop.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"dpop.js","sourceRoot":"","sources":["../../../src/identity/authorization/dpop.ts"],"names":[],"mappings":"AAmBA,yEAAyE;AACzE,MAAM,UAAU,gBAAgB,CAAC,KAAa;IAC5C,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC;IAC3B,IAAI,CAAC,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC;QAChD,MAAM,IAAI,SAAS,CAAC,iCAAiC,CAAC,CAAC;IACzD,CAAC;IACD,GAAG,CAAC,QAAQ,GAAG,EAAE,CAAC;IAClB,GAAG,CAAC,QAAQ,GAAG,EAAE,CAAC;IAClB,GAAG,CAAC,MAAM,GAAG,EAAE,CAAC;IAChB,GAAG,CAAC,IAAI,GAAG,EAAE,CAAC;IACd,OAAO,GAAG,CAAC,QAAQ,EAAE,CAAC;AACxB,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,KAAa;IAC/C,MAAM,MAAM,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IAC1C,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC;QAAE,MAAM,IAAI,SAAS,CAAC,wBAAwB,CAAC,CAAC;IAC5E,OAAO,MAAM,CAAC;AAChB,CAAC"}
1
+ {"version":3,"file":"dpop.js","sourceRoot":"","sources":["../../../src/identity/authorization/dpop.ts"],"names":[],"mappings":"AAmBA,yEAAyE;AACzE,MAAM,UAAU,gBAAgB,CAAC,KAAa;IAC5C,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC;IAC3B,IAAI,CAAC,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC;QAChD,MAAM,IAAI,SAAS,CAAC,iCAAiC,CAAC,CAAC;IACzD,CAAC;IACD,GAAG,CAAC,QAAQ,GAAG,EAAE,CAAC;IAClB,GAAG,CAAC,QAAQ,GAAG,EAAE,CAAC;IAClB,GAAG,CAAC,MAAM,GAAG,EAAE,CAAC;IAChB,GAAG,CAAC,IAAI,GAAG,EAAE,CAAC;IACd,OAAO,GAAG,CAAC,QAAQ,EAAE,CAAC;AACxB,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,KAAa;IAC/C,MAAM,MAAM,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IAC1C,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC;QAAE,MAAM,IAAI,SAAS,CAAC,wBAAwB,CAAC,CAAC;IAC5E,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,wBAAwB,CAAC,YAAoB,EAAE,aAAqB;IAClF,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,YAAY,CAAC,CAAC;IACrC,MAAM,QAAQ,GAAG,MAAM,CAAC,QAAQ,KAAK,WAAW,IAAI,MAAM,CAAC,QAAQ,KAAK,WAAW,CAAC;IACpF,IACE,CAAC,MAAM,CAAC,QAAQ,KAAK,QAAQ,IAAI,CAAC,CAAC,QAAQ,IAAI,MAAM,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC;WACzE,MAAM,CAAC,QAAQ;WACf,MAAM,CAAC,QAAQ;WACf,MAAM,CAAC,QAAQ,KAAK,GAAG;WACvB,MAAM,CAAC,MAAM;WACb,MAAM,CAAC,IAAI;QACd,MAAM,IAAI,SAAS,CAAC,gDAAgD,CAAC,CAAC;IACxE,IAAI,CAAC,aAAa,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,aAAa,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;QACrE,MAAM,IAAI,SAAS,CAAC,8CAA8C,CAAC,CAAC;IACtE,CAAC;IACD,OAAO,IAAI,GAAG,CAAC,aAAa,EAAE,MAAM,CAAC,CAAC,QAAQ,EAAE,CAAC;AACnD,CAAC"}
@@ -16,14 +16,16 @@ needs.
16
16
  set, expiry, token id, signing key, and device-key thumbprint.
17
17
  3. Every resource request has a fresh DPoP proof bound to its method, URL,
18
18
  access token, and machine key.
19
- 4. The broker caches an exact grant, refreshes before expiry with jitter,
19
+ 4. A proxied resource reconstructs that URL from its configured public origin
20
+ and the origin-form request target; forwarding headers are not authority.
21
+ 5. The broker caches an exact grant, refreshes before expiry with jitter,
20
22
  single-flights concurrent renewal, and performs no silent auth fallback.
21
- 5. Audiences and scopes are closed sets. Adding a consumer changes this module
23
+ 6. Audiences and scopes are closed sets. Adding a consumer changes this module
22
24
  and its tests before any issuer or verifier accepts it.
23
- 6. A machine key is pinned once. Replacement requires an explicit, browser-
25
+ 7. A machine key is pinned once. Replacement requires an explicit, browser-
24
26
  approved recovery bound to the expected old thumbprint and a different
25
27
  candidate key; retrying an already completed replacement is idempotent.
26
- 7. Provider access is memory-only. Registration and machine resume never
28
+ 8. Provider access is memory-only. Registration and machine resume never
27
29
  persist an access token, DPoP proof, or provider proxy credential; resume
28
30
  removes retired proxy and HMAC fields left by older installations.
29
31
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@amalgm/core",
3
- "version": "0.4.3",
3
+ "version": "0.4.4",
4
4
  "description": "The Amalgm kernel SDK — identity, transport, supervision, and host capability contracts behind host-injected adapters.",
5
5
  "type": "module",
6
6
  "license": "UNLICENSED",