@spfn/auth 0.3.0-beta.22 → 0.3.0-beta.24
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/README.md +308 -4
- package/dist/client-proof.js +13 -5
- package/dist/client-proof.js.map +1 -1
- package/dist/client.d.ts +52 -1
- package/dist/client.js +40 -0
- package/dist/client.js.map +1 -1
- package/dist/config.d.ts +120 -0
- package/dist/config.js +55 -0
- package/dist/config.js.map +1 -1
- package/dist/crypto.d.ts +1 -1
- package/dist/errors.d.ts +208 -3
- package/dist/errors.js +131 -2
- package/dist/errors.js.map +1 -1
- package/dist/index.d.ts +71 -5
- package/dist/index.js +134 -3
- package/dist/index.js.map +1 -1
- package/dist/{machine-principals-B7N8gux0.d.ts → machine-principals-ZJd9anVT.d.ts} +2045 -886
- package/dist/nextjs/api.js +156 -6
- package/dist/nextjs/api.js.map +1 -1
- package/dist/nextjs/server.d.ts +42 -24
- package/dist/nextjs/server.js +72 -5
- package/dist/nextjs/server.js.map +1 -1
- package/dist/server.d.ts +1033 -598
- package/dist/server.js +3239 -1541
- package/dist/server.js.map +1 -1
- package/dist/{session-Dfwu5g2W.d.ts → session-BbhAGZtA.d.ts} +57 -1
- package/dist/{types-DYyhze28.d.ts → types-CTdoTOxM.d.ts} +24 -1
- package/migrations/20260918162828_handy_titania/migration.sql +35 -0
- package/migrations/20260918162828_handy_titania/snapshot.json +5948 -0
- package/migrations/20260918184037_happy_mordo/migration.sql +4 -0
- package/migrations/20260918184037_happy_mordo/snapshot.json +6000 -0
- package/migrations/20260918184152_dear_rictor/migration.sql +3 -0
- package/migrations/20260918184152_dear_rictor/snapshot.json +6039 -0
- package/package.json +1 -1
package/dist/server.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { A as AuthInitOptions,
|
|
2
|
-
export {
|
|
1
|
+
import { A as AuthInitOptions, y as OAuthProvider, N as NewUserPublicKey, w as VerificationPurpose, z as NewPasskey, B as Passkey, E as MfaVerification, G as MfaVerificationMethod, u as PermissionCategory, H as UserPublicKey, J as AuthContext } from './machine-principals-ZJd9anVT.js';
|
|
2
|
+
export { Q as ApproveDeviceAuthParams, W as AssertStepUpParams, X as AuthDeletionCancelledPayload, Y as AuthDeletionCompletedPayload, Z as AuthDeletionRequestedPayload, _ as AuthDeviceRegisteredPayload, $ as AuthLoginPayload, a0 as AuthPasswordResetPayload, a1 as AuthProfileOutcome, a2 as AuthProfileVerifier, a3 as AuthProviderSchema, a4 as AuthRegisterPayload, a5 as BearerOutcome, a6 as BearerRefusal, a7 as ChangePasswordParams, a8 as CompletePasswordResetParams, a9 as CompleteSignupParams, aa as ConfirmPasswordResetParams, d as ConfirmPasswordResetResult, ab as ConfirmSignupLinkParams, C as ConfirmSignupLinkResult, ac as ConfirmTotpParams, h as ConfirmTotpResult, ad as DenyDeviceAuthParams, ae as DeviceAuthApprovedResult, af as DeviceAuthInfoParams, D as DeviceAuthInfoResult, ag as DeviceAuthPendingResult, ah as DeviceAuthPollResponseSchema, ai as DeviceNameSchema, aj as DeviceRegistrationChannel, ak as DisableSessionBindingParams, al as EmailSchema, am as FingerprintSchema, an as FinishPasskeyEnrollmentParams, F as FinishPasskeyEnrollmentResult, ao as FinishPasskeyLoginParams, ap as FinishSessionRenewParams, aq as InvitationAcceptedPayload, ar as InvitationCreatedPayload, I as IssueOneTimeTokenResult, as as KEY_FINGERPRINT_PREFIX_LENGTH, at as KeyIdSchema, K as KeySummary, au as LoginParams, e as LoginResult, av as LogoutParams, aw as MFA_VERIFICATION_METHODS, ax as MachinePrincipal, ay as MachineVerifierRegistration, az as MarkPasskeyParams, M as MfaStatus, aA as NativeVerifyOptions, aB as NewMfaVerification, aC as NormalizedIdentity, q as OAuth2AuthorizationCodeIssued, aD as OAuth2AuthorizeParams, p as OAuth2ConsentView, r as OAuth2GrantSummary, aE as OAuth2ScopeDescription, aF as OAuthCallbackParams, aG as OAuthCallbackResult, aH as OAuthCodeExchangeOptions, aI as OAuthNativeParams, n as OAuthNativeResult, aJ as OAuthStartParams, O as OAuthStartResult, aK as OAuthTokens, aL as OAuthUnlinkedPayload, aM as PASSKEY_DEVICE_TYPES, aN as PASSKEY_LABEL_MAX_LENGTH, aO as PasskeyDeviceType, g as PasskeySummary, aP as PasswordSchema, aQ as PhoneSchema, aR as PlatformSchema, aS as PollDeviceAuthParams, aT as PollDeviceAuthResult, aU as PublicKeySchema, aV as RecentAuthenticationParams, aW as RegisterParams, aX as RegisterPublicKeyParams, a as RegisterResult, aY as RenamePasskeyParams, aZ as RequestPasswordResetParams, c as RequestPasswordResetResult, a_ as RequestSignupLinkParams, b as RequestSignupLinkResult, a$ as RevokeAllKeysParams, j as RevokeAllKeysResult, b0 as RevokeKeyParams, b1 as RevokePasskeyParams, b2 as RotateKeyParams, i as RotateKeyResult, b3 as SendVerificationCodeParams, S as SendVerificationCodeResult, b4 as SessionBindingParams, k as SessionBindingResult, b5 as StartDeviceAuthParams, f as StartDeviceAuthResult, b6 as StartPasskeyEnrollmentParams, b7 as StartSessionRenewParams, b8 as StepUpParams, b9 as TargetTypeSchema, T as TotpEnrolmentResult, ba as UnlinkNotification, bb as UnlinkNotifyRejection, bc as UnlinkNotifyRequest, bd as UnlinkNotifyResult, be as UserCodeSchema, V as VERIFICATION_PURPOSES, v as VERIFICATION_TARGET_TYPES, bf as VerificationPurposeSchema, x as VerificationTargetType, bg as VerifyCodeParams, bh as VerifyCodeResult, bi as admitBearerKey, bj as approveDeviceAuthService, bk as approveOAuth2AuthorizeService, bl as assertNotLastRecoveryCredential, bm as assertRecentAuthentication, bn as assertStepUp, bo as authDeletionCancelledEvent, bp as authDeletionCompletedEvent, bq as authDeletionRequestedEvent, br as authDeviceRegisteredEvent, bs as authLoginEvent, bt as authPasswordResetEvent, bu as authRegisterEvent, m as authRouter, bv as authenticate, bw as bearerAuthContext, bx as buildOAuthErrorUrl, by as carryStepUpVerification, bz as changePasswordService, bA as completePasswordResetService, bB as completeSignupService, bC as confirmPasswordResetService, bD as confirmSignupLinkService, bE as confirmTotpEnrolmentService, bF as denyDeviceAuthService, bG as denyOAuth2AuthorizeService, bH as describeOAuth2AuthorizeRequestService, bI as disableMfaService, bJ as disableSessionBindingService, bK as enableSessionBindingService, bL as finishPasskeyEnrollmentService, bM as finishPasskeyLoginService, bN as finishSessionRenewService, bO as getDeviceAuthInfoService, bP as getEnabledOAuthProviders, bQ as getGoogleAccessToken, bR as getMachinePrincipal, bS as getOAuthProvider, bT as getRegisteredProviders, bU as getSessionBindingService, bV as invitationAcceptedEvent, bW as invitationCreatedEvent, bX as isOAuthProviderEnabled, bY as issueOneTimeTokenService, bZ as keySessionBindingService, b_ as listKeysService, b$ as listOAuth2GrantsService, c0 as listPasskeysService, c1 as loginService, c2 as logoutService, c3 as machineAuth, c4 as markPasskeySecondFactorService, c5 as mfaEnrolledForUser, c6 as mfaStatusService, c7 as mfaVerifications, c8 as oauthCallbackService, c9 as oauthNativeService, ca as oauthStartService, cb as oauthUnlinkNotifyService, cc as oauthUnlinkedEvent, cd as optionalAuth, ce as passkeys, cf as pollDeviceAuthService, cg as regenerateRecoveryCodesService, ch as registerAuthProfile, ci as registerMachineVerifier, cj as registerOAuthProvider, ck as registerPublicKeyService, cl as registerService, cm as renamePasskeyService, cn as requestPasswordResetService, co as requestSignupLinkService, cp as requireEnabledProvider, cq as requireMachineScope, cr as resolveAuthenticatedUser, cs as revokeAllKeysService, ct as revokeAllOAuth2GrantsForUser, cu as revokeKeyService, cv as revokeOAuth2GrantService, cw as revokePasskeyService, cx as rotateKeyService, cy as runAuthProfile, cz as selectAuthProfile, cA as sendVerificationCodeService, cB as startDeviceAuthService, cC as startPasskeyEnrollmentService, cD as startPasskeyLoginService, cE as startSessionBindingDisableService, cF as startSessionRenewService, cG as startStepUpService, cH as startTotpEnrolmentService, cI as stepUpService, cJ as sweepUnconfirmedMfaService, cK as userPublicKeys, cL as verifyCodeService, cM as verifyOneTimeTokenService, cN as verifySecondFactor } from './machine-principals-ZJd9anVT.js';
|
|
3
3
|
import * as drizzle_orm_pg_core from 'drizzle-orm/pg-core';
|
|
4
|
-
import {
|
|
5
|
-
export { A as ACCOUNT_DELETION_REQUESTED_BY, a as ACCOUNT_DELETION_REQUEST_STATUSES, b as AccountDeletionRequestStatus, I as INVITATION_STATUSES, e as KEY_ALGORITHM, f as KEY_DEVICE_NAME_MAX_LENGTH, g as KEY_PLATFORM, h as KeyPlatformType, P as PURGE_STRATEGIES,
|
|
4
|
+
import { l as SocialProvider, K as KeyAlgorithmType, d as InvitationStatus, c as AccountDeletionRequestedBy, i as PurgeStrategy } from './types-CTdoTOxM.js';
|
|
5
|
+
export { A as ACCOUNT_DELETION_REQUESTED_BY, a as ACCOUNT_DELETION_REQUEST_STATUSES, b as AccountDeletionRequestStatus, I as INVITATION_STATUSES, e as KEY_ALGORITHM, f as KEY_DEVICE_NAME_MAX_LENGTH, g as KEY_PLATFORM, h as KeyPlatformType, P as PURGE_STRATEGIES, j as SESSION_BINDINGS, k as SOCIAL_PROVIDERS, S as SessionBindingType, U as USER_STATUSES, m as UserStatus } from './types-CTdoTOxM.js';
|
|
6
6
|
import { UserProfile as UserProfile$1, ProfileInfo } from '@spfn/auth';
|
|
7
7
|
import { BaseRepository } from '@spfn/core/db';
|
|
8
8
|
import { c as ClientIdentity } from './wire-version-CtzMKvBB.js';
|
|
@@ -10,7 +10,7 @@ import { Context } from 'hono';
|
|
|
10
10
|
import * as _spfn_core_route from '@spfn/core/route';
|
|
11
11
|
import { NamedMiddleware } from '@spfn/core/route';
|
|
12
12
|
export { KeyPair, generateClientToken, generateKeyPair, generateKeyPairES256, generateKeyPairRS256, getKeySize, shouldRotateKey } from './crypto.js';
|
|
13
|
-
export { S as SessionData, g as getSessionInfo, i as isSafeReturnPath, s as sealSession, a as shouldRefreshSession, u as unsealSession } from './session-
|
|
13
|
+
export { S as SessionData, g as getSessionInfo, i as isSafeReturnPath, s as sealSession, a as shouldRefreshSession, u as unsealSession } from './session-BbhAGZtA.js';
|
|
14
14
|
import { JWTPayload } from 'jose';
|
|
15
15
|
import { SSETokenManager, SSETokenStore } from '@spfn/core/event/sse';
|
|
16
16
|
import * as _spfn_core_logger from '@spfn/core/logger';
|
|
@@ -21,95 +21,6 @@ import '@spfn/core/event';
|
|
|
21
21
|
import '@spfn/auth/server';
|
|
22
22
|
import 'jsonwebtoken';
|
|
23
23
|
|
|
24
|
-
/**
|
|
25
|
-
* @spfn/auth - Signed Sign-Out-Everywhere Link
|
|
26
|
-
*
|
|
27
|
-
* A link an app mails to an account's proven address, which signs every device
|
|
28
|
-
* of that account out without a session. It exists for the case the rest of the
|
|
29
|
-
* key surface cannot serve: the owner suspects a device they do not recognise,
|
|
30
|
-
* and the device they would have to sign in on to do something about it is the
|
|
31
|
-
* one they no longer trust.
|
|
32
|
-
*
|
|
33
|
-
* Three calls, and each is deliberately not the other two. `createRevokeAllLink`
|
|
34
|
-
* mints the capability and hands the app a URL. `describeRevokeAllLink` says
|
|
35
|
-
* whether that URL still works and changes nothing, so a mail scanner opening
|
|
36
|
-
* the page costs nothing. `consumeRevokeAllLink` is the only one that revokes,
|
|
37
|
-
* and it takes the owner pressing the button.
|
|
38
|
-
*
|
|
39
|
-
* The caller's obligation, which this package cannot enforce: the URL
|
|
40
|
-
* `createRevokeAllLink` returns carries the plaintext token, because the package
|
|
41
|
-
* sends no mail here. Do not log it, do not persist it, do not put it in a job
|
|
42
|
-
* payload — hand it to the mail template and let it go. Every other link in this
|
|
43
|
-
* package is minted inside the worker that sends it precisely so that no caller
|
|
44
|
-
* ever holds one; this one cannot be, and the obligation moves to the app.
|
|
45
|
-
*/
|
|
46
|
-
interface CreateRevokeAllLinkOptions {
|
|
47
|
-
/**
|
|
48
|
-
* Minutes the link stays valid. Defaults to
|
|
49
|
-
* `SPFN_AUTH_REVOKE_ALL_LINK_TTL_MINUTES`, itself 30.
|
|
50
|
-
*/
|
|
51
|
-
ttlMinutes?: number;
|
|
52
|
-
}
|
|
53
|
-
interface RevokeAllLink {
|
|
54
|
-
/** Absolute URL of the app page, token in its query string. Never log it. */
|
|
55
|
-
url: string;
|
|
56
|
-
expiresAt: Date;
|
|
57
|
-
}
|
|
58
|
-
/** What the describe call tells the page, so it can say what pressing the button does. */
|
|
59
|
-
interface RevokeAllLinkDescription {
|
|
60
|
-
expiresAt: Date;
|
|
61
|
-
activeKeyCount: number;
|
|
62
|
-
}
|
|
63
|
-
/**
|
|
64
|
-
* Mint a sign-out-everywhere link for an account.
|
|
65
|
-
*
|
|
66
|
-
* Issuing supersedes every live link the account already has, the rule the
|
|
67
|
-
* password-reset flow follows: an owner who asks twice must not leave the first
|
|
68
|
-
* capability working in their mailbox after using the second.
|
|
69
|
-
*
|
|
70
|
-
* The row records the account's key generation, so the link dies the moment any
|
|
71
|
-
* other path signs every device out — a password reset, a password change, a
|
|
72
|
-
* deletion request, or the ordinary revoke-all route.
|
|
73
|
-
*
|
|
74
|
-
* Send it beside a password reset link. It ends the sessions; it does not change
|
|
75
|
-
* the password that let them start.
|
|
76
|
-
*
|
|
77
|
-
* @param userId - The account to issue for
|
|
78
|
-
* @throws ValidationError `ttlMinutes` that is not a positive integer — no row is written
|
|
79
|
-
* @throws NotFoundError no such account, rather than a foreign-key failure at the insert
|
|
80
|
-
*/
|
|
81
|
-
declare function createRevokeAllLink(userId: string | number, options?: CreateRevokeAllLinkOptions): Promise<RevokeAllLink>;
|
|
82
|
-
/**
|
|
83
|
-
* Say whether a presented link still works, and what pressing the button would
|
|
84
|
-
* do. Changes nothing — a mail scanner that opens the page has done nothing.
|
|
85
|
-
*
|
|
86
|
-
* @throws RevokeAllLinkError every refusal, in one shape
|
|
87
|
-
*/
|
|
88
|
-
declare function describeRevokeAllLink(token: string): Promise<RevokeAllLinkDescription>;
|
|
89
|
-
/**
|
|
90
|
-
* Spend a link and sign every device of the account out.
|
|
91
|
-
*
|
|
92
|
-
* The claim is one statement, so of two requests carrying the same token exactly
|
|
93
|
-
* one revokes and the other is refused as if the token were unknown — which by
|
|
94
|
-
* then it is. `includeCurrent` is true because there is no current device here:
|
|
95
|
-
* the caller holds a mailbox, not a session, and sparing something would mean
|
|
96
|
-
* sparing whatever the owner is trying to cut off.
|
|
97
|
-
*
|
|
98
|
-
* @returns how many device keys were revoked; zero is a success, not a refusal
|
|
99
|
-
* @throws RevokeAllLinkError every refusal, in the same shape `describe` uses
|
|
100
|
-
*/
|
|
101
|
-
declare function consumeRevokeAllLink(token: string): Promise<{
|
|
102
|
-
revokedCount: number;
|
|
103
|
-
}>;
|
|
104
|
-
/**
|
|
105
|
-
* Delete link rows that can no longer answer anything.
|
|
106
|
-
*
|
|
107
|
-
* @returns number of rows deleted
|
|
108
|
-
*/
|
|
109
|
-
declare function purgeRevokeAllTokensService(): Promise<{
|
|
110
|
-
deleted: number;
|
|
111
|
-
}>;
|
|
112
|
-
|
|
113
24
|
/**
|
|
114
25
|
* @spfn/auth - Global Configuration
|
|
115
26
|
*
|
|
@@ -341,6 +252,27 @@ declare function getCsrfMode(): CsrfMode;
|
|
|
341
252
|
* Get the paths exempted from the CSRF check (exact match, backend route paths)
|
|
342
253
|
*/
|
|
343
254
|
declare function getCsrfExemptPaths(): string[];
|
|
255
|
+
/**
|
|
256
|
+
* How long a key bound to a passkey lives, in milliseconds.
|
|
257
|
+
*
|
|
258
|
+
* A positive override is honoured; anything else falls back to the policy
|
|
259
|
+
* constant. Nothing refuses boot over it — unlike the passkey relying party, a
|
|
260
|
+
* nonsensical value here does not make every ceremony fail, it just means the
|
|
261
|
+
* default applies.
|
|
262
|
+
*/
|
|
263
|
+
declare function getBoundKeyTtlMs(): number;
|
|
264
|
+
/** How long past expiry a bound key may still be renewed, in milliseconds. */
|
|
265
|
+
declare function getBoundKeyRenewGraceMs(): number;
|
|
266
|
+
/** How close two sightings from two addresses must be to count as concurrent. */
|
|
267
|
+
declare function getConcurrentUseWindowMs(): number;
|
|
268
|
+
/**
|
|
269
|
+
* The page a bound session whose key expired is sent to.
|
|
270
|
+
*
|
|
271
|
+
* `RequireAuth` redirects here instead of to the sign-in page; the app renders a
|
|
272
|
+
* client component there that calls `renewSession(api)` and returns the person to
|
|
273
|
+
* where they were.
|
|
274
|
+
*/
|
|
275
|
+
declare function getSessionRenewPath(): string;
|
|
344
276
|
/**
|
|
345
277
|
* The relying party this deployment presents to authenticators, resolved.
|
|
346
278
|
*
|
|
@@ -399,6 +331,116 @@ declare function getPasskeyConfig(env?: PasskeyEnvSource): PasskeyConfig;
|
|
|
399
331
|
* @throws PasskeyConfigError when a passkey variable is set and cannot be honoured
|
|
400
332
|
*/
|
|
401
333
|
declare function assertPasskeyConfig(env?: PasskeyEnvSource): void;
|
|
334
|
+
/** What the second-factor routes read out of the environment. */
|
|
335
|
+
interface MfaConfig {
|
|
336
|
+
/** Name the authenticator app files the account under. */
|
|
337
|
+
issuer: string;
|
|
338
|
+
/** How long a device's step-up stays good for a sensitive change. */
|
|
339
|
+
stepUpWindowMs: number;
|
|
340
|
+
}
|
|
341
|
+
/**
|
|
342
|
+
* Resolve the second-factor configuration.
|
|
343
|
+
*
|
|
344
|
+
* Deliberately reads no passkey setting beyond `SPFN_AUTH_PASSKEY_RP_NAME`,
|
|
345
|
+
* and reads that as a plain string rather than through `getPasskeyConfig()`:
|
|
346
|
+
* an app with no passkeys configured at all must be able to enrol a TOTP and
|
|
347
|
+
* to step up, and `getPasskeyConfig()` refuses to resolve for such an app.
|
|
348
|
+
*
|
|
349
|
+
* Nothing here can fail the way the passkey config can, so there is no boot
|
|
350
|
+
* check to match: a bad step-up window falls back to the default rather than
|
|
351
|
+
* refusing to start, because the value it would refuse over is a number of
|
|
352
|
+
* minutes and the default is the safe one.
|
|
353
|
+
*/
|
|
354
|
+
declare function getMfaConfig(): MfaConfig;
|
|
355
|
+
|
|
356
|
+
/**
|
|
357
|
+
* @spfn/auth - Signed Sign-Out-Everywhere Link
|
|
358
|
+
*
|
|
359
|
+
* A link an app mails to an account's proven address, which signs every device
|
|
360
|
+
* of that account out without a session. It exists for the case the rest of the
|
|
361
|
+
* key surface cannot serve: the owner suspects a device they do not recognise,
|
|
362
|
+
* and the device they would have to sign in on to do something about it is the
|
|
363
|
+
* one they no longer trust.
|
|
364
|
+
*
|
|
365
|
+
* Three calls, and each is deliberately not the other two. `createRevokeAllLink`
|
|
366
|
+
* mints the capability and hands the app a URL. `describeRevokeAllLink` says
|
|
367
|
+
* whether that URL still works and changes nothing, so a mail scanner opening
|
|
368
|
+
* the page costs nothing. `consumeRevokeAllLink` is the only one that revokes,
|
|
369
|
+
* and it takes the owner pressing the button.
|
|
370
|
+
*
|
|
371
|
+
* The caller's obligation, which this package cannot enforce: the URL
|
|
372
|
+
* `createRevokeAllLink` returns carries the plaintext token, because the package
|
|
373
|
+
* sends no mail here. Do not log it, do not persist it, do not put it in a job
|
|
374
|
+
* payload — hand it to the mail template and let it go. Every other link in this
|
|
375
|
+
* package is minted inside the worker that sends it precisely so that no caller
|
|
376
|
+
* ever holds one; this one cannot be, and the obligation moves to the app.
|
|
377
|
+
*/
|
|
378
|
+
interface CreateRevokeAllLinkOptions {
|
|
379
|
+
/**
|
|
380
|
+
* Minutes the link stays valid. Defaults to
|
|
381
|
+
* `SPFN_AUTH_REVOKE_ALL_LINK_TTL_MINUTES`, itself 30.
|
|
382
|
+
*/
|
|
383
|
+
ttlMinutes?: number;
|
|
384
|
+
}
|
|
385
|
+
interface RevokeAllLink {
|
|
386
|
+
/** Absolute URL of the app page, token in its query string. Never log it. */
|
|
387
|
+
url: string;
|
|
388
|
+
expiresAt: Date;
|
|
389
|
+
}
|
|
390
|
+
/** What the describe call tells the page, so it can say what pressing the button does. */
|
|
391
|
+
interface RevokeAllLinkDescription {
|
|
392
|
+
expiresAt: Date;
|
|
393
|
+
activeKeyCount: number;
|
|
394
|
+
}
|
|
395
|
+
/**
|
|
396
|
+
* Mint a sign-out-everywhere link for an account.
|
|
397
|
+
*
|
|
398
|
+
* Issuing supersedes every live link the account already has, the rule the
|
|
399
|
+
* password-reset flow follows: an owner who asks twice must not leave the first
|
|
400
|
+
* capability working in their mailbox after using the second.
|
|
401
|
+
*
|
|
402
|
+
* The row records the account's key generation, so the link dies the moment any
|
|
403
|
+
* other path signs every device out — a password reset, a password change, a
|
|
404
|
+
* deletion request, or the ordinary revoke-all route.
|
|
405
|
+
*
|
|
406
|
+
* Send it beside a password reset link. It ends the sessions; it does not change
|
|
407
|
+
* the password that let them start.
|
|
408
|
+
*
|
|
409
|
+
* @param userId - The account to issue for
|
|
410
|
+
* @throws ValidationError `ttlMinutes` that is not a positive integer — no row is written
|
|
411
|
+
* @throws NotFoundError no such account, rather than a foreign-key failure at the insert
|
|
412
|
+
*/
|
|
413
|
+
declare function createRevokeAllLink(userId: string | number, options?: CreateRevokeAllLinkOptions): Promise<RevokeAllLink>;
|
|
414
|
+
/**
|
|
415
|
+
* Say whether a presented link still works, and what pressing the button would
|
|
416
|
+
* do. Changes nothing — a mail scanner that opens the page has done nothing.
|
|
417
|
+
*
|
|
418
|
+
* @throws RevokeAllLinkError every refusal, in one shape
|
|
419
|
+
*/
|
|
420
|
+
declare function describeRevokeAllLink(token: string): Promise<RevokeAllLinkDescription>;
|
|
421
|
+
/**
|
|
422
|
+
* Spend a link and sign every device of the account out.
|
|
423
|
+
*
|
|
424
|
+
* The claim is one statement, so of two requests carrying the same token exactly
|
|
425
|
+
* one revokes and the other is refused as if the token were unknown — which by
|
|
426
|
+
* then it is. `includeCurrent` is true because there is no current device here:
|
|
427
|
+
* the caller holds a mailbox, not a session, and sparing something would mean
|
|
428
|
+
* sparing whatever the owner is trying to cut off.
|
|
429
|
+
*
|
|
430
|
+
* @returns how many device keys were revoked; zero is a success, not a refusal
|
|
431
|
+
* @throws RevokeAllLinkError every refusal, in the same shape `describe` uses
|
|
432
|
+
*/
|
|
433
|
+
declare function consumeRevokeAllLink(token: string): Promise<{
|
|
434
|
+
revokedCount: number;
|
|
435
|
+
}>;
|
|
436
|
+
/**
|
|
437
|
+
* Delete link rows that can no longer answer anything.
|
|
438
|
+
*
|
|
439
|
+
* @returns number of rows deleted
|
|
440
|
+
*/
|
|
441
|
+
declare function purgeRevokeAllTokensService(): Promise<{
|
|
442
|
+
deleted: number;
|
|
443
|
+
}>;
|
|
402
444
|
|
|
403
445
|
/**
|
|
404
446
|
* @spfn/auth - Users Entity
|
|
@@ -657,6 +699,36 @@ declare const users: drizzle_orm_pg_core.PgTableWithColumns<{
|
|
|
657
699
|
identity: undefined;
|
|
658
700
|
generated: undefined;
|
|
659
701
|
}>;
|
|
702
|
+
sessionBinding: drizzle_orm_pg_core.PgBuildColumn<"users", drizzle_orm_pg_core.SetHasDefault<drizzle_orm_pg_core.SetNotNull<drizzle_orm_pg_core.PgTextBuilder<["none", "passkey"] & [string, ...string[]]>>>, {
|
|
703
|
+
name: string;
|
|
704
|
+
tableName: "users";
|
|
705
|
+
dataType: "string enum";
|
|
706
|
+
data: "none" | "passkey";
|
|
707
|
+
driverParam: string;
|
|
708
|
+
notNull: true;
|
|
709
|
+
hasDefault: true;
|
|
710
|
+
isPrimaryKey: false;
|
|
711
|
+
isAutoincrement: false;
|
|
712
|
+
hasRuntimeDefault: false;
|
|
713
|
+
enumValues: ["none", "passkey"] & [string, ...string[]];
|
|
714
|
+
identity: undefined;
|
|
715
|
+
generated: undefined;
|
|
716
|
+
}>;
|
|
717
|
+
sessionBindingChangedAt: drizzle_orm_pg_core.PgBuildColumn<"users", drizzle_orm_pg_core.PgTimestampBuilder, {
|
|
718
|
+
name: string;
|
|
719
|
+
tableName: "users";
|
|
720
|
+
dataType: "object date";
|
|
721
|
+
data: Date;
|
|
722
|
+
driverParam: string;
|
|
723
|
+
notNull: false;
|
|
724
|
+
hasDefault: false;
|
|
725
|
+
isPrimaryKey: false;
|
|
726
|
+
isAutoincrement: false;
|
|
727
|
+
hasRuntimeDefault: false;
|
|
728
|
+
enumValues: undefined;
|
|
729
|
+
identity: undefined;
|
|
730
|
+
generated: undefined;
|
|
731
|
+
}>;
|
|
660
732
|
lastLoginAt: drizzle_orm_pg_core.PgBuildColumn<"users", drizzle_orm_pg_core.PgTimestampBuilder, {
|
|
661
733
|
name: string;
|
|
662
734
|
tableName: "users";
|
|
@@ -704,6 +776,8 @@ declare function getUserByIdService(userId: number): Promise<{
|
|
|
704
776
|
emailVerifiedAt: Date | null;
|
|
705
777
|
phoneVerifiedAt: Date | null;
|
|
706
778
|
keyEpoch: number;
|
|
779
|
+
sessionBinding: "none" | "passkey";
|
|
780
|
+
sessionBindingChangedAt: Date | null;
|
|
707
781
|
lastLoginAt: Date | null;
|
|
708
782
|
}>;
|
|
709
783
|
/**
|
|
@@ -726,6 +800,8 @@ declare function getUserByEmailService(email: string): Promise<{
|
|
|
726
800
|
emailVerifiedAt: Date | null;
|
|
727
801
|
phoneVerifiedAt: Date | null;
|
|
728
802
|
keyEpoch: number;
|
|
803
|
+
sessionBinding: "none" | "passkey";
|
|
804
|
+
sessionBindingChangedAt: Date | null;
|
|
729
805
|
lastLoginAt: Date | null;
|
|
730
806
|
}>;
|
|
731
807
|
/**
|
|
@@ -748,6 +824,8 @@ declare function getUserByPhoneService(phone: string): Promise<{
|
|
|
748
824
|
emailVerifiedAt: Date | null;
|
|
749
825
|
phoneVerifiedAt: Date | null;
|
|
750
826
|
keyEpoch: number;
|
|
827
|
+
sessionBinding: "none" | "passkey";
|
|
828
|
+
sessionBindingChangedAt: Date | null;
|
|
751
829
|
lastLoginAt: Date | null;
|
|
752
830
|
}>;
|
|
753
831
|
/**
|
|
@@ -789,6 +867,8 @@ declare function updateUsernameService(userId: string | number | bigint, usernam
|
|
|
789
867
|
emailVerifiedAt: Date | null;
|
|
790
868
|
phoneVerifiedAt: Date | null;
|
|
791
869
|
keyEpoch: number;
|
|
870
|
+
sessionBinding: "none" | "passkey";
|
|
871
|
+
sessionBindingChangedAt: Date | null;
|
|
792
872
|
lastLoginAt: Date | null;
|
|
793
873
|
}>;
|
|
794
874
|
|
|
@@ -2002,6 +2082,14 @@ declare function verifyIdToken(params: VerifyIdTokenParams): Promise<JWTPayload>
|
|
|
2002
2082
|
* Never include token or key material in logs or error messages.
|
|
2003
2083
|
*/
|
|
2004
2084
|
|
|
2085
|
+
/**
|
|
2086
|
+
* Framing prefix of the current at-rest format: `enc:v2:<keyId>:<payload>`.
|
|
2087
|
+
*
|
|
2088
|
+
* Exported because the MFA secret cipher writes the same frame over the same
|
|
2089
|
+
* keyring (`lib/mfa-cipher.ts`) — one format for everything this package
|
|
2090
|
+
* encrypts at rest, rather than a second one nobody would remember to rotate.
|
|
2091
|
+
*/
|
|
2092
|
+
declare const V2_PREFIX = "enc:v2:";
|
|
2005
2093
|
type OAuthTokenType = 'access' | 'refresh';
|
|
2006
2094
|
interface OAuthTokenContext {
|
|
2007
2095
|
provider: SocialProvider;
|
|
@@ -2017,6 +2105,21 @@ interface OAuthTokenCipher {
|
|
|
2017
2105
|
encrypt(value: string, context: OAuthTokenContext): Promise<string>;
|
|
2018
2106
|
decrypt(value: string, context: OAuthTokenContext): Promise<DecryptedOAuthToken>;
|
|
2019
2107
|
}
|
|
2108
|
+
interface TokenEncryptionKey {
|
|
2109
|
+
keyId: string;
|
|
2110
|
+
key: Buffer;
|
|
2111
|
+
}
|
|
2112
|
+
/**
|
|
2113
|
+
* Parse `<keyId>:<base64-encoded 32-byte key>` entries. The first entry is active.
|
|
2114
|
+
*
|
|
2115
|
+
* Empty when the variable is unset — whether that is a configuration error is
|
|
2116
|
+
* the caller's to decide, and the two callers answer it differently: an OAuth
|
|
2117
|
+
* token refuses outright, while an MFA secret raises `MfaConfigError` so the
|
|
2118
|
+
* refusal cannot be mistaken for a wrong code.
|
|
2119
|
+
*
|
|
2120
|
+
* @throws Error when an entry is present but malformed
|
|
2121
|
+
*/
|
|
2122
|
+
declare function getEncryptionKeyring(): TokenEncryptionKey[];
|
|
2020
2123
|
declare class EnvironmentKeyringTokenCipher implements OAuthTokenCipher {
|
|
2021
2124
|
encrypt(value: string, context: OAuthTokenContext): Promise<string>;
|
|
2022
2125
|
decrypt(value: string, context: OAuthTokenContext): Promise<DecryptedOAuthToken>;
|
|
@@ -3115,25 +3218,20 @@ type UserProfile = typeof userProfiles.$inferSelect;
|
|
|
3115
3218
|
type NewUserProfile = typeof userProfiles.$inferInsert;
|
|
3116
3219
|
|
|
3117
3220
|
/**
|
|
3118
|
-
* @spfn/auth - User
|
|
3221
|
+
* @spfn/auth - User Social Accounts Entity
|
|
3119
3222
|
*
|
|
3120
|
-
* Stores
|
|
3121
|
-
* Supports key rotation and multi-key management per user
|
|
3122
|
-
*/
|
|
3123
|
-
/**
|
|
3124
|
-
* User Public Keys Table
|
|
3125
|
-
* Each user can have multiple public keys (for rotation)
|
|
3223
|
+
* Stores OAuth connections for social login providers
|
|
3126
3224
|
*/
|
|
3127
|
-
declare const
|
|
3128
|
-
name: "
|
|
3225
|
+
declare const userSocialAccounts: drizzle_orm_pg_core.PgTableWithColumns<{
|
|
3226
|
+
name: "user_social_accounts";
|
|
3129
3227
|
schema: string;
|
|
3130
3228
|
columns: {
|
|
3131
|
-
|
|
3229
|
+
createdAt: drizzle_orm_pg_core.PgBuildColumn<"user_social_accounts", drizzle_orm_pg_core.SetNotNull<drizzle_orm_pg_core.SetHasDefault<drizzle_orm_pg_core.PgTimestampBuilder>>, {
|
|
3132
3230
|
name: string;
|
|
3133
|
-
tableName: "
|
|
3134
|
-
dataType: "
|
|
3135
|
-
data:
|
|
3136
|
-
driverParam:
|
|
3231
|
+
tableName: "user_social_accounts";
|
|
3232
|
+
dataType: "object date";
|
|
3233
|
+
data: Date;
|
|
3234
|
+
driverParam: string;
|
|
3137
3235
|
notNull: true;
|
|
3138
3236
|
hasDefault: true;
|
|
3139
3237
|
isPrimaryKey: false;
|
|
@@ -3143,14 +3241,14 @@ declare const userPublicKeys: drizzle_orm_pg_core.PgTableWithColumns<{
|
|
|
3143
3241
|
identity: undefined;
|
|
3144
3242
|
generated: undefined;
|
|
3145
3243
|
}>;
|
|
3146
|
-
|
|
3244
|
+
updatedAt: drizzle_orm_pg_core.PgBuildColumn<"user_social_accounts", drizzle_orm_pg_core.SetHasDefault<drizzle_orm_pg_core.SetNotNull<drizzle_orm_pg_core.SetHasDefault<drizzle_orm_pg_core.PgTimestampBuilder>>>, {
|
|
3147
3245
|
name: string;
|
|
3148
|
-
tableName: "
|
|
3149
|
-
dataType: "
|
|
3150
|
-
data:
|
|
3151
|
-
driverParam: string
|
|
3246
|
+
tableName: "user_social_accounts";
|
|
3247
|
+
dataType: "object date";
|
|
3248
|
+
data: Date;
|
|
3249
|
+
driverParam: string;
|
|
3152
3250
|
notNull: true;
|
|
3153
|
-
hasDefault:
|
|
3251
|
+
hasDefault: true;
|
|
3154
3252
|
isPrimaryKey: false;
|
|
3155
3253
|
isAutoincrement: false;
|
|
3156
3254
|
hasRuntimeDefault: false;
|
|
@@ -3158,27 +3256,27 @@ declare const userPublicKeys: drizzle_orm_pg_core.PgTableWithColumns<{
|
|
|
3158
3256
|
identity: undefined;
|
|
3159
3257
|
generated: undefined;
|
|
3160
3258
|
}>;
|
|
3161
|
-
|
|
3259
|
+
id: drizzle_orm_pg_core.PgBuildColumn<"user_social_accounts", drizzle_orm_pg_core.SetIsPrimaryKey<drizzle_orm_pg_core.PgBigSerial53Builder>, {
|
|
3162
3260
|
name: string;
|
|
3163
|
-
tableName: "
|
|
3164
|
-
dataType: "
|
|
3165
|
-
data:
|
|
3166
|
-
driverParam:
|
|
3167
|
-
notNull: true;
|
|
3168
|
-
hasDefault:
|
|
3169
|
-
isPrimaryKey: false;
|
|
3261
|
+
tableName: "user_social_accounts";
|
|
3262
|
+
dataType: "number int53";
|
|
3263
|
+
data: number;
|
|
3264
|
+
driverParam: number;
|
|
3265
|
+
notNull: true;
|
|
3266
|
+
hasDefault: true;
|
|
3267
|
+
isPrimaryKey: false;
|
|
3170
3268
|
isAutoincrement: false;
|
|
3171
3269
|
hasRuntimeDefault: false;
|
|
3172
3270
|
enumValues: undefined;
|
|
3173
3271
|
identity: undefined;
|
|
3174
3272
|
generated: undefined;
|
|
3175
3273
|
}>;
|
|
3176
|
-
|
|
3274
|
+
userId: drizzle_orm_pg_core.PgBuildColumn<"user_social_accounts", drizzle_orm_pg_core.SetNotNull<drizzle_orm_pg_core.PgBigInt53Builder>, {
|
|
3177
3275
|
name: string;
|
|
3178
|
-
tableName: "
|
|
3179
|
-
dataType: "
|
|
3180
|
-
data:
|
|
3181
|
-
driverParam: string;
|
|
3276
|
+
tableName: "user_social_accounts";
|
|
3277
|
+
dataType: "number int53";
|
|
3278
|
+
data: number;
|
|
3279
|
+
driverParam: string | number;
|
|
3182
3280
|
notNull: true;
|
|
3183
3281
|
hasDefault: false;
|
|
3184
3282
|
isPrimaryKey: false;
|
|
@@ -3188,24 +3286,24 @@ declare const userPublicKeys: drizzle_orm_pg_core.PgTableWithColumns<{
|
|
|
3188
3286
|
identity: undefined;
|
|
3189
3287
|
generated: undefined;
|
|
3190
3288
|
}>;
|
|
3191
|
-
|
|
3289
|
+
provider: drizzle_orm_pg_core.PgBuildColumn<"user_social_accounts", drizzle_orm_pg_core.SetNotNull<drizzle_orm_pg_core.PgTextBuilder<["google", "apple", "github", "kakao", "naver", "superself"] & [string, ...string[]]>>, {
|
|
3192
3290
|
name: string;
|
|
3193
|
-
tableName: "
|
|
3291
|
+
tableName: "user_social_accounts";
|
|
3194
3292
|
dataType: "string enum";
|
|
3195
|
-
data: "
|
|
3293
|
+
data: "google" | "apple" | "github" | "kakao" | "naver" | "superself";
|
|
3196
3294
|
driverParam: string;
|
|
3197
3295
|
notNull: true;
|
|
3198
|
-
hasDefault:
|
|
3296
|
+
hasDefault: false;
|
|
3199
3297
|
isPrimaryKey: false;
|
|
3200
3298
|
isAutoincrement: false;
|
|
3201
3299
|
hasRuntimeDefault: false;
|
|
3202
|
-
enumValues: ["
|
|
3300
|
+
enumValues: ["google", "apple", "github", "kakao", "naver", "superself"] & [string, ...string[]];
|
|
3203
3301
|
identity: undefined;
|
|
3204
3302
|
generated: undefined;
|
|
3205
3303
|
}>;
|
|
3206
|
-
|
|
3304
|
+
providerUserId: drizzle_orm_pg_core.PgBuildColumn<"user_social_accounts", drizzle_orm_pg_core.SetNotNull<drizzle_orm_pg_core.PgTextBuilder<[string, ...string[]]>>, {
|
|
3207
3305
|
name: string;
|
|
3208
|
-
tableName: "
|
|
3306
|
+
tableName: "user_social_accounts";
|
|
3209
3307
|
dataType: "string";
|
|
3210
3308
|
data: string;
|
|
3211
3309
|
driverParam: string;
|
|
@@ -3218,9 +3316,9 @@ declare const userPublicKeys: drizzle_orm_pg_core.PgTableWithColumns<{
|
|
|
3218
3316
|
identity: undefined;
|
|
3219
3317
|
generated: undefined;
|
|
3220
3318
|
}>;
|
|
3221
|
-
|
|
3319
|
+
providerEmail: drizzle_orm_pg_core.PgBuildColumn<"user_social_accounts", drizzle_orm_pg_core.PgTextBuilder<[string, ...string[]]>, {
|
|
3222
3320
|
name: string;
|
|
3223
|
-
tableName: "
|
|
3321
|
+
tableName: "user_social_accounts";
|
|
3224
3322
|
dataType: "string";
|
|
3225
3323
|
data: string;
|
|
3226
3324
|
driverParam: string;
|
|
@@ -3233,24 +3331,24 @@ declare const userPublicKeys: drizzle_orm_pg_core.PgTableWithColumns<{
|
|
|
3233
3331
|
identity: undefined;
|
|
3234
3332
|
generated: undefined;
|
|
3235
3333
|
}>;
|
|
3236
|
-
|
|
3334
|
+
accessToken: drizzle_orm_pg_core.PgBuildColumn<"user_social_accounts", drizzle_orm_pg_core.PgTextBuilder<[string, ...string[]]>, {
|
|
3237
3335
|
name: string;
|
|
3238
|
-
tableName: "
|
|
3239
|
-
dataType: "string
|
|
3240
|
-
data:
|
|
3336
|
+
tableName: "user_social_accounts";
|
|
3337
|
+
dataType: "string";
|
|
3338
|
+
data: string;
|
|
3241
3339
|
driverParam: string;
|
|
3242
3340
|
notNull: false;
|
|
3243
3341
|
hasDefault: false;
|
|
3244
3342
|
isPrimaryKey: false;
|
|
3245
3343
|
isAutoincrement: false;
|
|
3246
3344
|
hasRuntimeDefault: false;
|
|
3247
|
-
enumValues:
|
|
3345
|
+
enumValues: undefined;
|
|
3248
3346
|
identity: undefined;
|
|
3249
3347
|
generated: undefined;
|
|
3250
3348
|
}>;
|
|
3251
|
-
|
|
3349
|
+
refreshToken: drizzle_orm_pg_core.PgBuildColumn<"user_social_accounts", drizzle_orm_pg_core.PgTextBuilder<[string, ...string[]]>, {
|
|
3252
3350
|
name: string;
|
|
3253
|
-
tableName: "
|
|
3351
|
+
tableName: "user_social_accounts";
|
|
3254
3352
|
dataType: "string";
|
|
3255
3353
|
data: string;
|
|
3256
3354
|
driverParam: string;
|
|
@@ -3263,11 +3361,11 @@ declare const userPublicKeys: drizzle_orm_pg_core.PgTableWithColumns<{
|
|
|
3263
3361
|
identity: undefined;
|
|
3264
3362
|
generated: undefined;
|
|
3265
3363
|
}>;
|
|
3266
|
-
|
|
3364
|
+
tokenExpiresAt: drizzle_orm_pg_core.PgBuildColumn<"user_social_accounts", drizzle_orm_pg_core.PgTimestampBuilder, {
|
|
3267
3365
|
name: string;
|
|
3268
|
-
tableName: "
|
|
3269
|
-
dataType: "
|
|
3270
|
-
data:
|
|
3366
|
+
tableName: "user_social_accounts";
|
|
3367
|
+
dataType: "object date";
|
|
3368
|
+
data: Date;
|
|
3271
3369
|
driverParam: string;
|
|
3272
3370
|
notNull: false;
|
|
3273
3371
|
hasDefault: false;
|
|
@@ -3278,29 +3376,45 @@ declare const userPublicKeys: drizzle_orm_pg_core.PgTableWithColumns<{
|
|
|
3278
3376
|
identity: undefined;
|
|
3279
3377
|
generated: undefined;
|
|
3280
3378
|
}>;
|
|
3281
|
-
|
|
3379
|
+
};
|
|
3380
|
+
dialect: "pg";
|
|
3381
|
+
}>;
|
|
3382
|
+
type UserSocialAccount = typeof userSocialAccounts.$inferSelect;
|
|
3383
|
+
type NewUserSocialAccount = typeof userSocialAccounts.$inferInsert;
|
|
3384
|
+
|
|
3385
|
+
/**
|
|
3386
|
+
* @spfn/auth - Verification Codes Entity
|
|
3387
|
+
*
|
|
3388
|
+
* Stores verification codes for email and phone verification
|
|
3389
|
+
* Codes expire after a configurable time period
|
|
3390
|
+
*/
|
|
3391
|
+
declare const verificationCodes: drizzle_orm_pg_core.PgTableWithColumns<{
|
|
3392
|
+
name: "verification_codes";
|
|
3393
|
+
schema: string;
|
|
3394
|
+
columns: {
|
|
3395
|
+
createdAt: drizzle_orm_pg_core.PgBuildColumn<"verification_codes", drizzle_orm_pg_core.SetNotNull<drizzle_orm_pg_core.SetHasDefault<drizzle_orm_pg_core.PgTimestampBuilder>>, {
|
|
3282
3396
|
name: string;
|
|
3283
|
-
tableName: "
|
|
3284
|
-
dataType: "
|
|
3285
|
-
data:
|
|
3397
|
+
tableName: "verification_codes";
|
|
3398
|
+
dataType: "object date";
|
|
3399
|
+
data: Date;
|
|
3286
3400
|
driverParam: string;
|
|
3287
|
-
notNull:
|
|
3288
|
-
hasDefault:
|
|
3401
|
+
notNull: true;
|
|
3402
|
+
hasDefault: true;
|
|
3289
3403
|
isPrimaryKey: false;
|
|
3290
3404
|
isAutoincrement: false;
|
|
3291
3405
|
hasRuntimeDefault: false;
|
|
3292
|
-
enumValues:
|
|
3406
|
+
enumValues: undefined;
|
|
3293
3407
|
identity: undefined;
|
|
3294
3408
|
generated: undefined;
|
|
3295
3409
|
}>;
|
|
3296
|
-
|
|
3410
|
+
updatedAt: drizzle_orm_pg_core.PgBuildColumn<"verification_codes", drizzle_orm_pg_core.SetHasDefault<drizzle_orm_pg_core.SetNotNull<drizzle_orm_pg_core.SetHasDefault<drizzle_orm_pg_core.PgTimestampBuilder>>>, {
|
|
3297
3411
|
name: string;
|
|
3298
|
-
tableName: "
|
|
3299
|
-
dataType: "
|
|
3300
|
-
data:
|
|
3412
|
+
tableName: "verification_codes";
|
|
3413
|
+
dataType: "object date";
|
|
3414
|
+
data: Date;
|
|
3301
3415
|
driverParam: string;
|
|
3302
|
-
notNull:
|
|
3303
|
-
hasDefault:
|
|
3416
|
+
notNull: true;
|
|
3417
|
+
hasDefault: true;
|
|
3304
3418
|
isPrimaryKey: false;
|
|
3305
3419
|
isAutoincrement: false;
|
|
3306
3420
|
hasRuntimeDefault: false;
|
|
@@ -3308,14 +3422,14 @@ declare const userPublicKeys: drizzle_orm_pg_core.PgTableWithColumns<{
|
|
|
3308
3422
|
identity: undefined;
|
|
3309
3423
|
generated: undefined;
|
|
3310
3424
|
}>;
|
|
3311
|
-
|
|
3425
|
+
id: drizzle_orm_pg_core.PgBuildColumn<"verification_codes", drizzle_orm_pg_core.SetIsPrimaryKey<drizzle_orm_pg_core.PgBigSerial53Builder>, {
|
|
3312
3426
|
name: string;
|
|
3313
|
-
tableName: "
|
|
3314
|
-
dataType: "
|
|
3315
|
-
data:
|
|
3316
|
-
driverParam:
|
|
3317
|
-
notNull:
|
|
3318
|
-
hasDefault:
|
|
3427
|
+
tableName: "verification_codes";
|
|
3428
|
+
dataType: "number int53";
|
|
3429
|
+
data: number;
|
|
3430
|
+
driverParam: number;
|
|
3431
|
+
notNull: true;
|
|
3432
|
+
hasDefault: true;
|
|
3319
3433
|
isPrimaryKey: false;
|
|
3320
3434
|
isAutoincrement: false;
|
|
3321
3435
|
hasRuntimeDefault: false;
|
|
@@ -3323,13 +3437,13 @@ declare const userPublicKeys: drizzle_orm_pg_core.PgTableWithColumns<{
|
|
|
3323
3437
|
identity: undefined;
|
|
3324
3438
|
generated: undefined;
|
|
3325
3439
|
}>;
|
|
3326
|
-
|
|
3440
|
+
target: drizzle_orm_pg_core.PgBuildColumn<"verification_codes", drizzle_orm_pg_core.SetNotNull<drizzle_orm_pg_core.PgTextBuilder<[string, ...string[]]>>, {
|
|
3327
3441
|
name: string;
|
|
3328
|
-
tableName: "
|
|
3329
|
-
dataType: "
|
|
3330
|
-
data:
|
|
3442
|
+
tableName: "verification_codes";
|
|
3443
|
+
dataType: "string";
|
|
3444
|
+
data: string;
|
|
3331
3445
|
driverParam: string;
|
|
3332
|
-
notNull:
|
|
3446
|
+
notNull: true;
|
|
3333
3447
|
hasDefault: false;
|
|
3334
3448
|
isPrimaryKey: false;
|
|
3335
3449
|
isAutoincrement: false;
|
|
@@ -3338,29 +3452,29 @@ declare const userPublicKeys: drizzle_orm_pg_core.PgTableWithColumns<{
|
|
|
3338
3452
|
identity: undefined;
|
|
3339
3453
|
generated: undefined;
|
|
3340
3454
|
}>;
|
|
3341
|
-
|
|
3455
|
+
targetType: drizzle_orm_pg_core.PgBuildColumn<"verification_codes", drizzle_orm_pg_core.SetNotNull<drizzle_orm_pg_core.PgTextBuilder<["email", "phone"] & [string, ...string[]]>>, {
|
|
3342
3456
|
name: string;
|
|
3343
|
-
tableName: "
|
|
3344
|
-
dataType: "
|
|
3345
|
-
data:
|
|
3346
|
-
driverParam:
|
|
3457
|
+
tableName: "verification_codes";
|
|
3458
|
+
dataType: "string enum";
|
|
3459
|
+
data: "email" | "phone";
|
|
3460
|
+
driverParam: string;
|
|
3347
3461
|
notNull: true;
|
|
3348
|
-
hasDefault:
|
|
3462
|
+
hasDefault: false;
|
|
3349
3463
|
isPrimaryKey: false;
|
|
3350
3464
|
isAutoincrement: false;
|
|
3351
3465
|
hasRuntimeDefault: false;
|
|
3352
|
-
enumValues:
|
|
3466
|
+
enumValues: ["email", "phone"] & [string, ...string[]];
|
|
3353
3467
|
identity: undefined;
|
|
3354
3468
|
generated: undefined;
|
|
3355
3469
|
}>;
|
|
3356
|
-
|
|
3470
|
+
code: drizzle_orm_pg_core.PgBuildColumn<"verification_codes", drizzle_orm_pg_core.SetNotNull<drizzle_orm_pg_core.PgTextBuilder<[string, ...string[]]>>, {
|
|
3357
3471
|
name: string;
|
|
3358
|
-
tableName: "
|
|
3359
|
-
dataType: "
|
|
3360
|
-
data:
|
|
3472
|
+
tableName: "verification_codes";
|
|
3473
|
+
dataType: "string";
|
|
3474
|
+
data: string;
|
|
3361
3475
|
driverParam: string;
|
|
3362
3476
|
notNull: true;
|
|
3363
|
-
hasDefault:
|
|
3477
|
+
hasDefault: false;
|
|
3364
3478
|
isPrimaryKey: false;
|
|
3365
3479
|
isAutoincrement: false;
|
|
3366
3480
|
hasRuntimeDefault: false;
|
|
@@ -3368,28 +3482,28 @@ declare const userPublicKeys: drizzle_orm_pg_core.PgTableWithColumns<{
|
|
|
3368
3482
|
identity: undefined;
|
|
3369
3483
|
generated: undefined;
|
|
3370
3484
|
}>;
|
|
3371
|
-
|
|
3485
|
+
purpose: drizzle_orm_pg_core.PgBuildColumn<"verification_codes", drizzle_orm_pg_core.SetNotNull<drizzle_orm_pg_core.PgTextBuilder<["registration", "login", "password_reset", "email_change", "phone_change", "account_deletion"] & [string, ...string[]]>>, {
|
|
3372
3486
|
name: string;
|
|
3373
|
-
tableName: "
|
|
3374
|
-
dataType: "
|
|
3375
|
-
data:
|
|
3487
|
+
tableName: "verification_codes";
|
|
3488
|
+
dataType: "string enum";
|
|
3489
|
+
data: "registration" | "login" | "password_reset" | "email_change" | "phone_change" | "account_deletion";
|
|
3376
3490
|
driverParam: string;
|
|
3377
|
-
notNull:
|
|
3491
|
+
notNull: true;
|
|
3378
3492
|
hasDefault: false;
|
|
3379
3493
|
isPrimaryKey: false;
|
|
3380
3494
|
isAutoincrement: false;
|
|
3381
3495
|
hasRuntimeDefault: false;
|
|
3382
|
-
enumValues:
|
|
3496
|
+
enumValues: ["registration", "login", "password_reset", "email_change", "phone_change", "account_deletion"] & [string, ...string[]];
|
|
3383
3497
|
identity: undefined;
|
|
3384
3498
|
generated: undefined;
|
|
3385
3499
|
}>;
|
|
3386
|
-
expiresAt: drizzle_orm_pg_core.PgBuildColumn<"
|
|
3500
|
+
expiresAt: drizzle_orm_pg_core.PgBuildColumn<"verification_codes", drizzle_orm_pg_core.SetNotNull<drizzle_orm_pg_core.PgTimestampBuilder>, {
|
|
3387
3501
|
name: string;
|
|
3388
|
-
tableName: "
|
|
3502
|
+
tableName: "verification_codes";
|
|
3389
3503
|
dataType: "object date";
|
|
3390
3504
|
data: Date;
|
|
3391
3505
|
driverParam: string;
|
|
3392
|
-
notNull:
|
|
3506
|
+
notNull: true;
|
|
3393
3507
|
hasDefault: false;
|
|
3394
3508
|
isPrimaryKey: false;
|
|
3395
3509
|
isAutoincrement: false;
|
|
@@ -3398,9 +3512,9 @@ declare const userPublicKeys: drizzle_orm_pg_core.PgTableWithColumns<{
|
|
|
3398
3512
|
identity: undefined;
|
|
3399
3513
|
generated: undefined;
|
|
3400
3514
|
}>;
|
|
3401
|
-
|
|
3515
|
+
usedAt: drizzle_orm_pg_core.PgBuildColumn<"verification_codes", drizzle_orm_pg_core.PgTimestampBuilder, {
|
|
3402
3516
|
name: string;
|
|
3403
|
-
tableName: "
|
|
3517
|
+
tableName: "verification_codes";
|
|
3404
3518
|
dataType: "object date";
|
|
3405
3519
|
data: Date;
|
|
3406
3520
|
driverParam: string;
|
|
@@ -3413,14 +3527,14 @@ declare const userPublicKeys: drizzle_orm_pg_core.PgTableWithColumns<{
|
|
|
3413
3527
|
identity: undefined;
|
|
3414
3528
|
generated: undefined;
|
|
3415
3529
|
}>;
|
|
3416
|
-
|
|
3530
|
+
attempts: drizzle_orm_pg_core.PgBuildColumn<"verification_codes", drizzle_orm_pg_core.SetHasDefault<drizzle_orm_pg_core.SetNotNull<drizzle_orm_pg_core.PgIntegerBuilder>>, {
|
|
3417
3531
|
name: string;
|
|
3418
|
-
tableName: "
|
|
3419
|
-
dataType: "
|
|
3420
|
-
data:
|
|
3421
|
-
driverParam: string;
|
|
3422
|
-
notNull:
|
|
3423
|
-
hasDefault:
|
|
3532
|
+
tableName: "verification_codes";
|
|
3533
|
+
dataType: "number int32";
|
|
3534
|
+
data: number;
|
|
3535
|
+
driverParam: string | number;
|
|
3536
|
+
notNull: true;
|
|
3537
|
+
hasDefault: true;
|
|
3424
3538
|
isPrimaryKey: false;
|
|
3425
3539
|
isAutoincrement: false;
|
|
3426
3540
|
hasRuntimeDefault: false;
|
|
@@ -3431,21 +3545,29 @@ declare const userPublicKeys: drizzle_orm_pg_core.PgTableWithColumns<{
|
|
|
3431
3545
|
};
|
|
3432
3546
|
dialect: "pg";
|
|
3433
3547
|
}>;
|
|
3434
|
-
type
|
|
3435
|
-
type
|
|
3548
|
+
type VerificationCode = typeof verificationCodes.$inferSelect;
|
|
3549
|
+
type NewVerificationCode = typeof verificationCodes.$inferInsert;
|
|
3436
3550
|
|
|
3437
3551
|
/**
|
|
3438
|
-
* @spfn/auth -
|
|
3552
|
+
* @spfn/auth - Signup Link Tokens Entity
|
|
3439
3553
|
*
|
|
3440
|
-
*
|
|
3554
|
+
* Backs the verified-email signup flow: a one-time confirmation link is emailed,
|
|
3555
|
+
* opening it mints a short-lived setup session, and setting a password on that
|
|
3556
|
+
* session creates the account.
|
|
3557
|
+
*
|
|
3558
|
+
* A separate table from `verification_codes` on purpose. That table stores its
|
|
3559
|
+
* six-digit code in plaintext, which is acceptable for a short-lived numeric code
|
|
3560
|
+
* bounded by an attempt counter, but a link token is a bearer credential sitting
|
|
3561
|
+
* in someone's mailbox and must only ever be stored as a hash. Sharing one table
|
|
3562
|
+
* would make "plaintext or hash" a per-row property that nothing enforces.
|
|
3441
3563
|
*/
|
|
3442
|
-
declare const
|
|
3443
|
-
name: "
|
|
3564
|
+
declare const signupLinkTokens: drizzle_orm_pg_core.PgTableWithColumns<{
|
|
3565
|
+
name: "signup_link_tokens";
|
|
3444
3566
|
schema: string;
|
|
3445
3567
|
columns: {
|
|
3446
|
-
createdAt: drizzle_orm_pg_core.PgBuildColumn<"
|
|
3568
|
+
createdAt: drizzle_orm_pg_core.PgBuildColumn<"signup_link_tokens", drizzle_orm_pg_core.SetNotNull<drizzle_orm_pg_core.SetHasDefault<drizzle_orm_pg_core.PgTimestampBuilder>>, {
|
|
3447
3569
|
name: string;
|
|
3448
|
-
tableName: "
|
|
3570
|
+
tableName: "signup_link_tokens";
|
|
3449
3571
|
dataType: "object date";
|
|
3450
3572
|
data: Date;
|
|
3451
3573
|
driverParam: string;
|
|
@@ -3458,9 +3580,9 @@ declare const userSocialAccounts: drizzle_orm_pg_core.PgTableWithColumns<{
|
|
|
3458
3580
|
identity: undefined;
|
|
3459
3581
|
generated: undefined;
|
|
3460
3582
|
}>;
|
|
3461
|
-
updatedAt: drizzle_orm_pg_core.PgBuildColumn<"
|
|
3583
|
+
updatedAt: drizzle_orm_pg_core.PgBuildColumn<"signup_link_tokens", drizzle_orm_pg_core.SetHasDefault<drizzle_orm_pg_core.SetNotNull<drizzle_orm_pg_core.SetHasDefault<drizzle_orm_pg_core.PgTimestampBuilder>>>, {
|
|
3462
3584
|
name: string;
|
|
3463
|
-
tableName: "
|
|
3585
|
+
tableName: "signup_link_tokens";
|
|
3464
3586
|
dataType: "object date";
|
|
3465
3587
|
data: Date;
|
|
3466
3588
|
driverParam: string;
|
|
@@ -3473,9 +3595,9 @@ declare const userSocialAccounts: drizzle_orm_pg_core.PgTableWithColumns<{
|
|
|
3473
3595
|
identity: undefined;
|
|
3474
3596
|
generated: undefined;
|
|
3475
3597
|
}>;
|
|
3476
|
-
id: drizzle_orm_pg_core.PgBuildColumn<"
|
|
3598
|
+
id: drizzle_orm_pg_core.PgBuildColumn<"signup_link_tokens", drizzle_orm_pg_core.SetIsPrimaryKey<drizzle_orm_pg_core.PgBigSerial53Builder>, {
|
|
3477
3599
|
name: string;
|
|
3478
|
-
tableName: "
|
|
3600
|
+
tableName: "signup_link_tokens";
|
|
3479
3601
|
dataType: "number int53";
|
|
3480
3602
|
data: number;
|
|
3481
3603
|
driverParam: number;
|
|
@@ -3488,39 +3610,9 @@ declare const userSocialAccounts: drizzle_orm_pg_core.PgTableWithColumns<{
|
|
|
3488
3610
|
identity: undefined;
|
|
3489
3611
|
generated: undefined;
|
|
3490
3612
|
}>;
|
|
3491
|
-
|
|
3492
|
-
name: string;
|
|
3493
|
-
tableName: "user_social_accounts";
|
|
3494
|
-
dataType: "number int53";
|
|
3495
|
-
data: number;
|
|
3496
|
-
driverParam: string | number;
|
|
3497
|
-
notNull: true;
|
|
3498
|
-
hasDefault: false;
|
|
3499
|
-
isPrimaryKey: false;
|
|
3500
|
-
isAutoincrement: false;
|
|
3501
|
-
hasRuntimeDefault: false;
|
|
3502
|
-
enumValues: undefined;
|
|
3503
|
-
identity: undefined;
|
|
3504
|
-
generated: undefined;
|
|
3505
|
-
}>;
|
|
3506
|
-
provider: drizzle_orm_pg_core.PgBuildColumn<"user_social_accounts", drizzle_orm_pg_core.SetNotNull<drizzle_orm_pg_core.PgTextBuilder<["google", "apple", "github", "kakao", "naver", "superself"] & [string, ...string[]]>>, {
|
|
3507
|
-
name: string;
|
|
3508
|
-
tableName: "user_social_accounts";
|
|
3509
|
-
dataType: "string enum";
|
|
3510
|
-
data: "google" | "apple" | "github" | "kakao" | "naver" | "superself";
|
|
3511
|
-
driverParam: string;
|
|
3512
|
-
notNull: true;
|
|
3513
|
-
hasDefault: false;
|
|
3514
|
-
isPrimaryKey: false;
|
|
3515
|
-
isAutoincrement: false;
|
|
3516
|
-
hasRuntimeDefault: false;
|
|
3517
|
-
enumValues: ["google", "apple", "github", "kakao", "naver", "superself"] & [string, ...string[]];
|
|
3518
|
-
identity: undefined;
|
|
3519
|
-
generated: undefined;
|
|
3520
|
-
}>;
|
|
3521
|
-
providerUserId: drizzle_orm_pg_core.PgBuildColumn<"user_social_accounts", drizzle_orm_pg_core.SetNotNull<drizzle_orm_pg_core.PgTextBuilder<[string, ...string[]]>>, {
|
|
3613
|
+
email: drizzle_orm_pg_core.PgBuildColumn<"signup_link_tokens", drizzle_orm_pg_core.SetNotNull<drizzle_orm_pg_core.PgTextBuilder<[string, ...string[]]>>, {
|
|
3522
3614
|
name: string;
|
|
3523
|
-
tableName: "
|
|
3615
|
+
tableName: "signup_link_tokens";
|
|
3524
3616
|
dataType: "string";
|
|
3525
3617
|
data: string;
|
|
3526
3618
|
driverParam: string;
|
|
@@ -3533,24 +3625,9 @@ declare const userSocialAccounts: drizzle_orm_pg_core.PgTableWithColumns<{
|
|
|
3533
3625
|
identity: undefined;
|
|
3534
3626
|
generated: undefined;
|
|
3535
3627
|
}>;
|
|
3536
|
-
|
|
3537
|
-
name: string;
|
|
3538
|
-
tableName: "user_social_accounts";
|
|
3539
|
-
dataType: "string";
|
|
3540
|
-
data: string;
|
|
3541
|
-
driverParam: string;
|
|
3542
|
-
notNull: false;
|
|
3543
|
-
hasDefault: false;
|
|
3544
|
-
isPrimaryKey: false;
|
|
3545
|
-
isAutoincrement: false;
|
|
3546
|
-
hasRuntimeDefault: false;
|
|
3547
|
-
enumValues: undefined;
|
|
3548
|
-
identity: undefined;
|
|
3549
|
-
generated: undefined;
|
|
3550
|
-
}>;
|
|
3551
|
-
accessToken: drizzle_orm_pg_core.PgBuildColumn<"user_social_accounts", drizzle_orm_pg_core.PgTextBuilder<[string, ...string[]]>, {
|
|
3628
|
+
tokenHash: drizzle_orm_pg_core.PgBuildColumn<"signup_link_tokens", drizzle_orm_pg_core.PgTextBuilder<[string, ...string[]]>, {
|
|
3552
3629
|
name: string;
|
|
3553
|
-
tableName: "
|
|
3630
|
+
tableName: "signup_link_tokens";
|
|
3554
3631
|
dataType: "string";
|
|
3555
3632
|
data: string;
|
|
3556
3633
|
driverParam: string;
|
|
@@ -3563,9 +3640,9 @@ declare const userSocialAccounts: drizzle_orm_pg_core.PgTableWithColumns<{
|
|
|
3563
3640
|
identity: undefined;
|
|
3564
3641
|
generated: undefined;
|
|
3565
3642
|
}>;
|
|
3566
|
-
|
|
3643
|
+
returnPath: drizzle_orm_pg_core.PgBuildColumn<"signup_link_tokens", drizzle_orm_pg_core.PgTextBuilder<[string, ...string[]]>, {
|
|
3567
3644
|
name: string;
|
|
3568
|
-
tableName: "
|
|
3645
|
+
tableName: "signup_link_tokens";
|
|
3569
3646
|
dataType: "string";
|
|
3570
3647
|
data: string;
|
|
3571
3648
|
driverParam: string;
|
|
@@ -3578,13 +3655,13 @@ declare const userSocialAccounts: drizzle_orm_pg_core.PgTableWithColumns<{
|
|
|
3578
3655
|
identity: undefined;
|
|
3579
3656
|
generated: undefined;
|
|
3580
3657
|
}>;
|
|
3581
|
-
|
|
3658
|
+
expiresAt: drizzle_orm_pg_core.PgBuildColumn<"signup_link_tokens", drizzle_orm_pg_core.SetNotNull<drizzle_orm_pg_core.PgTimestampBuilder>, {
|
|
3582
3659
|
name: string;
|
|
3583
|
-
tableName: "
|
|
3660
|
+
tableName: "signup_link_tokens";
|
|
3584
3661
|
dataType: "object date";
|
|
3585
3662
|
data: Date;
|
|
3586
3663
|
driverParam: string;
|
|
3587
|
-
notNull:
|
|
3664
|
+
notNull: true;
|
|
3588
3665
|
hasDefault: false;
|
|
3589
3666
|
isPrimaryKey: false;
|
|
3590
3667
|
isAutoincrement: false;
|
|
@@ -3593,30 +3670,14 @@ declare const userSocialAccounts: drizzle_orm_pg_core.PgTableWithColumns<{
|
|
|
3593
3670
|
identity: undefined;
|
|
3594
3671
|
generated: undefined;
|
|
3595
3672
|
}>;
|
|
3596
|
-
|
|
3597
|
-
dialect: "pg";
|
|
3598
|
-
}>;
|
|
3599
|
-
type UserSocialAccount = typeof userSocialAccounts.$inferSelect;
|
|
3600
|
-
type NewUserSocialAccount = typeof userSocialAccounts.$inferInsert;
|
|
3601
|
-
|
|
3602
|
-
/**
|
|
3603
|
-
* @spfn/auth - Verification Codes Entity
|
|
3604
|
-
*
|
|
3605
|
-
* Stores verification codes for email and phone verification
|
|
3606
|
-
* Codes expire after a configurable time period
|
|
3607
|
-
*/
|
|
3608
|
-
declare const verificationCodes: drizzle_orm_pg_core.PgTableWithColumns<{
|
|
3609
|
-
name: "verification_codes";
|
|
3610
|
-
schema: string;
|
|
3611
|
-
columns: {
|
|
3612
|
-
createdAt: drizzle_orm_pg_core.PgBuildColumn<"verification_codes", drizzle_orm_pg_core.SetNotNull<drizzle_orm_pg_core.SetHasDefault<drizzle_orm_pg_core.PgTimestampBuilder>>, {
|
|
3673
|
+
consumedAt: drizzle_orm_pg_core.PgBuildColumn<"signup_link_tokens", drizzle_orm_pg_core.PgTimestampBuilder, {
|
|
3613
3674
|
name: string;
|
|
3614
|
-
tableName: "
|
|
3675
|
+
tableName: "signup_link_tokens";
|
|
3615
3676
|
dataType: "object date";
|
|
3616
3677
|
data: Date;
|
|
3617
3678
|
driverParam: string;
|
|
3618
|
-
notNull:
|
|
3619
|
-
hasDefault:
|
|
3679
|
+
notNull: false;
|
|
3680
|
+
hasDefault: false;
|
|
3620
3681
|
isPrimaryKey: false;
|
|
3621
3682
|
isAutoincrement: false;
|
|
3622
3683
|
hasRuntimeDefault: false;
|
|
@@ -3624,43 +3685,13 @@ declare const verificationCodes: drizzle_orm_pg_core.PgTableWithColumns<{
|
|
|
3624
3685
|
identity: undefined;
|
|
3625
3686
|
generated: undefined;
|
|
3626
3687
|
}>;
|
|
3627
|
-
|
|
3688
|
+
supersededAt: drizzle_orm_pg_core.PgBuildColumn<"signup_link_tokens", drizzle_orm_pg_core.PgTimestampBuilder, {
|
|
3628
3689
|
name: string;
|
|
3629
|
-
tableName: "
|
|
3690
|
+
tableName: "signup_link_tokens";
|
|
3630
3691
|
dataType: "object date";
|
|
3631
3692
|
data: Date;
|
|
3632
3693
|
driverParam: string;
|
|
3633
|
-
notNull:
|
|
3634
|
-
hasDefault: true;
|
|
3635
|
-
isPrimaryKey: false;
|
|
3636
|
-
isAutoincrement: false;
|
|
3637
|
-
hasRuntimeDefault: false;
|
|
3638
|
-
enumValues: undefined;
|
|
3639
|
-
identity: undefined;
|
|
3640
|
-
generated: undefined;
|
|
3641
|
-
}>;
|
|
3642
|
-
id: drizzle_orm_pg_core.PgBuildColumn<"verification_codes", drizzle_orm_pg_core.SetIsPrimaryKey<drizzle_orm_pg_core.PgBigSerial53Builder>, {
|
|
3643
|
-
name: string;
|
|
3644
|
-
tableName: "verification_codes";
|
|
3645
|
-
dataType: "number int53";
|
|
3646
|
-
data: number;
|
|
3647
|
-
driverParam: number;
|
|
3648
|
-
notNull: true;
|
|
3649
|
-
hasDefault: true;
|
|
3650
|
-
isPrimaryKey: false;
|
|
3651
|
-
isAutoincrement: false;
|
|
3652
|
-
hasRuntimeDefault: false;
|
|
3653
|
-
enumValues: undefined;
|
|
3654
|
-
identity: undefined;
|
|
3655
|
-
generated: undefined;
|
|
3656
|
-
}>;
|
|
3657
|
-
target: drizzle_orm_pg_core.PgBuildColumn<"verification_codes", drizzle_orm_pg_core.SetNotNull<drizzle_orm_pg_core.PgTextBuilder<[string, ...string[]]>>, {
|
|
3658
|
-
name: string;
|
|
3659
|
-
tableName: "verification_codes";
|
|
3660
|
-
dataType: "string";
|
|
3661
|
-
data: string;
|
|
3662
|
-
driverParam: string;
|
|
3663
|
-
notNull: true;
|
|
3694
|
+
notNull: false;
|
|
3664
3695
|
hasDefault: false;
|
|
3665
3696
|
isPrimaryKey: false;
|
|
3666
3697
|
isAutoincrement: false;
|
|
@@ -3669,28 +3700,13 @@ declare const verificationCodes: drizzle_orm_pg_core.PgTableWithColumns<{
|
|
|
3669
3700
|
identity: undefined;
|
|
3670
3701
|
generated: undefined;
|
|
3671
3702
|
}>;
|
|
3672
|
-
|
|
3673
|
-
name: string;
|
|
3674
|
-
tableName: "verification_codes";
|
|
3675
|
-
dataType: "string enum";
|
|
3676
|
-
data: "email" | "phone";
|
|
3677
|
-
driverParam: string;
|
|
3678
|
-
notNull: true;
|
|
3679
|
-
hasDefault: false;
|
|
3680
|
-
isPrimaryKey: false;
|
|
3681
|
-
isAutoincrement: false;
|
|
3682
|
-
hasRuntimeDefault: false;
|
|
3683
|
-
enumValues: ["email", "phone"] & [string, ...string[]];
|
|
3684
|
-
identity: undefined;
|
|
3685
|
-
generated: undefined;
|
|
3686
|
-
}>;
|
|
3687
|
-
code: drizzle_orm_pg_core.PgBuildColumn<"verification_codes", drizzle_orm_pg_core.SetNotNull<drizzle_orm_pg_core.PgTextBuilder<[string, ...string[]]>>, {
|
|
3703
|
+
setupSecretHash: drizzle_orm_pg_core.PgBuildColumn<"signup_link_tokens", drizzle_orm_pg_core.PgTextBuilder<[string, ...string[]]>, {
|
|
3688
3704
|
name: string;
|
|
3689
|
-
tableName: "
|
|
3705
|
+
tableName: "signup_link_tokens";
|
|
3690
3706
|
dataType: "string";
|
|
3691
3707
|
data: string;
|
|
3692
3708
|
driverParam: string;
|
|
3693
|
-
notNull:
|
|
3709
|
+
notNull: false;
|
|
3694
3710
|
hasDefault: false;
|
|
3695
3711
|
isPrimaryKey: false;
|
|
3696
3712
|
isAutoincrement: false;
|
|
@@ -3699,28 +3715,13 @@ declare const verificationCodes: drizzle_orm_pg_core.PgTableWithColumns<{
|
|
|
3699
3715
|
identity: undefined;
|
|
3700
3716
|
generated: undefined;
|
|
3701
3717
|
}>;
|
|
3702
|
-
|
|
3703
|
-
name: string;
|
|
3704
|
-
tableName: "verification_codes";
|
|
3705
|
-
dataType: "string enum";
|
|
3706
|
-
data: "registration" | "login" | "password_reset" | "email_change" | "phone_change" | "account_deletion";
|
|
3707
|
-
driverParam: string;
|
|
3708
|
-
notNull: true;
|
|
3709
|
-
hasDefault: false;
|
|
3710
|
-
isPrimaryKey: false;
|
|
3711
|
-
isAutoincrement: false;
|
|
3712
|
-
hasRuntimeDefault: false;
|
|
3713
|
-
enumValues: ["registration", "login", "password_reset", "email_change", "phone_change", "account_deletion"] & [string, ...string[]];
|
|
3714
|
-
identity: undefined;
|
|
3715
|
-
generated: undefined;
|
|
3716
|
-
}>;
|
|
3717
|
-
expiresAt: drizzle_orm_pg_core.PgBuildColumn<"verification_codes", drizzle_orm_pg_core.SetNotNull<drizzle_orm_pg_core.PgTimestampBuilder>, {
|
|
3718
|
+
setupExpiresAt: drizzle_orm_pg_core.PgBuildColumn<"signup_link_tokens", drizzle_orm_pg_core.PgTimestampBuilder, {
|
|
3718
3719
|
name: string;
|
|
3719
|
-
tableName: "
|
|
3720
|
+
tableName: "signup_link_tokens";
|
|
3720
3721
|
dataType: "object date";
|
|
3721
3722
|
data: Date;
|
|
3722
3723
|
driverParam: string;
|
|
3723
|
-
notNull:
|
|
3724
|
+
notNull: false;
|
|
3724
3725
|
hasDefault: false;
|
|
3725
3726
|
isPrimaryKey: false;
|
|
3726
3727
|
isAutoincrement: false;
|
|
@@ -3729,9 +3730,9 @@ declare const verificationCodes: drizzle_orm_pg_core.PgTableWithColumns<{
|
|
|
3729
3730
|
identity: undefined;
|
|
3730
3731
|
generated: undefined;
|
|
3731
3732
|
}>;
|
|
3732
|
-
|
|
3733
|
+
completedAt: drizzle_orm_pg_core.PgBuildColumn<"signup_link_tokens", drizzle_orm_pg_core.PgTimestampBuilder, {
|
|
3733
3734
|
name: string;
|
|
3734
|
-
tableName: "
|
|
3735
|
+
tableName: "signup_link_tokens";
|
|
3735
3736
|
dataType: "object date";
|
|
3736
3737
|
data: Date;
|
|
3737
3738
|
driverParam: string;
|
|
@@ -3744,47 +3745,53 @@ declare const verificationCodes: drizzle_orm_pg_core.PgTableWithColumns<{
|
|
|
3744
3745
|
identity: undefined;
|
|
3745
3746
|
generated: undefined;
|
|
3746
3747
|
}>;
|
|
3747
|
-
attempts: drizzle_orm_pg_core.PgBuildColumn<"verification_codes", drizzle_orm_pg_core.SetHasDefault<drizzle_orm_pg_core.SetNotNull<drizzle_orm_pg_core.PgIntegerBuilder>>, {
|
|
3748
|
-
name: string;
|
|
3749
|
-
tableName: "verification_codes";
|
|
3750
|
-
dataType: "number int32";
|
|
3751
|
-
data: number;
|
|
3752
|
-
driverParam: string | number;
|
|
3753
|
-
notNull: true;
|
|
3754
|
-
hasDefault: true;
|
|
3755
|
-
isPrimaryKey: false;
|
|
3756
|
-
isAutoincrement: false;
|
|
3757
|
-
hasRuntimeDefault: false;
|
|
3758
|
-
enumValues: undefined;
|
|
3759
|
-
identity: undefined;
|
|
3760
|
-
generated: undefined;
|
|
3761
|
-
}>;
|
|
3762
3748
|
};
|
|
3763
3749
|
dialect: "pg";
|
|
3764
3750
|
}>;
|
|
3765
|
-
type
|
|
3766
|
-
type
|
|
3751
|
+
type SignupLinkToken = typeof signupLinkTokens.$inferSelect;
|
|
3752
|
+
type NewSignupLinkToken = typeof signupLinkTokens.$inferInsert;
|
|
3767
3753
|
|
|
3768
3754
|
/**
|
|
3769
|
-
* @spfn/auth -
|
|
3755
|
+
* @spfn/auth - Password Reset Tokens Entity
|
|
3770
3756
|
*
|
|
3771
|
-
* Backs the
|
|
3772
|
-
* opening it mints a short-lived setup session, and
|
|
3773
|
-
* session
|
|
3757
|
+
* Backs the password reset flow: a one-time link is emailed to an address the
|
|
3758
|
+
* account has already proved, opening it mints a short-lived setup session, and
|
|
3759
|
+
* setting a password on that session replaces the old one and signs the browser
|
|
3760
|
+
* in.
|
|
3774
3761
|
*
|
|
3775
|
-
* A separate table from `
|
|
3776
|
-
*
|
|
3777
|
-
*
|
|
3778
|
-
*
|
|
3779
|
-
*
|
|
3762
|
+
* A separate table from `signup_link_tokens` even though the two carry the same
|
|
3763
|
+
* columns. They are the same shape, not the same thing: one names an address
|
|
3764
|
+
* that has no account and the other names a user that does, and the setup
|
|
3765
|
+
* secrets they mint must not be interchangeable. Sharing one table would make
|
|
3766
|
+
* "which flow is this row" a per-row property that the lookup would have to
|
|
3767
|
+
* remember to filter on — and a lookup that forgets would accept a signup secret
|
|
3768
|
+
* as a reset secret.
|
|
3769
|
+
*
|
|
3770
|
+
* The link token and the setup secret are bearer credentials, so only their
|
|
3771
|
+
* SHA-256 hashes are stored.
|
|
3780
3772
|
*/
|
|
3781
|
-
declare const
|
|
3782
|
-
name: "
|
|
3773
|
+
declare const passwordResetTokens: drizzle_orm_pg_core.PgTableWithColumns<{
|
|
3774
|
+
name: "password_reset_tokens";
|
|
3783
3775
|
schema: string;
|
|
3784
3776
|
columns: {
|
|
3785
|
-
createdAt: drizzle_orm_pg_core.PgBuildColumn<"
|
|
3777
|
+
createdAt: drizzle_orm_pg_core.PgBuildColumn<"password_reset_tokens", drizzle_orm_pg_core.SetNotNull<drizzle_orm_pg_core.SetHasDefault<drizzle_orm_pg_core.PgTimestampBuilder>>, {
|
|
3778
|
+
name: string;
|
|
3779
|
+
tableName: "password_reset_tokens";
|
|
3780
|
+
dataType: "object date";
|
|
3781
|
+
data: Date;
|
|
3782
|
+
driverParam: string;
|
|
3783
|
+
notNull: true;
|
|
3784
|
+
hasDefault: true;
|
|
3785
|
+
isPrimaryKey: false;
|
|
3786
|
+
isAutoincrement: false;
|
|
3787
|
+
hasRuntimeDefault: false;
|
|
3788
|
+
enumValues: undefined;
|
|
3789
|
+
identity: undefined;
|
|
3790
|
+
generated: undefined;
|
|
3791
|
+
}>;
|
|
3792
|
+
updatedAt: drizzle_orm_pg_core.PgBuildColumn<"password_reset_tokens", drizzle_orm_pg_core.SetHasDefault<drizzle_orm_pg_core.SetNotNull<drizzle_orm_pg_core.SetHasDefault<drizzle_orm_pg_core.PgTimestampBuilder>>>, {
|
|
3786
3793
|
name: string;
|
|
3787
|
-
tableName: "
|
|
3794
|
+
tableName: "password_reset_tokens";
|
|
3788
3795
|
dataType: "object date";
|
|
3789
3796
|
data: Date;
|
|
3790
3797
|
driverParam: string;
|
|
@@ -3797,12 +3804,12 @@ declare const signupLinkTokens: drizzle_orm_pg_core.PgTableWithColumns<{
|
|
|
3797
3804
|
identity: undefined;
|
|
3798
3805
|
generated: undefined;
|
|
3799
3806
|
}>;
|
|
3800
|
-
|
|
3807
|
+
id: drizzle_orm_pg_core.PgBuildColumn<"password_reset_tokens", drizzle_orm_pg_core.SetIsPrimaryKey<drizzle_orm_pg_core.PgBigSerial53Builder>, {
|
|
3801
3808
|
name: string;
|
|
3802
|
-
tableName: "
|
|
3803
|
-
dataType: "
|
|
3804
|
-
data:
|
|
3805
|
-
driverParam:
|
|
3809
|
+
tableName: "password_reset_tokens";
|
|
3810
|
+
dataType: "number int53";
|
|
3811
|
+
data: number;
|
|
3812
|
+
driverParam: number;
|
|
3806
3813
|
notNull: true;
|
|
3807
3814
|
hasDefault: true;
|
|
3808
3815
|
isPrimaryKey: false;
|
|
@@ -3812,14 +3819,14 @@ declare const signupLinkTokens: drizzle_orm_pg_core.PgTableWithColumns<{
|
|
|
3812
3819
|
identity: undefined;
|
|
3813
3820
|
generated: undefined;
|
|
3814
3821
|
}>;
|
|
3815
|
-
|
|
3822
|
+
userId: drizzle_orm_pg_core.PgBuildColumn<"password_reset_tokens", drizzle_orm_pg_core.SetNotNull<drizzle_orm_pg_core.PgBigInt53Builder>, {
|
|
3816
3823
|
name: string;
|
|
3817
|
-
tableName: "
|
|
3824
|
+
tableName: "password_reset_tokens";
|
|
3818
3825
|
dataType: "number int53";
|
|
3819
3826
|
data: number;
|
|
3820
|
-
driverParam: number;
|
|
3827
|
+
driverParam: string | number;
|
|
3821
3828
|
notNull: true;
|
|
3822
|
-
hasDefault:
|
|
3829
|
+
hasDefault: false;
|
|
3823
3830
|
isPrimaryKey: false;
|
|
3824
3831
|
isAutoincrement: false;
|
|
3825
3832
|
hasRuntimeDefault: false;
|
|
@@ -3827,9 +3834,9 @@ declare const signupLinkTokens: drizzle_orm_pg_core.PgTableWithColumns<{
|
|
|
3827
3834
|
identity: undefined;
|
|
3828
3835
|
generated: undefined;
|
|
3829
3836
|
}>;
|
|
3830
|
-
email: drizzle_orm_pg_core.PgBuildColumn<"
|
|
3837
|
+
email: drizzle_orm_pg_core.PgBuildColumn<"password_reset_tokens", drizzle_orm_pg_core.SetNotNull<drizzle_orm_pg_core.PgTextBuilder<[string, ...string[]]>>, {
|
|
3831
3838
|
name: string;
|
|
3832
|
-
tableName: "
|
|
3839
|
+
tableName: "password_reset_tokens";
|
|
3833
3840
|
dataType: "string";
|
|
3834
3841
|
data: string;
|
|
3835
3842
|
driverParam: string;
|
|
@@ -3842,9 +3849,9 @@ declare const signupLinkTokens: drizzle_orm_pg_core.PgTableWithColumns<{
|
|
|
3842
3849
|
identity: undefined;
|
|
3843
3850
|
generated: undefined;
|
|
3844
3851
|
}>;
|
|
3845
|
-
tokenHash: drizzle_orm_pg_core.PgBuildColumn<"
|
|
3852
|
+
tokenHash: drizzle_orm_pg_core.PgBuildColumn<"password_reset_tokens", drizzle_orm_pg_core.PgTextBuilder<[string, ...string[]]>, {
|
|
3846
3853
|
name: string;
|
|
3847
|
-
tableName: "
|
|
3854
|
+
tableName: "password_reset_tokens";
|
|
3848
3855
|
dataType: "string";
|
|
3849
3856
|
data: string;
|
|
3850
3857
|
driverParam: string;
|
|
@@ -3857,9 +3864,9 @@ declare const signupLinkTokens: drizzle_orm_pg_core.PgTableWithColumns<{
|
|
|
3857
3864
|
identity: undefined;
|
|
3858
3865
|
generated: undefined;
|
|
3859
3866
|
}>;
|
|
3860
|
-
returnPath: drizzle_orm_pg_core.PgBuildColumn<"
|
|
3867
|
+
returnPath: drizzle_orm_pg_core.PgBuildColumn<"password_reset_tokens", drizzle_orm_pg_core.PgTextBuilder<[string, ...string[]]>, {
|
|
3861
3868
|
name: string;
|
|
3862
|
-
tableName: "
|
|
3869
|
+
tableName: "password_reset_tokens";
|
|
3863
3870
|
dataType: "string";
|
|
3864
3871
|
data: string;
|
|
3865
3872
|
driverParam: string;
|
|
@@ -3872,9 +3879,9 @@ declare const signupLinkTokens: drizzle_orm_pg_core.PgTableWithColumns<{
|
|
|
3872
3879
|
identity: undefined;
|
|
3873
3880
|
generated: undefined;
|
|
3874
3881
|
}>;
|
|
3875
|
-
expiresAt: drizzle_orm_pg_core.PgBuildColumn<"
|
|
3882
|
+
expiresAt: drizzle_orm_pg_core.PgBuildColumn<"password_reset_tokens", drizzle_orm_pg_core.SetNotNull<drizzle_orm_pg_core.PgTimestampBuilder>, {
|
|
3876
3883
|
name: string;
|
|
3877
|
-
tableName: "
|
|
3884
|
+
tableName: "password_reset_tokens";
|
|
3878
3885
|
dataType: "object date";
|
|
3879
3886
|
data: Date;
|
|
3880
3887
|
driverParam: string;
|
|
@@ -3887,9 +3894,9 @@ declare const signupLinkTokens: drizzle_orm_pg_core.PgTableWithColumns<{
|
|
|
3887
3894
|
identity: undefined;
|
|
3888
3895
|
generated: undefined;
|
|
3889
3896
|
}>;
|
|
3890
|
-
consumedAt: drizzle_orm_pg_core.PgBuildColumn<"
|
|
3897
|
+
consumedAt: drizzle_orm_pg_core.PgBuildColumn<"password_reset_tokens", drizzle_orm_pg_core.PgTimestampBuilder, {
|
|
3891
3898
|
name: string;
|
|
3892
|
-
tableName: "
|
|
3899
|
+
tableName: "password_reset_tokens";
|
|
3893
3900
|
dataType: "object date";
|
|
3894
3901
|
data: Date;
|
|
3895
3902
|
driverParam: string;
|
|
@@ -3902,9 +3909,9 @@ declare const signupLinkTokens: drizzle_orm_pg_core.PgTableWithColumns<{
|
|
|
3902
3909
|
identity: undefined;
|
|
3903
3910
|
generated: undefined;
|
|
3904
3911
|
}>;
|
|
3905
|
-
supersededAt: drizzle_orm_pg_core.PgBuildColumn<"
|
|
3912
|
+
supersededAt: drizzle_orm_pg_core.PgBuildColumn<"password_reset_tokens", drizzle_orm_pg_core.PgTimestampBuilder, {
|
|
3906
3913
|
name: string;
|
|
3907
|
-
tableName: "
|
|
3914
|
+
tableName: "password_reset_tokens";
|
|
3908
3915
|
dataType: "object date";
|
|
3909
3916
|
data: Date;
|
|
3910
3917
|
driverParam: string;
|
|
@@ -3917,9 +3924,9 @@ declare const signupLinkTokens: drizzle_orm_pg_core.PgTableWithColumns<{
|
|
|
3917
3924
|
identity: undefined;
|
|
3918
3925
|
generated: undefined;
|
|
3919
3926
|
}>;
|
|
3920
|
-
setupSecretHash: drizzle_orm_pg_core.PgBuildColumn<"
|
|
3927
|
+
setupSecretHash: drizzle_orm_pg_core.PgBuildColumn<"password_reset_tokens", drizzle_orm_pg_core.PgTextBuilder<[string, ...string[]]>, {
|
|
3921
3928
|
name: string;
|
|
3922
|
-
tableName: "
|
|
3929
|
+
tableName: "password_reset_tokens";
|
|
3923
3930
|
dataType: "string";
|
|
3924
3931
|
data: string;
|
|
3925
3932
|
driverParam: string;
|
|
@@ -3932,9 +3939,9 @@ declare const signupLinkTokens: drizzle_orm_pg_core.PgTableWithColumns<{
|
|
|
3932
3939
|
identity: undefined;
|
|
3933
3940
|
generated: undefined;
|
|
3934
3941
|
}>;
|
|
3935
|
-
setupExpiresAt: drizzle_orm_pg_core.PgBuildColumn<"
|
|
3942
|
+
setupExpiresAt: drizzle_orm_pg_core.PgBuildColumn<"password_reset_tokens", drizzle_orm_pg_core.PgTimestampBuilder, {
|
|
3936
3943
|
name: string;
|
|
3937
|
-
tableName: "
|
|
3944
|
+
tableName: "password_reset_tokens";
|
|
3938
3945
|
dataType: "object date";
|
|
3939
3946
|
data: Date;
|
|
3940
3947
|
driverParam: string;
|
|
@@ -3947,9 +3954,9 @@ declare const signupLinkTokens: drizzle_orm_pg_core.PgTableWithColumns<{
|
|
|
3947
3954
|
identity: undefined;
|
|
3948
3955
|
generated: undefined;
|
|
3949
3956
|
}>;
|
|
3950
|
-
completedAt: drizzle_orm_pg_core.PgBuildColumn<"
|
|
3957
|
+
completedAt: drizzle_orm_pg_core.PgBuildColumn<"password_reset_tokens", drizzle_orm_pg_core.PgTimestampBuilder, {
|
|
3951
3958
|
name: string;
|
|
3952
|
-
tableName: "
|
|
3959
|
+
tableName: "password_reset_tokens";
|
|
3953
3960
|
dataType: "object date";
|
|
3954
3961
|
data: Date;
|
|
3955
3962
|
driverParam: string;
|
|
@@ -3965,35 +3972,34 @@ declare const signupLinkTokens: drizzle_orm_pg_core.PgTableWithColumns<{
|
|
|
3965
3972
|
};
|
|
3966
3973
|
dialect: "pg";
|
|
3967
3974
|
}>;
|
|
3968
|
-
type
|
|
3969
|
-
type
|
|
3975
|
+
type PasswordResetToken = typeof passwordResetTokens.$inferSelect;
|
|
3976
|
+
type NewPasswordResetToken = typeof passwordResetTokens.$inferInsert;
|
|
3970
3977
|
|
|
3971
3978
|
/**
|
|
3972
|
-
* @spfn/auth -
|
|
3979
|
+
* @spfn/auth - Revoke-All Link Tokens Entity
|
|
3973
3980
|
*
|
|
3974
|
-
* Backs the
|
|
3975
|
-
* account
|
|
3976
|
-
*
|
|
3977
|
-
* in
|
|
3981
|
+
* Backs the signed sign-out-everywhere link: a one-time token an app mails to
|
|
3982
|
+
* an account's proven address, which revokes every device key of that account
|
|
3983
|
+
* without a session. It is the action an owner can take from a mailbox when the
|
|
3984
|
+
* device they would otherwise have to sign in on is the one they no longer
|
|
3985
|
+
* trust.
|
|
3978
3986
|
*
|
|
3979
|
-
*
|
|
3980
|
-
*
|
|
3981
|
-
*
|
|
3982
|
-
*
|
|
3983
|
-
*
|
|
3984
|
-
* remember to filter on — and a lookup that forgets would accept a signup secret
|
|
3985
|
-
* as a reset secret.
|
|
3987
|
+
* `key_epoch` is what makes the link dead rather than merely spent. It records
|
|
3988
|
+
* the account's key generation at issue time, and the consume statement joins it
|
|
3989
|
+
* against `users.key_epoch` — so a password reset, a password change, a deletion
|
|
3990
|
+
* request or an earlier revoke-all, every one of which moves the counter, leaves
|
|
3991
|
+
* the outstanding link answering the same 404 an unknown token gets.
|
|
3986
3992
|
*
|
|
3987
|
-
* The
|
|
3988
|
-
*
|
|
3993
|
+
* The token is a bearer credential, so only its SHA-256 hash is stored, the same
|
|
3994
|
+
* way the signup and reset links store theirs.
|
|
3989
3995
|
*/
|
|
3990
|
-
declare const
|
|
3991
|
-
name: "
|
|
3996
|
+
declare const keyRevokeAllTokens: drizzle_orm_pg_core.PgTableWithColumns<{
|
|
3997
|
+
name: "key_revoke_all_tokens";
|
|
3992
3998
|
schema: string;
|
|
3993
3999
|
columns: {
|
|
3994
|
-
createdAt: drizzle_orm_pg_core.PgBuildColumn<"
|
|
4000
|
+
createdAt: drizzle_orm_pg_core.PgBuildColumn<"key_revoke_all_tokens", drizzle_orm_pg_core.SetNotNull<drizzle_orm_pg_core.SetHasDefault<drizzle_orm_pg_core.PgTimestampBuilder>>, {
|
|
3995
4001
|
name: string;
|
|
3996
|
-
tableName: "
|
|
4002
|
+
tableName: "key_revoke_all_tokens";
|
|
3997
4003
|
dataType: "object date";
|
|
3998
4004
|
data: Date;
|
|
3999
4005
|
driverParam: string;
|
|
@@ -4006,9 +4012,9 @@ declare const passwordResetTokens: drizzle_orm_pg_core.PgTableWithColumns<{
|
|
|
4006
4012
|
identity: undefined;
|
|
4007
4013
|
generated: undefined;
|
|
4008
4014
|
}>;
|
|
4009
|
-
updatedAt: drizzle_orm_pg_core.PgBuildColumn<"
|
|
4015
|
+
updatedAt: drizzle_orm_pg_core.PgBuildColumn<"key_revoke_all_tokens", drizzle_orm_pg_core.SetHasDefault<drizzle_orm_pg_core.SetNotNull<drizzle_orm_pg_core.SetHasDefault<drizzle_orm_pg_core.PgTimestampBuilder>>>, {
|
|
4010
4016
|
name: string;
|
|
4011
|
-
tableName: "
|
|
4017
|
+
tableName: "key_revoke_all_tokens";
|
|
4012
4018
|
dataType: "object date";
|
|
4013
4019
|
data: Date;
|
|
4014
4020
|
driverParam: string;
|
|
@@ -4021,9 +4027,9 @@ declare const passwordResetTokens: drizzle_orm_pg_core.PgTableWithColumns<{
|
|
|
4021
4027
|
identity: undefined;
|
|
4022
4028
|
generated: undefined;
|
|
4023
4029
|
}>;
|
|
4024
|
-
id: drizzle_orm_pg_core.PgBuildColumn<"
|
|
4030
|
+
id: drizzle_orm_pg_core.PgBuildColumn<"key_revoke_all_tokens", drizzle_orm_pg_core.SetIsPrimaryKey<drizzle_orm_pg_core.PgBigSerial53Builder>, {
|
|
4025
4031
|
name: string;
|
|
4026
|
-
tableName: "
|
|
4032
|
+
tableName: "key_revoke_all_tokens";
|
|
4027
4033
|
dataType: "number int53";
|
|
4028
4034
|
data: number;
|
|
4029
4035
|
driverParam: number;
|
|
@@ -4036,9 +4042,9 @@ declare const passwordResetTokens: drizzle_orm_pg_core.PgTableWithColumns<{
|
|
|
4036
4042
|
identity: undefined;
|
|
4037
4043
|
generated: undefined;
|
|
4038
4044
|
}>;
|
|
4039
|
-
userId: drizzle_orm_pg_core.PgBuildColumn<"
|
|
4045
|
+
userId: drizzle_orm_pg_core.PgBuildColumn<"key_revoke_all_tokens", drizzle_orm_pg_core.SetNotNull<drizzle_orm_pg_core.PgBigInt53Builder>, {
|
|
4040
4046
|
name: string;
|
|
4041
|
-
tableName: "
|
|
4047
|
+
tableName: "key_revoke_all_tokens";
|
|
4042
4048
|
dataType: "number int53";
|
|
4043
4049
|
data: number;
|
|
4044
4050
|
driverParam: string | number;
|
|
@@ -4051,9 +4057,9 @@ declare const passwordResetTokens: drizzle_orm_pg_core.PgTableWithColumns<{
|
|
|
4051
4057
|
identity: undefined;
|
|
4052
4058
|
generated: undefined;
|
|
4053
4059
|
}>;
|
|
4054
|
-
|
|
4060
|
+
tokenHash: drizzle_orm_pg_core.PgBuildColumn<"key_revoke_all_tokens", drizzle_orm_pg_core.SetNotNull<drizzle_orm_pg_core.PgTextBuilder<[string, ...string[]]>>, {
|
|
4055
4061
|
name: string;
|
|
4056
|
-
tableName: "
|
|
4062
|
+
tableName: "key_revoke_all_tokens";
|
|
4057
4063
|
dataType: "string";
|
|
4058
4064
|
data: string;
|
|
4059
4065
|
driverParam: string;
|
|
@@ -4066,13 +4072,13 @@ declare const passwordResetTokens: drizzle_orm_pg_core.PgTableWithColumns<{
|
|
|
4066
4072
|
identity: undefined;
|
|
4067
4073
|
generated: undefined;
|
|
4068
4074
|
}>;
|
|
4069
|
-
|
|
4075
|
+
keyEpoch: drizzle_orm_pg_core.PgBuildColumn<"key_revoke_all_tokens", drizzle_orm_pg_core.SetNotNull<drizzle_orm_pg_core.PgIntegerBuilder>, {
|
|
4070
4076
|
name: string;
|
|
4071
|
-
tableName: "
|
|
4072
|
-
dataType: "
|
|
4073
|
-
data:
|
|
4074
|
-
driverParam: string;
|
|
4075
|
-
notNull:
|
|
4077
|
+
tableName: "key_revoke_all_tokens";
|
|
4078
|
+
dataType: "number int32";
|
|
4079
|
+
data: number;
|
|
4080
|
+
driverParam: string | number;
|
|
4081
|
+
notNull: true;
|
|
4076
4082
|
hasDefault: false;
|
|
4077
4083
|
isPrimaryKey: false;
|
|
4078
4084
|
isAutoincrement: false;
|
|
@@ -4081,13 +4087,13 @@ declare const passwordResetTokens: drizzle_orm_pg_core.PgTableWithColumns<{
|
|
|
4081
4087
|
identity: undefined;
|
|
4082
4088
|
generated: undefined;
|
|
4083
4089
|
}>;
|
|
4084
|
-
|
|
4090
|
+
expiresAt: drizzle_orm_pg_core.PgBuildColumn<"key_revoke_all_tokens", drizzle_orm_pg_core.SetNotNull<drizzle_orm_pg_core.PgTimestampBuilder>, {
|
|
4085
4091
|
name: string;
|
|
4086
|
-
tableName: "
|
|
4087
|
-
dataType: "
|
|
4088
|
-
data:
|
|
4092
|
+
tableName: "key_revoke_all_tokens";
|
|
4093
|
+
dataType: "object date";
|
|
4094
|
+
data: Date;
|
|
4089
4095
|
driverParam: string;
|
|
4090
|
-
notNull:
|
|
4096
|
+
notNull: true;
|
|
4091
4097
|
hasDefault: false;
|
|
4092
4098
|
isPrimaryKey: false;
|
|
4093
4099
|
isAutoincrement: false;
|
|
@@ -4096,13 +4102,13 @@ declare const passwordResetTokens: drizzle_orm_pg_core.PgTableWithColumns<{
|
|
|
4096
4102
|
identity: undefined;
|
|
4097
4103
|
generated: undefined;
|
|
4098
4104
|
}>;
|
|
4099
|
-
|
|
4105
|
+
consumedAt: drizzle_orm_pg_core.PgBuildColumn<"key_revoke_all_tokens", drizzle_orm_pg_core.PgTimestampBuilder, {
|
|
4100
4106
|
name: string;
|
|
4101
|
-
tableName: "
|
|
4107
|
+
tableName: "key_revoke_all_tokens";
|
|
4102
4108
|
dataType: "object date";
|
|
4103
4109
|
data: Date;
|
|
4104
4110
|
driverParam: string;
|
|
4105
|
-
notNull:
|
|
4111
|
+
notNull: false;
|
|
4106
4112
|
hasDefault: false;
|
|
4107
4113
|
isPrimaryKey: false;
|
|
4108
4114
|
isAutoincrement: false;
|
|
@@ -4111,9 +4117,9 @@ declare const passwordResetTokens: drizzle_orm_pg_core.PgTableWithColumns<{
|
|
|
4111
4117
|
identity: undefined;
|
|
4112
4118
|
generated: undefined;
|
|
4113
4119
|
}>;
|
|
4114
|
-
|
|
4120
|
+
supersededAt: drizzle_orm_pg_core.PgBuildColumn<"key_revoke_all_tokens", drizzle_orm_pg_core.PgTimestampBuilder, {
|
|
4115
4121
|
name: string;
|
|
4116
|
-
tableName: "
|
|
4122
|
+
tableName: "key_revoke_all_tokens";
|
|
4117
4123
|
dataType: "object date";
|
|
4118
4124
|
data: Date;
|
|
4119
4125
|
driverParam: string;
|
|
@@ -4126,14 +4132,64 @@ declare const passwordResetTokens: drizzle_orm_pg_core.PgTableWithColumns<{
|
|
|
4126
4132
|
identity: undefined;
|
|
4127
4133
|
generated: undefined;
|
|
4128
4134
|
}>;
|
|
4129
|
-
|
|
4135
|
+
};
|
|
4136
|
+
dialect: "pg";
|
|
4137
|
+
}>;
|
|
4138
|
+
type KeyRevokeAllToken = typeof keyRevokeAllTokens.$inferSelect;
|
|
4139
|
+
type NewKeyRevokeAllToken = typeof keyRevokeAllTokens.$inferInsert;
|
|
4140
|
+
|
|
4141
|
+
/**
|
|
4142
|
+
* @spfn/auth - WebAuthn Challenges Entity
|
|
4143
|
+
*
|
|
4144
|
+
* The random value an authenticator signs, parked between the `options` call
|
|
4145
|
+
* that minted it and the `verify` call that spends it.
|
|
4146
|
+
*
|
|
4147
|
+
* In the database rather than in a cookie or in memory, for two reasons: the
|
|
4148
|
+
* check that makes a challenge one-time has to be a conditional UPDATE that two
|
|
4149
|
+
* concurrent verifies cannot both win, and several API instances serve the same
|
|
4150
|
+
* browser — an in-process map would let a replay land on the instance that never
|
|
4151
|
+
* saw the first attempt.
|
|
4152
|
+
*
|
|
4153
|
+
* Only the SHA-256 of the challenge is stored, following the rule the package
|
|
4154
|
+
* already applies to signup link tokens. A challenge is a nonce rather than a
|
|
4155
|
+
* bearer credential, so this buys less than it does there; it costs nothing, and
|
|
4156
|
+
* it keeps "plaintext or hash" from becoming a per-table judgement call.
|
|
4157
|
+
*/
|
|
4158
|
+
/**
|
|
4159
|
+
* Which ceremony the challenge was minted for.
|
|
4160
|
+
*
|
|
4161
|
+
* Recorded and matched at consume time so a registration challenge cannot be
|
|
4162
|
+
* presented to `login/verify` or the other way round — the two ceremonies
|
|
4163
|
+
* authorize very different things, and only the kind tells them apart once the
|
|
4164
|
+
* value itself is just 32 random bytes.
|
|
4165
|
+
*
|
|
4166
|
+
* `'mfa'` is the third: a step-up assertion, minted for an identified account
|
|
4167
|
+
* and spent by `POST /_auth/mfa/step-up`. It buys the same separation in the
|
|
4168
|
+
* direction that matters most — an assertion collected as a second factor is
|
|
4169
|
+
* not a sign-in, and `passkeys/login/verify` refuses it for exactly the reason
|
|
4170
|
+
* the column exists.
|
|
4171
|
+
*
|
|
4172
|
+
* `'renewal'` is the fourth: the assertion that renews a bound session key, and
|
|
4173
|
+
* the one that lets an account leave `session_binding: 'passkey'`. It is its own
|
|
4174
|
+
* kind rather than a reused `'authentication'` because that kind's challenge is
|
|
4175
|
+
* minted for nobody in particular — a discoverable sign-in names no account —
|
|
4176
|
+
* while a renewal challenge is bound to the account it was issued for, and
|
|
4177
|
+
* spending one where the other was expected would cross those two rules.
|
|
4178
|
+
*/
|
|
4179
|
+
declare const WEBAUTHN_CHALLENGE_KINDS: readonly ["registration", "authentication", "mfa", "renewal"];
|
|
4180
|
+
type WebAuthnChallengeKind = typeof WEBAUTHN_CHALLENGE_KINDS[number];
|
|
4181
|
+
declare const webauthnChallenges: drizzle_orm_pg_core.PgTableWithColumns<{
|
|
4182
|
+
name: "webauthn_challenges";
|
|
4183
|
+
schema: string;
|
|
4184
|
+
columns: {
|
|
4185
|
+
id: drizzle_orm_pg_core.PgBuildColumn<"webauthn_challenges", drizzle_orm_pg_core.SetIsPrimaryKey<drizzle_orm_pg_core.PgBigSerial53Builder>, {
|
|
4130
4186
|
name: string;
|
|
4131
|
-
tableName: "
|
|
4132
|
-
dataType: "
|
|
4133
|
-
data:
|
|
4134
|
-
driverParam:
|
|
4135
|
-
notNull:
|
|
4136
|
-
hasDefault:
|
|
4187
|
+
tableName: "webauthn_challenges";
|
|
4188
|
+
dataType: "number int53";
|
|
4189
|
+
data: number;
|
|
4190
|
+
driverParam: number;
|
|
4191
|
+
notNull: true;
|
|
4192
|
+
hasDefault: true;
|
|
4137
4193
|
isPrimaryKey: false;
|
|
4138
4194
|
isAutoincrement: false;
|
|
4139
4195
|
hasRuntimeDefault: false;
|
|
@@ -4141,12 +4197,42 @@ declare const passwordResetTokens: drizzle_orm_pg_core.PgTableWithColumns<{
|
|
|
4141
4197
|
identity: undefined;
|
|
4142
4198
|
generated: undefined;
|
|
4143
4199
|
}>;
|
|
4144
|
-
|
|
4200
|
+
challengeHash: drizzle_orm_pg_core.PgBuildColumn<"webauthn_challenges", drizzle_orm_pg_core.SetNotNull<drizzle_orm_pg_core.PgTextBuilder<[string, ...string[]]>>, {
|
|
4145
4201
|
name: string;
|
|
4146
|
-
tableName: "
|
|
4202
|
+
tableName: "webauthn_challenges";
|
|
4147
4203
|
dataType: "string";
|
|
4148
4204
|
data: string;
|
|
4149
4205
|
driverParam: string;
|
|
4206
|
+
notNull: true;
|
|
4207
|
+
hasDefault: false;
|
|
4208
|
+
isPrimaryKey: false;
|
|
4209
|
+
isAutoincrement: false;
|
|
4210
|
+
hasRuntimeDefault: false;
|
|
4211
|
+
enumValues: undefined;
|
|
4212
|
+
identity: undefined;
|
|
4213
|
+
generated: undefined;
|
|
4214
|
+
}>;
|
|
4215
|
+
kind: drizzle_orm_pg_core.PgBuildColumn<"webauthn_challenges", drizzle_orm_pg_core.SetNotNull<drizzle_orm_pg_core.PgTextBuilder<["registration", "authentication", "mfa", "renewal"] & [string, ...string[]]>>, {
|
|
4216
|
+
name: string;
|
|
4217
|
+
tableName: "webauthn_challenges";
|
|
4218
|
+
dataType: "string enum";
|
|
4219
|
+
data: "registration" | "authentication" | "mfa" | "renewal";
|
|
4220
|
+
driverParam: string;
|
|
4221
|
+
notNull: true;
|
|
4222
|
+
hasDefault: false;
|
|
4223
|
+
isPrimaryKey: false;
|
|
4224
|
+
isAutoincrement: false;
|
|
4225
|
+
hasRuntimeDefault: false;
|
|
4226
|
+
enumValues: ["registration", "authentication", "mfa", "renewal"] & [string, ...string[]];
|
|
4227
|
+
identity: undefined;
|
|
4228
|
+
generated: undefined;
|
|
4229
|
+
}>;
|
|
4230
|
+
userId: drizzle_orm_pg_core.PgBuildColumn<"webauthn_challenges", drizzle_orm_pg_core.PgBigInt53Builder, {
|
|
4231
|
+
name: string;
|
|
4232
|
+
tableName: "webauthn_challenges";
|
|
4233
|
+
dataType: "number int53";
|
|
4234
|
+
data: number;
|
|
4235
|
+
driverParam: string | number;
|
|
4150
4236
|
notNull: false;
|
|
4151
4237
|
hasDefault: false;
|
|
4152
4238
|
isPrimaryKey: false;
|
|
@@ -4156,13 +4242,13 @@ declare const passwordResetTokens: drizzle_orm_pg_core.PgTableWithColumns<{
|
|
|
4156
4242
|
identity: undefined;
|
|
4157
4243
|
generated: undefined;
|
|
4158
4244
|
}>;
|
|
4159
|
-
|
|
4245
|
+
expiresAt: drizzle_orm_pg_core.PgBuildColumn<"webauthn_challenges", drizzle_orm_pg_core.SetNotNull<drizzle_orm_pg_core.PgTimestampBuilder>, {
|
|
4160
4246
|
name: string;
|
|
4161
|
-
tableName: "
|
|
4247
|
+
tableName: "webauthn_challenges";
|
|
4162
4248
|
dataType: "object date";
|
|
4163
4249
|
data: Date;
|
|
4164
4250
|
driverParam: string;
|
|
4165
|
-
notNull:
|
|
4251
|
+
notNull: true;
|
|
4166
4252
|
hasDefault: false;
|
|
4167
4253
|
isPrimaryKey: false;
|
|
4168
4254
|
isAutoincrement: false;
|
|
@@ -4171,9 +4257,9 @@ declare const passwordResetTokens: drizzle_orm_pg_core.PgTableWithColumns<{
|
|
|
4171
4257
|
identity: undefined;
|
|
4172
4258
|
generated: undefined;
|
|
4173
4259
|
}>;
|
|
4174
|
-
|
|
4260
|
+
consumedAt: drizzle_orm_pg_core.PgBuildColumn<"webauthn_challenges", drizzle_orm_pg_core.PgTimestampBuilder, {
|
|
4175
4261
|
name: string;
|
|
4176
|
-
tableName: "
|
|
4262
|
+
tableName: "webauthn_challenges";
|
|
4177
4263
|
dataType: "object date";
|
|
4178
4264
|
data: Date;
|
|
4179
4265
|
driverParam: string;
|
|
@@ -4186,37 +4272,56 @@ declare const passwordResetTokens: drizzle_orm_pg_core.PgTableWithColumns<{
|
|
|
4186
4272
|
identity: undefined;
|
|
4187
4273
|
generated: undefined;
|
|
4188
4274
|
}>;
|
|
4275
|
+
createdAt: drizzle_orm_pg_core.PgBuildColumn<"webauthn_challenges", drizzle_orm_pg_core.SetHasDefault<drizzle_orm_pg_core.SetNotNull<drizzle_orm_pg_core.PgTimestampBuilder>>, {
|
|
4276
|
+
name: string;
|
|
4277
|
+
tableName: "webauthn_challenges";
|
|
4278
|
+
dataType: "object date";
|
|
4279
|
+
data: Date;
|
|
4280
|
+
driverParam: string;
|
|
4281
|
+
notNull: true;
|
|
4282
|
+
hasDefault: true;
|
|
4283
|
+
isPrimaryKey: false;
|
|
4284
|
+
isAutoincrement: false;
|
|
4285
|
+
hasRuntimeDefault: false;
|
|
4286
|
+
enumValues: undefined;
|
|
4287
|
+
identity: undefined;
|
|
4288
|
+
generated: undefined;
|
|
4289
|
+
}>;
|
|
4189
4290
|
};
|
|
4190
4291
|
dialect: "pg";
|
|
4191
4292
|
}>;
|
|
4192
|
-
type
|
|
4193
|
-
type
|
|
4293
|
+
type WebAuthnChallenge = typeof webauthnChallenges.$inferSelect;
|
|
4294
|
+
type NewWebAuthnChallenge = typeof webauthnChallenges.$inferInsert;
|
|
4194
4295
|
|
|
4195
4296
|
/**
|
|
4196
|
-
* @spfn/auth -
|
|
4297
|
+
* @spfn/auth - TOTP Enrolment Entity
|
|
4197
4298
|
*
|
|
4198
|
-
*
|
|
4199
|
-
*
|
|
4200
|
-
*
|
|
4201
|
-
*
|
|
4202
|
-
* trust.
|
|
4299
|
+
* One row per account that has started enrolling an authenticator app. The row
|
|
4300
|
+
* exists from the moment `totp/enroll` mints a secret; `confirmed_at` is what
|
|
4301
|
+
* turns it into a second factor, so an abandoned enrolment never gates anything
|
|
4302
|
+
* and is swept away a day later.
|
|
4203
4303
|
*
|
|
4204
|
-
* `
|
|
4205
|
-
* the
|
|
4206
|
-
*
|
|
4207
|
-
|
|
4208
|
-
|
|
4304
|
+
* `secret_enc` is the ciphertext `lib/mfa-cipher.ts` produces, bound to this
|
|
4305
|
+
* `user_id` by the AEAD's additional data. A row copied to another account does
|
|
4306
|
+
* not decrypt.
|
|
4307
|
+
*/
|
|
4308
|
+
/**
|
|
4309
|
+
* How many wrong codes an unconfirmed enrolment survives.
|
|
4209
4310
|
*
|
|
4210
|
-
*
|
|
4211
|
-
*
|
|
4311
|
+
* Small, because the row is throwaway: five wrong codes means the person is
|
|
4312
|
+
* reading the wrong entry in their app, and starting over with a fresh secret
|
|
4313
|
+
* is both the remedy and the thing that resets the counter. A confirmed row is
|
|
4314
|
+
* never deleted this way — that would be a remote way to strip someone's second
|
|
4315
|
+
* factor.
|
|
4212
4316
|
*/
|
|
4213
|
-
declare const
|
|
4214
|
-
|
|
4317
|
+
declare const MFA_CONFIRM_ATTEMPT_LIMIT = 5;
|
|
4318
|
+
declare const mfaTotp: drizzle_orm_pg_core.PgTableWithColumns<{
|
|
4319
|
+
name: "mfa_totp";
|
|
4215
4320
|
schema: string;
|
|
4216
4321
|
columns: {
|
|
4217
|
-
createdAt: drizzle_orm_pg_core.PgBuildColumn<"
|
|
4322
|
+
createdAt: drizzle_orm_pg_core.PgBuildColumn<"mfa_totp", drizzle_orm_pg_core.SetNotNull<drizzle_orm_pg_core.SetHasDefault<drizzle_orm_pg_core.PgTimestampBuilder>>, {
|
|
4218
4323
|
name: string;
|
|
4219
|
-
tableName: "
|
|
4324
|
+
tableName: "mfa_totp";
|
|
4220
4325
|
dataType: "object date";
|
|
4221
4326
|
data: Date;
|
|
4222
4327
|
driverParam: string;
|
|
@@ -4229,9 +4334,9 @@ declare const keyRevokeAllTokens: drizzle_orm_pg_core.PgTableWithColumns<{
|
|
|
4229
4334
|
identity: undefined;
|
|
4230
4335
|
generated: undefined;
|
|
4231
4336
|
}>;
|
|
4232
|
-
updatedAt: drizzle_orm_pg_core.PgBuildColumn<"
|
|
4337
|
+
updatedAt: drizzle_orm_pg_core.PgBuildColumn<"mfa_totp", drizzle_orm_pg_core.SetHasDefault<drizzle_orm_pg_core.SetNotNull<drizzle_orm_pg_core.SetHasDefault<drizzle_orm_pg_core.PgTimestampBuilder>>>, {
|
|
4233
4338
|
name: string;
|
|
4234
|
-
tableName: "
|
|
4339
|
+
tableName: "mfa_totp";
|
|
4235
4340
|
dataType: "object date";
|
|
4236
4341
|
data: Date;
|
|
4237
4342
|
driverParam: string;
|
|
@@ -4244,9 +4349,9 @@ declare const keyRevokeAllTokens: drizzle_orm_pg_core.PgTableWithColumns<{
|
|
|
4244
4349
|
identity: undefined;
|
|
4245
4350
|
generated: undefined;
|
|
4246
4351
|
}>;
|
|
4247
|
-
id: drizzle_orm_pg_core.PgBuildColumn<"
|
|
4352
|
+
id: drizzle_orm_pg_core.PgBuildColumn<"mfa_totp", drizzle_orm_pg_core.SetIsPrimaryKey<drizzle_orm_pg_core.PgBigSerial53Builder>, {
|
|
4248
4353
|
name: string;
|
|
4249
|
-
tableName: "
|
|
4354
|
+
tableName: "mfa_totp";
|
|
4250
4355
|
dataType: "number int53";
|
|
4251
4356
|
data: number;
|
|
4252
4357
|
driverParam: number;
|
|
@@ -4259,9 +4364,9 @@ declare const keyRevokeAllTokens: drizzle_orm_pg_core.PgTableWithColumns<{
|
|
|
4259
4364
|
identity: undefined;
|
|
4260
4365
|
generated: undefined;
|
|
4261
4366
|
}>;
|
|
4262
|
-
userId: drizzle_orm_pg_core.PgBuildColumn<"
|
|
4367
|
+
userId: drizzle_orm_pg_core.PgBuildColumn<"mfa_totp", drizzle_orm_pg_core.SetNotNull<drizzle_orm_pg_core.PgBigInt53Builder>, {
|
|
4263
4368
|
name: string;
|
|
4264
|
-
tableName: "
|
|
4369
|
+
tableName: "mfa_totp";
|
|
4265
4370
|
dataType: "number int53";
|
|
4266
4371
|
data: number;
|
|
4267
4372
|
driverParam: string | number;
|
|
@@ -4274,9 +4379,9 @@ declare const keyRevokeAllTokens: drizzle_orm_pg_core.PgTableWithColumns<{
|
|
|
4274
4379
|
identity: undefined;
|
|
4275
4380
|
generated: undefined;
|
|
4276
4381
|
}>;
|
|
4277
|
-
|
|
4382
|
+
secretEnc: drizzle_orm_pg_core.PgBuildColumn<"mfa_totp", drizzle_orm_pg_core.SetNotNull<drizzle_orm_pg_core.PgTextBuilder<[string, ...string[]]>>, {
|
|
4278
4383
|
name: string;
|
|
4279
|
-
tableName: "
|
|
4384
|
+
tableName: "mfa_totp";
|
|
4280
4385
|
dataType: "string";
|
|
4281
4386
|
data: string;
|
|
4282
4387
|
driverParam: string;
|
|
@@ -4289,28 +4394,13 @@ declare const keyRevokeAllTokens: drizzle_orm_pg_core.PgTableWithColumns<{
|
|
|
4289
4394
|
identity: undefined;
|
|
4290
4395
|
generated: undefined;
|
|
4291
4396
|
}>;
|
|
4292
|
-
|
|
4293
|
-
name: string;
|
|
4294
|
-
tableName: "key_revoke_all_tokens";
|
|
4295
|
-
dataType: "number int32";
|
|
4296
|
-
data: number;
|
|
4297
|
-
driverParam: string | number;
|
|
4298
|
-
notNull: true;
|
|
4299
|
-
hasDefault: false;
|
|
4300
|
-
isPrimaryKey: false;
|
|
4301
|
-
isAutoincrement: false;
|
|
4302
|
-
hasRuntimeDefault: false;
|
|
4303
|
-
enumValues: undefined;
|
|
4304
|
-
identity: undefined;
|
|
4305
|
-
generated: undefined;
|
|
4306
|
-
}>;
|
|
4307
|
-
expiresAt: drizzle_orm_pg_core.PgBuildColumn<"key_revoke_all_tokens", drizzle_orm_pg_core.SetNotNull<drizzle_orm_pg_core.PgTimestampBuilder>, {
|
|
4397
|
+
confirmedAt: drizzle_orm_pg_core.PgBuildColumn<"mfa_totp", drizzle_orm_pg_core.PgTimestampBuilder, {
|
|
4308
4398
|
name: string;
|
|
4309
|
-
tableName: "
|
|
4399
|
+
tableName: "mfa_totp";
|
|
4310
4400
|
dataType: "object date";
|
|
4311
4401
|
data: Date;
|
|
4312
4402
|
driverParam: string;
|
|
4313
|
-
notNull:
|
|
4403
|
+
notNull: false;
|
|
4314
4404
|
hasDefault: false;
|
|
4315
4405
|
isPrimaryKey: false;
|
|
4316
4406
|
isAutoincrement: false;
|
|
@@ -4319,12 +4409,12 @@ declare const keyRevokeAllTokens: drizzle_orm_pg_core.PgTableWithColumns<{
|
|
|
4319
4409
|
identity: undefined;
|
|
4320
4410
|
generated: undefined;
|
|
4321
4411
|
}>;
|
|
4322
|
-
|
|
4412
|
+
lastUsedStep: drizzle_orm_pg_core.PgBuildColumn<"mfa_totp", drizzle_orm_pg_core.PgBigInt53Builder, {
|
|
4323
4413
|
name: string;
|
|
4324
|
-
tableName: "
|
|
4325
|
-
dataType: "
|
|
4326
|
-
data:
|
|
4327
|
-
driverParam: string;
|
|
4414
|
+
tableName: "mfa_totp";
|
|
4415
|
+
dataType: "number int53";
|
|
4416
|
+
data: number;
|
|
4417
|
+
driverParam: string | number;
|
|
4328
4418
|
notNull: false;
|
|
4329
4419
|
hasDefault: false;
|
|
4330
4420
|
isPrimaryKey: false;
|
|
@@ -4334,14 +4424,14 @@ declare const keyRevokeAllTokens: drizzle_orm_pg_core.PgTableWithColumns<{
|
|
|
4334
4424
|
identity: undefined;
|
|
4335
4425
|
generated: undefined;
|
|
4336
4426
|
}>;
|
|
4337
|
-
|
|
4427
|
+
failedConfirmAttempts: drizzle_orm_pg_core.PgBuildColumn<"mfa_totp", drizzle_orm_pg_core.SetHasDefault<drizzle_orm_pg_core.SetNotNull<drizzle_orm_pg_core.PgIntegerBuilder>>, {
|
|
4338
4428
|
name: string;
|
|
4339
|
-
tableName: "
|
|
4340
|
-
dataType: "
|
|
4341
|
-
data:
|
|
4342
|
-
driverParam: string;
|
|
4343
|
-
notNull:
|
|
4344
|
-
hasDefault:
|
|
4429
|
+
tableName: "mfa_totp";
|
|
4430
|
+
dataType: "number int32";
|
|
4431
|
+
data: number;
|
|
4432
|
+
driverParam: string | number;
|
|
4433
|
+
notNull: true;
|
|
4434
|
+
hasDefault: true;
|
|
4345
4435
|
isPrimaryKey: false;
|
|
4346
4436
|
isAutoincrement: false;
|
|
4347
4437
|
hasRuntimeDefault: false;
|
|
@@ -4352,46 +4442,33 @@ declare const keyRevokeAllTokens: drizzle_orm_pg_core.PgTableWithColumns<{
|
|
|
4352
4442
|
};
|
|
4353
4443
|
dialect: "pg";
|
|
4354
4444
|
}>;
|
|
4355
|
-
type
|
|
4356
|
-
type
|
|
4445
|
+
type MfaTotp = typeof mfaTotp.$inferSelect;
|
|
4446
|
+
type NewMfaTotp = typeof mfaTotp.$inferInsert;
|
|
4357
4447
|
|
|
4358
4448
|
/**
|
|
4359
|
-
* @spfn/auth -
|
|
4360
|
-
*
|
|
4361
|
-
* The random value an authenticator signs, parked between the `options` call
|
|
4362
|
-
* that minted it and the `verify` call that spends it.
|
|
4363
|
-
*
|
|
4364
|
-
* In the database rather than in a cookie or in memory, for two reasons: the
|
|
4365
|
-
* check that makes a challenge one-time has to be a conditional UPDATE that two
|
|
4366
|
-
* concurrent verifies cannot both win, and several API instances serve the same
|
|
4367
|
-
* browser — an in-process map would let a replay land on the instance that never
|
|
4368
|
-
* saw the first attempt.
|
|
4449
|
+
* @spfn/auth - Recovery Codes Entity
|
|
4369
4450
|
*
|
|
4370
|
-
*
|
|
4371
|
-
*
|
|
4372
|
-
*
|
|
4373
|
-
*
|
|
4374
|
-
|
|
4375
|
-
/**
|
|
4376
|
-
* Which ceremony the challenge was minted for.
|
|
4451
|
+
* The ten single-use codes an enrolled account is shown once. Only the hash is
|
|
4452
|
+
* stored, and it is a **password** hash rather than the unsalted SHA-256 the
|
|
4453
|
+
* link flows use — a code a human transcribes is short enough that a leaked
|
|
4454
|
+
* dump of unsalted hashes falls to an offline sweep. `lib/recovery-codes.ts`
|
|
4455
|
+
* sets out the reasoning.
|
|
4377
4456
|
*
|
|
4378
|
-
*
|
|
4379
|
-
*
|
|
4380
|
-
*
|
|
4381
|
-
*
|
|
4457
|
+
* Codes come in generations. Regenerating raises the generation rather than
|
|
4458
|
+
* deleting the old rows, so a code someone wrote down last year is refused with
|
|
4459
|
+
* the same body as one that never existed, and the history of which generation
|
|
4460
|
+
* a code was spent from survives.
|
|
4382
4461
|
*/
|
|
4383
|
-
declare const
|
|
4384
|
-
|
|
4385
|
-
declare const webauthnChallenges: drizzle_orm_pg_core.PgTableWithColumns<{
|
|
4386
|
-
name: "webauthn_challenges";
|
|
4462
|
+
declare const mfaRecoveryCodes: drizzle_orm_pg_core.PgTableWithColumns<{
|
|
4463
|
+
name: "mfa_recovery_codes";
|
|
4387
4464
|
schema: string;
|
|
4388
4465
|
columns: {
|
|
4389
|
-
|
|
4466
|
+
createdAt: drizzle_orm_pg_core.PgBuildColumn<"mfa_recovery_codes", drizzle_orm_pg_core.SetNotNull<drizzle_orm_pg_core.SetHasDefault<drizzle_orm_pg_core.PgTimestampBuilder>>, {
|
|
4390
4467
|
name: string;
|
|
4391
|
-
tableName: "
|
|
4392
|
-
dataType: "
|
|
4393
|
-
data:
|
|
4394
|
-
driverParam:
|
|
4468
|
+
tableName: "mfa_recovery_codes";
|
|
4469
|
+
dataType: "object date";
|
|
4470
|
+
data: Date;
|
|
4471
|
+
driverParam: string;
|
|
4395
4472
|
notNull: true;
|
|
4396
4473
|
hasDefault: true;
|
|
4397
4474
|
isPrimaryKey: false;
|
|
@@ -4401,14 +4478,14 @@ declare const webauthnChallenges: drizzle_orm_pg_core.PgTableWithColumns<{
|
|
|
4401
4478
|
identity: undefined;
|
|
4402
4479
|
generated: undefined;
|
|
4403
4480
|
}>;
|
|
4404
|
-
|
|
4481
|
+
updatedAt: drizzle_orm_pg_core.PgBuildColumn<"mfa_recovery_codes", drizzle_orm_pg_core.SetHasDefault<drizzle_orm_pg_core.SetNotNull<drizzle_orm_pg_core.SetHasDefault<drizzle_orm_pg_core.PgTimestampBuilder>>>, {
|
|
4405
4482
|
name: string;
|
|
4406
|
-
tableName: "
|
|
4407
|
-
dataType: "
|
|
4408
|
-
data:
|
|
4483
|
+
tableName: "mfa_recovery_codes";
|
|
4484
|
+
dataType: "object date";
|
|
4485
|
+
data: Date;
|
|
4409
4486
|
driverParam: string;
|
|
4410
4487
|
notNull: true;
|
|
4411
|
-
hasDefault:
|
|
4488
|
+
hasDefault: true;
|
|
4412
4489
|
isPrimaryKey: false;
|
|
4413
4490
|
isAutoincrement: false;
|
|
4414
4491
|
hasRuntimeDefault: false;
|
|
@@ -4416,28 +4493,28 @@ declare const webauthnChallenges: drizzle_orm_pg_core.PgTableWithColumns<{
|
|
|
4416
4493
|
identity: undefined;
|
|
4417
4494
|
generated: undefined;
|
|
4418
4495
|
}>;
|
|
4419
|
-
|
|
4496
|
+
id: drizzle_orm_pg_core.PgBuildColumn<"mfa_recovery_codes", drizzle_orm_pg_core.SetIsPrimaryKey<drizzle_orm_pg_core.PgBigSerial53Builder>, {
|
|
4420
4497
|
name: string;
|
|
4421
|
-
tableName: "
|
|
4422
|
-
dataType: "
|
|
4423
|
-
data:
|
|
4424
|
-
driverParam:
|
|
4498
|
+
tableName: "mfa_recovery_codes";
|
|
4499
|
+
dataType: "number int53";
|
|
4500
|
+
data: number;
|
|
4501
|
+
driverParam: number;
|
|
4425
4502
|
notNull: true;
|
|
4426
|
-
hasDefault:
|
|
4503
|
+
hasDefault: true;
|
|
4427
4504
|
isPrimaryKey: false;
|
|
4428
4505
|
isAutoincrement: false;
|
|
4429
4506
|
hasRuntimeDefault: false;
|
|
4430
|
-
enumValues:
|
|
4507
|
+
enumValues: undefined;
|
|
4431
4508
|
identity: undefined;
|
|
4432
4509
|
generated: undefined;
|
|
4433
4510
|
}>;
|
|
4434
|
-
userId: drizzle_orm_pg_core.PgBuildColumn<"
|
|
4511
|
+
userId: drizzle_orm_pg_core.PgBuildColumn<"mfa_recovery_codes", drizzle_orm_pg_core.SetNotNull<drizzle_orm_pg_core.PgBigInt53Builder>, {
|
|
4435
4512
|
name: string;
|
|
4436
|
-
tableName: "
|
|
4513
|
+
tableName: "mfa_recovery_codes";
|
|
4437
4514
|
dataType: "number int53";
|
|
4438
4515
|
data: number;
|
|
4439
4516
|
driverParam: string | number;
|
|
4440
|
-
notNull:
|
|
4517
|
+
notNull: true;
|
|
4441
4518
|
hasDefault: false;
|
|
4442
4519
|
isPrimaryKey: false;
|
|
4443
4520
|
isAutoincrement: false;
|
|
@@ -4446,12 +4523,12 @@ declare const webauthnChallenges: drizzle_orm_pg_core.PgTableWithColumns<{
|
|
|
4446
4523
|
identity: undefined;
|
|
4447
4524
|
generated: undefined;
|
|
4448
4525
|
}>;
|
|
4449
|
-
|
|
4526
|
+
generation: drizzle_orm_pg_core.PgBuildColumn<"mfa_recovery_codes", drizzle_orm_pg_core.SetNotNull<drizzle_orm_pg_core.PgIntegerBuilder>, {
|
|
4450
4527
|
name: string;
|
|
4451
|
-
tableName: "
|
|
4452
|
-
dataType: "
|
|
4453
|
-
data:
|
|
4454
|
-
driverParam: string;
|
|
4528
|
+
tableName: "mfa_recovery_codes";
|
|
4529
|
+
dataType: "number int32";
|
|
4530
|
+
data: number;
|
|
4531
|
+
driverParam: string | number;
|
|
4455
4532
|
notNull: true;
|
|
4456
4533
|
hasDefault: false;
|
|
4457
4534
|
isPrimaryKey: false;
|
|
@@ -4461,13 +4538,13 @@ declare const webauthnChallenges: drizzle_orm_pg_core.PgTableWithColumns<{
|
|
|
4461
4538
|
identity: undefined;
|
|
4462
4539
|
generated: undefined;
|
|
4463
4540
|
}>;
|
|
4464
|
-
|
|
4541
|
+
codeHash: drizzle_orm_pg_core.PgBuildColumn<"mfa_recovery_codes", drizzle_orm_pg_core.SetNotNull<drizzle_orm_pg_core.PgTextBuilder<[string, ...string[]]>>, {
|
|
4465
4542
|
name: string;
|
|
4466
|
-
tableName: "
|
|
4467
|
-
dataType: "
|
|
4468
|
-
data:
|
|
4543
|
+
tableName: "mfa_recovery_codes";
|
|
4544
|
+
dataType: "string";
|
|
4545
|
+
data: string;
|
|
4469
4546
|
driverParam: string;
|
|
4470
|
-
notNull:
|
|
4547
|
+
notNull: true;
|
|
4471
4548
|
hasDefault: false;
|
|
4472
4549
|
isPrimaryKey: false;
|
|
4473
4550
|
isAutoincrement: false;
|
|
@@ -4476,14 +4553,14 @@ declare const webauthnChallenges: drizzle_orm_pg_core.PgTableWithColumns<{
|
|
|
4476
4553
|
identity: undefined;
|
|
4477
4554
|
generated: undefined;
|
|
4478
4555
|
}>;
|
|
4479
|
-
|
|
4556
|
+
usedAt: drizzle_orm_pg_core.PgBuildColumn<"mfa_recovery_codes", drizzle_orm_pg_core.PgTimestampBuilder, {
|
|
4480
4557
|
name: string;
|
|
4481
|
-
tableName: "
|
|
4558
|
+
tableName: "mfa_recovery_codes";
|
|
4482
4559
|
dataType: "object date";
|
|
4483
4560
|
data: Date;
|
|
4484
4561
|
driverParam: string;
|
|
4485
|
-
notNull:
|
|
4486
|
-
hasDefault:
|
|
4562
|
+
notNull: false;
|
|
4563
|
+
hasDefault: false;
|
|
4487
4564
|
isPrimaryKey: false;
|
|
4488
4565
|
isAutoincrement: false;
|
|
4489
4566
|
hasRuntimeDefault: false;
|
|
@@ -4494,8 +4571,8 @@ declare const webauthnChallenges: drizzle_orm_pg_core.PgTableWithColumns<{
|
|
|
4494
4571
|
};
|
|
4495
4572
|
dialect: "pg";
|
|
4496
4573
|
}>;
|
|
4497
|
-
type
|
|
4498
|
-
type
|
|
4574
|
+
type MfaRecoveryCode = typeof mfaRecoveryCodes.$inferSelect;
|
|
4575
|
+
type NewMfaRecoveryCode = typeof mfaRecoveryCodes.$inferInsert;
|
|
4499
4576
|
|
|
4500
4577
|
/**
|
|
4501
4578
|
* @spfn/auth - Device Authorizations Entity
|
|
@@ -5963,6 +6040,8 @@ declare class UsersRepository extends BaseRepository {
|
|
|
5963
6040
|
emailVerifiedAt: Date | null;
|
|
5964
6041
|
phoneVerifiedAt: Date | null;
|
|
5965
6042
|
keyEpoch: number;
|
|
6043
|
+
sessionBinding: "none" | "passkey";
|
|
6044
|
+
sessionBindingChangedAt: Date | null;
|
|
5966
6045
|
lastLoginAt: Date | null;
|
|
5967
6046
|
}>;
|
|
5968
6047
|
/**
|
|
@@ -5989,6 +6068,8 @@ declare class UsersRepository extends BaseRepository {
|
|
|
5989
6068
|
emailVerifiedAt: Date | null;
|
|
5990
6069
|
phoneVerifiedAt: Date | null;
|
|
5991
6070
|
keyEpoch: number;
|
|
6071
|
+
sessionBinding: "none" | "passkey";
|
|
6072
|
+
sessionBindingChangedAt: Date | null;
|
|
5992
6073
|
lastLoginAt: Date | null;
|
|
5993
6074
|
}>;
|
|
5994
6075
|
/**
|
|
@@ -6026,6 +6107,8 @@ declare class UsersRepository extends BaseRepository {
|
|
|
6026
6107
|
emailVerifiedAt: Date | null;
|
|
6027
6108
|
phoneVerifiedAt: Date | null;
|
|
6028
6109
|
keyEpoch: number;
|
|
6110
|
+
sessionBinding: "none" | "passkey";
|
|
6111
|
+
sessionBindingChangedAt: Date | null;
|
|
6029
6112
|
lastLoginAt: Date | null;
|
|
6030
6113
|
}>;
|
|
6031
6114
|
/**
|
|
@@ -6059,6 +6142,8 @@ declare class UsersRepository extends BaseRepository {
|
|
|
6059
6142
|
emailVerifiedAt: Date | null;
|
|
6060
6143
|
phoneVerifiedAt: Date | null;
|
|
6061
6144
|
keyEpoch: number;
|
|
6145
|
+
sessionBinding: "none" | "passkey";
|
|
6146
|
+
sessionBindingChangedAt: Date | null;
|
|
6062
6147
|
lastLoginAt: Date | null;
|
|
6063
6148
|
}>;
|
|
6064
6149
|
/**
|
|
@@ -6082,6 +6167,8 @@ declare class UsersRepository extends BaseRepository {
|
|
|
6082
6167
|
emailVerifiedAt: Date | null;
|
|
6083
6168
|
phoneVerifiedAt: Date | null;
|
|
6084
6169
|
keyEpoch: number;
|
|
6170
|
+
sessionBinding: "none" | "passkey";
|
|
6171
|
+
sessionBindingChangedAt: Date | null;
|
|
6085
6172
|
lastLoginAt: Date | null;
|
|
6086
6173
|
}>;
|
|
6087
6174
|
/**
|
|
@@ -6105,6 +6192,8 @@ declare class UsersRepository extends BaseRepository {
|
|
|
6105
6192
|
emailVerifiedAt: Date | null;
|
|
6106
6193
|
phoneVerifiedAt: Date | null;
|
|
6107
6194
|
keyEpoch: number;
|
|
6195
|
+
sessionBinding: "none" | "passkey";
|
|
6196
|
+
sessionBindingChangedAt: Date | null;
|
|
6108
6197
|
lastLoginAt: Date | null;
|
|
6109
6198
|
}>;
|
|
6110
6199
|
/**
|
|
@@ -6128,6 +6217,8 @@ declare class UsersRepository extends BaseRepository {
|
|
|
6128
6217
|
emailVerifiedAt: Date | null;
|
|
6129
6218
|
phoneVerifiedAt: Date | null;
|
|
6130
6219
|
keyEpoch: number;
|
|
6220
|
+
sessionBinding: "none" | "passkey";
|
|
6221
|
+
sessionBindingChangedAt: Date | null;
|
|
6131
6222
|
lastLoginAt: Date | null;
|
|
6132
6223
|
}>;
|
|
6133
6224
|
/**
|
|
@@ -6151,6 +6242,8 @@ declare class UsersRepository extends BaseRepository {
|
|
|
6151
6242
|
emailVerifiedAt: Date | null;
|
|
6152
6243
|
phoneVerifiedAt: Date | null;
|
|
6153
6244
|
keyEpoch: number;
|
|
6245
|
+
sessionBinding: "none" | "passkey";
|
|
6246
|
+
sessionBindingChangedAt: Date | null;
|
|
6154
6247
|
lastLoginAt: Date | null;
|
|
6155
6248
|
} | null>;
|
|
6156
6249
|
/**
|
|
@@ -6177,6 +6270,8 @@ declare class UsersRepository extends BaseRepository {
|
|
|
6177
6270
|
emailVerifiedAt: Date | null;
|
|
6178
6271
|
phoneVerifiedAt: Date | null;
|
|
6179
6272
|
keyEpoch: number;
|
|
6273
|
+
sessionBinding: "none" | "passkey";
|
|
6274
|
+
sessionBindingChangedAt: Date | null;
|
|
6180
6275
|
lastLoginAt: Date | null;
|
|
6181
6276
|
};
|
|
6182
6277
|
role: {
|
|
@@ -6192,6 +6287,7 @@ declare class UsersRepository extends BaseRepository {
|
|
|
6192
6287
|
create(data: NewUser): Promise<{
|
|
6193
6288
|
email: string | null;
|
|
6194
6289
|
phone: string | null;
|
|
6290
|
+
sessionBinding: "none" | "passkey";
|
|
6195
6291
|
status: "active" | "inactive" | "suspended" | "pending_deletion" | "deleted";
|
|
6196
6292
|
publicId: string;
|
|
6197
6293
|
passwordChangeRequired: boolean;
|
|
@@ -6204,6 +6300,7 @@ declare class UsersRepository extends BaseRepository {
|
|
|
6204
6300
|
emailVerifiedAt: Date | null;
|
|
6205
6301
|
phoneVerifiedAt: Date | null;
|
|
6206
6302
|
keyEpoch: number;
|
|
6303
|
+
sessionBindingChangedAt: Date | null;
|
|
6207
6304
|
lastLoginAt: Date | null;
|
|
6208
6305
|
deletedAt: Date | null;
|
|
6209
6306
|
deletedBy: string | null;
|
|
@@ -6274,6 +6371,8 @@ declare class UsersRepository extends BaseRepository {
|
|
|
6274
6371
|
emailVerifiedAt: Date | null;
|
|
6275
6372
|
phoneVerifiedAt: Date | null;
|
|
6276
6373
|
keyEpoch: number;
|
|
6374
|
+
sessionBinding: "none" | "passkey";
|
|
6375
|
+
sessionBindingChangedAt: Date | null;
|
|
6277
6376
|
lastLoginAt: Date | null;
|
|
6278
6377
|
}>;
|
|
6279
6378
|
/**
|
|
@@ -6302,6 +6401,8 @@ declare class UsersRepository extends BaseRepository {
|
|
|
6302
6401
|
emailVerifiedAt: Date | null;
|
|
6303
6402
|
phoneVerifiedAt: Date | null;
|
|
6304
6403
|
keyEpoch: number;
|
|
6404
|
+
sessionBinding: "none" | "passkey";
|
|
6405
|
+
sessionBindingChangedAt: Date | null;
|
|
6305
6406
|
lastLoginAt: Date | null;
|
|
6306
6407
|
}>;
|
|
6307
6408
|
/**
|
|
@@ -6325,6 +6426,8 @@ declare class UsersRepository extends BaseRepository {
|
|
|
6325
6426
|
emailVerifiedAt: Date | null;
|
|
6326
6427
|
phoneVerifiedAt: Date | null;
|
|
6327
6428
|
keyEpoch: number;
|
|
6429
|
+
sessionBinding: "none" | "passkey";
|
|
6430
|
+
sessionBindingChangedAt: Date | null;
|
|
6328
6431
|
lastLoginAt: Date | null;
|
|
6329
6432
|
}>;
|
|
6330
6433
|
/**
|
|
@@ -6348,6 +6451,8 @@ declare class UsersRepository extends BaseRepository {
|
|
|
6348
6451
|
emailVerifiedAt: Date | null;
|
|
6349
6452
|
phoneVerifiedAt: Date | null;
|
|
6350
6453
|
keyEpoch: number;
|
|
6454
|
+
sessionBinding: "none" | "passkey";
|
|
6455
|
+
sessionBindingChangedAt: Date | null;
|
|
6351
6456
|
lastLoginAt: Date | null;
|
|
6352
6457
|
}>;
|
|
6353
6458
|
/**
|
|
@@ -6357,6 +6462,7 @@ declare class UsersRepository extends BaseRepository {
|
|
|
6357
6462
|
deleteById(id: number): Promise<{
|
|
6358
6463
|
email: string | null;
|
|
6359
6464
|
phone: string | null;
|
|
6465
|
+
sessionBinding: "none" | "passkey";
|
|
6360
6466
|
status: "active" | "inactive" | "suspended" | "pending_deletion" | "deleted";
|
|
6361
6467
|
publicId: string;
|
|
6362
6468
|
passwordChangeRequired: boolean;
|
|
@@ -6369,6 +6475,7 @@ declare class UsersRepository extends BaseRepository {
|
|
|
6369
6475
|
emailVerifiedAt: Date | null;
|
|
6370
6476
|
phoneVerifiedAt: Date | null;
|
|
6371
6477
|
keyEpoch: number;
|
|
6478
|
+
sessionBindingChangedAt: Date | null;
|
|
6372
6479
|
lastLoginAt: Date | null;
|
|
6373
6480
|
deletedAt: Date | null;
|
|
6374
6481
|
deletedBy: string | null;
|
|
@@ -6472,6 +6579,11 @@ declare class KeysRepository extends BaseRepository {
|
|
|
6472
6579
|
platform: "ios" | "android" | "web" | "desktop" | null;
|
|
6473
6580
|
registeredIp: string | null;
|
|
6474
6581
|
registeredUserAgent: string | null;
|
|
6582
|
+
registeredUaFamily: string | null;
|
|
6583
|
+
lastSeenIp: string | null;
|
|
6584
|
+
lastSeenAt: Date | null;
|
|
6585
|
+
concurrentUseAt: Date | null;
|
|
6586
|
+
binding: "none" | "passkey";
|
|
6475
6587
|
clientKind: "ios" | "android" | "web" | null;
|
|
6476
6588
|
clientVersion: string | null;
|
|
6477
6589
|
clientContractVersion: string | null;
|
|
@@ -6498,6 +6610,11 @@ declare class KeysRepository extends BaseRepository {
|
|
|
6498
6610
|
platform: "ios" | "android" | "web" | "desktop" | null;
|
|
6499
6611
|
registeredIp: string | null;
|
|
6500
6612
|
registeredUserAgent: string | null;
|
|
6613
|
+
registeredUaFamily: string | null;
|
|
6614
|
+
lastSeenIp: string | null;
|
|
6615
|
+
lastSeenAt: Date | null;
|
|
6616
|
+
concurrentUseAt: Date | null;
|
|
6617
|
+
binding: "none" | "passkey";
|
|
6501
6618
|
clientKind: "ios" | "android" | "web" | null;
|
|
6502
6619
|
clientVersion: string | null;
|
|
6503
6620
|
clientContractVersion: string | null;
|
|
@@ -6524,6 +6641,11 @@ declare class KeysRepository extends BaseRepository {
|
|
|
6524
6641
|
platform: "ios" | "android" | "web" | "desktop" | null;
|
|
6525
6642
|
registeredIp: string | null;
|
|
6526
6643
|
registeredUserAgent: string | null;
|
|
6644
|
+
registeredUaFamily: string | null;
|
|
6645
|
+
lastSeenIp: string | null;
|
|
6646
|
+
lastSeenAt: Date | null;
|
|
6647
|
+
concurrentUseAt: Date | null;
|
|
6648
|
+
binding: "none" | "passkey";
|
|
6527
6649
|
clientKind: "ios" | "android" | "web" | null;
|
|
6528
6650
|
clientVersion: string | null;
|
|
6529
6651
|
clientContractVersion: string | null;
|
|
@@ -6543,6 +6665,10 @@ declare class KeysRepository extends BaseRepository {
|
|
|
6543
6665
|
*
|
|
6544
6666
|
* `includeRevoked`는 이미 끊은 기기까지 보여준다 — "내가 언제 무엇을 끊었나"를
|
|
6545
6667
|
* 확인하는 용도라, 폐기 시각과 사유를 함께 고른다.
|
|
6668
|
+
*
|
|
6669
|
+
* `lastSeenIp` is not selected, deliberately. The concurrent-use moment is
|
|
6670
|
+
* what the owner acts on; the trail of addresses behind it is stored PII the
|
|
6671
|
+
* account surface has no use for.
|
|
6546
6672
|
* Read replica 사용
|
|
6547
6673
|
*/
|
|
6548
6674
|
listForUser(userId: number, includeRevoked?: boolean): Promise<{
|
|
@@ -6558,6 +6684,8 @@ declare class KeysRepository extends BaseRepository {
|
|
|
6558
6684
|
revokedAt: Date | null;
|
|
6559
6685
|
registeredIp: string | null;
|
|
6560
6686
|
registeredUserAgent: string | null;
|
|
6687
|
+
binding: "none" | "passkey";
|
|
6688
|
+
concurrentUseAt: Date | null;
|
|
6561
6689
|
}[]>;
|
|
6562
6690
|
/**
|
|
6563
6691
|
* 공개키 생성
|
|
@@ -6579,6 +6707,11 @@ declare class KeysRepository extends BaseRepository {
|
|
|
6579
6707
|
lastUsedAt: Date | null;
|
|
6580
6708
|
registeredIp: string | null;
|
|
6581
6709
|
registeredUserAgent: string | null;
|
|
6710
|
+
registeredUaFamily: string | null;
|
|
6711
|
+
lastSeenIp: string | null;
|
|
6712
|
+
lastSeenAt: Date | null;
|
|
6713
|
+
concurrentUseAt: Date | null;
|
|
6714
|
+
binding: "none" | "passkey";
|
|
6582
6715
|
clientKind: "ios" | "android" | "web" | null;
|
|
6583
6716
|
clientVersion: string | null;
|
|
6584
6717
|
clientContractVersion: string | null;
|
|
@@ -6606,6 +6739,11 @@ declare class KeysRepository extends BaseRepository {
|
|
|
6606
6739
|
platform: "ios" | "android" | "web" | "desktop" | null;
|
|
6607
6740
|
registeredIp: string | null;
|
|
6608
6741
|
registeredUserAgent: string | null;
|
|
6742
|
+
registeredUaFamily: string | null;
|
|
6743
|
+
lastSeenIp: string | null;
|
|
6744
|
+
lastSeenAt: Date | null;
|
|
6745
|
+
concurrentUseAt: Date | null;
|
|
6746
|
+
binding: "none" | "passkey";
|
|
6609
6747
|
clientKind: "ios" | "android" | "web" | null;
|
|
6610
6748
|
clientVersion: string | null;
|
|
6611
6749
|
clientContractVersion: string | null;
|
|
@@ -6669,6 +6807,11 @@ declare class KeysRepository extends BaseRepository {
|
|
|
6669
6807
|
lastUsedAt: Date | null;
|
|
6670
6808
|
registeredIp: string | null;
|
|
6671
6809
|
registeredUserAgent: string | null;
|
|
6810
|
+
registeredUaFamily: string | null;
|
|
6811
|
+
lastSeenIp: string | null;
|
|
6812
|
+
lastSeenAt: Date | null;
|
|
6813
|
+
concurrentUseAt: Date | null;
|
|
6814
|
+
binding: "none" | "passkey";
|
|
6672
6815
|
clientKind: "ios" | "android" | "web" | null;
|
|
6673
6816
|
clientVersion: string | null;
|
|
6674
6817
|
clientContractVersion: string | null;
|
|
@@ -6698,6 +6841,11 @@ declare class KeysRepository extends BaseRepository {
|
|
|
6698
6841
|
platform: "ios" | "android" | "web" | "desktop" | null;
|
|
6699
6842
|
registeredIp: string | null;
|
|
6700
6843
|
registeredUserAgent: string | null;
|
|
6844
|
+
registeredUaFamily: string | null;
|
|
6845
|
+
lastSeenIp: string | null;
|
|
6846
|
+
lastSeenAt: Date | null;
|
|
6847
|
+
concurrentUseAt: Date | null;
|
|
6848
|
+
binding: "none" | "passkey";
|
|
6701
6849
|
clientKind: "ios" | "android" | "web" | null;
|
|
6702
6850
|
clientVersion: string | null;
|
|
6703
6851
|
clientContractVersion: string | null;
|
|
@@ -6724,6 +6872,46 @@ declare class KeysRepository extends BaseRepository {
|
|
|
6724
6872
|
platform: "ios" | "android" | "web" | "desktop" | null;
|
|
6725
6873
|
registeredIp: string | null;
|
|
6726
6874
|
registeredUserAgent: string | null;
|
|
6875
|
+
registeredUaFamily: string | null;
|
|
6876
|
+
lastSeenIp: string | null;
|
|
6877
|
+
lastSeenAt: Date | null;
|
|
6878
|
+
concurrentUseAt: Date | null;
|
|
6879
|
+
binding: "none" | "passkey";
|
|
6880
|
+
clientKind: "ios" | "android" | "web" | null;
|
|
6881
|
+
clientVersion: string | null;
|
|
6882
|
+
clientContractVersion: string | null;
|
|
6883
|
+
clientSeenAt: Date | null;
|
|
6884
|
+
isActive: boolean;
|
|
6885
|
+
createdAt: Date;
|
|
6886
|
+
lastUsedAt: Date | null;
|
|
6887
|
+
expiresAt: Date | null;
|
|
6888
|
+
revokedAt: Date | null;
|
|
6889
|
+
revokedReason: string | null;
|
|
6890
|
+
}>;
|
|
6891
|
+
/**
|
|
6892
|
+
* Bind one live key to the account's passkey, and give it the short life
|
|
6893
|
+
* that goes with it.
|
|
6894
|
+
*
|
|
6895
|
+
* Scoped by user and by `isActive`, like every other targeted update here, so
|
|
6896
|
+
* the answer is "this call bound something" rather than "a row exists".
|
|
6897
|
+
* Write primary 사용
|
|
6898
|
+
*/
|
|
6899
|
+
bindByKeyIdAndUserId(keyId: string, userId: number, expiresAt: Date): Promise<{
|
|
6900
|
+
id: number;
|
|
6901
|
+
userId: number;
|
|
6902
|
+
keyId: string;
|
|
6903
|
+
publicKey: string;
|
|
6904
|
+
algorithm: "ES256" | "RS256";
|
|
6905
|
+
fingerprint: string;
|
|
6906
|
+
deviceName: string | null;
|
|
6907
|
+
platform: "ios" | "android" | "web" | "desktop" | null;
|
|
6908
|
+
registeredIp: string | null;
|
|
6909
|
+
registeredUserAgent: string | null;
|
|
6910
|
+
registeredUaFamily: string | null;
|
|
6911
|
+
lastSeenIp: string | null;
|
|
6912
|
+
lastSeenAt: Date | null;
|
|
6913
|
+
concurrentUseAt: Date | null;
|
|
6914
|
+
binding: "none" | "passkey";
|
|
6727
6915
|
clientKind: "ios" | "android" | "web" | null;
|
|
6728
6916
|
clientVersion: string | null;
|
|
6729
6917
|
clientContractVersion: string | null;
|
|
@@ -6735,6 +6923,15 @@ declare class KeysRepository extends BaseRepository {
|
|
|
6735
6923
|
revokedAt: Date | null;
|
|
6736
6924
|
revokedReason: string | null;
|
|
6737
6925
|
}>;
|
|
6926
|
+
/**
|
|
6927
|
+
* Return every one of a user's bound keys to an ordinary long-lived key.
|
|
6928
|
+
*
|
|
6929
|
+
* One statement, because turning the setting off has to leave no key behind:
|
|
6930
|
+
* a row still marked `'passkey'` would keep expiring in hours with nothing
|
|
6931
|
+
* left to renew it, and its owner has just said they do not want that.
|
|
6932
|
+
* Write primary 사용
|
|
6933
|
+
*/
|
|
6934
|
+
unbindActiveByUserId(userId: number, expiresAt: Date): Promise<number>;
|
|
6738
6935
|
/**
|
|
6739
6936
|
* Key ID로 공개키 조회 — 활성 여부 무관 (clientProofV1 admission의 revocation 판정용)
|
|
6740
6937
|
*
|
|
@@ -6753,6 +6950,11 @@ declare class KeysRepository extends BaseRepository {
|
|
|
6753
6950
|
platform: "ios" | "android" | "web" | "desktop" | null;
|
|
6754
6951
|
registeredIp: string | null;
|
|
6755
6952
|
registeredUserAgent: string | null;
|
|
6953
|
+
registeredUaFamily: string | null;
|
|
6954
|
+
lastSeenIp: string | null;
|
|
6955
|
+
lastSeenAt: Date | null;
|
|
6956
|
+
concurrentUseAt: Date | null;
|
|
6957
|
+
binding: "none" | "passkey";
|
|
6756
6958
|
clientKind: "ios" | "android" | "web" | null;
|
|
6757
6959
|
clientVersion: string | null;
|
|
6758
6960
|
clientContractVersion: string | null;
|
|
@@ -6779,6 +6981,11 @@ declare class KeysRepository extends BaseRepository {
|
|
|
6779
6981
|
platform: "ios" | "android" | "web" | "desktop" | null;
|
|
6780
6982
|
registeredIp: string | null;
|
|
6781
6983
|
registeredUserAgent: string | null;
|
|
6984
|
+
registeredUaFamily: string | null;
|
|
6985
|
+
lastSeenIp: string | null;
|
|
6986
|
+
lastSeenAt: Date | null;
|
|
6987
|
+
concurrentUseAt: Date | null;
|
|
6988
|
+
binding: "none" | "passkey";
|
|
6782
6989
|
clientKind: "ios" | "android" | "web" | null;
|
|
6783
6990
|
clientVersion: string | null;
|
|
6784
6991
|
clientContractVersion: string | null;
|
|
@@ -6809,8 +7016,28 @@ declare class KeysRepository extends BaseRepository {
|
|
|
6809
7016
|
* `clientSeenAt` moves only when one of the three values differs from what is
|
|
6810
7017
|
* stored, so it answers "since when has this device been on this release"
|
|
6811
7018
|
* rather than "when was it last seen", which lastUsedAt already answers.
|
|
7019
|
+
*
|
|
7020
|
+
* `ip` is the client address this request resolved to, or null when none did.
|
|
7021
|
+
* It joins this statement rather than getting one of its own: the rule the
|
|
7022
|
+
* concurrent-use signal needs — write the address, and move
|
|
7023
|
+
* `concurrentUseAt` when it differs from the stored one inside the window —
|
|
7024
|
+
* is the rule already implemented here, and a second fire-and-forget write
|
|
7025
|
+
* beside it would double the per-request write on the authenticated path. It
|
|
7026
|
+
* is also why the comparison is a `CASE` over the stored value rather than a
|
|
7027
|
+
* read followed by a write: the row comes off the read replica, and a
|
|
7028
|
+
* replica-lagged address compared in application code both misses real
|
|
7029
|
+
* switches and invents ones that did not happen.
|
|
7030
|
+
*/
|
|
7031
|
+
updateLastUsedById(id: number, identity?: ClientIdentity | null, ip?: string | null): Promise<void>;
|
|
7032
|
+
/**
|
|
7033
|
+
* The boundary a previous sighting has to be newer than to count as concurrent.
|
|
7034
|
+
*
|
|
7035
|
+
* Computed here rather than written as `now() - interval` so that the moment
|
|
7036
|
+
* the row is stamped with and the moment the window is measured from are the
|
|
7037
|
+
* same one — a statement that used the database clock for the boundary and
|
|
7038
|
+
* ours for the value would disagree with itself by the round trip.
|
|
6812
7039
|
*/
|
|
6813
|
-
|
|
7040
|
+
private concurrentUseSince;
|
|
6814
7041
|
}
|
|
6815
7042
|
declare const keysRepository: KeysRepository;
|
|
6816
7043
|
|
|
@@ -7261,6 +7488,31 @@ declare class PasskeysRepository extends BaseRepository {
|
|
|
7261
7488
|
* @returns the updated row, or null if it is not theirs or already revoked
|
|
7262
7489
|
*/
|
|
7263
7490
|
revokeByIdAndUserId(id: number, userId: number, reason: string): Promise<Passkey | null>;
|
|
7491
|
+
/**
|
|
7492
|
+
* Mark or unmark a live credential as the owner's second factor.
|
|
7493
|
+
*
|
|
7494
|
+
* Owner-scoped and live-only, so somebody else's passkey and an already
|
|
7495
|
+
* revoked one are both "no such row" — the same answer every other
|
|
7496
|
+
* management statement here gives.
|
|
7497
|
+
*
|
|
7498
|
+
* @returns the updated row, or null if it is not theirs or already revoked
|
|
7499
|
+
*/
|
|
7500
|
+
markSecondFactorByIdAndUserId(id: number, userId: number, secondFactor: boolean): Promise<Passkey | null>;
|
|
7501
|
+
/**
|
|
7502
|
+
* The account's live credentials that satisfy a step-up.
|
|
7503
|
+
*
|
|
7504
|
+
* Used to check an assertion against the marked ones only: a passkey that
|
|
7505
|
+
* signs the owner in is not a second factor until they say it is.
|
|
7506
|
+
*/
|
|
7507
|
+
listLiveSecondFactorByUserId(userId: number): Promise<Passkey[]>;
|
|
7508
|
+
/**
|
|
7509
|
+
* Take the second-factor mark off every one of an account's credentials.
|
|
7510
|
+
*
|
|
7511
|
+
* What `mfa/disable` does to the passkey half of an enrolment. The
|
|
7512
|
+
* credentials themselves are untouched — they still sign the owner in.
|
|
7513
|
+
* Write primary.
|
|
7514
|
+
*/
|
|
7515
|
+
clearSecondFactorByUserId(userId: number): Promise<void>;
|
|
7264
7516
|
/**
|
|
7265
7517
|
* Delete every passkey of an account (account destruction).
|
|
7266
7518
|
* Write primary.
|
|
@@ -7313,6 +7565,158 @@ declare class WebAuthnChallengesRepository extends BaseRepository {
|
|
|
7313
7565
|
}
|
|
7314
7566
|
declare const webauthnChallengesRepository: WebAuthnChallengesRepository;
|
|
7315
7567
|
|
|
7568
|
+
/**
|
|
7569
|
+
* MFA TOTP Repository
|
|
7570
|
+
*
|
|
7571
|
+
* Data access for the one enrolment row an account may have. Extends
|
|
7572
|
+
* BaseRepository for transaction-context detection and read/write splitting.
|
|
7573
|
+
*
|
|
7574
|
+
* `secret_enc` is a ciphertext and is only ever moved through this layer as an
|
|
7575
|
+
* opaque string — nothing here decrypts, and nothing here logs a row.
|
|
7576
|
+
*/
|
|
7577
|
+
|
|
7578
|
+
declare class MfaTotpRepository extends BaseRepository {
|
|
7579
|
+
/** The account's enrolment row, confirmed or not. */
|
|
7580
|
+
findByUserId(userId: number): Promise<MfaTotp | null>;
|
|
7581
|
+
/**
|
|
7582
|
+
* Start an enrolment, replacing an unconfirmed one.
|
|
7583
|
+
*
|
|
7584
|
+
* Upsert rather than insert: calling `enroll` twice is the ordinary case —
|
|
7585
|
+
* a user closes the app before scanning — and the second call must hand out
|
|
7586
|
+
* a fresh secret rather than a 409. The failed-attempt counter resets with
|
|
7587
|
+
* it, which is what makes "start over" the documented remedy for a row that
|
|
7588
|
+
* spent its five tries.
|
|
7589
|
+
*
|
|
7590
|
+
* A **confirmed** row is refused by the service before this is reached, so
|
|
7591
|
+
* this can never overwrite a working second factor.
|
|
7592
|
+
*/
|
|
7593
|
+
startEnrolment(userId: number, secretEnc: string): Promise<MfaTotp>;
|
|
7594
|
+
/**
|
|
7595
|
+
* Mark the enrolment confirmed and record the step its first code spent.
|
|
7596
|
+
* Write primary.
|
|
7597
|
+
*/
|
|
7598
|
+
confirm(userId: number, step: number): Promise<void>;
|
|
7599
|
+
/** Record the newest step this account has spent, so it cannot be replayed. */
|
|
7600
|
+
recordUsedStep(userId: number, step: number): Promise<void>;
|
|
7601
|
+
/**
|
|
7602
|
+
* Count one wrong code against an unconfirmed row.
|
|
7603
|
+
*
|
|
7604
|
+
* @returns the count after this attempt
|
|
7605
|
+
*/
|
|
7606
|
+
countFailedConfirm(userId: number): Promise<number>;
|
|
7607
|
+
/** Rewrite the ciphertext in place, after a read on a retired key. */
|
|
7608
|
+
updateSecret(userId: number, secretEnc: string): Promise<void>;
|
|
7609
|
+
/** Drop the account's enrolment. Write primary. */
|
|
7610
|
+
deleteByUserId(userId: number): Promise<void>;
|
|
7611
|
+
/**
|
|
7612
|
+
* Drop enrolments nobody ever confirmed. The sweep job's statement.
|
|
7613
|
+
*
|
|
7614
|
+
* @returns number of rows deleted
|
|
7615
|
+
*/
|
|
7616
|
+
deleteUnconfirmedBefore(cutoff: Date): Promise<number>;
|
|
7617
|
+
}
|
|
7618
|
+
declare const mfaTotpRepository: MfaTotpRepository;
|
|
7619
|
+
|
|
7620
|
+
/**
|
|
7621
|
+
* MFA Recovery Codes Repository
|
|
7622
|
+
*
|
|
7623
|
+
* Data access for the ten single-use codes of an account's current generation.
|
|
7624
|
+
* Extends BaseRepository for transaction-context detection and read/write
|
|
7625
|
+
* splitting.
|
|
7626
|
+
*
|
|
7627
|
+
* Every read is scoped by `(user_id, generation)`. A code from an older
|
|
7628
|
+
* generation, or from another account, is not "not found" by accident — it is
|
|
7629
|
+
* outside every query this class can make.
|
|
7630
|
+
*/
|
|
7631
|
+
|
|
7632
|
+
declare class MfaRecoveryCodesRepository extends BaseRepository {
|
|
7633
|
+
/**
|
|
7634
|
+
* The account's newest generation, or 0 when it has never had codes.
|
|
7635
|
+
*
|
|
7636
|
+
* 0 rather than null so the caller's `+ 1` is the same expression on both
|
|
7637
|
+
* paths: a first enrolment writes generation 1.
|
|
7638
|
+
*/
|
|
7639
|
+
currentGeneration(userId: number): Promise<number>;
|
|
7640
|
+
/** Write one generation of codes. Write primary. */
|
|
7641
|
+
createGeneration(userId: number, generation: number, hashes: string[]): Promise<void>;
|
|
7642
|
+
/** The account's unspent codes of one generation. */
|
|
7643
|
+
listUnused(userId: number, generation: number): Promise<MfaRecoveryCode[]>;
|
|
7644
|
+
/** How many of a generation are left, for `status` and the "2 remaining" warning. */
|
|
7645
|
+
countUnused(userId: number, generation: number): Promise<number>;
|
|
7646
|
+
/**
|
|
7647
|
+
* Spend one code, if this call is the one that spends it.
|
|
7648
|
+
*
|
|
7649
|
+
* One conditional UPDATE, like the WebAuthn challenge consume and for the
|
|
7650
|
+
* same reason: two requests arriving with the same code must produce one
|
|
7651
|
+
* winner, not two, and a read-then-write would let both read it as unused.
|
|
7652
|
+
*
|
|
7653
|
+
* @returns true when this call spent the row
|
|
7654
|
+
*/
|
|
7655
|
+
consume(id: number): Promise<boolean>;
|
|
7656
|
+
/** Drop every generation the account has. Write primary. */
|
|
7657
|
+
deleteByUserId(userId: number): Promise<void>;
|
|
7658
|
+
}
|
|
7659
|
+
declare const mfaRecoveryCodesRepository: MfaRecoveryCodesRepository;
|
|
7660
|
+
|
|
7661
|
+
/**
|
|
7662
|
+
* MFA Verifications Repository
|
|
7663
|
+
*
|
|
7664
|
+
* Data access for "when did this device last prove the second factor". Extends
|
|
7665
|
+
* BaseRepository for transaction-context detection and read/write splitting.
|
|
7666
|
+
*
|
|
7667
|
+
* One row per device key, replaced rather than appended to: only the newest
|
|
7668
|
+
* verification decides anything, and a history of them would be a table that
|
|
7669
|
+
* grows with every step-up for no reader.
|
|
7670
|
+
*/
|
|
7671
|
+
|
|
7672
|
+
declare class MfaVerificationsRepository extends BaseRepository {
|
|
7673
|
+
/** When this device last stepped up, if it ever did. */
|
|
7674
|
+
findByKeyId(keyId: string): Promise<MfaVerification | null>;
|
|
7675
|
+
/** Record a fresh verification for this device, replacing any earlier one. */
|
|
7676
|
+
record(keyId: string, userId: number, method: MfaVerificationMethod): Promise<void>;
|
|
7677
|
+
/**
|
|
7678
|
+
* Carry a verification across a key rotation.
|
|
7679
|
+
*
|
|
7680
|
+
* Scoped by owner, so a caller naming somebody else's key moves nothing.
|
|
7681
|
+
* Nothing to move is not an error: a device that never stepped up rotates
|
|
7682
|
+
* exactly as it does today.
|
|
7683
|
+
*/
|
|
7684
|
+
moveToKeyId(userId: number, fromKeyId: string, toKeyId: string): Promise<void>;
|
|
7685
|
+
/** Forget every device's verification — what disabling the second factor means. */
|
|
7686
|
+
deleteByUserId(userId: number): Promise<void>;
|
|
7687
|
+
}
|
|
7688
|
+
declare const mfaVerificationsRepository: MfaVerificationsRepository;
|
|
7689
|
+
|
|
7690
|
+
/**
|
|
7691
|
+
* MFA Enrolment Repository
|
|
7692
|
+
*
|
|
7693
|
+
* One question, asked on every sensitive route and at every device
|
|
7694
|
+
* registration: does this account have a second factor at all?
|
|
7695
|
+
*
|
|
7696
|
+
* It spans two tables — a confirmed `mfa_totp` row, or at least one live passkey
|
|
7697
|
+
* the owner marked as a second factor — so it lives here rather than in either
|
|
7698
|
+
* table's repository, and it is deliberately **one** statement. `assertStepUp`
|
|
7699
|
+
* asks it first and returns immediately when the answer is no, so an account
|
|
7700
|
+
* that never enrolled pays one round trip against two indexed lookups
|
|
7701
|
+
* (`mfa_totp_user_id_idx`, unique, and `passkeys_user_id_idx`) and nothing else:
|
|
7702
|
+
* no second query, and no passkey configuration read.
|
|
7703
|
+
*
|
|
7704
|
+
* `UNION ALL ... LIMIT 1` rather than two `EXISTS` counts, so Postgres stops at
|
|
7705
|
+
* the first row either side produces. Both halves select `user_id` — a column
|
|
7706
|
+
* rather than a literal, so the two sides agree on a shape without a raw-SQL
|
|
7707
|
+
* alias, and the value is thrown away either way.
|
|
7708
|
+
*/
|
|
7709
|
+
|
|
7710
|
+
declare class MfaEnrolmentRepository extends BaseRepository {
|
|
7711
|
+
/** Whether the account has a confirmed TOTP or a live second-factor passkey. */
|
|
7712
|
+
isEnrolled(userId: number): Promise<boolean>;
|
|
7713
|
+
/** The other half of the union, as its own read for `status` to reuse. */
|
|
7714
|
+
private liveSecondFactorPasskeys;
|
|
7715
|
+
/** Whether at least one live passkey is marked as a second factor. */
|
|
7716
|
+
hasSecondFactorPasskey(userId: number): Promise<boolean>;
|
|
7717
|
+
}
|
|
7718
|
+
declare const mfaEnrolmentRepository: MfaEnrolmentRepository;
|
|
7719
|
+
|
|
7316
7720
|
/**
|
|
7317
7721
|
* Device Authorizations Repository
|
|
7318
7722
|
*
|
|
@@ -9153,6 +9557,31 @@ declare function verifyKeyFingerprint(publicKeyB64: string, expectedFingerprint:
|
|
|
9153
9557
|
*/
|
|
9154
9558
|
declare function assertKeyMatchesAlgorithm(publicKeyB64: string, algorithm: KeyAlgorithmType): void;
|
|
9155
9559
|
|
|
9560
|
+
/**
|
|
9561
|
+
* Whether a key may sign a renewal — the one clause that differs from `authenticate`.
|
|
9562
|
+
*
|
|
9563
|
+
* Bound, and within its grace. Early renewal is allowed, because a browser that
|
|
9564
|
+
* asks a minute before its key runs out should not have to wait for the failure
|
|
9565
|
+
* first; late renewal is allowed for the grace window, so a laptop closed over a
|
|
9566
|
+
* long weekend comes back to one prompt instead of a sign-in. Past it there is
|
|
9567
|
+
* nothing to continue, and an unbound key was never in this ceremony at all.
|
|
9568
|
+
*/
|
|
9569
|
+
declare function admitsForRenewal(key: UserPublicKey): boolean;
|
|
9570
|
+
/**
|
|
9571
|
+
* Renewal authentication middleware
|
|
9572
|
+
*
|
|
9573
|
+
* Auto-skips the global `auth` middleware, the way `optionalAuth` does: a route
|
|
9574
|
+
* that carries this one must not also be asked for a live key.
|
|
9575
|
+
*
|
|
9576
|
+
* @example
|
|
9577
|
+
* ```typescript
|
|
9578
|
+
* export const sessionRenewOptions = route.post('/_auth/session/renew/options')
|
|
9579
|
+
* .use([authenticateForRenewal])
|
|
9580
|
+
* .handler(async (c) => startSessionRenewService({ expiredKeyId: getAuth(c).keyId }));
|
|
9581
|
+
* ```
|
|
9582
|
+
*/
|
|
9583
|
+
declare const authenticateForRenewal: _spfn_core_route.NamedMiddleware<"authForRenewal">;
|
|
9584
|
+
|
|
9156
9585
|
/**
|
|
9157
9586
|
* @spfn/auth - Permission Middleware
|
|
9158
9587
|
*
|
|
@@ -9497,6 +9926,7 @@ declare function getUser(c: Context | {
|
|
|
9497
9926
|
}): {
|
|
9498
9927
|
email: string | null;
|
|
9499
9928
|
phone: string | null;
|
|
9929
|
+
sessionBinding: "none" | "passkey";
|
|
9500
9930
|
status: "active" | "inactive" | "suspended" | "pending_deletion" | "deleted";
|
|
9501
9931
|
publicId: string;
|
|
9502
9932
|
passwordChangeRequired: boolean;
|
|
@@ -9509,6 +9939,7 @@ declare function getUser(c: Context | {
|
|
|
9509
9939
|
emailVerifiedAt: Date | null;
|
|
9510
9940
|
phoneVerifiedAt: Date | null;
|
|
9511
9941
|
keyEpoch: number;
|
|
9942
|
+
sessionBindingChangedAt: Date | null;
|
|
9512
9943
|
lastLoginAt: Date | null;
|
|
9513
9944
|
deletedAt: Date | null;
|
|
9514
9945
|
deletedBy: string | null;
|
|
@@ -10439,8 +10870,8 @@ declare const linkMailJob: _spfn_core_job.JobDef<{
|
|
|
10439
10870
|
|
|
10440
10871
|
/**
|
|
10441
10872
|
* Build the auth job router: the account-deletion purge sweep, the OAuth 2.1
|
|
10442
|
-
* stale-client sweep, the sign-out-everywhere link sweep,
|
|
10443
|
-
* sender.
|
|
10873
|
+
* stale-client sweep, the sign-out-everywhere link sweep, the abandoned
|
|
10874
|
+
* second-factor enrolment sweep, and the link-mail sender.
|
|
10444
10875
|
*
|
|
10445
10876
|
* The cron is a parameter because `job(...).cron(expression)` bakes the string in
|
|
10446
10877
|
* at module-import time, which always happens before `createAuthLifecycle()` runs
|
|
@@ -10451,15 +10882,18 @@ declare const linkMailJob: _spfn_core_job.JobDef<{
|
|
|
10451
10882
|
* @param options.purgeCron - Deletion purge schedule; defaults to daily at 04:00
|
|
10452
10883
|
* @param options.oauth2ClientPurgeCron - Stale OAuth client sweep; defaults to daily at 05:00
|
|
10453
10884
|
* @param options.revokeAllTokenPurgeCron - Sign-out-everywhere link sweep; defaults to daily at 06:00
|
|
10885
|
+
* @param options.mfaSweepCron - Abandoned second-factor enrolment sweep; defaults to daily at 07:00
|
|
10454
10886
|
*/
|
|
10455
10887
|
declare function createAuthJobRouter(options?: {
|
|
10456
10888
|
purgeCron?: string;
|
|
10457
10889
|
oauth2ClientPurgeCron?: string;
|
|
10458
10890
|
revokeAllTokenPurgeCron?: string;
|
|
10891
|
+
mfaSweepCron?: string;
|
|
10459
10892
|
}): _spfn_core_job.JobRouter<{
|
|
10460
10893
|
deletionPurge: _spfn_core_job.JobDef<void, void>;
|
|
10461
10894
|
oauth2ClientPurge: _spfn_core_job.JobDef<void, void>;
|
|
10462
10895
|
revokeAllTokenPurge: _spfn_core_job.JobDef<void, void>;
|
|
10896
|
+
mfaSweep: _spfn_core_job.JobDef<void, void>;
|
|
10463
10897
|
linkMail: _spfn_core_job.JobDef<{
|
|
10464
10898
|
kind: "signup-link";
|
|
10465
10899
|
rowId: number;
|
|
@@ -10480,6 +10914,7 @@ declare const authJobRouter: _spfn_core_job.JobRouter<{
|
|
|
10480
10914
|
deletionPurge: _spfn_core_job.JobDef<void, void>;
|
|
10481
10915
|
oauth2ClientPurge: _spfn_core_job.JobDef<void, void>;
|
|
10482
10916
|
revokeAllTokenPurge: _spfn_core_job.JobDef<void, void>;
|
|
10917
|
+
mfaSweep: _spfn_core_job.JobDef<void, void>;
|
|
10483
10918
|
linkMail: _spfn_core_job.JobDef<{
|
|
10484
10919
|
kind: "signup-link";
|
|
10485
10920
|
rowId: number;
|
|
@@ -10499,4 +10934,4 @@ declare const authJobRouter: _spfn_core_job.JobRouter<{
|
|
|
10499
10934
|
*/
|
|
10500
10935
|
declare const createAuthDeletionJobRouter: typeof createAuthJobRouter;
|
|
10501
10936
|
|
|
10502
|
-
export { AUTHORIZE_PATH, type AccountDeletionPurgeUser, type AccountDeletionRequest, AccountDeletionRequestedBy, AccountDeletionRequestsRepository, type AuthConfig, AuthContext, type AuthCsrfConfig, type AuthDeletionConfig, type AuthDeviceAuthConfig, type AuthLifecycleConfig, type AuthLifecycleOptions, type AuthMetadataEntity, AuthMetadataRepository, type AuthorizationServerConfig, type AuthorizationServerOptions, type BeforeRegisterContext, COOKIE_NAMES, CSRF_HEADER, type CancelAccountDeletionParams, type CancelAccountDeletionResult, type CreateOAuthStateParams, type CreateRevokeAllLinkOptions, type CsrfMode, DEFAULT_ACCESS_TOKEN_TTL_MS, DEFAULT_CODE_TTL_MS, DEFAULT_DELETION_ALLOW_SELF_IMMEDIATE, DEFAULT_DELETION_GRACE_PERIOD_DAYS, DEFAULT_DELETION_PURGE_CRON, DEFAULT_DELETION_PURGE_STRATEGY, DEFAULT_DELETION_SEND_NOTIFICATIONS, DEFAULT_DEVICE_AUTH_INTERVAL_MS, DEFAULT_DEVICE_AUTH_TTL_MS, DEFAULT_REFRESH_TOKEN_TTL_MS, DEFAULT_REVOKE_ALL_TOKEN_PURGE_CRON, DEVICE_AUTH_STATUSES, type DecryptedOAuthToken, type DeviceAuthStatus, type DeviceAuthorization, DeviceAuthorizationsRepository, type EmailNormalizationResult, EnvironmentKeyringTokenCipher, type GoogleTokenResponse, type GoogleUserInfo, type Invitation, InvitationStatus, InvitationsRepository, type IssuedOpsToken, KeyAlgorithmType, type KeyRevokeAllToken, KeyRevokeAllTokensRepository, KeysRepository, type LiveRevokeAllLink, MAX_UNGRANTED_CLIENTS_PER_IP, type NewAccountDeletionRequest, type NewAuthMetadataEntity, type NewDeviceAuthorization, type NewInvitation, type NewKeyRevokeAllToken, type NewOAuth2AuthorizationCode, type NewOAuth2Client, type NewOAuth2Grant, type NewOAuth2Token, type NewOpsToken, NewPasskey, type NewPasswordResetToken, type NewPermission, type NewPermissionEntity, type NewRole, type NewRoleEntity, type NewRolePermission, type NewSignupLinkToken, type NewUser, type NewUserPermission, type NewUserProfile,
|
|
10937
|
+
export { AUTHORIZE_PATH, type AccountDeletionPurgeUser, type AccountDeletionRequest, AccountDeletionRequestedBy, AccountDeletionRequestsRepository, type AuthConfig, AuthContext, type AuthCsrfConfig, type AuthDeletionConfig, type AuthDeviceAuthConfig, type AuthLifecycleConfig, type AuthLifecycleOptions, type AuthMetadataEntity, AuthMetadataRepository, type AuthorizationServerConfig, type AuthorizationServerOptions, type BeforeRegisterContext, COOKIE_NAMES, CSRF_HEADER, type CancelAccountDeletionParams, type CancelAccountDeletionResult, type CreateOAuthStateParams, type CreateRevokeAllLinkOptions, type CsrfMode, DEFAULT_ACCESS_TOKEN_TTL_MS, DEFAULT_CODE_TTL_MS, DEFAULT_DELETION_ALLOW_SELF_IMMEDIATE, DEFAULT_DELETION_GRACE_PERIOD_DAYS, DEFAULT_DELETION_PURGE_CRON, DEFAULT_DELETION_PURGE_STRATEGY, DEFAULT_DELETION_SEND_NOTIFICATIONS, DEFAULT_DEVICE_AUTH_INTERVAL_MS, DEFAULT_DEVICE_AUTH_TTL_MS, DEFAULT_REFRESH_TOKEN_TTL_MS, DEFAULT_REVOKE_ALL_TOKEN_PURGE_CRON, DEVICE_AUTH_STATUSES, type DecryptedOAuthToken, type DeviceAuthStatus, type DeviceAuthorization, DeviceAuthorizationsRepository, type EmailNormalizationResult, EnvironmentKeyringTokenCipher, type GoogleTokenResponse, type GoogleUserInfo, type Invitation, InvitationStatus, InvitationsRepository, type IssuedOpsToken, KeyAlgorithmType, type KeyRevokeAllToken, KeyRevokeAllTokensRepository, KeysRepository, type LiveRevokeAllLink, MAX_UNGRANTED_CLIENTS_PER_IP, MFA_CONFIRM_ATTEMPT_LIMIT, type MfaConfig, MfaEnrolmentRepository, type MfaRecoveryCode, MfaRecoveryCodesRepository, type MfaTotp, MfaTotpRepository, MfaVerification, MfaVerificationMethod, MfaVerificationsRepository, type NewAccountDeletionRequest, type NewAuthMetadataEntity, type NewDeviceAuthorization, type NewInvitation, type NewKeyRevokeAllToken, type NewMfaRecoveryCode, type NewMfaTotp, type NewOAuth2AuthorizationCode, type NewOAuth2Client, type NewOAuth2Grant, type NewOAuth2Token, type NewOpsToken, NewPasskey, type NewPasswordResetToken, type NewPermission, type NewPermissionEntity, type NewRole, type NewRoleEntity, type NewRolePermission, type NewSignupLinkToken, type NewUser, type NewUserPermission, type NewUserProfile, NewUserPublicKey, type NewUserSocialAccount, type NewVerificationCode, type NewWebAuthnChallenge, OAUTH2_ACCESS_TOKEN_PREFIX, OAUTH2_REFRESH_TOKEN_PREFIX, OAUTH2_TOKEN_KINDS, type OAuth2AuthorizationCode, OAuth2AuthorizationCodesRepository, type OAuth2Client, OAuth2ClientsRepository, type OAuth2Grant, type OAuth2GrantWithClient, OAuth2GrantsRepository, type OAuth2RegisterRefusal, type OAuth2RegisterRequest, type OAuth2RegisterResult, type OAuth2RegisteredClient, type OAuth2Token, type OAuth2TokenKind, type OAuth2TokenRefusal, type OAuth2TokenRequest, type OAuth2TokenResponse, type OAuth2TokenResult, OAuth2TokensRepository, OAuthProvider, type OAuthState, type OAuthTokenCipher, type OAuthTokenContext, type OAuthTokenType, OPS_TOKEN_PREFIX, type OpsOrUserConfig, type OpsToken, OpsTokensRepository, Passkey, type PasskeyConfig, type PasskeyUserVerification, PasskeysRepository, type PasswordResetToken, PasswordResetTokensRepository, type PendingDeletionInfo, type Permission, type PermissionEntity, PermissionsRepository, PurgeStrategy, type PurgeUserResult, type RedirectUriRefusal, type RegisterChannel, type RequestAccountDeletionParams, type RequestAccountDeletionResult, type RevokeAllLink, type RevokeAllLinkDescription, type RevokedKey, type Role, type RoleEntity, type RoleGuardOptions, type RolePermission, RolePermissionsRepository, RolesRepository, STALE_CLIENT_MAX_AGE_MS, SUPPORTED_GRANT_TYPES, SUPPORTED_RESPONSE_TYPES, type SessionPayload, type SignupLinkToken, SignupLinkTokensRepository, SocialAccountsRepository, SocialProvider, type SweepDuePurgesResult, type TokenEncryptionKey, type TokenPayload, USER_CODE_ALPHABET, USER_CODE_LENGTH, type UpdateProfileParams, type User, type UserPermission, UserPermissionsRepository, type UserProfile, UserProfilesRepository, UserPublicKey, type UserSocialAccount, UsersRepository, V2_PREFIX, type VerificationCode, VerificationCodesRepository, VerificationPurpose, type VerifiedOAuth2AccessToken, type VerifiedOpsToken, type VerifyIdTokenParams, WEBAUTHN_CHALLENGE_KINDS, type WebAuthnChallenge, type WebAuthnChallengeKind, WebAuthnChallengesRepository, acceptInvitation, accountDeletionRequests, accountDeletionRequestsRepository, addPermissionToRole, admitsForRenewal, appleProvider, assertAuthorizationServerIssuer, assertCanAssignRole, assertKeyMatchesAlgorithm, assertPasskeyConfig, authJobRouter, authLogger, authMetadata, authMetadataRepository, authSchema, authenticateForRenewal, cancelAccountDeletionService, cancelInvitation, checkUsernameAvailableService, configureAuth, configureAuthorizationServer, configureDeletion, configureDeviceAuth, configureOAuthTokenCipher, consumeRevokeAllLink, createAuthDeletionJobRouter, createAuthDeletionPurgeJob, createAuthJobRouter, createAuthLifecycle, createInvitation, createOAuthState, createRevokeAllLink, createRevokeAllTokenPurgeJob, createRole, decodeToken, decryptToken, deleteInvitation, deleteRole, deriveCsrfToken, describeRevokeAllLink, deviceAuthorizations, deviceAuthorizationsRepository, encryptToken, exchangeCodeForTokens, expireOldInvitations, formatUserCode, generateAccessToken, generateAuthorizationCode, generateDeviceCode, generateOAuthNonce, generateRefreshToken, generateToken, generateUserCode, getAllRoles, getAuth, getAuthConfig, getAuthSessionService, getAuthorizationServerConfig, getBoundKeyRenewGraceMs, getBoundKeyTtlMs, getConcurrentUseWindowMs, getCsrfExemptPaths, getCsrfMode, getDeletionConfig, getDeviceAuthConfig, getDummyPasswordHash, getEncryptionKeyring, getGoogleAuthUrl, getGoogleOAuthConfig, getGoogleUserInfo, getInvitationByToken, getInvitationWithDetails, getKeyId, getLocale, getMfaConfig, getOneTimeTokenManager, getOpsToken, getOptionalAuth, getPasskeyConfig, getPendingDeletionInfo, getRole, getRoleByName, getRolePermissions, getSessionRenewPath, getSessionTtl, getUser, getUserByEmailService, getUserByIdService, getUserByPhoneService, getUserId, getUserPermissions, getUserProfileService, getUserRole, githubProvider, googleProvider, hasAllPermissions, hasAnyPermission, hasAnyRole, hasPermission, hasRole, hashDeviceCode, hashOAuth2Secret, hashPassword, initOneTimeTokenManager, initializeAuth, invitationsRepository, isAccessTokenShaped, isEncrypted, isGoogleOAuthEnabled, isLoopbackHostname, isOpsToken, isPkceS256ChallengeShaped, isPkceVerifierShaped, issueOpsTokenService, kakaoProvider, keyRevokeAllTokens, keyRevokeAllTokensRepository, keysRepository, linkMailJob, listInvitations, listOpsTokensService, matchOAuthCsrfCookies, matchesCsrfToken, matchesRegisteredRedirectUri, mfaEnrolmentRepository, mfaRecoveryCodes, mfaRecoveryCodesRepository, mfaTotp, mfaTotpRepository, mfaVerificationsRepository, naverProvider, normalizeEmail, normalizeOptionalEmail, normalizeResource, normalizeStoredEmails, normalizeUserCode, oauth2AuthorizationCodes, oauth2AuthorizationCodesRepository, oauth2Clients, oauth2ClientsRepository, oauth2Grants, oauth2GrantsRepository, oauth2TokenService, oauth2Tokens, oauth2TokensRepository, oneTimeTokenAuth, opsOrUser, opsTokenAuth, opsTokens, opsTokensRepository, parseDuration, passkeysRepository, passwordResetTokens, passwordResetTokensRepository, permissions, permissionsRepository, pkceChallengeFor, purgeRevokeAllTokensService, purgeStaleOAuth2ClientsService, purgeUserService, redirectHostOf, refreshAccessToken, refuseRedirectUriRegistration, registerOAuth2ClientService, removePermissionFromRole, requestAccountDeletionService, requireAnyPermission, requireOpsScope, requirePermissions, requireRole, resendInvitation, resolveIssuerSource, revokeOAuth2TokenService, revokeOpsTokenService, roleGuard, rolePermissions, rolePermissionsRepository, roles, rolesRepository, runBeforeRegister, sameOAuth2Hash, sameResource, secondsUntil, setRolePermissions, signupLinkTokens, signupLinkTokensRepository, socialAccountsRepository, sweepDuePurges, toEpochSeconds, updateLastLoginService, updateLocaleService, updateRole, updateUserProfileService, updateUserService, updateUsernameService, userInvitations, userPermissions, userPermissionsRepository, userProfiles, userProfilesRepository, userSocialAccounts, users, usersRepository, validateInvitation, validatePasswordStrength, verificationCodes, verificationCodesRepository, verifyAccessToken, verifyClientToken, verifyIdToken, verifyKeyFingerprint, verifyOAuthState, verifyOpsTokenService, verifyPassword, verifyToken, webauthnChallenges, webauthnChallengesRepository };
|