@spinajs/authn-keys 3.0.2 → 3.0.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.
Files changed (140) hide show
  1. package/README.md +11 -3
  2. package/lib/cjs/index.d.ts +0 -1
  3. package/lib/cjs/index.d.ts.map +1 -1
  4. package/lib/cjs/index.js +0 -1
  5. package/lib/cjs/index.js.map +1 -1
  6. package/lib/cjs/jws/index.d.ts +1 -0
  7. package/lib/cjs/jws/index.d.ts.map +1 -1
  8. package/lib/cjs/jws/index.js +1 -0
  9. package/lib/cjs/jws/index.js.map +1 -1
  10. package/lib/cjs/jws/register.d.ts +18 -0
  11. package/lib/cjs/jws/register.d.ts.map +1 -0
  12. package/lib/cjs/jws/register.js +66 -0
  13. package/lib/cjs/jws/register.js.map +1 -0
  14. package/lib/cjs/models/index.d.ts +0 -1
  15. package/lib/cjs/models/index.d.ts.map +1 -1
  16. package/lib/cjs/models/index.js +0 -1
  17. package/lib/cjs/models/index.js.map +1 -1
  18. package/lib/cjs/options/options.d.ts +10 -0
  19. package/lib/cjs/options/options.d.ts.map +1 -1
  20. package/lib/cjs/options/options.js +9 -0
  21. package/lib/cjs/options/options.js.map +1 -1
  22. package/lib/cjs/registry/cache.d.ts +26 -0
  23. package/lib/cjs/registry/cache.d.ts.map +1 -0
  24. package/lib/cjs/registry/cache.js +73 -0
  25. package/lib/cjs/registry/cache.js.map +1 -0
  26. package/lib/cjs/registry/index.d.ts +1 -0
  27. package/lib/cjs/registry/index.d.ts.map +1 -1
  28. package/lib/cjs/registry/index.js +1 -0
  29. package/lib/cjs/registry/index.js.map +1 -1
  30. package/lib/cjs/registry/registry.d.ts +15 -2
  31. package/lib/cjs/registry/registry.d.ts.map +1 -1
  32. package/lib/cjs/registry/registry.js +35 -2
  33. package/lib/cjs/registry/registry.js.map +1 -1
  34. package/lib/cjs/schema.d.ts +40 -0
  35. package/lib/cjs/schema.d.ts.map +1 -1
  36. package/lib/cjs/schema.js +19 -0
  37. package/lib/cjs/schema.js.map +1 -1
  38. package/lib/cjs/strategies/assertion.d.ts +4 -5
  39. package/lib/cjs/strategies/assertion.d.ts.map +1 -1
  40. package/lib/cjs/strategies/assertion.js +6 -5
  41. package/lib/cjs/strategies/assertion.js.map +1 -1
  42. package/lib/cjs/strategies/httpsig.d.ts +5 -4
  43. package/lib/cjs/strategies/httpsig.d.ts.map +1 -1
  44. package/lib/cjs/strategies/httpsig.js +9 -5
  45. package/lib/cjs/strategies/httpsig.js.map +1 -1
  46. package/lib/cjs/strategies/index.d.ts +1 -0
  47. package/lib/cjs/strategies/index.d.ts.map +1 -1
  48. package/lib/cjs/strategies/index.js +1 -0
  49. package/lib/cjs/strategies/index.js.map +1 -1
  50. package/lib/cjs/strategies/keys.d.ts +3 -1
  51. package/lib/cjs/strategies/keys.d.ts.map +1 -1
  52. package/lib/cjs/strategies/keys.js +9 -0
  53. package/lib/cjs/strategies/keys.js.map +1 -1
  54. package/lib/cjs/strategies/nonce-key.d.ts +3 -0
  55. package/lib/cjs/strategies/nonce-key.d.ts.map +1 -0
  56. package/lib/cjs/strategies/nonce-key.js +8 -0
  57. package/lib/cjs/strategies/nonce-key.js.map +1 -0
  58. package/lib/mjs/index.d.ts +0 -1
  59. package/lib/mjs/index.d.ts.map +1 -1
  60. package/lib/mjs/index.js +0 -1
  61. package/lib/mjs/index.js.map +1 -1
  62. package/lib/mjs/jws/index.d.ts +1 -0
  63. package/lib/mjs/jws/index.d.ts.map +1 -1
  64. package/lib/mjs/jws/index.js +1 -0
  65. package/lib/mjs/jws/index.js.map +1 -1
  66. package/lib/mjs/jws/register.d.ts +18 -0
  67. package/lib/mjs/jws/register.d.ts.map +1 -0
  68. package/lib/mjs/jws/register.js +62 -0
  69. package/lib/mjs/jws/register.js.map +1 -0
  70. package/lib/mjs/models/index.d.ts +0 -1
  71. package/lib/mjs/models/index.d.ts.map +1 -1
  72. package/lib/mjs/models/index.js +0 -1
  73. package/lib/mjs/models/index.js.map +1 -1
  74. package/lib/mjs/options/options.d.ts +10 -0
  75. package/lib/mjs/options/options.d.ts.map +1 -1
  76. package/lib/mjs/options/options.js +8 -0
  77. package/lib/mjs/options/options.js.map +1 -1
  78. package/lib/mjs/registry/cache.d.ts +26 -0
  79. package/lib/mjs/registry/cache.d.ts.map +1 -0
  80. package/lib/mjs/registry/cache.js +69 -0
  81. package/lib/mjs/registry/cache.js.map +1 -0
  82. package/lib/mjs/registry/index.d.ts +1 -0
  83. package/lib/mjs/registry/index.d.ts.map +1 -1
  84. package/lib/mjs/registry/index.js +1 -0
  85. package/lib/mjs/registry/index.js.map +1 -1
  86. package/lib/mjs/registry/registry.d.ts +15 -2
  87. package/lib/mjs/registry/registry.d.ts.map +1 -1
  88. package/lib/mjs/registry/registry.js +37 -4
  89. package/lib/mjs/registry/registry.js.map +1 -1
  90. package/lib/mjs/schema.d.ts +40 -0
  91. package/lib/mjs/schema.d.ts.map +1 -1
  92. package/lib/mjs/schema.js +19 -0
  93. package/lib/mjs/schema.js.map +1 -1
  94. package/lib/mjs/strategies/assertion.d.ts +4 -5
  95. package/lib/mjs/strategies/assertion.d.ts.map +1 -1
  96. package/lib/mjs/strategies/assertion.js +7 -6
  97. package/lib/mjs/strategies/assertion.js.map +1 -1
  98. package/lib/mjs/strategies/httpsig.d.ts +5 -4
  99. package/lib/mjs/strategies/httpsig.d.ts.map +1 -1
  100. package/lib/mjs/strategies/httpsig.js +10 -6
  101. package/lib/mjs/strategies/httpsig.js.map +1 -1
  102. package/lib/mjs/strategies/index.d.ts +1 -0
  103. package/lib/mjs/strategies/index.d.ts.map +1 -1
  104. package/lib/mjs/strategies/index.js +1 -0
  105. package/lib/mjs/strategies/index.js.map +1 -1
  106. package/lib/mjs/strategies/keys.d.ts +3 -1
  107. package/lib/mjs/strategies/keys.d.ts.map +1 -1
  108. package/lib/mjs/strategies/keys.js +8 -0
  109. package/lib/mjs/strategies/keys.js.map +1 -1
  110. package/lib/mjs/strategies/nonce-key.d.ts +3 -0
  111. package/lib/mjs/strategies/nonce-key.d.ts.map +1 -0
  112. package/lib/mjs/strategies/nonce-key.js +4 -0
  113. package/lib/mjs/strategies/nonce-key.js.map +1 -0
  114. package/lib/tsconfig.cjs.tsbuildinfo +1 -1
  115. package/lib/tsconfig.mjs.tsbuildinfo +1 -1
  116. package/package.json +20 -11
  117. package/lib/cjs/models/AuthnNonce.d.ts +0 -8
  118. package/lib/cjs/models/AuthnNonce.d.ts.map +0 -1
  119. package/lib/cjs/models/AuthnNonce.js +0 -31
  120. package/lib/cjs/models/AuthnNonce.js.map +0 -1
  121. package/lib/cjs/nonce/index.d.ts +0 -2
  122. package/lib/cjs/nonce/index.d.ts.map +0 -1
  123. package/lib/cjs/nonce/index.js +0 -18
  124. package/lib/cjs/nonce/index.js.map +0 -1
  125. package/lib/cjs/nonce/store.d.ts +0 -22
  126. package/lib/cjs/nonce/store.d.ts.map +0 -1
  127. package/lib/cjs/nonce/store.js +0 -98
  128. package/lib/cjs/nonce/store.js.map +0 -1
  129. package/lib/mjs/models/AuthnNonce.d.ts +0 -8
  130. package/lib/mjs/models/AuthnNonce.d.ts.map +0 -1
  131. package/lib/mjs/models/AuthnNonce.js +0 -28
  132. package/lib/mjs/models/AuthnNonce.js.map +0 -1
  133. package/lib/mjs/nonce/index.d.ts +0 -2
  134. package/lib/mjs/nonce/index.d.ts.map +0 -1
  135. package/lib/mjs/nonce/index.js +0 -2
  136. package/lib/mjs/nonce/index.js.map +0 -1
  137. package/lib/mjs/nonce/store.d.ts +0 -22
  138. package/lib/mjs/nonce/store.d.ts.map +0 -1
  139. package/lib/mjs/nonce/store.js +0 -92
  140. package/lib/mjs/nonce/store.js.map +0 -1
package/README.md CHANGED
@@ -24,8 +24,15 @@ The registry and the strategies get their dependencies through DI. Tests
24
24
  build them with `new`, passing the dependencies in one object, e.g.
25
25
  `new DefaultKeyRegistry({ store, secrets, throttle, options })` or
26
26
  `new HttpSignatureStrategy({ registry, nonces, options })`. `OrmKeyStore`
27
- and `DbKeyNonceStore` inject the `Orm`, so the `authn:key-*` commands bring
28
- the database up on their own.
27
+ injects the `Orm`, so the `authn:key-*` commands bring the database up on
28
+ their own.
29
+
30
+ `JwsAssertionStrategy` and `HttpSignatureStrategy` claim each `jti` and
31
+ signature nonce in the core `NonceStore` (`@spinajs/authn/contracts`). Only
32
+ `@spinajs/authn-orm` registers one (`DbNonceStore`), so import it, or register
33
+ your own `NonceStore`; without one the strategies fail at boot with an error
34
+ naming `@spinajs/authn-orm`. `MemoryNonceStore` from `@spinajs/authn/nonces`
35
+ is for tests and single-process apps, and is not registered for you.
29
36
 
30
37
  ## Challenges
31
38
 
@@ -146,7 +153,8 @@ unknown key with the same work and result as a bad signature, throttles by
146
153
  | `httpSignature.skewSeconds` | `30` |
147
154
  | `httpSignature.requiredComponents` | `['@method', '@target-uri', 'content-digest']` |
148
155
 
149
- `authn_nonce` comes with `@spinajs/authn-orm`'s `AuthnInitial` migration.
156
+ `authn_nonce` and the `NonceStore` that fills it (`DbNonceStore`) come with
157
+ `@spinajs/authn-orm`; this package has no nonce table or model of its own.
150
158
 
151
159
  List the strategies an app uses in `authn.strategies`; `service` is the
152
160
  class name:
@@ -5,7 +5,6 @@ export * from './models/index.js';
5
5
  export * from './migrations/index.js';
6
6
  export * from './registry/index.js';
7
7
  export * from './jws/index.js';
8
- export * from './nonce/index.js';
9
8
  export * from './strategies/index.js';
10
9
  export * from './httpsig/index.js';
11
10
  export * from './schema.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,gBAAgB,CAAC;AAC/B,cAAc,sBAAsB,CAAC;AACrC,cAAc,oBAAoB,CAAC;AACnC,cAAc,mBAAmB,CAAC;AAClC,cAAc,uBAAuB,CAAC;AACtC,cAAc,qBAAqB,CAAC;AACpC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,kBAAkB,CAAC;AACjC,cAAc,uBAAuB,CAAC;AACtC,cAAc,oBAAoB,CAAC;AACnC,cAAc,aAAa,CAAC;AAC5B,cAAc,gBAAgB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,gBAAgB,CAAC;AAC/B,cAAc,sBAAsB,CAAC;AACrC,cAAc,oBAAoB,CAAC;AACnC,cAAc,mBAAmB,CAAC;AAClC,cAAc,uBAAuB,CAAC;AACtC,cAAc,qBAAqB,CAAC;AACpC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,uBAAuB,CAAC;AACtC,cAAc,oBAAoB,CAAC;AACnC,cAAc,aAAa,CAAC;AAC5B,cAAc,gBAAgB,CAAC"}
package/lib/cjs/index.js CHANGED
@@ -21,7 +21,6 @@ __exportStar(require("./models/index.js"), exports);
21
21
  __exportStar(require("./migrations/index.js"), exports);
22
22
  __exportStar(require("./registry/index.js"), exports);
23
23
  __exportStar(require("./jws/index.js"), exports);
24
- __exportStar(require("./nonce/index.js"), exports);
25
24
  __exportStar(require("./strategies/index.js"), exports);
26
25
  __exportStar(require("./httpsig/index.js"), exports);
27
26
  __exportStar(require("./schema.js"), exports);
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,iDAA+B;AAC/B,uDAAqC;AACrC,qDAAmC;AACnC,oDAAkC;AAClC,wDAAsC;AACtC,sDAAoC;AACpC,iDAA+B;AAC/B,mDAAiC;AACjC,wDAAsC;AACtC,qDAAmC;AACnC,8CAA4B;AAC5B,iDAA+B"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,iDAA+B;AAC/B,uDAAqC;AACrC,qDAAmC;AACnC,oDAAkC;AAClC,wDAAsC;AACtC,sDAAoC;AACpC,iDAA+B;AAC/B,wDAAsC;AACtC,qDAAmC;AACnC,8CAA4B;AAC5B,iDAA+B"}
@@ -1,4 +1,5 @@
1
1
  export * from './json.js';
2
2
  export * from './verifier.js';
3
3
  export * from './signer.js';
4
+ export * from './register.js';
4
5
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/jws/index.ts"],"names":[],"mappings":"AAAA,cAAc,WAAW,CAAC;AAC1B,cAAc,eAAe,CAAC;AAC9B,cAAc,aAAa,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/jws/index.ts"],"names":[],"mappings":"AAAA,cAAc,WAAW,CAAC;AAC1B,cAAc,eAAe,CAAC;AAC9B,cAAc,aAAa,CAAC;AAC5B,cAAc,eAAe,CAAC"}
@@ -17,4 +17,5 @@ Object.defineProperty(exports, "__esModule", { value: true });
17
17
  __exportStar(require("./json.js"), exports);
18
18
  __exportStar(require("./verifier.js"), exports);
19
19
  __exportStar(require("./signer.js"), exports);
20
+ __exportStar(require("./register.js"), exports);
20
21
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/jws/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,4CAA0B;AAC1B,gDAA8B;AAC9B,8CAA4B"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/jws/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,4CAA0B;AAC1B,gDAA8B;AAC9B,8CAA4B;AAC5B,gDAA8B"}
@@ -0,0 +1,18 @@
1
+ import { Bootstrapper } from '@spinajs/di';
2
+ import type { IContainer } from '@spinajs/di';
3
+ import '../register-schema.js';
4
+ import { LocalJwsSigner } from './signer.js';
5
+ /** `authn.keys.signer`. */
6
+ export interface SignerConfig {
7
+ readonly current: string;
8
+ /** Secret references the configuration resolves to private JWKs as JSON text. */
9
+ readonly keys: readonly string[];
10
+ }
11
+ /** Registers a JwsSigner built from `authn.keys.signer` in `container`; null, and nothing registered, when it is null. */
12
+ export declare function registerJwsSigner(container: IContainer): Promise<LocalJwsSigner | null>;
13
+ /** Registers the configured JwsSigner at boot, so the JWKS route and the verifiers' key lookup find it. */
14
+ export declare class AuthnKeysSignerBootstrapper extends Bootstrapper {
15
+ protected Container: IContainer;
16
+ bootstrap(): Promise<void>;
17
+ }
18
+ //# sourceMappingURL=register.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"register.d.ts","sourceRoot":"","sources":["../../../src/jws/register.ts"],"names":[],"mappings":"AAAA,OAAO,EAAc,YAAY,EAAyB,MAAM,aAAa,CAAC;AAC9E,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAM9C,OAAO,uBAAuB,CAAC;AAC/B,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAG7C,2BAA2B;AAC3B,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,iFAAiF;IACjF,QAAQ,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,CAAC;CAClC;AAgBD,0HAA0H;AAC1H,wBAAsB,iBAAiB,CAAC,SAAS,EAAE,UAAU,GAAG,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC,CAe7F;AAED,2GAA2G;AAC3G,qBACa,2BAA4B,SAAQ,YAAY;IAE3D,SAAS,CAAC,SAAS,EAAG,UAAU,CAAC;IAEpB,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC,CAEtC;CACF"}
@@ -0,0 +1,66 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.AuthnKeysSignerBootstrapper = void 0;
13
+ exports.registerJwsSigner = registerJwsSigner;
14
+ const di_1 = require("@spinajs/di");
15
+ const configuration_1 = require("@spinajs/configuration");
16
+ const contracts_1 = require("@spinajs/authn/contracts");
17
+ const exceptions_1 = require("@spinajs/exceptions");
18
+ const util_1 = require("@spinajs/util");
19
+ require("../register-schema.js");
20
+ const signer_js_1 = require("./signer.js");
21
+ // The error names the position only: the text is a private key.
22
+ function privateJwkOf(secret, index) {
23
+ let jwk;
24
+ try {
25
+ jwk = JSON.parse(secret);
26
+ }
27
+ catch {
28
+ jwk = undefined;
29
+ }
30
+ if (!(0, util_1.isPlainObject)(jwk)) {
31
+ throw new exceptions_1.InvalidOption(`authn.keys.signer.keys.${index} does not resolve to a private JWK as a JSON object`);
32
+ }
33
+ return jwk;
34
+ }
35
+ /** Registers a JwsSigner built from `authn.keys.signer` in `container`; null, and nothing registered, when it is null. */
36
+ async function registerJwsSigner(container) {
37
+ const configuration = await container.resolve(configuration_1.Configuration);
38
+ const config = configuration.get('authn.keys.signer', null);
39
+ if (!config) {
40
+ return null;
41
+ }
42
+ let signer;
43
+ try {
44
+ signer = new signer_js_1.LocalJwsSigner(config.keys.map(privateJwkOf), { current: config.current });
45
+ }
46
+ catch (e) {
47
+ throw e instanceof exceptions_1.InvalidArgument ? new exceptions_1.InvalidOption(`authn.keys.signer: ${e.message}`) : e;
48
+ }
49
+ container.register({ ConfiguredJwsSigner: () => signer }.ConfiguredJwsSigner).as(contracts_1.JwsSigner);
50
+ return signer;
51
+ }
52
+ /** Registers the configured JwsSigner at boot, so the JWKS route and the verifiers' key lookup find it. */
53
+ let AuthnKeysSignerBootstrapper = class AuthnKeysSignerBootstrapper extends di_1.Bootstrapper {
54
+ async bootstrap() {
55
+ await registerJwsSigner(this.Container);
56
+ }
57
+ };
58
+ exports.AuthnKeysSignerBootstrapper = AuthnKeysSignerBootstrapper;
59
+ __decorate([
60
+ (0, di_1.Autoinject)(di_1.Container),
61
+ __metadata("design:type", Object)
62
+ ], AuthnKeysSignerBootstrapper.prototype, "Container", void 0);
63
+ exports.AuthnKeysSignerBootstrapper = AuthnKeysSignerBootstrapper = __decorate([
64
+ (0, di_1.Injectable)(di_1.Bootstrapper)
65
+ ], AuthnKeysSignerBootstrapper);
66
+ //# sourceMappingURL=register.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"register.js","sourceRoot":"","sources":["../../../src/jws/register.ts"],"names":[],"mappings":";;;;;;;;;;;;;AAAA,oCAA8E;AAE9E,0DAAuD;AACvD,wDAAqD;AACrD,oDAAqE;AACrE,wCAA8C;AAE9C,iCAA+B;AAC/B,2CAA6C;AAU7C,gEAAgE;AAChE,SAAS,YAAY,CAAC,MAAc,EAAE,KAAa;IACjD,IAAI,GAAY,CAAC;IACjB,IAAI,CAAC;QACH,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IAC3B,CAAC;IAAC,MAAM,CAAC;QACP,GAAG,GAAG,SAAS,CAAC;IAClB,CAAC;IACD,IAAI,CAAC,IAAA,oBAAa,EAAC,GAAG,CAAC,EAAE,CAAC;QACxB,MAAM,IAAI,0BAAa,CAAC,0BAA0B,KAAK,qDAAqD,CAAC,CAAC;IAChH,CAAC;IACD,OAAO,GAA4B,CAAC;AACtC,CAAC;AAED,0HAA0H;AACnH,KAAK,4BAA4B,SAAqB;IAC3D,MAAM,aAAa,GAAG,MAAM,SAAS,CAAC,OAAO,CAAC,6BAAa,CAAC,CAAC;IAC7D,MAAM,MAAM,GAAG,aAAa,CAAC,GAAG,CAAsB,mBAAmB,EAAE,IAAI,CAAC,CAAC;IACjF,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,OAAO,IAAI,CAAC;IACd,CAAC;IAED,IAAI,MAAsB,CAAC;IAC3B,IAAI,CAAC;QACH,MAAM,GAAG,IAAI,0BAAc,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,YAAY,CAAC,EAAE,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC;IAC1F,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,MAAM,CAAC,YAAY,4BAAe,CAAC,CAAC,CAAC,IAAI,0BAAa,CAAC,sBAAsB,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAChG,CAAC;IACD,SAAS,CAAC,QAAQ,CAAC,EAAE,mBAAmB,EAAE,GAAG,EAAE,CAAC,MAAM,EAAE,CAAC,mBAAmB,CAAC,CAAC,EAAE,CAAC,qBAAS,CAAC,CAAC;IAC5F,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,2GAA2G;AAEpG,IAAM,2BAA2B,GAAjC,MAAM,2BAA4B,SAAQ,iBAAY;IAIpD,KAAK,CAAC,SAAS;QACpB,MAAM,iBAAiB,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IAC1C,CAAC;CACF,CAAA;;AALW;IADT,IAAA,eAAU,EAAC,cAAS,CAAC;;8DACW;sCAFtB,2BAA2B;IADvC,IAAA,eAAU,EAAC,iBAAY,CAAC;GACZ,2BAA2B,CAOvC"}
@@ -1,3 +1,2 @@
1
1
  export * from './AuthnKey.js';
2
- export * from './AuthnNonce.js';
3
2
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/models/index.ts"],"names":[],"mappings":"AAAA,cAAc,eAAe,CAAC;AAC9B,cAAc,iBAAiB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/models/index.ts"],"names":[],"mappings":"AAAA,cAAc,eAAe,CAAC"}
@@ -15,5 +15,4 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
17
  __exportStar(require("./AuthnKey.js"), exports);
18
- __exportStar(require("./AuthnNonce.js"), exports);
19
18
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/models/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,gDAA8B;AAC9B,kDAAgC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/models/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,gDAA8B"}
@@ -17,7 +17,16 @@ export interface KeysConfig {
17
17
  readonly skewSeconds: number;
18
18
  readonly requiredComponents: readonly string[];
19
19
  };
20
+ /** Absent: {@link DEFAULT_KEY_CACHE}. */
21
+ readonly cache?: KeyCacheOptions;
20
22
  }
23
+ /** `authn.keys.cache`: how long `KeyRegistry.byId` serves a key from memory. */
24
+ export interface KeyCacheOptions {
25
+ /** 0 turns the cache off. */
26
+ readonly ttlSeconds: number;
27
+ readonly maxEntries: number;
28
+ }
29
+ export declare const DEFAULT_KEY_CACHE: KeyCacheOptions;
21
30
  /** `authn.keys` (design §22.5) after defaults. */
22
31
  export interface KeysOptions {
23
32
  readonly algorithms: readonly KeyAlgorithm[];
@@ -38,6 +47,7 @@ export interface KeysOptions {
38
47
  readonly skewSeconds: number;
39
48
  readonly requiredComponents: readonly string[];
40
49
  };
50
+ readonly cache: KeyCacheOptions;
41
51
  }
42
52
  /**
43
53
  * The options of a validated `authn.keys`: frozen, with the challenge audience falling back to the assertion audience.
@@ -1 +1 @@
1
- {"version":3,"file":"options.d.ts","sourceRoot":"","sources":["../../../src/options/options.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAG7D,4DAA4D;AAC5D,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,UAAU,EAAE,SAAS,YAAY,EAAE,CAAC;IAC7C,QAAQ,CAAC,SAAS,EAAE;QAAE,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,CAAC;IACtF,QAAQ,CAAC,SAAS,EAAE;QAAE,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,QAAQ,CAAC,kBAAkB,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;KAAE,CAAC;IAClJ,QAAQ,CAAC,aAAa,EAAE;QAAE,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,kBAAkB,EAAE,SAAS,MAAM,EAAE,CAAA;KAAE,CAAC;CAC1I;AAED,kDAAkD;AAClD,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,UAAU,EAAE,SAAS,YAAY,EAAE,CAAC;IAC7C,QAAQ,CAAC,SAAS,EAAE;QAClB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;QAC5B,iHAAiH;QACjH,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;KAClC,CAAC;IACF,QAAQ,CAAC,SAAS,EAAE;QAClB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;QACrB,gEAAgE;QAChE,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;QACjC,QAAQ,CAAC,kBAAkB,EAAE,MAAM,CAAC;QACpC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;KAC9B,CAAC;IACF,QAAQ,CAAC,aAAa,EAAE;QACtB,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;QAC/B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;QAC7B,QAAQ,CAAC,kBAAkB,EAAE,SAAS,MAAM,EAAE,CAAC;KAChD,CAAC;CACH;AAuBD;;;GAGG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,UAAU,GAAG,WAAW,CAc7D"}
1
+ {"version":3,"file":"options.d.ts","sourceRoot":"","sources":["../../../src/options/options.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAG7D,4DAA4D;AAC5D,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,UAAU,EAAE,SAAS,YAAY,EAAE,CAAC;IAC7C,QAAQ,CAAC,SAAS,EAAE;QAAE,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,CAAC;IACtF,QAAQ,CAAC,SAAS,EAAE;QAAE,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,QAAQ,CAAC,kBAAkB,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;KAAE,CAAC;IAClJ,QAAQ,CAAC,aAAa,EAAE;QAAE,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,kBAAkB,EAAE,SAAS,MAAM,EAAE,CAAA;KAAE,CAAC;IACzI,yCAAyC;IACzC,QAAQ,CAAC,KAAK,CAAC,EAAE,eAAe,CAAC;CAClC;AAED,gFAAgF;AAChF,MAAM,WAAW,eAAe;IAC9B,6BAA6B;IAC7B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;CAC7B;AAED,eAAO,MAAM,iBAAiB,EAAE,eAAuE,CAAC;AAExG,kDAAkD;AAClD,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,UAAU,EAAE,SAAS,YAAY,EAAE,CAAC;IAC7C,QAAQ,CAAC,SAAS,EAAE;QAClB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;QAC5B,iHAAiH;QACjH,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;KAClC,CAAC;IACF,QAAQ,CAAC,SAAS,EAAE;QAClB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;QACrB,gEAAgE;QAChE,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;QACjC,QAAQ,CAAC,kBAAkB,EAAE,MAAM,CAAC;QACpC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;KAC9B,CAAC;IACF,QAAQ,CAAC,aAAa,EAAE;QACtB,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;QAC/B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;QAC7B,QAAQ,CAAC,kBAAkB,EAAE,SAAS,MAAM,EAAE,CAAC;KAChD,CAAC;IACF,QAAQ,CAAC,KAAK,EAAE,eAAe,CAAC;CACjC;AA6BD;;;GAGG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,UAAU,GAAG,WAAW,CAe7D"}
@@ -1,7 +1,9 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DEFAULT_KEY_CACHE = void 0;
3
4
  exports.keysOptionsOf = keysOptionsOf;
4
5
  const exceptions_1 = require("@spinajs/exceptions");
6
+ exports.DEFAULT_KEY_CACHE = Object.freeze({ ttlSeconds: 10, maxEntries: 10_000 });
5
7
  const derived = new WeakMap();
6
8
  const RANGES = [
7
9
  ['challenge', 'ttlSeconds', 1, 3600],
@@ -19,6 +21,12 @@ function checkRanges(config) {
19
21
  throw new exceptions_1.InvalidOption(`authn.keys.${block}.${key} must be an integer from ${min} to ${max}`);
20
22
  }
21
23
  }
24
+ if (config.cache !== undefined) {
25
+ const { ttlSeconds, maxEntries } = config.cache;
26
+ if (!(Number.isInteger(ttlSeconds) && ttlSeconds >= 0 && Number.isInteger(maxEntries) && maxEntries >= 1)) {
27
+ throw new exceptions_1.InvalidOption('authn.keys.cache needs an integer ttlSeconds >= 0 and an integer maxEntries >= 1');
28
+ }
29
+ }
22
30
  }
23
31
  /**
24
32
  * The options of a validated `authn.keys`: frozen, with the challenge audience falling back to the assertion audience.
@@ -33,6 +41,7 @@ function keysOptionsOf(config) {
33
41
  challenge: Object.freeze({ ttlSeconds: config.challenge.ttlSeconds, audience: config.challenge.audience ?? config.assertion.audience }),
34
42
  assertion: Object.freeze({ ...config.assertion }),
35
43
  httpSignature: Object.freeze({ ...config.httpSignature, requiredComponents: Object.freeze([...config.httpSignature.requiredComponents]) }),
44
+ cache: Object.freeze({ ...exports.DEFAULT_KEY_CACHE, ...config.cache }),
36
45
  });
37
46
  derived.set(config, options);
38
47
  derived.set(options, options);
@@ -1 +1 @@
1
- {"version":3,"file":"options.js","sourceRoot":"","sources":["../../../src/options/options.ts"],"names":[],"mappings":";;;AACA,oDAAoD;AAgCpD,MAAM,OAAO,GAAG,IAAI,OAAO,EAAuB,CAAC;AAEnD,MAAM,MAAM,GAAsH;IAChI,CAAC,WAAW,EAAE,YAAY,EAAE,CAAC,EAAE,IAAI,CAAC;IACpC,CAAC,WAAW,EAAE,oBAAoB,EAAE,CAAC,EAAE,GAAG,CAAC;IAC3C,CAAC,WAAW,EAAE,aAAa,EAAE,CAAC,EAAE,GAAG,CAAC;IACpC,CAAC,eAAe,EAAE,eAAe,EAAE,CAAC,EAAE,GAAG,CAAC;IAC1C,CAAC,eAAe,EAAE,aAAa,EAAE,CAAC,EAAE,GAAG,CAAC;CACzC,CAAC;AAEF,4GAA4G;AAC5G,wFAAwF;AACxF,SAAS,WAAW,CAAC,MAAkB;IACrC,KAAK,MAAM,CAAC,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,IAAI,MAAM,EAAE,CAAC;QAC5C,MAAM,KAAK,GAAa,MAAM,CAAC,KAAK,CAAoD,EAAE,CAAC,GAAG,CAAC,CAAC;QAChG,IAAI,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,IAAK,KAAgB,IAAI,GAAG,IAAK,KAAgB,IAAI,GAAG,CAAC,EAAE,CAAC;YACvF,MAAM,IAAI,0BAAa,CAAC,cAAc,KAAK,IAAI,GAAG,4BAA4B,GAAG,OAAO,GAAG,EAAE,CAAC,CAAC;QACjG,CAAC;IACH,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,uBAA8B,MAAkB;IAC9C,IAAI,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IAClC,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,WAAW,CAAC,MAAM,CAAC,CAAC;QACpB,OAAO,GAAG,MAAM,CAAC,MAAM,CAAC;YACtB,UAAU,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,MAAM,CAAC,UAAU,CAAC,CAAC;YACjD,SAAS,EAAE,MAAM,CAAC,MAAM,CAAC,EAAE,UAAU,EAAE,MAAM,CAAC,SAAS,CAAC,UAAU,EAAE,QAAQ,EAAE,MAAM,CAAC,SAAS,CAAC,QAAQ,IAAI,MAAM,CAAC,SAAS,CAAC,QAAQ,EAAE,CAAC;YACvI,SAAS,EAAE,MAAM,CAAC,MAAM,CAAC,EAAE,GAAG,MAAM,CAAC,SAAS,EAAE,CAAC;YACjD,aAAa,EAAE,MAAM,CAAC,MAAM,CAAC,EAAE,GAAG,MAAM,CAAC,aAAa,EAAE,kBAAkB,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,MAAM,CAAC,aAAa,CAAC,kBAAkB,CAAC,CAAC,EAAE,CAAC;SAC3I,CAAC,CAAC;QACH,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QAC7B,OAAO,CAAC,GAAG,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IAChC,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC"}
1
+ {"version":3,"file":"options.js","sourceRoot":"","sources":["../../../src/options/options.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ import type { CredentialChangeBus, IdentityRef, KeyRecord } from '@spinajs/authn/contracts';
2
+ import type { KeyCacheOptions } from '../options/options.js';
3
+ import { KeyStore } from './store.js';
4
+ /**
5
+ * A KeyStore whose `get` is served from memory for `ttlSeconds`. Every write through it and every change the bus
6
+ * delivers evicts; a key revoked in another process is seen within the ttl. Unknown kids are never cached.
7
+ */
8
+ export declare class CachedKeyStore extends KeyStore {
9
+ protected readonly inner: KeyStore;
10
+ protected readonly options: KeyCacheOptions;
11
+ protected readonly bus?: CredentialChangeBus | undefined;
12
+ private readonly keys;
13
+ /** Bumped by every eviction: a read that started before it must not store what it read. */
14
+ private epoch;
15
+ private readonly unsubscribe;
16
+ constructor(inner: KeyStore, options: KeyCacheOptions, bus?: CredentialChangeBus | undefined);
17
+ insert(key: KeyRecord): Promise<'inserted' | 'duplicate'>;
18
+ get(kid: string): Promise<KeyRecord | null>;
19
+ listByOwner(owner: IdentityRef): Promise<readonly KeyRecord[]>;
20
+ revoke(owner: IdentityRef, kid: string, at: Date): Promise<'revoked' | 'already' | 'none'>;
21
+ touch(kid: string, at: Date): Promise<void>;
22
+ /** Stops listening to the bus. */
23
+ dispose(): Promise<void>;
24
+ private evict;
25
+ }
26
+ //# sourceMappingURL=cache.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../../../src/registry/cache.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,mBAAmB,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AAG5F,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAC7D,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAEtC;;;GAGG;AACH,qBAAa,cAAe,SAAQ,QAAQ;IAOxC,SAAS,CAAC,QAAQ,CAAC,KAAK,EAAE,QAAQ;IAClC,SAAS,CAAC,QAAQ,CAAC,OAAO,EAAE,eAAe;IAC3C,SAAS,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,mBAAmB;IAR9C,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAwC;IAC7D,2FAA2F;IAC3F,OAAO,CAAC,KAAK,CAAK;IAClB,OAAO,CAAC,QAAQ,CAAC,WAAW,CAA2B;IAEvD,YACqB,KAAK,EAAE,QAAQ,EACf,OAAO,EAAE,eAAe,EACxB,GAAG,CAAC,EAAE,mBAAmB,YAAA,EAK7C;IAEY,MAAM,CAAC,GAAG,EAAE,SAAS,GAAG,OAAO,CAAC,UAAU,GAAG,WAAW,CAAC,CAMrE;IAEY,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC,CAWvD;IAEM,WAAW,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO,CAAC,SAAS,SAAS,EAAE,CAAC,CAEpE;IAEY,MAAM,CAAC,KAAK,EAAE,WAAW,EAAE,GAAG,EAAE,MAAM,EAAE,EAAE,EAAE,IAAI,GAAG,OAAO,CAAC,SAAS,GAAG,SAAS,GAAG,MAAM,CAAC,CAMtG;IAEY,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,EAAE,EAAE,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAMvD;IAED,kCAAkC;IAC3B,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAI9B;IAED,OAAO,CAAC,KAAK;CAId"}
@@ -0,0 +1,73 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.CachedKeyStore = void 0;
4
+ const bus_1 = require("@spinajs/authn/bus");
5
+ const util_1 = require("@spinajs/util");
6
+ const store_js_1 = require("./store.js");
7
+ /**
8
+ * A KeyStore whose `get` is served from memory for `ttlSeconds`. Every write through it and every change the bus
9
+ * delivers evicts; a key revoked in another process is seen within the ttl. Unknown kids are never cached.
10
+ */
11
+ class CachedKeyStore extends store_js_1.KeyStore {
12
+ constructor(inner, options, bus) {
13
+ super();
14
+ this.inner = inner;
15
+ this.options = options;
16
+ this.bus = bus;
17
+ /** Bumped by every eviction: a read that started before it must not store what it read. */
18
+ this.epoch = 0;
19
+ this.keys = options.ttlSeconds > 0 ? new util_1.LruTtlCache({ maxEntries: options.maxEntries, ttlMs: options.ttlSeconds * 1000, expireOnClockRewind: true }) : null;
20
+ this.unsubscribe = this.keys && bus ? bus.subscribe((change) => this.evict((0, bus_1.credentialChangeTags)(change))) : undefined;
21
+ }
22
+ async insert(key) {
23
+ try {
24
+ return await this.inner.insert(key);
25
+ }
26
+ finally {
27
+ this.evict([(0, bus_1.credentialTag)('key', key.kid)]);
28
+ }
29
+ }
30
+ async get(kid) {
31
+ const cached = this.keys?.get(kid);
32
+ if (cached !== undefined) {
33
+ return cached;
34
+ }
35
+ const since = this.epoch;
36
+ const key = await this.inner.get(kid);
37
+ if (key !== null && this.keys !== null && since === this.epoch) {
38
+ this.keys.set(kid, key, { tags: [(0, bus_1.credentialTag)('key', kid), (0, bus_1.identityTag)(key.owner)] });
39
+ }
40
+ return key;
41
+ }
42
+ listByOwner(owner) {
43
+ return this.inner.listByOwner(owner);
44
+ }
45
+ async revoke(owner, kid, at) {
46
+ try {
47
+ return await this.inner.revoke(owner, kid, at);
48
+ }
49
+ finally {
50
+ this.evict([(0, bus_1.credentialTag)('key', kid)]);
51
+ }
52
+ }
53
+ async touch(kid, at) {
54
+ try {
55
+ await this.inner.touch(kid, at);
56
+ }
57
+ finally {
58
+ this.evict([(0, bus_1.credentialTag)('key', kid)]);
59
+ }
60
+ }
61
+ /** Stops listening to the bus. */
62
+ dispose() {
63
+ this.unsubscribe?.();
64
+ this.keys?.clear();
65
+ return Promise.resolve();
66
+ }
67
+ evict(tags) {
68
+ this.epoch++;
69
+ this.keys?.invalidate(tags);
70
+ }
71
+ }
72
+ exports.CachedKeyStore = CachedKeyStore;
73
+ //# sourceMappingURL=cache.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cache.js","sourceRoot":"","sources":["../../../src/registry/cache.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,5 @@
1
1
  export * from './store.js';
2
2
  export * from './orm-store.js';
3
+ export * from './cache.js';
3
4
  export * from './registry.js';
4
5
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/registry/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,eAAe,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/registry/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,YAAY,CAAC;AAC3B,cAAc,eAAe,CAAC"}
@@ -16,5 +16,6 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
17
  __exportStar(require("./store.js"), exports);
18
18
  __exportStar(require("./orm-store.js"), exports);
19
+ __exportStar(require("./cache.js"), exports);
19
20
  __exportStar(require("./registry.js"), exports);
20
21
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/registry/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,6CAA2B;AAC3B,iDAA+B;AAC/B,gDAA8B"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/registry/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,6CAA2B;AAC3B,iDAA+B;AAC/B,6CAA2B;AAC3B,gDAA8B"}
@@ -1,8 +1,10 @@
1
1
  import '../register-schema.js';
2
2
  import { AuthnAudit } from '@spinajs/authn/audit';
3
+ import '@spinajs/authn/bus';
3
4
  import type { AuthnAuditor, AuthnEventBody } from '@spinajs/authn/audit';
4
- import { AuthnThrottle, KeyRegistry, SecretStore } from '@spinajs/authn/contracts';
5
+ import { AuthnThrottle, CredentialChangeBus, KeyRegistry, SecretStore } from '@spinajs/authn/contracts';
5
6
  import type { AuthnContext, IdentityRef, KeyChallengeRequest, KeyChallengeResult, KeyMaterial, KeyOwner, KeyRecord, KeyRegisterResult, KeyRegistration, PrincipalRef } from '@spinajs/authn/contracts';
7
+ import { Log } from '@spinajs/log';
6
8
  import type { KeysConfig, KeysOptions } from '../options/options.js';
7
9
  import { KeyStore } from './store.js';
8
10
  /** Usable for verification: neither revoked nor expired at `now`. */
@@ -21,8 +23,13 @@ export interface DefaultKeyRegistryDeps {
21
23
  readonly audit?: AuthnAuditor;
22
24
  /** Complete options that bypass the configuration. */
23
25
  readonly options?: KeysOptions;
26
+ /** Told about revoked keys, and evicts the key cache; otherwise the registered CredentialChangeBus. */
27
+ readonly bus?: CredentialChangeBus;
24
28
  }
25
- /** KeyRegistry over a KeyStore, challenges in SecretStore (lane notes D7, D12). */
29
+ /**
30
+ * KeyRegistry over a KeyStore, challenges in SecretStore (lane notes D7, D12). The store is wrapped in a
31
+ * {@link CachedKeyStore} unless `authn.keys.cache.ttlSeconds` is 0.
32
+ */
26
33
  export declare class DefaultKeyRegistry extends KeyRegistry {
27
34
  protected readonly Deps?: DefaultKeyRegistryDeps | undefined;
28
35
  protected KeysConfig: KeysConfig;
@@ -30,11 +37,15 @@ export declare class DefaultKeyRegistry extends KeyRegistry {
30
37
  protected Store: KeyStore;
31
38
  protected Secrets: SecretStore;
32
39
  protected Throttle: AuthnThrottle;
40
+ protected Bus: CredentialChangeBus | undefined;
41
+ protected Log: Log;
42
+ private cached;
33
43
  private readonly stamped;
34
44
  /** Kids whose last stamp is remembered; past this the least recently stamped is forgotten and costs one extra write. */
35
45
  protected readonly maxStamped: number;
36
46
  constructor(Deps?: DefaultKeyRegistryDeps | undefined);
37
47
  protected get store(): KeyStore;
48
+ protected get bus(): CredentialChangeBus | undefined;
38
49
  protected get secrets(): SecretStore;
39
50
  protected get throttle(): AuthnThrottle;
40
51
  protected get options(): KeysOptions;
@@ -46,6 +57,8 @@ export declare class DefaultKeyRegistry extends KeyRegistry {
46
57
  revoke(owner: IdentityRef, kid: string, ctx: AuthnContext, opts?: {
47
58
  readonly actor?: PrincipalRef;
48
59
  }): Promise<boolean>;
60
+ /** The store already evicted its own cache; this tells the other caches of the process. */
61
+ protected changed(kid: string): Promise<void>;
49
62
  byId(kid: string): Promise<KeyRecord | null>;
50
63
  /** Stamps last_used_at after a successful verification, at most once a minute per key so busy clients write little. */
51
64
  touch(kid: string, at: Date): Promise<void>;
@@ -1 +1 @@
1
- {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../../src/registry/registry.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../../src/registry/registry.ts"],"names":[],"mappings":"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"}
@@ -15,12 +15,16 @@ const di_1 = require("@spinajs/di");
15
15
  const configuration_1 = require("@spinajs/configuration");
16
16
  require("../register-schema.js");
17
17
  const audit_1 = require("@spinajs/authn/audit");
18
+ // Registers the default CredentialChangeBus.
19
+ require("@spinajs/authn/bus");
18
20
  const contracts_1 = require("@spinajs/authn/contracts");
19
21
  const util_1 = require("@spinajs/util");
20
22
  const exceptions_1 = require("@spinajs/exceptions");
23
+ const log_1 = require("@spinajs/log");
21
24
  const challenge_js_1 = require("../challenge/challenge.js");
22
25
  const keys_js_1 = require("../jwk/keys.js");
23
26
  const options_js_1 = require("../options/options.js");
27
+ const cache_js_1 = require("./cache.js");
24
28
  const store_js_1 = require("./store.js");
25
29
  const OWNER_TYPES = ['user', 'service', 'agent'];
26
30
  const MAX_OWNER_ID = 64;
@@ -67,7 +71,10 @@ exports.isUsableKey = isUsableKey;
67
71
  */
68
72
  const loginChallengeIdentity = (kid) => ({ type: 'key', id: (0, keys_js_1.isValidKid)(kid) ? kid : (0, node_crypto_1.createHash)('sha256').update(kid, 'utf8').digest('hex') });
69
73
  exports.loginChallengeIdentity = loginChallengeIdentity;
70
- /** KeyRegistry over a KeyStore, challenges in SecretStore (lane notes D7, D12). */
74
+ /**
75
+ * KeyRegistry over a KeyStore, challenges in SecretStore (lane notes D7, D12). The store is wrapped in a
76
+ * {@link CachedKeyStore} unless `authn.keys.cache.ttlSeconds` is 0.
77
+ */
71
78
  let DefaultKeyRegistry = class DefaultKeyRegistry extends contracts_1.KeyRegistry {
72
79
  constructor(Deps) {
73
80
  super();
@@ -77,7 +84,15 @@ let DefaultKeyRegistry = class DefaultKeyRegistry extends contracts_1.KeyRegistr
77
84
  this.maxStamped = 10_000;
78
85
  }
79
86
  get store() {
80
- return this.Deps?.store ?? this.Store;
87
+ const inner = this.Deps?.store ?? this.Store;
88
+ if (this.cached?.inner !== inner) {
89
+ const cache = this.options.cache ?? options_js_1.DEFAULT_KEY_CACHE;
90
+ this.cached = { inner, store: cache.ttlSeconds > 0 ? new cache_js_1.CachedKeyStore(inner, cache, this.bus) : inner };
91
+ }
92
+ return this.cached.store;
93
+ }
94
+ get bus() {
95
+ return this.Deps?.bus ?? this.Bus;
81
96
  }
82
97
  get secrets() {
83
98
  return this.Deps?.secrets ?? this.Secrets;
@@ -160,12 +175,22 @@ let DefaultKeyRegistry = class DefaultKeyRegistry extends contracts_1.KeyRegistr
160
175
  if (done === 'none') {
161
176
  return false;
162
177
  }
178
+ await this.changed(kid);
163
179
  if (done === 'already') {
164
180
  return true;
165
181
  }
166
182
  await this.publish(ctx, { type: 'key.revoke', outcome: 'success', identity: owner, ...(opts?.actor ? { actor: opts.actor } : {}), data: { kid } });
167
183
  return true;
168
184
  }
185
+ /** The store already evicted its own cache; this tells the other caches of the process. */
186
+ async changed(kid) {
187
+ try {
188
+ await this.bus?.publish({ kind: 'key', id: kid });
189
+ }
190
+ catch (err) {
191
+ this.Log.error({ error: err, kid }, 'Could not publish the revoke of key ${kid}');
192
+ }
193
+ }
169
194
  async byId(kid) {
170
195
  return (0, keys_js_1.isValidKid)(kid) ? this.store.get(kid) : null;
171
196
  }
@@ -237,6 +262,14 @@ __decorate([
237
262
  (0, di_1.Autoinject)(contracts_1.AuthnThrottle),
238
263
  __metadata("design:type", contracts_1.AuthnThrottle)
239
264
  ], DefaultKeyRegistry.prototype, "Throttle", void 0);
265
+ __decorate([
266
+ (0, di_1.Autoinject)(contracts_1.CredentialChangeBus, { optional: true }),
267
+ __metadata("design:type", Object)
268
+ ], DefaultKeyRegistry.prototype, "Bus", void 0);
269
+ __decorate([
270
+ (0, log_1.Logger)('authn-keys'),
271
+ __metadata("design:type", log_1.Log)
272
+ ], DefaultKeyRegistry.prototype, "Log", void 0);
240
273
  exports.DefaultKeyRegistry = DefaultKeyRegistry = __decorate([
241
274
  (0, di_1.Injectable)(contracts_1.KeyRegistry),
242
275
  __metadata("design:paramtypes", [Object])