@nxgt/janus 0.5.0 → 0.7.0

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 (48) hide show
  1. package/README.md +116 -23
  2. package/dist/auth/config.d.ts +3 -0
  3. package/dist/auth/config.d.ts.map +1 -1
  4. package/dist/auth/context.d.ts +12 -0
  5. package/dist/auth/context.d.ts.map +1 -1
  6. package/dist/auth/email-flows.d.ts +11 -0
  7. package/dist/auth/email-flows.d.ts.map +1 -0
  8. package/dist/auth/index.d.ts +1 -1
  9. package/dist/auth/index.d.ts.map +1 -1
  10. package/dist/auth/one-time.d.ts +66 -6
  11. package/dist/auth/one-time.d.ts.map +1 -1
  12. package/dist/auth/password-written.d.ts +24 -0
  13. package/dist/auth/password-written.d.ts.map +1 -0
  14. package/dist/auth/port/assert-stores.d.ts.map +1 -1
  15. package/dist/auth/port/types.d.ts +23 -1
  16. package/dist/auth/port/types.d.ts.map +1 -1
  17. package/dist/auth/second-factor/challenge.d.ts +0 -6
  18. package/dist/auth/second-factor/challenge.d.ts.map +1 -1
  19. package/dist/auth/second-factor/factor.d.ts +1 -4
  20. package/dist/auth/second-factor/factor.d.ts.map +1 -1
  21. package/dist/auth/second-factor/flows.d.ts +7 -3
  22. package/dist/auth/second-factor/flows.d.ts.map +1 -1
  23. package/dist/auth/second-factor/lifecycle.d.ts.map +1 -1
  24. package/dist/auth/sign-in-code.d.ts +20 -0
  25. package/dist/auth/sign-in-code.d.ts.map +1 -0
  26. package/dist/auth/types.d.ts +56 -1
  27. package/dist/auth/types.d.ts.map +1 -1
  28. package/dist/auth/users.d.ts +2 -2
  29. package/dist/auth/users.d.ts.map +1 -1
  30. package/dist/chunks/{index-gbwn2tts.js → index-c0jajeda.js} +12 -2
  31. package/dist/chunks/{index-gbwn2tts.js.map → index-c0jajeda.js.map} +3 -3
  32. package/dist/conformance/cases/outage.d.ts.map +1 -1
  33. package/dist/conformance/cases/tokens.d.ts.map +1 -1
  34. package/dist/conformance/index.js +73 -2
  35. package/dist/conformance/index.js.map +4 -4
  36. package/dist/index.js +253 -116
  37. package/dist/index.js.map +15 -12
  38. package/docs/README.md +2 -1
  39. package/docs/guide/adapters.md +56 -3
  40. package/docs/guide/email-flows.md +11 -1
  41. package/docs/guide/errors.md +3 -3
  42. package/docs/guide/second-factor.md +31 -4
  43. package/docs/guide/sign-in-code.md +489 -0
  44. package/docs/guide/users.md +5 -4
  45. package/docs/guide/vocabulary.md +7 -6
  46. package/docs/roadmap.md +28 -13
  47. package/docs/troubleshooting.md +193 -28
  48. package/package.json +1 -1
package/README.md CHANGED
@@ -46,7 +46,7 @@ a published entry point is a promise.
46
46
  ## Three ways to use it
47
47
 
48
48
  Janus has two sides. **Identities** answers *who is this?* — users, their
49
- logins and passwords, a TOTP second factor, sessions, one-time tokens. **Permissions** answers *may
49
+ logins and passwords, codes sent by e-mail, a TOTP second factor, sessions, one-time tokens. **Permissions** answers *may
50
50
  they?* — a model, the tuples stored against it, and `can`. Each side is usable
51
51
  alone, and neither loads the other's code: a spec reads the import graph of
52
52
  each entry point and fails if one reaches into the other.
@@ -177,7 +177,7 @@ compilation of callers that exhaust it:
177
177
  | `USER_INVALID` | 400, field by field from `issues` |
178
178
  | `PASSWORD_TOO_SHORT`, `HASH_UNSUPPORTED` | 400 |
179
179
  | `CREDENTIALS_INVALID` | 401 — one code for an unknown login, no password and a wrong one |
180
- | `CODE_INVALID` | 401 — a second factor's code that does not match or was already accepted; `attemptsLeft` from `confirm` belongs in the body |
180
+ | `CODE_INVALID` | 401 — a one-time code that does not match: a second factor's, or one sent by e-mail; `attemptsLeft` from either `confirm` belongs in the body |
181
181
  | `SECOND_FACTOR_NOT_ENROLLED`, `SECOND_FACTOR_ACTIVE` | 409 — the factor is not in the state the call needs |
182
182
  | `USER_INACTIVE` | 403 |
183
183
  | `TOKEN_UNKNOWN`, `TOKEN_SPENT`, `TOKEN_EXPIRED`, `TOKEN_STALE` | 400 |
@@ -311,6 +311,8 @@ await auth.verifyEmail.send(user); // { token, email, expiresAt
311
311
  await auth.verifyEmail.confirm(token);
312
312
  await auth.resetPassword.request(email); // … | null
313
313
  await auth.resetPassword.confirm(token, newPassword);
314
+ await auth.signInCode.request(email); // { code, challenge, email, expiresAt, user } | null
315
+ await auth.signInCode.confirm(challenge, code); // { status: 'signedIn', user, session, token }
314
316
 
315
317
  // Several user types
316
318
  const clinic = janus({
@@ -351,8 +353,9 @@ else reaches the store and is asynchronous.
351
353
  compile error on `login`, and the message lists the fields you could have
352
354
  meant. It is normalised with `'lowercaseTrim'` unless you say otherwise.
353
355
  - **`email`** defaults to the field named `email`. A type without one has no
354
- `verifyEmail` and no `resetPassword` — they are absent from its type, not
355
- failing at run time. Changing the e-mail sets `emailVerified` back to `false`.
356
+ `verifyEmail`, no `resetPassword` and no `signInCode` — they are absent from
357
+ its type, not failing at run time. Changing the e-mail sets `emailVerified`
358
+ back to `false`.
356
359
  - **Per type**: `create`, `find` (or `null`), `get` (or `NOT_FOUND`), `list`,
357
360
  `update(user, patch)` — merged over the stored fields, then validated whole —
358
361
  `setActive` and `delete`; with a password, `signUp`, `signIn`, `findByLogin`,
@@ -426,10 +429,38 @@ await tokens.countAttempt(tokenHash, 'signInCode'); // { …, attempts: 1 }
426
429
  await tokens.countAttempt(tokenHash, 'verifyEmail'); // null: no token of that kind
427
430
  ```
428
431
 
432
+ `spendUserTokens(userId, kind, at, except?)` spends the unspent tokens of one
433
+ user and one kind — but the one whose hash is `except` — and answers how many:
434
+ what issuing a sign-in code and writing a password call:
435
+
436
+ ```ts
437
+ const userId = mintId();
438
+ const now = new Date();
439
+ const code = (tokenHash: string) => ({
440
+ tokenHash,
441
+ kind: 'signInCode' as const,
442
+ userId,
443
+ address: 'ada@example.test',
444
+ codeHash: 'c'.repeat(64),
445
+ attempts: 0,
446
+ expiresAt: new Date(now.getTime() + 10 * 60_000),
447
+ spentAt: null,
448
+ createdAt: now,
449
+ });
450
+ const kept = code('d'.repeat(64));
451
+ await tokens.insertToken(kept);
452
+ await tokens.insertToken(code('e'.repeat(64)));
453
+ await tokens.spendUserTokens(userId, 'signInCode', now, kept.tokenHash); // 1: the other one
454
+ await tokens.spendUserTokens(userId, 'signInCode', now); // 1: `kept`, now
455
+ await tokens.spendUserTokens(userId, 'signInCode', now); // 0: none left unspent
456
+ ```
457
+
429
458
  An adapter written against `@nxgt/janus` 0.3 does not compile against this
430
- port until it implements `countAttempt`, and `janus()` refuses it at wiring —
431
- [Writing an adapter](docs/guide/adapters.md#tokenstorecountattempt) has the
432
- contract.
459
+ port until it implements `countAttempt`, nor one written against 0.6 until it
460
+ implements `spendUserTokens`, and `janus()` refuses either at wiring —
461
+ [Writing an adapter](docs/guide/adapters.md) has the contracts:
462
+ [`countAttempt`](docs/guide/adapters.md#tokenstorecountattempt) and
463
+ [`spendUserTokens`](docs/guide/adapters.md#tokenstorespendusertokens).
433
464
 
434
465
  ### Second factor — `secondFactor`
435
466
 
@@ -465,7 +496,7 @@ every user type with a password.
465
496
 
466
497
  - **`signIn` answers a union once `secondFactor` is configured**:
467
498
  `{ status: 'signedIn', user, session, token }`, or
468
- `{ status: 'secondFactor', challenge, expiresAt }` for a user whose factor
499
+ `{ status: 'secondFactor', challenge, expiresAt, userId }` for a user whose factor
469
500
  is active. Switch on `status`: reading `token` before that is a compile
470
501
  error. Without `secondFactor`, `signIn` answers a session, as before.
471
502
  - **A factor is enrolled, then active.** `enroll` answers the secret and its
@@ -487,6 +518,48 @@ every user type with a password.
487
518
  error and state, key rotation, and a sign-in route with the challenge in a
488
519
  cookie.
489
520
 
521
+ ### Sign-in codes — `signInCode`
522
+
523
+ ```ts
524
+ import { z } from 'zod';
525
+ import { createMemoryStores, janus } from '@nxgt/janus';
526
+
527
+ const auth = janus({
528
+ user: z.object({ email: z.email(), name: z.string() }), // no password: codes only
529
+ store: createMemoryStores(),
530
+ });
531
+
532
+ const issued = await auth.signInCode.request(email); // null for nobody, or an inactive user
533
+ if (issued !== null) {
534
+ await sendMail(issued.email, `Your sign-in code: ${issued.code}`); // the code, and only the code
535
+ }
536
+ // answer the same page either way; keep issued.challenge with the visitor — a cookie, never a URL
537
+
538
+ const signedIn = await auth.signInCode.confirm(challenge, code); // { status: 'signedIn', user, session, token }
539
+ ```
540
+
541
+ A six-digit code sent to the user's e-mail signs them in, with no password.
542
+
543
+ - **On every user type with an e-mail**, with a password or without one. A
544
+ type with no password signs in by code alone; a type with no e-mail has no
545
+ `signInCode` at all.
546
+ - **`request(email)` answers `null`** when nobody of this type holds that
547
+ e-mail, or the user is inactive — never say which. It answers the `code`
548
+ for the e-mail and the `challenge` for the visitor; the code's hash is
549
+ stored, keyed by the challenge.
550
+ - **`confirm(challenge, code)`** marks the e-mail verified and opens the
551
+ session. A challenge lives `'10m'` (`tokens.signInCode`) and takes five
552
+ attempts: a wrong code is `CODE_INVALID` with `attemptsLeft`, and the fifth
553
+ spends it. An e-mail changed since is `TOKEN_STALE`; a user deactivated
554
+ since is `USER_INACTIVE`.
555
+ - **An active second factor is still asked for**: with `secondFactor`
556
+ configured, `confirm` answers `SignInResult` on a type with a password, and
557
+ a user whose factor is active gets a challenge for `secondFactor.confirm`
558
+ — switch on `status`, as after `signIn`.
559
+
560
+ [The sign-in code guide](docs/guide/sign-in-code.md) has the request that
561
+ tells nobody who exists, the challenge in a cookie, every error, and a test.
562
+
490
563
  ### Permissions — `@nxgt/janus/permissions`
491
564
 
492
565
  ```ts
@@ -597,7 +670,7 @@ describeJanusStores({
597
670
  });
598
671
  ```
599
672
 
600
- There are 45 cases. They cover:
673
+ There are 49 cases. They cover:
601
674
  - round-trip, byte for byte — including every edge character the core lets
602
675
  through (control characters, U+FFFF, a surrogate pair);
603
676
  - uniqueness, as a constraint: of twenty concurrent inserts of one login,
@@ -610,12 +683,15 @@ There are 45 cases. They cover:
610
683
  - one-time tokens: of twenty concurrent redemptions, exactly one succeeds;
611
684
  of twenty concurrent `countAttempt` calls, each answers a distinct count,
612
685
  and none is counted once a racing redemption spent the token;
686
+ - spending a user's tokens of one kind — `spendUserTokens` — spends only the
687
+ unspent ones of that user and kind, spares the one named by `except`, and
688
+ never spends the same token as a racing redemption;
613
689
  - a second-factor challenge, whose address is `''`, kept, counted and spent;
614
690
  - a user's second factor: round-trip, kept by a patch that does not name it,
615
691
  removed by one that names `null`;
616
692
  - deletion: a user's logins are freed, and every session and token of theirs
617
693
  goes, with a replay answering `false` or `0` rather than failing;
618
- - **outages**, one case for each of the twelve methods whose honest answer can
694
+ - **outages**, one case for each of the thirteen methods whose honest answer can
619
695
  be "nothing".
620
696
 
621
697
  The suite imports no test framework and no assertion library. It runs under
@@ -647,14 +723,29 @@ example; `allRelationCases`, `relationStoreCases`, `relationOutageCases` and
647
723
 
648
724
  ## Traps
649
725
 
650
- **Once `secondFactor` is configured, switch on `signIn`'s `status`.** A user
651
- whose factor is active gets `{ status: 'secondFactor', challenge }`, with no
652
- `token` and no `session`: `if (result.status === 'secondFactor') …` before
653
- anything reads them.
654
-
655
- **A challenge is a secret, like a session token.** Keep it in a short-lived
656
- `HttpOnly` cookie or the body of the code form — never in a URL, where logs,
657
- proxies and the `Referer` header see it, and never in a log.
726
+ **Once `secondFactor` is configured, switch on `signIn`'s `status`** — and
727
+ on `signInCode.confirm`'s. A user whose factor is active gets
728
+ `{ status: 'secondFactor', challenge, expiresAt, userId }`, with no `token`
729
+ and no `session`: an e-mailed code proves the e-mail, not the factor.
730
+ `userId` is for your logs and rate limits — answer the visitor the
731
+ challenge alone.
732
+ `if (result.status === 'secondFactor') …` before anything reads them.
733
+
734
+ **A challenge is a secret, like a session token** — `signIn`'s and
735
+ `signInCode.request`'s alike. Keep it in a short-lived `HttpOnly` cookie or
736
+ the body of the code form — never in the e-mail, never in a URL, where logs,
737
+ proxies and the `Referer` header see it, and never in a log. The e-mail holds
738
+ the code and nothing else.
739
+
740
+ **Answer `signInCode.request` the same whether it issued a code or not** —
741
+ the same status, body and cookie: set a random challenge when it answered
742
+ `null`. The code route then still tells a decoy (`TOKEN_UNKNOWN`) from a
743
+ real challenge (`CODE_INVALID`, `attemptsLeft`, or `TOKEN_SPENT` once a later
744
+ request spent it): answer its refusals alike
745
+ where addresses must stay secret. And rate-limit the request **per
746
+ address**: at most one code is live per user — a new `request` spends the one
747
+ before — so without a limit anyone who knows an address can fill its inbox,
748
+ or cancel its owner's code before they type it.
658
749
 
659
750
  **Every `janus()` that signs users in needs the same `secondFactor`.** An
660
751
  instance without keys never signs in a user whose factor is active: `signIn`
@@ -701,7 +792,9 @@ denied. `resetPassword.request` answers `null` for an unknown e-mail for the
701
792
  same reason: answer the visitor the same page either way.
702
793
 
703
794
  **`resetPassword.confirm` signs the user out everywhere, and opens no session.**
704
- Whoever had the old password loses their sessions; what the visitor does next is
795
+ Whoever had the old password loses their sessions, and a sign-in they left
796
+ waiting on its second factor is spent with them — as it is by `setPassword`
797
+ and `changePassword`; what the visitor does next is
705
798
  your policy. A password refused for its length does not spend the token.
706
799
 
707
800
  **A sign-in can move a user's `version`.** Rewriting a stale hash is a write. A
@@ -774,16 +867,16 @@ could not answer: that is a denial made of an outage.
774
867
 
775
868
  ## Type safety, counted
776
869
 
777
- **One hundred and eleven plausible mistakes, one hundred and eleven refused at compile time — and
870
+ **One hundred and fifteen plausible mistakes, one hundred and fifteen refused at compile time — and
778
871
  two gaps, named.**
779
872
 
780
873
  The lists are typechecked and never run, with one `@ts-expect-error` per
781
874
  mistake beside the shapes that must keep compiling:
782
875
  `test/types/refusals.ts` (fourteen, on the shared vocabulary),
783
- `test/types/port.ts` (twenty-one, on the identity stores' port, from the point
784
- of view of the person implementing it), `test/types/auth.ts` (twenty-eight, on
876
+ `test/types/port.ts` (twenty-two, on the identity stores' port, from the point
877
+ of view of the person implementing it), `test/types/auth.ts` (thirty-one, on
785
878
  `janus()`, from the point of view of the application — eight of them on the
786
- second factor) and `test/types/permissions.ts` (forty-eight, on the
879
+ second factor, three on sign-in codes) and `test/types/permissions.ts` (forty-eight, on the
787
880
  permission model and the questions asked of it). The rule
788
881
  comes from `nxgt-data`, and so does the reason to
789
882
  distrust the claim without the files: when it was last measured on
@@ -137,6 +137,8 @@ interface SharedConfig {
137
137
  readonly verifyEmail?: Duration;
138
138
  /** `'1h'` when absent. */
139
139
  readonly resetPassword?: Duration;
140
+ /** How long an e-mailed sign-in code waits. `'10m'` when absent. */
141
+ readonly signInCode?: Duration;
140
142
  };
141
143
  /**
142
144
  * A TOTP second factor, for every user type with a password. Absent, no
@@ -203,6 +205,7 @@ export interface ResolvedConfig {
203
205
  readonly tokenTtlMs: {
204
206
  readonly verifyEmail: number;
205
207
  readonly resetPassword: number;
208
+ readonly signInCode: number;
206
209
  };
207
210
  readonly secondFactor: {
208
211
  readonly issuer: string;
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/auth/config.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/auth/config.ts"],"names":[],"mappings":"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"}
@@ -49,6 +49,12 @@ export declare function emailOf(type: ResolvedType, fields: JsonObject): string
49
49
  * still be found by the e-mail a reset is requested for.
50
50
  */
51
51
  export declare function loginsOf(type: ResolvedType, fields: JsonObject, where: string): string[];
52
+ /** The type's password rule, or a wiring refusal for a JavaScript caller. */
53
+ export declare function passwordRule(type: ResolvedType, where: string): {
54
+ readonly login: string;
55
+ readonly normalize: (value: string) => string;
56
+ readonly minLength: number;
57
+ };
52
58
  /** Refuses a password shorter than the policy. Reports the policy, never the password. */
53
59
  export declare function checkPassword(type: ResolvedType, password: string, where: string): void;
54
60
  /** The hasher. `janus()` refused a password type without one, so this is a wiring net. */
@@ -84,4 +90,10 @@ export declare function getRecord(context: Context, id: string, type: string | n
84
90
  * `VERSION_CONFLICT`, and nothing is written.
85
91
  */
86
92
  export declare function writeUser(context: Context, user: UserRef, type: ResolvedType, options: WriteOptions | undefined, where: string, patchOf: (record: UserRecord, now: Date) => Omit<UserPatch, 'updatedAt'> | Promise<Omit<UserPatch, 'updatedAt'>>): Promise<UserRecord>;
93
+ /**
94
+ * The user of this type whose e-mail this is, or `null`. Looked up as a
95
+ * login — every e-mail is one — and then compared, so a username that only
96
+ * looks like an e-mail is nobody's.
97
+ */
98
+ export declare function holderOfEmail(context: Context, type: ResolvedType, email: string): Promise<UserRecord | null>;
87
99
  //# sourceMappingURL=context.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../src/auth/context.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAUH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAE/D,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AAC3C,OAAO,EAEN,KAAK,cAAc,EAEnB,KAAK,cAAc,EACnB,KAAK,YAAY,EACjB,MAAM,UAAU,CAAC;AAElB,OAAO,KAAK,EACX,WAAW,EAEX,UAAU,EACV,iBAAiB,EACjB,SAAS,EACT,UAAU,EACV,MAAM,cAAc,CAAC;AAEtB,OAAO,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAE3D,MAAM,WAAW,OAAO;IACvB,QAAQ,CAAC,MAAM,EAAE,cAAc,CAAC;IAChC,iDAAiD;IACjD,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAC;IAC5B,+DAA+D;IAC/D,QAAQ,CAAC,SAAS,EAAE,aAAa,GAAG,IAAI,CAAC;IACzC,QAAQ,CAAC,YAAY,EAAE,iBAAiB,CAAC;IACzC,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,cAAc,GAAG,IAAI,CAAC;IACvC,kFAAkF;IAClF,QAAQ,CAAC,SAAS,EAAE,SAAS,cAAc,EAAE,CAAC;IAC9C,+EAA+E;IAC/E,SAAS,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC;CAC7B;AAED,wBAAgB,aAAa,CAC5B,MAAM,EAAE,cAAc,EACtB,KAAK,EAAE,WAAW,EAClB,SAAS,EAAE,aAAa,GAAG,IAAI,EAC/B,YAAY,EAAE,iBAAiB,EAC/B,KAAK,EAAE,KAAK,EACZ,MAAM,EAAE,cAAc,GAAG,IAAI,EAC7B,SAAS,EAAE,SAAS,cAAc,EAAE,GAClC,OAAO,CAmBT;AAED,kEAAkE;AAClE,MAAM,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;AAE5D;;;;GAIG;AACH,wBAAgB,MAAM,CAAC,MAAM,EAAE,UAAU,GAAG,OAAO,CAalD;AAED,sCAAsC;AACtC,eAAO,MAAM,IAAI,GAAI,MAAM,OAAO,KAAG,MACK,CAAC;AAE3C;;;GAGG;AACH,wBAAsB,cAAc,CACnC,IAAI,EAAE,YAAY,EAClB,KAAK,EAAE,OAAO,EACd,KAAK,EAAE,MAAM,GACX,OAAO,CAAC,UAAU,CAAC,CAmCrB;AA+DD,gFAAgF;AAChF,wBAAgB,OAAO,CAAC,IAAI,EAAE,YAAY,EAAE,MAAM,EAAE,UAAU,GAAG,MAAM,GAAG,IAAI,CAG7E;AAED;;;;GAIG;AACH,wBAAgB,QAAQ,CACvB,IAAI,EAAE,YAAY,EAClB,MAAM,EAAE,UAAU,EAClB,KAAK,EAAE,MAAM,GACX,MAAM,EAAE,CAiCV;AAED,0FAA0F;AAC1F,wBAAgB,aAAa,CAC5B,IAAI,EAAE,YAAY,EAClB,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,MAAM,GACX,IAAI,CASN;AAED,0FAA0F;AAC1F,wBAAgB,aAAa,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,GAAG,cAAc,CAO7E;AAED;;;GAGG;AACH,wBAAsB,eAAe,CACpC,OAAO,EAAE,OAAO,EAChB,MAAM,EAAE,UAAU,EAClB,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,MAAM,GACX,OAAO,CAAC,OAAO,CAAC,CAiBlB;AAED;;;;;;;;GAQG;AACH,wBAAsB,QAAQ,CAC7B,OAAO,EAAE,OAAO,EAChB,MAAM,EAAE,UAAU,EAClB,QAAQ,EAAE,MAAM,GACd,OAAO,CAAC,UAAU,CAAC,CAyBrB;AAUD;;;;;GAKG;AACH,wBAAsB,UAAU,CAC/B,OAAO,EAAE,OAAO,EAChB,EAAE,EAAE,MAAM,EACV,IAAI,EAAE,MAAM,GAAG,IAAI,GACjB,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CAM5B;AAED,gCAAgC;AAChC,wBAAsB,SAAS,CAC9B,OAAO,EAAE,OAAO,EAChB,EAAE,EAAE,MAAM,EACV,IAAI,EAAE,MAAM,GAAG,IAAI,EACnB,KAAK,EAAE,MAAM,GACX,OAAO,CAAC,UAAU,CAAC,CAIrB;AAED;;;;;GAKG;AACH,wBAAsB,SAAS,CAC9B,OAAO,EAAE,OAAO,EAChB,IAAI,EAAE,OAAO,EACb,IAAI,EAAE,YAAY,EAClB,OAAO,EAAE,YAAY,GAAG,SAAS,EACjC,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,CACR,MAAM,EAAE,UAAU,EAClB,GAAG,EAAE,IAAI,KACL,IAAI,CAAC,SAAS,EAAE,WAAW,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,SAAS,EAAE,WAAW,CAAC,CAAC,GACvE,OAAO,CAAC,UAAU,CAAC,CAyBrB"}
1
+ {"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../src/auth/context.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ import type { ResolvedType } from './config';
2
+ import { type AnyUser, type Context } from './context';
3
+ import type { ResetPasswordApi, VerifyEmailApi } from './types';
4
+ /**
5
+ * The e-mail flows: send a one-time token by e-mail, then confirm it —
6
+ * verifying the address, or resetting the password. Both confirm the same
7
+ * way: spend the token, read the user, and check the address again on the
8
+ * very record the write replaces.
9
+ */
10
+ export declare function emailFlows(context: Context, type: ResolvedType, at: (operation: string) => string): VerifyEmailApi<AnyUser> & ResetPasswordApi<AnyUser>;
11
+ //# sourceMappingURL=email-flows.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"email-flows.d.ts","sourceRoot":"","sources":["../../src/auth/email-flows.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAC7C,OAAO,EACN,KAAK,OAAO,EACZ,KAAK,OAAO,EAWZ,MAAM,WAAW,CAAC;AASnB,OAAO,KAAK,EAAe,gBAAgB,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAE7E;;;;;GAKG;AACH,wBAAgB,UAAU,CACzB,OAAO,EAAE,OAAO,EAChB,IAAI,EAAE,YAAY,EAClB,EAAE,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,MAAM,GAC/B,cAAc,CAAC,OAAO,CAAC,GAAG,gBAAgB,CAAC,OAAO,CAAC,CAyHrD"}
@@ -6,5 +6,5 @@ export { createMemoryStores } from './port/memory';
6
6
  export type { JanusStores, Json, JsonObject, PasswordRecord, SecondFactorRecord, SessionId, SessionRecord, SessionStore, StoreCapabilities, TokenKind, TokenRecord, TokenStore, UserPageRequest, UserPatch, UserRecord, UserStore, } from './port/types';
7
7
  export type { SealingKey } from './sealing';
8
8
  export type { StandardSchemaV1 } from './standard-schema';
9
- export type { Authenticated, Checked, EmailOf, HeaderRecord, IssuedToken, Janus, LoginOf, PasswordApi, RequestLike, RequiredStringKeys, ResetPasswordApi, SecondFactorApi, SecondFactorEnrolment, SecondFactorRequired, Session, SharedApi, SignedIn, SignInResult, TypeApi, TypesOf, User, UserBase, UserOf, UserRef, UserTypeApi, VerifyEmailApi, WriteOptions, } from './types';
9
+ export type { Authenticated, Checked, EmailOf, HeaderRecord, IssuedCode, IssuedToken, Janus, LoginOf, PasswordApi, RequestLike, RequiredStringKeys, ResetPasswordApi, SecondFactorApi, SecondFactorEnrolment, SecondFactorRequired, Session, SharedApi, SignedIn, SignInCodeApi, SignInResult, TypeApi, TypesOf, User, UserBase, UserOf, UserRef, UserTypeApi, VerifyEmailApi, WriteOptions, } from './types';
10
10
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/auth/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACX,YAAY,EACZ,UAAU,EACV,WAAW,EACX,eAAe,EACf,SAAS,EACT,cAAc,EACd,cAAc,EACd,kBAAkB,EAClB,aAAa,EACb,gBAAgB,EAChB,UAAU,EACV,cAAc,GACd,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AACpD,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAChC,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACpD,OAAO,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AACnD,YAAY,EACX,WAAW,EACX,IAAI,EACJ,UAAU,EACV,cAAc,EACd,kBAAkB,EAClB,SAAS,EACT,aAAa,EACb,YAAY,EACZ,iBAAiB,EACjB,SAAS,EACT,WAAW,EACX,UAAU,EACV,eAAe,EACf,SAAS,EACT,UAAU,EACV,SAAS,GACT,MAAM,cAAc,CAAC;AACtB,YAAY,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAC5C,YAAY,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAC1D,YAAY,EACX,aAAa,EACb,OAAO,EACP,OAAO,EACP,YAAY,EACZ,WAAW,EACX,KAAK,EACL,OAAO,EACP,WAAW,EACX,WAAW,EACX,kBAAkB,EAClB,gBAAgB,EAChB,eAAe,EACf,qBAAqB,EACrB,oBAAoB,EACpB,OAAO,EACP,SAAS,EACT,QAAQ,EACR,YAAY,EACZ,OAAO,EACP,OAAO,EACP,IAAI,EACJ,QAAQ,EACR,MAAM,EACN,OAAO,EACP,WAAW,EACX,cAAc,EACd,YAAY,GACZ,MAAM,SAAS,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/auth/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACX,YAAY,EACZ,UAAU,EACV,WAAW,EACX,eAAe,EACf,SAAS,EACT,cAAc,EACd,cAAc,EACd,kBAAkB,EAClB,aAAa,EACb,gBAAgB,EAChB,UAAU,EACV,cAAc,GACd,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AACpD,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAChC,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACpD,OAAO,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AACnD,YAAY,EACX,WAAW,EACX,IAAI,EACJ,UAAU,EACV,cAAc,EACd,kBAAkB,EAClB,SAAS,EACT,aAAa,EACb,YAAY,EACZ,iBAAiB,EACjB,SAAS,EACT,WAAW,EACX,UAAU,EACV,eAAe,EACf,SAAS,EACT,UAAU,EACV,SAAS,GACT,MAAM,cAAc,CAAC;AACtB,YAAY,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAC5C,YAAY,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAC1D,YAAY,EACX,aAAa,EACb,OAAO,EACP,OAAO,EACP,YAAY,EACZ,UAAU,EACV,WAAW,EACX,KAAK,EACL,OAAO,EACP,WAAW,EACX,WAAW,EACX,kBAAkB,EAClB,gBAAgB,EAChB,eAAe,EACf,qBAAqB,EACrB,oBAAoB,EACpB,OAAO,EACP,SAAS,EACT,QAAQ,EACR,aAAa,EACb,YAAY,EACZ,OAAO,EACP,OAAO,EACP,IAAI,EACJ,QAAQ,EACR,MAAM,EACN,OAAO,EACP,WAAW,EACX,cAAc,EACd,YAAY,GACZ,MAAM,SAAS,CAAC"}
@@ -1,6 +1,7 @@
1
1
  import { TokenError } from '../errors/janus-error';
2
- import type { Context } from './context';
3
- import type { TokenKind, TokenRecord } from './port/types';
2
+ import { type ResolvedType } from './config';
3
+ import { type Context } from './context';
4
+ import type { TokenKind, TokenRecord, UserRecord } from './port/types';
4
5
  /**
5
6
  * The rules every one-time token shares — an e-mail link, a second-factor
6
7
  * challenge — kept in one place so the two cannot drift apart.
@@ -9,6 +10,33 @@ import type { TokenKind, TokenRecord } from './port/types';
9
10
  * what `signIn` answers. No message names the secret or its hash.
10
11
  */
11
12
  export type OneTimeNoun = 'token' | 'challenge';
13
+ /**
14
+ * How many codes one challenge takes — a second factor's or an e-mail
15
+ * code's. A six-digit code has a million values: five attempts is a
16
+ * one-in-200,000 chance **per challenge**, and the attempts are counted by
17
+ * the store in one write, never read then written.
18
+ */
19
+ export declare const CODE_ATTEMPTS = 5;
20
+ /**
21
+ * Counts one attempt at a challenge's code, before anything is compared: a
22
+ * guess that fails for any reason has still cost one. Refuses a challenge
23
+ * that cannot be used, and one past its last attempt — a call that raced the
24
+ * one that spent it — unread.
25
+ */
26
+ export declare function countCodeAttempt(context: Context, secret: string, kind: TokenKind, where: string, userType: string): Promise<{
27
+ readonly token: TokenRecord;
28
+ readonly attemptsLeft: number;
29
+ }>;
30
+ /**
31
+ * A code that does not match — a second factor's or an e-mailed one — or a
32
+ * TOTP code already used. `attemptsLeft` only when a challenge counted it.
33
+ */
34
+ export declare function codeInvalid(where: string, userId: string, userType: string, attemptsLeft?: number): TokenError;
35
+ /**
36
+ * Refuses a token sent to an e-mail the user no longer has: redeeming it
37
+ * would prove an address nobody holds any more.
38
+ */
39
+ export declare function refuseStale(type: ResolvedType, user: UserRecord, token: TokenRecord, where: string, noun: 'token' | 'code'): void;
12
40
  /**
13
41
  * Refuses a token that cannot be used: none, spent, or lapsed. What a store
14
42
  * answered — before a `consumeToken`, after a `countAttempt` — is read the
@@ -17,6 +45,13 @@ export type OneTimeNoun = 'token' | 'challenge';
17
45
  export declare function refuseUnusable(token: TokenRecord | null, now: Date, where: string, noun: OneTimeNoun): asserts token is TokenRecord;
18
46
  /** The refusal for a token whose user is gone, or of another type. */
19
47
  export declare const unknownOneTime: (where: string, noun: OneTimeNoun) => TokenError;
48
+ /**
49
+ * The refusal for a challenge whose user is gone, or of another type — the
50
+ * API of the wrong type compares no code. Its attempt was counted all the
51
+ * same, before the type was known, so the last one spends the challenge, as
52
+ * a wrong code would: past it, every call answers `TOKEN_SPENT`.
53
+ */
54
+ export declare function unknownChallenge(context: Context, token: TokenRecord, secret: string, where: string): Promise<TokenError>;
20
55
  /**
21
56
  * Spends a token, and refuses it when this call did not: the store answers it
22
57
  * **as it was before**, so exactly one call ever reads `spentAt: null`. A
@@ -24,16 +59,41 @@ export declare const unknownOneTime: (where: string, noun: OneTimeNoun) => Token
24
59
  */
25
60
  export declare function spendOneTime(context: Context, secret: string, kind: TokenKind, where: string, noun: OneTimeNoun): Promise<TokenRecord>;
26
61
  /**
27
- * Issues a one-time token: 32 random bytes, given back once, and only their
28
- * hash stored.
62
+ * Spends a token whose last attempt failed. Its answer is not read: a racing
63
+ * call that spent it first changes nothing for this one, which is refused
64
+ * for its code either way.
65
+ */
66
+ export declare function burnOneTime(context: Context, secret: string, kind: TokenKind): Promise<void>;
67
+ /**
68
+ * A code's hash, **keyed by its challenge**: the tokens alone — a dump, a
69
+ * log of the table — do not reveal the code, since a million guesses at it
70
+ * each need the challenge, which only the visitor holds.
29
71
  */
30
- export declare function issueOneTime(context: Context, token: {
72
+ export declare const hashCode: (challenge: string, code: string) => string;
73
+ /** Whether `code` is the one whose hash the token holds, compared in constant time. */
74
+ export declare function codeMatches(token: TokenRecord, challenge: string, code: string): boolean;
75
+ interface OneTimeRequest {
31
76
  readonly kind: TokenKind;
32
77
  readonly userId: string;
33
78
  readonly address: string;
34
79
  readonly ttlMs: number;
35
- }): Promise<{
80
+ }
81
+ /**
82
+ * Issues a one-time token: 32 random bytes, given back once, and only their
83
+ * hash stored.
84
+ */
85
+ export declare function issueOneTime(context: Context, token: OneTimeRequest): Promise<{
86
+ readonly secret: string;
87
+ readonly expiresAt: Date;
88
+ }>;
89
+ /**
90
+ * Issues a one-time token with a six-digit code for a person to type: the
91
+ * token is the challenge, and only the code's hash is stored, keyed by it.
92
+ */
93
+ export declare function issueCode(context: Context, token: OneTimeRequest): Promise<{
36
94
  readonly secret: string;
37
95
  readonly expiresAt: Date;
96
+ readonly code: string;
38
97
  }>;
98
+ export {};
39
99
  //# sourceMappingURL=one-time.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"one-time.d.ts","sourceRoot":"","sources":["../../src/auth/one-time.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AACnD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAG3D;;;;;;GAMG;AACH,MAAM,MAAM,WAAW,GAAG,OAAO,GAAG,WAAW,CAAC;AAEhD;;;;GAIG;AACH,wBAAgB,cAAc,CAC7B,KAAK,EAAE,WAAW,GAAG,IAAI,EACzB,GAAG,EAAE,IAAI,EACT,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,WAAW,GACf,OAAO,CAAC,KAAK,IAAI,WAAW,CAkB9B;AAED,sEAAsE;AACtE,eAAO,MAAM,cAAc,GAAI,OAAO,MAAM,EAAE,MAAM,WAAW,eAG5D,CAAC;AAEJ;;;;GAIG;AACH,wBAAsB,YAAY,CACjC,OAAO,EAAE,OAAO,EAChB,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,SAAS,EACf,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,WAAW,GACf,OAAO,CAAC,WAAW,CAAC,CAStB;AAED;;;GAGG;AACH,wBAAsB,YAAY,CACjC,OAAO,EAAE,OAAO,EAChB,KAAK,EAAE;IACN,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IACzB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACvB,GACC,OAAO,CAAC;IAAE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,SAAS,EAAE,IAAI,CAAA;CAAE,CAAC,CAiBhE"}
1
+ {"version":3,"file":"one-time.d.ts","sourceRoot":"","sources":["../../src/auth/one-time.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ import type { Id } from '../ids/id';
2
+ import type { ResolvedType } from './config';
3
+ import { type AnyUser, type Context } from './context';
4
+ import type { UserRecord } from './port/types';
5
+ import type { SignInResult } from './types';
6
+ /**
7
+ * What writing a password ends besides: every second-factor challenge of the
8
+ * user still open, so a sign-in started with the old password cannot be
9
+ * finished. Called **after** the write — the other half of
10
+ * {@link heldByPassword}, which reads **after** it issued.
11
+ */
12
+ export declare function endSignInsWaiting(context: Context, userId: Id): Promise<void>;
13
+ /**
14
+ * Whether the password a sign-in verified is still the user's, once the
15
+ * sign-in answered. A password written meanwhile ends the sign-in: its
16
+ * session is revoked, or its challenge spent, and `false` is answered.
17
+ *
18
+ * A password writer writes, then spends the challenges waiting; a sign-in
19
+ * issues, then reads here. Whichever order they interleave in, one of the two
20
+ * sees the other. A hash that changed with the same password — a concurrent
21
+ * sign-in rehashing it — is not a change: the password is compared again.
22
+ */
23
+ export declare function heldByPassword(context: Context, type: ResolvedType, verified: UserRecord, password: string, result: SignInResult<AnyUser>, where: string): Promise<boolean>;
24
+ //# sourceMappingURL=password-written.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"password-written.d.ts","sourceRoot":"","sources":["../../src/auth/password-written.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAC7C,OAAO,EACN,KAAK,OAAO,EACZ,KAAK,OAAO,EAGZ,MAAM,WAAW,CAAC;AAEnB,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAE5C;;;;;GAKG;AACH,wBAAsB,iBAAiB,CACtC,OAAO,EAAE,OAAO,EAChB,MAAM,EAAE,EAAE,GACR,OAAO,CAAC,IAAI,CAAC,CAMf;AAED;;;;;;;;;GASG;AACH,wBAAsB,cAAc,CACnC,OAAO,EAAE,OAAO,EAChB,IAAI,EAAE,YAAY,EAClB,QAAQ,EAAE,UAAU,EACpB,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,YAAY,CAAC,OAAO,CAAC,EAC7B,KAAK,EAAE,MAAM,GACX,OAAO,CAAC,OAAO,CAAC,CAkBlB"}
@@ -1 +1 @@
1
- {"version":3,"file":"assert-stores.d.ts","sourceRoot":"","sources":["../../../src/auth/port/assert-stores.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAe,iBAAiB,EAAE,MAAM,SAAS,CAAC;AA6B9D;;;;;;;;;;;;GAYG;AACH,wBAAgB,YAAY,CAC3B,MAAM,EAAE,OAAO,EACf,KAAK,EAAE,MAAM,GACX,iBAAiB,CAmCnB"}
1
+ {"version":3,"file":"assert-stores.d.ts","sourceRoot":"","sources":["../../../src/auth/port/assert-stores.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAe,iBAAiB,EAAE,MAAM,SAAS,CAAC;AAmC9D;;;;;;;;;;;;GAYG;AACH,wBAAgB,YAAY,CAC3B,MAAM,EAAE,OAAO,EACf,KAAK,EAAE,MAAM,GACX,iBAAiB,CAmCnB"}
@@ -35,7 +35,11 @@
35
35
  * 5. **Every method is atomic on its own.** Nothing composes into a
36
36
  * transaction, and the core never opens one. An adapter may open one
37
37
  * *inside* a method — a normalised SQL schema writes several rows per
38
- * user — but the port exposes none.
38
+ * user — but the port exposes none. And **a read sees every write that
39
+ * completed before it**: never a secondary or a read replica. A sign-in
40
+ * that re-reads the user after answering, and a new code spending the
41
+ * ones issued before it, both count on it — the one promise here no suite
42
+ * can check.
39
43
  * 6. **Schema management is not on this interface.** An adapter exposes its own
40
44
  * `sync()`; the core never calls it.
41
45
  *
@@ -441,6 +445,24 @@ export interface TokenStore {
441
445
  * core's decision, after the call; spending the token is `consumeToken`.
442
446
  */
443
447
  countAttempt(tokenHash: string, kind: TokenKind): Promise<TokenRecord | null>;
448
+ /**
449
+ * Spends every **unspent** token of one user and one `kind` at `at` —
450
+ * but the one whose hash is `except`, when given — and answers how many
451
+ * it spent. What issuing a sign-in code calls, sparing the code it just
452
+ * issued, so only the last code sent works; and what writing a password
453
+ * calls, so no second-factor challenge opened with the old one survives.
454
+ *
455
+ * - A spent token keeps its `spentAt`: it never changes once set.
456
+ * - A token of another `kind`, or of another user, is not touched.
457
+ * - An expired token is spent all the same, or not counted by a store that
458
+ * already dropped it.
459
+ * - `0` for a user with none: an absence, not a failure.
460
+ *
461
+ * Each token is spent by a conditional write, as `consumeToken` spends
462
+ * one: a token `consumeToken` spends at the same moment is counted by
463
+ * exactly one of the two calls.
464
+ */
465
+ spendUserTokens(userId: Id, kind: TokenKind, at: Date, except?: string): Promise<number>;
444
466
  /**
445
467
  * Deletes every token of one user, spent or not, and answers how many.
446
468
  * What deleting a user calls: a token holds the e-mail it was sent to, which
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/auth/port/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/auth/port/types.ts"],"names":[],"mappings":"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"}
@@ -2,12 +2,6 @@ import type { ResolvedType } from '../config';
2
2
  import { type AnyUser, type Context } from '../context';
3
3
  import type { UserRecord } from '../port/types';
4
4
  import type { SecondFactorRequired, SignedIn } from '../types';
5
- /**
6
- * How many codes one challenge takes. A six-digit code has a million values:
7
- * five tries is a one-in-200,000 chance per password guessed right, and the
8
- * attempts are counted by the store in one write, never read then written.
9
- */
10
- export declare const CHALLENGE_ATTEMPTS = 5;
11
5
  /**
12
6
  * The challenge `signIn` answers instead of a session, and the code that
13
7
  * redeems it. **Only the challenge's hash is stored**, like a session
@@ -1 +1 @@
1
- {"version":3,"file":"challenge.d.ts","sourceRoot":"","sources":["../../../src/auth/second-factor/challenge.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAC9C,OAAO,EAAE,KAAK,OAAO,EAAE,KAAK,OAAO,EAAc,MAAM,YAAY,CAAC;AAOpE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAGhD,OAAO,KAAK,EAAE,oBAAoB,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AAG/D;;;;GAIG;AACH,eAAO,MAAM,kBAAkB,IAAI,CAAC;AAEpC;;;;GAIG;AACH,wBAAgB,cAAc,CAC7B,OAAO,EAAE,OAAO,EAChB,IAAI,EAAE,YAAY,EAClB,EAAE,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,MAAM;kBAQvB,UAAU,SACX,MAAM,GACX,OAAO,CAAC,oBAAoB,CAAC;uBAgBP,MAAM,QAAQ,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;EAmE3E"}
1
+ {"version":3,"file":"challenge.d.ts","sourceRoot":"","sources":["../../../src/auth/second-factor/challenge.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAC9C,OAAO,EAAE,KAAK,OAAO,EAAE,KAAK,OAAO,EAAc,MAAM,YAAY,CAAC;AASpE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAEhD,OAAO,KAAK,EAAE,oBAAoB,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AAG/D;;;;GAIG;AACH,wBAAgB,cAAc,CAC7B,OAAO,EAAE,OAAO,EAChB,IAAI,EAAE,YAAY,EAClB,EAAE,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,MAAM;kBAQvB,UAAU,SACX,MAAM,GACX,OAAO,CAAC,oBAAoB,CAAC;uBAqBP,MAAM,QAAQ,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;EAkE3E"}
@@ -1,5 +1,4 @@
1
- import { TokenError } from '../../errors/janus-error';
2
- import type { ResolvedConfig, ResolvedType } from '../config';
1
+ import type { ResolvedConfig } from '../config';
3
2
  import type { Context } from '../context';
4
3
  import type { SecondFactorRecord, UserRecord } from '../port/types';
5
4
  /**
@@ -24,7 +23,5 @@ export declare function requireSettings(context: Context, where: string, why: st
24
23
  * or was already used.
25
24
  */
26
25
  export declare function acceptCode(configured: Settings, record: UserRecord, factor: SecondFactorRecord, code: string, now: Date, where: string): SecondFactorRecord | null;
27
- /** A code that does not match. `attemptsLeft` only when a challenge counted it. */
28
- export declare function codeInvalid(type: ResolvedType, where: string, userId: string, attemptsLeft?: number): TokenError;
29
26
  export {};
30
27
  //# sourceMappingURL=factor.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"factor.d.ts","sourceRoot":"","sources":["../../../src/auth/second-factor/factor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AACtD,OAAO,KAAK,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAC9D,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,KAAK,EAAE,kBAAkB,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAIpE;;;;;;;GAOG;AAEH,MAAM,MAAM,QAAQ,GAAG,WAAW,CAAC,cAAc,CAAC,cAAc,CAAC,CAAC,CAAC;AAEnE,KAAK,YAAY,GAAG,kBAAkB,GAAG;IAAE,QAAQ,CAAC,WAAW,EAAE,IAAI,CAAA;CAAE,CAAC;AAExE,eAAO,MAAM,QAAQ,GACpB,QAAQ,kBAAkB,GAAG,IAAI,KAC/B,MAAM,IAAI,YAA8D,CAAC;AAE5E,yEAAyE;AACzE,wBAAgB,eAAe,CAC9B,OAAO,EAAE,OAAO,EAChB,KAAK,EAAE,MAAM,EACb,GAAG,EAAE,MAAM,GACT,QAAQ,CAQV;AAED;;;;;GAKG;AACH,wBAAgB,UAAU,CACzB,UAAU,EAAE,QAAQ,EACpB,MAAM,EAAE,UAAU,EAClB,MAAM,EAAE,kBAAkB,EAC1B,IAAI,EAAE,MAAM,EACZ,GAAG,EAAE,IAAI,EACT,KAAK,EAAE,MAAM,GACX,kBAAkB,GAAG,IAAI,CAiB3B;AAED,mFAAmF;AACnF,wBAAgB,WAAW,CAC1B,IAAI,EAAE,YAAY,EAClB,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,EACd,YAAY,CAAC,EAAE,MAAM,GACnB,UAAU,CAWZ"}
1
+ {"version":3,"file":"factor.d.ts","sourceRoot":"","sources":["../../../src/auth/second-factor/factor.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAChD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,KAAK,EAAE,kBAAkB,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAIpE;;;;;;;GAOG;AAEH,MAAM,MAAM,QAAQ,GAAG,WAAW,CAAC,cAAc,CAAC,cAAc,CAAC,CAAC,CAAC;AAEnE,KAAK,YAAY,GAAG,kBAAkB,GAAG;IAAE,QAAQ,CAAC,WAAW,EAAE,IAAI,CAAA;CAAE,CAAC;AAExE,eAAO,MAAM,QAAQ,GACpB,QAAQ,kBAAkB,GAAG,IAAI,KAC/B,MAAM,IAAI,YAA8D,CAAC;AAE5E,yEAAyE;AACzE,wBAAgB,eAAe,CAC9B,OAAO,EAAE,OAAO,EAChB,KAAK,EAAE,MAAM,EACb,GAAG,EAAE,MAAM,GACT,QAAQ,CAQV;AAED;;;;;GAKG;AACH,wBAAgB,UAAU,CACzB,UAAU,EAAE,QAAQ,EACpB,MAAM,EAAE,UAAU,EAClB,MAAM,EAAE,kBAAkB,EAC1B,IAAI,EAAE,MAAM,EACZ,GAAG,EAAE,IAAI,EACT,KAAK,EAAE,MAAM,GACX,kBAAkB,GAAG,IAAI,CAiB3B"}