@spfn/auth 0.3.0-beta.25 → 0.3.0-beta.27
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 +49 -7
- package/dist/client-proof.js +3 -2
- package/dist/client-proof.js.map +1 -1
- package/dist/index.d.ts +194 -189
- package/dist/index.js +40 -40
- package/dist/index.js.map +1 -1
- package/dist/{machine-principals-CdEgxOB1.d.ts → machine-principals-BvRw8b8t.d.ts} +18 -0
- package/dist/nextjs/api.js +16 -13
- package/dist/nextjs/api.js.map +1 -1
- package/dist/server.d.ts +37 -4
- package/dist/server.js +210 -33
- package/dist/server.js.map +1 -1
- package/package.json +1 -1
package/dist/server.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { A as AuthInitOptions, z as OAuthProvider, N as NewUserPublicKey, x as VerificationPurpose, B as NewPasskey, E as Passkey, G as MfaVerification, H as MfaVerificationMethod, J as NewMfaChallenge, Q as MfaChallenge, u as PermissionCategory, W as UserPublicKey, X as AuthContext } from './machine-principals-
|
|
2
|
-
export { Y as ApproveDeviceAuthParams, Z as AssertStepUpParams, _ as AuthDeletionCancelledPayload, $ as AuthDeletionCompletedPayload, a0 as AuthDeletionRequestedPayload, a1 as AuthDeviceRegisteredPayload, a2 as AuthLoginPayload, a3 as AuthPasswordResetPayload, a4 as AuthProfileOutcome, a5 as AuthProfileVerifier, a6 as AuthProviderSchema, a7 as AuthRegisterPayload, a8 as BearerOutcome, a9 as BearerRefusal, aa as ChangePasswordParams, ab as CompletePasswordResetParams, ac as CompleteSignupParams, ad as ConfirmPasswordResetParams, d as ConfirmPasswordResetResult, ae as ConfirmSignupLinkParams, C as ConfirmSignupLinkResult, af as ConfirmTotpParams, g as ConfirmTotpResult, ag as DeferredLoginEvent, ah as DenyDeviceAuthParams, ai as DeviceAuthApprovedResult, aj as DeviceAuthInfoParams, D as DeviceAuthInfoResult, ak as DeviceAuthPendingResult, al as DeviceAuthPollResponseSchema, am as DeviceNameSchema, an as DeviceRegistrationChannel, ao as DisableSessionBindingParams, ap as EmailSchema, aq as FingerprintSchema, ar as FinishPasskeyEnrollmentParams, F as FinishPasskeyEnrollmentResult, as as FinishPasskeyLoginParams, at as FinishSessionRenewParams, au as InvitationAcceptedPayload, av as InvitationCreatedPayload, I as IssueOneTimeTokenResult, aw as KEY_FINGERPRINT_PREFIX_LENGTH, ax as KeyIdSchema, K as KeySummary, ay as LoginParams, L as LoginResult, az as LogoutParams, aA as MFA_CHALLENGE_ATTEMPT_LIMIT, aB as MFA_CHALLENGE_CHANNELS, aC as MFA_VERIFICATION_METHODS, aD as MachinePrincipal, aE as MachineVerifierRegistration, aF as MarkPasskeyParams, aG as MfaChallengeChannel, aH as MfaChallengeHandle, M as MfaStatus, aI as NativeVerifyOptions, aJ as NewMfaVerification, aK as NormalizedIdentity, q as OAuth2AuthorizationCodeIssued, aL as OAuth2AuthorizeParams, p as OAuth2ConsentView, r as OAuth2GrantSummary, aM as OAuth2ScopeDescription, aN as OAuthCallbackParams, aO as OAuthCallbackResult, aP as OAuthCodeExchangeOptions, aQ as OAuthNativeParams, n as OAuthNativeResult, aR as OAuthStartParams, O as OAuthStartResult, aS as OAuthTokens, aT as OAuthUnlinkedPayload, aU as OpenStepUpChallengeParams, aV as PASSKEY_DEVICE_TYPES, aW as PASSKEY_LABEL_MAX_LENGTH, aX as PasskeyDeviceType, f as PasskeySummary, aY as PasswordSchema, aZ as PhoneSchema, a_ as PlatformSchema, a$ as PollDeviceAuthParams, b0 as PollDeviceAuthResult, b1 as PublicKeySchema, b2 as RecentAuthenticationParams, b3 as RegisterParams, b4 as RegisterPublicKeyParams, b5 as RegisterPublicKeyResult, a as RegisterResult, b6 as RenamePasskeyParams, b7 as RequestPasswordResetParams, c as RequestPasswordResetResult, b8 as RequestSignupLinkParams, b as RequestSignupLinkResult, b9 as RevokeAllKeysParams, i as RevokeAllKeysResult, ba as RevokeKeyParams, bb as RevokePasskeyParams, bc as RotateKeyParams, h as RotateKeyResult, bd as SendVerificationCodeParams, S as SendVerificationCodeResult, be as SessionBindingParams, j as SessionBindingResult, bf as StartDeviceAuthParams, e as StartDeviceAuthResult, bg as StartPasskeyEnrollmentParams, bh as StartSessionRenewParams, bi as StepUpParams, bj as TargetTypeSchema, T as TotpEnrolmentResult, bk as UnlinkNotification, bl as UnlinkNotifyRejection, bm as UnlinkNotifyRequest, bn as UnlinkNotifyResult, bo as UserCodeSchema, v as VERIFICATION_PURPOSES, w as VERIFICATION_TARGET_TYPES, bp as VerificationPurposeSchema, y as VerificationTargetType, bq as VerifyCodeParams, br as VerifyCodeResult, bs as VerifyMfaChallengeParams, V as VerifyMfaChallengeResult, bt as admitBearerKey, bu as approveDeviceAuthService, bv as approveOAuth2AuthorizeService, bw as assertNotLastRecoveryCredential, bx as assertRecentAuthentication, by as assertStepUp, bz as attemptSecondFactor, bA as authDeletionCancelledEvent, bB as authDeletionCompletedEvent, bC as authDeletionRequestedEvent, bD as authDeviceRegisteredEvent, bE as authLoginEvent, bF as authPasswordResetEvent, bG as authRegisterEvent, m as authRouter, bH as authenticate, bI as bearerAuthContext, bJ as buildOAuthErrorUrl, bK as carryStepUpVerification, bL as changePasswordService, bM as completePasswordResetService, bN as completeSignupService, bO as confirmPasswordResetService, bP as confirmSignupLinkService, bQ as confirmTotpEnrolmentService, bR as denyDeviceAuthService, bS as denyOAuth2AuthorizeService, bT as describeOAuth2AuthorizeRequestService, bU as disableMfaService, bV as disableSessionBindingService, bW as enableSessionBindingService, bX as finishPasskeyEnrollmentService, bY as finishPasskeyLoginService, bZ as finishSessionRenewService, b_ as getDeviceAuthInfoService, b$ as getEnabledOAuthProviders, c0 as getGoogleAccessToken, c1 as getMachinePrincipal, c2 as getOAuthProvider, c3 as getRegisteredProviders, c4 as getSessionBindingService, c5 as invitationAcceptedEvent, c6 as invitationCreatedEvent, c7 as isOAuthProviderEnabled, c8 as issueOneTimeTokenService, c9 as keySessionBindingService, ca as listKeysService, cb as listOAuth2GrantsService, cc as listPasskeysService, cd as loginService, ce as logoutService, cf as machineAuth, cg as markPasskeySecondFactorService, ch as mfaChallenges, ci as mfaEnrolledForUser, cj as mfaStatusService, ck as mfaVerifications, cl as oauthCallbackService, cm as oauthNativeService, cn as oauthStartService, co as oauthUnlinkNotifyService, cp as oauthUnlinkedEvent, cq as openStepUpChallengeService, cr as optionalAuth, cs as passkeys, ct as pollDeviceAuthService, cu as regenerateRecoveryCodesService, cv as registerAuthProfile, cw as registerMachineVerifier, cx as registerOAuthProvider, cy as registerPublicKeyService, cz as registerService, cA as registeredBinding, cB as renamePasskeyService, cC as requestPasswordResetService, cD as requestSignupLinkService, cE as requireEnabledProvider, cF as requireMachineScope, cG as resolveAuthenticatedUser, cH as resumeStepUpChallengeService, cI as revokeAllKeysService, cJ as revokeAllOAuth2GrantsForUser, cK as revokeKeyService, cL as revokeOAuth2GrantService, cM as revokePasskeyService, cN as rotateKeyService, cO as runAuthProfile, cP as selectAuthProfile, cQ as sendVerificationCodeService, cR as startDeviceAuthService, cS as startMfaChallengeAssertionService, cT as startPasskeyEnrollmentService, cU as startPasskeyLoginService, cV as startSessionBindingDisableService, cW as startSessionRenewService, cX as startStepUpService, cY as startTotpEnrolmentService, cZ as stepUpService, c_ as sweepMfaChallengesService, c$ as sweepUnconfirmedMfaService, d0 as userPublicKeys, d1 as verifyCodeService, d2 as verifyMfaChallengeService, d3 as verifyOneTimeTokenService, d4 as verifySecondFactor } from './machine-principals-
|
|
1
|
+
import { A as AuthInitOptions, z as OAuthProvider, N as NewUserPublicKey, x as VerificationPurpose, B as NewPasskey, E as Passkey, G as MfaVerification, H as MfaVerificationMethod, J as NewMfaChallenge, Q as MfaChallenge, u as PermissionCategory, W as UserPublicKey, X as AuthContext } from './machine-principals-BvRw8b8t.js';
|
|
2
|
+
export { Y as ApproveDeviceAuthParams, Z as AssertStepUpParams, _ as AuthDeletionCancelledPayload, $ as AuthDeletionCompletedPayload, a0 as AuthDeletionRequestedPayload, a1 as AuthDeviceRegisteredPayload, a2 as AuthLoginPayload, a3 as AuthPasswordResetPayload, a4 as AuthProfileOutcome, a5 as AuthProfileVerifier, a6 as AuthProviderSchema, a7 as AuthRegisterPayload, a8 as BearerOutcome, a9 as BearerRefusal, aa as ChangePasswordParams, ab as CompletePasswordResetParams, ac as CompleteSignupParams, ad as ConfirmPasswordResetParams, d as ConfirmPasswordResetResult, ae as ConfirmSignupLinkParams, C as ConfirmSignupLinkResult, af as ConfirmTotpParams, g as ConfirmTotpResult, ag as DeferredLoginEvent, ah as DenyDeviceAuthParams, ai as DeviceAuthApprovedResult, aj as DeviceAuthInfoParams, D as DeviceAuthInfoResult, ak as DeviceAuthPendingResult, al as DeviceAuthPollResponseSchema, am as DeviceNameSchema, an as DeviceRegistrationChannel, ao as DisableSessionBindingParams, ap as EmailSchema, aq as FingerprintSchema, ar as FinishPasskeyEnrollmentParams, F as FinishPasskeyEnrollmentResult, as as FinishPasskeyLoginParams, at as FinishSessionRenewParams, au as InvitationAcceptedPayload, av as InvitationCreatedPayload, I as IssueOneTimeTokenResult, aw as KEY_FINGERPRINT_PREFIX_LENGTH, ax as KeyIdSchema, K as KeySummary, ay as LoginParams, L as LoginResult, az as LogoutParams, aA as MFA_CHALLENGE_ATTEMPT_LIMIT, aB as MFA_CHALLENGE_CHANNELS, aC as MFA_VERIFICATION_METHODS, aD as MachinePrincipal, aE as MachineVerifierRegistration, aF as MarkPasskeyParams, aG as MfaChallengeChannel, aH as MfaChallengeHandle, M as MfaStatus, aI as NativeVerifyOptions, aJ as NewMfaVerification, aK as NormalizedIdentity, q as OAuth2AuthorizationCodeIssued, aL as OAuth2AuthorizeParams, p as OAuth2ConsentView, r as OAuth2GrantSummary, aM as OAuth2ScopeDescription, aN as OAuthCallbackParams, aO as OAuthCallbackResult, aP as OAuthCodeExchangeOptions, aQ as OAuthNativeParams, n as OAuthNativeResult, aR as OAuthStartParams, O as OAuthStartResult, aS as OAuthTokens, aT as OAuthUnlinkedPayload, aU as OpenStepUpChallengeParams, aV as PASSKEY_DEVICE_TYPES, aW as PASSKEY_LABEL_MAX_LENGTH, aX as PasskeyDeviceType, f as PasskeySummary, aY as PasswordSchema, aZ as PhoneSchema, a_ as PlatformSchema, a$ as PollDeviceAuthParams, b0 as PollDeviceAuthResult, b1 as PublicKeySchema, b2 as RecentAuthenticationParams, b3 as RegisterParams, b4 as RegisterPublicKeyParams, b5 as RegisterPublicKeyResult, a as RegisterResult, b6 as RenamePasskeyParams, b7 as RequestPasswordResetParams, c as RequestPasswordResetResult, b8 as RequestSignupLinkParams, b as RequestSignupLinkResult, b9 as RevokeAllKeysParams, i as RevokeAllKeysResult, ba as RevokeKeyParams, bb as RevokePasskeyParams, bc as RotateKeyParams, h as RotateKeyResult, bd as SendVerificationCodeParams, S as SendVerificationCodeResult, be as SessionBindingParams, j as SessionBindingResult, bf as StartDeviceAuthParams, e as StartDeviceAuthResult, bg as StartPasskeyEnrollmentParams, bh as StartSessionRenewParams, bi as StepUpParams, bj as TargetTypeSchema, T as TotpEnrolmentResult, bk as UnlinkNotification, bl as UnlinkNotifyRejection, bm as UnlinkNotifyRequest, bn as UnlinkNotifyResult, bo as UserCodeSchema, v as VERIFICATION_PURPOSES, w as VERIFICATION_TARGET_TYPES, bp as VerificationPurposeSchema, y as VerificationTargetType, bq as VerifyCodeParams, br as VerifyCodeResult, bs as VerifyMfaChallengeParams, V as VerifyMfaChallengeResult, bt as admitBearerKey, bu as approveDeviceAuthService, bv as approveOAuth2AuthorizeService, bw as assertNotLastRecoveryCredential, bx as assertRecentAuthentication, by as assertStepUp, bz as attemptSecondFactor, bA as authDeletionCancelledEvent, bB as authDeletionCompletedEvent, bC as authDeletionRequestedEvent, bD as authDeviceRegisteredEvent, bE as authLoginEvent, bF as authPasswordResetEvent, bG as authRegisterEvent, m as authRouter, bH as authenticate, bI as bearerAuthContext, bJ as buildOAuthErrorUrl, bK as carryStepUpVerification, bL as changePasswordService, bM as completePasswordResetService, bN as completeSignupService, bO as confirmPasswordResetService, bP as confirmSignupLinkService, bQ as confirmTotpEnrolmentService, bR as denyDeviceAuthService, bS as denyOAuth2AuthorizeService, bT as describeOAuth2AuthorizeRequestService, bU as disableMfaService, bV as disableSessionBindingService, bW as enableSessionBindingService, bX as finishPasskeyEnrollmentService, bY as finishPasskeyLoginService, bZ as finishSessionRenewService, b_ as getDeviceAuthInfoService, b$ as getEnabledOAuthProviders, c0 as getGoogleAccessToken, c1 as getMachinePrincipal, c2 as getOAuthProvider, c3 as getRegisteredProviders, c4 as getSessionBindingService, c5 as invitationAcceptedEvent, c6 as invitationCreatedEvent, c7 as isOAuthProviderEnabled, c8 as issueOneTimeTokenService, c9 as keySessionBindingService, ca as listKeysService, cb as listOAuth2GrantsService, cc as listPasskeysService, cd as loginService, ce as logoutService, cf as machineAuth, cg as markPasskeySecondFactorService, ch as mfaChallenges, ci as mfaEnrolledForUser, cj as mfaStatusService, ck as mfaVerifications, cl as oauthCallbackService, cm as oauthNativeService, cn as oauthStartService, co as oauthUnlinkNotifyService, cp as oauthUnlinkedEvent, cq as openStepUpChallengeService, cr as optionalAuth, cs as passkeys, ct as pollDeviceAuthService, cu as regenerateRecoveryCodesService, cv as registerAuthProfile, cw as registerMachineVerifier, cx as registerOAuthProvider, cy as registerPublicKeyService, cz as registerService, cA as registeredBinding, cB as renamePasskeyService, cC as requestPasswordResetService, cD as requestSignupLinkService, cE as requireEnabledProvider, cF as requireMachineScope, cG as resolveAuthenticatedUser, cH as resumeStepUpChallengeService, cI as revokeAllKeysService, cJ as revokeAllOAuth2GrantsForUser, cK as revokeKeyService, cL as revokeOAuth2GrantService, cM as revokePasskeyService, cN as rotateKeyService, cO as runAuthProfile, cP as selectAuthProfile, cQ as sendVerificationCodeService, cR as startDeviceAuthService, cS as startMfaChallengeAssertionService, cT as startPasskeyEnrollmentService, cU as startPasskeyLoginService, cV as startSessionBindingDisableService, cW as startSessionRenewService, cX as startStepUpService, cY as startTotpEnrolmentService, cZ as stepUpService, c_ as sweepMfaChallengesService, c$ as sweepUnconfirmedMfaService, d0 as userPublicKeys, d1 as verifyCodeService, d2 as verifyMfaChallengeService, d3 as verifyOneTimeTokenService, d4 as verifySecondFactor } from './machine-principals-BvRw8b8t.js';
|
|
3
3
|
import * as drizzle_orm_pg_core from 'drizzle-orm/pg-core';
|
|
4
4
|
import { l as SocialProvider, K as KeyAlgorithmType, d as InvitationStatus, c as AccountDeletionRequestedBy, i as PurgeStrategy } from './types-CTdoTOxM.js';
|
|
5
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';
|
|
@@ -7896,6 +7896,12 @@ declare const mfaEnrolmentRepository: MfaEnrolmentRepository;
|
|
|
7896
7896
|
* most of all, since the poll that spends it is the one call that registers a
|
|
7897
7897
|
* key. Judging the clock only in the read would let that key be registered after
|
|
7898
7898
|
* the code was dead.
|
|
7899
|
+
*
|
|
7900
|
+
* The three transitions that answer a record — approve, deny, and the global
|
|
7901
|
+
* revocation's sweep — also wake any long poll parked on it, after commit. That
|
|
7902
|
+
* is done here rather than in each caller because the sweep has four callers
|
|
7903
|
+
* across the revocation paths, and a caller that forgot would leave a waiting
|
|
7904
|
+
* device on its slower recheck instead of telling it no.
|
|
7899
7905
|
*/
|
|
7900
7906
|
|
|
7901
7907
|
declare class DeviceAuthorizationsRepository extends BaseRepository {
|
|
@@ -7930,6 +7936,16 @@ declare class DeviceAuthorizationsRepository extends BaseRepository {
|
|
|
7930
7936
|
* Read replica.
|
|
7931
7937
|
*/
|
|
7932
7938
|
findByDeviceCodeHash(deviceCodeHash: string): Promise<DeviceAuthorization | null>;
|
|
7939
|
+
/**
|
|
7940
|
+
* `findByDeviceCodeHash`, read from the primary even outside a transaction.
|
|
7941
|
+
*
|
|
7942
|
+
* For the long poll's wait, which runs before any transaction opens: it is
|
|
7943
|
+
* woken right after an answer commits, and a replica that has not caught up
|
|
7944
|
+
* yet would show it the record still pending and send it back to sleep.
|
|
7945
|
+
*
|
|
7946
|
+
* Write primary.
|
|
7947
|
+
*/
|
|
7948
|
+
findByDeviceCodeHashOnPrimary(deviceCodeHash: string): Promise<DeviceAuthorization | null>;
|
|
7933
7949
|
/**
|
|
7934
7950
|
* Bind the approving user and move the record to `approved`, but only from
|
|
7935
7951
|
* `pending`.
|
|
@@ -7986,6 +8002,8 @@ declare class DeviceAuthorizationsRepository extends BaseRepository {
|
|
|
7986
8002
|
* @returns the spent row, or null if it was not approved (any more), or expired
|
|
7987
8003
|
*/
|
|
7988
8004
|
consumeApproved(deviceCodeHash: string): Promise<DeviceAuthorization | null>;
|
|
8005
|
+
/** Wake the polls parked on a record this call moved, and hand the row back. */
|
|
8006
|
+
private answered;
|
|
7989
8007
|
}
|
|
7990
8008
|
declare const deviceAuthorizationsRepository: DeviceAuthorizationsRepository;
|
|
7991
8009
|
|
|
@@ -10590,6 +10608,8 @@ interface AuthDeviceAuthConfig {
|
|
|
10590
10608
|
ttlMs: number;
|
|
10591
10609
|
/** How long the waiting device should wait between polls, in milliseconds. */
|
|
10592
10610
|
intervalMs: number;
|
|
10611
|
+
/** The longest a poll that asks to wait (`waitMillis`) is held open, in milliseconds. */
|
|
10612
|
+
maxWaitMs: number;
|
|
10593
10613
|
}
|
|
10594
10614
|
/**
|
|
10595
10615
|
* Ten minutes. Long enough to walk to the other device and type the code, short
|
|
@@ -10598,12 +10618,19 @@ interface AuthDeviceAuthConfig {
|
|
|
10598
10618
|
declare const DEFAULT_DEVICE_AUTH_TTL_MS: number;
|
|
10599
10619
|
/** Five seconds. The interval the server asks for; the rate limit is what enforces it. */
|
|
10600
10620
|
declare const DEFAULT_DEVICE_AUTH_INTERVAL_MS: number;
|
|
10621
|
+
/**
|
|
10622
|
+
* Twenty seconds. Load balancers commonly close a request that has sent nothing
|
|
10623
|
+
* for 30 seconds (Google Cloud's backend service default among them), and a long
|
|
10624
|
+
* poll cut off there reaches the device as a network error rather than as a
|
|
10625
|
+
* pending answer. Twenty leaves room under that for the request's own work.
|
|
10626
|
+
*/
|
|
10627
|
+
declare const DEFAULT_DEVICE_AUTH_MAX_WAIT_MS: number;
|
|
10601
10628
|
/**
|
|
10602
10629
|
* Set the resolved device-auth config. Called synchronously from
|
|
10603
10630
|
* `createAuthLifecycle()` for the same reason `configureDeletion` is: it must
|
|
10604
10631
|
* take effect before any handler that reads `getDeviceAuthConfig()` can run.
|
|
10605
10632
|
*
|
|
10606
|
-
*
|
|
10633
|
+
* Every knob is a whole millisecond count, and one that is not is refused here
|
|
10607
10634
|
* rather than served. `intervalMs` is the reason the check exists: it leaves as
|
|
10608
10635
|
* `intervalMillis` in the start and poll answers, which `DeviceAuthPollResponseSchema`
|
|
10609
10636
|
* declares an integer and the mobile contract exports as one, so a fractional
|
|
@@ -10911,6 +10938,12 @@ interface AuthLifecycleOptions extends AuthInitOptions {
|
|
|
10911
10938
|
* @default 5000
|
|
10912
10939
|
*/
|
|
10913
10940
|
intervalMs?: number;
|
|
10941
|
+
/**
|
|
10942
|
+
* The longest a poll that sends `waitMillis` is held open, in milliseconds.
|
|
10943
|
+
* Keep it under the idle timeout of every proxy in front of the server.
|
|
10944
|
+
* @default 20000
|
|
10945
|
+
*/
|
|
10946
|
+
maxWaitMs?: number;
|
|
10914
10947
|
};
|
|
10915
10948
|
/**
|
|
10916
10949
|
* OAuth 2.1 authorization server for MCP clients
|
|
@@ -11094,4 +11127,4 @@ declare const authJobRouter: _spfn_core_job.JobRouter<{
|
|
|
11094
11127
|
*/
|
|
11095
11128
|
declare const createAuthDeletionJobRouter: typeof createAuthJobRouter;
|
|
11096
11129
|
|
|
11097
|
-
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, MfaChallenge, MfaChallengesRepository, type MfaConfig, MfaEnrolmentRepository, type MfaRecoveryCode, MfaRecoveryCodesRepository, type MfaTotp, MfaTotpRepository, MfaVerification, MfaVerificationMethod, MfaVerificationsRepository, type NewAccountDeletionRequest, type NewAuthMetadataEntity, type NewDeviceAuthorization, type NewInvitation, type NewKeyRevokeAllToken, NewMfaChallenge, 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, mfaChallengesRepository, 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 };
|
|
11130
|
+
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_MAX_WAIT_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, MfaChallenge, MfaChallengesRepository, type MfaConfig, MfaEnrolmentRepository, type MfaRecoveryCode, MfaRecoveryCodesRepository, type MfaTotp, MfaTotpRepository, MfaVerification, MfaVerificationMethod, MfaVerificationsRepository, type NewAccountDeletionRequest, type NewAuthMetadataEntity, type NewDeviceAuthorization, type NewInvitation, type NewKeyRevokeAllToken, NewMfaChallenge, 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, mfaChallengesRepository, 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 };
|
package/dist/server.js
CHANGED
|
@@ -8505,6 +8505,77 @@ var init_mfa_enrolment_repository = __esm({
|
|
|
8505
8505
|
}
|
|
8506
8506
|
});
|
|
8507
8507
|
|
|
8508
|
+
// src/server/lib/device-auth-waiters.ts
|
|
8509
|
+
import { onAfterCommit } from "@spfn/core/db";
|
|
8510
|
+
function announceDeviceAuthAnswered(ids) {
|
|
8511
|
+
if (ids.length === 0) {
|
|
8512
|
+
return;
|
|
8513
|
+
}
|
|
8514
|
+
onAfterCommit(() => {
|
|
8515
|
+
for (const id26 of ids) {
|
|
8516
|
+
wake(id26);
|
|
8517
|
+
}
|
|
8518
|
+
});
|
|
8519
|
+
}
|
|
8520
|
+
function wake(id26) {
|
|
8521
|
+
const parked = waiters.get(id26);
|
|
8522
|
+
if (!parked) {
|
|
8523
|
+
return;
|
|
8524
|
+
}
|
|
8525
|
+
waiters.delete(id26);
|
|
8526
|
+
for (const resolve of parked) {
|
|
8527
|
+
resolve();
|
|
8528
|
+
}
|
|
8529
|
+
}
|
|
8530
|
+
function waitForDeviceAuthAnswer(id26, timeoutMs, signal) {
|
|
8531
|
+
if (signal?.aborted) {
|
|
8532
|
+
return Promise.resolve();
|
|
8533
|
+
}
|
|
8534
|
+
return new Promise((resolve) => {
|
|
8535
|
+
const parked = waiters.get(id26) ?? /* @__PURE__ */ new Set();
|
|
8536
|
+
const done = () => {
|
|
8537
|
+
clearTimeout(timer);
|
|
8538
|
+
signal?.removeEventListener("abort", done);
|
|
8539
|
+
unpark(id26, parked, done);
|
|
8540
|
+
resolve();
|
|
8541
|
+
};
|
|
8542
|
+
const timer = setTimeout(done, timeoutMs);
|
|
8543
|
+
signal?.addEventListener("abort", done, { once: true });
|
|
8544
|
+
parked.add(done);
|
|
8545
|
+
waiters.set(id26, parked);
|
|
8546
|
+
});
|
|
8547
|
+
}
|
|
8548
|
+
function unpark(id26, parked, resolver) {
|
|
8549
|
+
parked.delete(resolver);
|
|
8550
|
+
if (parked.size === 0 && waiters.get(id26) === parked) {
|
|
8551
|
+
waiters.delete(id26);
|
|
8552
|
+
}
|
|
8553
|
+
}
|
|
8554
|
+
function waitingOnDeviceAuth(id26) {
|
|
8555
|
+
return waiting.get(id26) ?? 0;
|
|
8556
|
+
}
|
|
8557
|
+
async function holdDeviceAuthWait(id26, wait) {
|
|
8558
|
+
waiting.set(id26, waitingOnDeviceAuth(id26) + 1);
|
|
8559
|
+
try {
|
|
8560
|
+
return await wait();
|
|
8561
|
+
} finally {
|
|
8562
|
+
const left = waitingOnDeviceAuth(id26) - 1;
|
|
8563
|
+
if (left > 0) {
|
|
8564
|
+
waiting.set(id26, left);
|
|
8565
|
+
} else {
|
|
8566
|
+
waiting.delete(id26);
|
|
8567
|
+
}
|
|
8568
|
+
}
|
|
8569
|
+
}
|
|
8570
|
+
var waiters, waiting;
|
|
8571
|
+
var init_device_auth_waiters = __esm({
|
|
8572
|
+
"src/server/lib/device-auth-waiters.ts"() {
|
|
8573
|
+
"use strict";
|
|
8574
|
+
waiters = /* @__PURE__ */ new Map();
|
|
8575
|
+
waiting = /* @__PURE__ */ new Map();
|
|
8576
|
+
}
|
|
8577
|
+
});
|
|
8578
|
+
|
|
8508
8579
|
// src/server/repositories/device-authorizations.repository.ts
|
|
8509
8580
|
import { BaseRepository as BaseRepository14 } from "@spfn/core/db";
|
|
8510
8581
|
import { eq as eq14, and as and14, gt as gt7, inArray as inArray2, sql as sql9 } from "drizzle-orm";
|
|
@@ -8513,6 +8584,7 @@ var init_device_authorizations_repository = __esm({
|
|
|
8513
8584
|
"src/server/repositories/device-authorizations.repository.ts"() {
|
|
8514
8585
|
"use strict";
|
|
8515
8586
|
init_device_authorizations();
|
|
8587
|
+
init_device_auth_waiters();
|
|
8516
8588
|
notExpired = () => gt7(deviceAuthorizations.expiresAt, sql9`now()`);
|
|
8517
8589
|
DeviceAuthorizationsRepository = class extends BaseRepository14 {
|
|
8518
8590
|
/**
|
|
@@ -8555,6 +8627,19 @@ var init_device_authorizations_repository = __esm({
|
|
|
8555
8627
|
const result = await this.readDb.select().from(deviceAuthorizations).where(eq14(deviceAuthorizations.deviceCodeHash, deviceCodeHash)).limit(1);
|
|
8556
8628
|
return result[0] ?? null;
|
|
8557
8629
|
}
|
|
8630
|
+
/**
|
|
8631
|
+
* `findByDeviceCodeHash`, read from the primary even outside a transaction.
|
|
8632
|
+
*
|
|
8633
|
+
* For the long poll's wait, which runs before any transaction opens: it is
|
|
8634
|
+
* woken right after an answer commits, and a replica that has not caught up
|
|
8635
|
+
* yet would show it the record still pending and send it back to sleep.
|
|
8636
|
+
*
|
|
8637
|
+
* Write primary.
|
|
8638
|
+
*/
|
|
8639
|
+
async findByDeviceCodeHashOnPrimary(deviceCodeHash) {
|
|
8640
|
+
const result = await this.db.select().from(deviceAuthorizations).where(eq14(deviceAuthorizations.deviceCodeHash, deviceCodeHash)).limit(1);
|
|
8641
|
+
return result[0] ?? null;
|
|
8642
|
+
}
|
|
8558
8643
|
/**
|
|
8559
8644
|
* Bind the approving user and move the record to `approved`, but only from
|
|
8560
8645
|
* `pending`.
|
|
@@ -8572,7 +8657,7 @@ var init_device_authorizations_repository = __esm({
|
|
|
8572
8657
|
notExpired()
|
|
8573
8658
|
)
|
|
8574
8659
|
).returning();
|
|
8575
|
-
return result[0] ?? null;
|
|
8660
|
+
return this.answered(result[0] ?? null);
|
|
8576
8661
|
}
|
|
8577
8662
|
/**
|
|
8578
8663
|
* Move the record to `denied`, but only from `pending`.
|
|
@@ -8589,7 +8674,7 @@ var init_device_authorizations_repository = __esm({
|
|
|
8589
8674
|
notExpired()
|
|
8590
8675
|
)
|
|
8591
8676
|
).returning();
|
|
8592
|
-
return result[0] ?? null;
|
|
8677
|
+
return this.answered(result[0] ?? null);
|
|
8593
8678
|
}
|
|
8594
8679
|
/**
|
|
8595
8680
|
* Refuse every authorization a user still has in flight.
|
|
@@ -8617,12 +8702,14 @@ var init_device_authorizations_repository = __esm({
|
|
|
8617
8702
|
* @returns the rows this call refused
|
|
8618
8703
|
*/
|
|
8619
8704
|
async denyAllActiveByUserId(userId) {
|
|
8620
|
-
|
|
8705
|
+
const denied = await this.db.update(deviceAuthorizations).set({ status: "denied" }).where(
|
|
8621
8706
|
and14(
|
|
8622
8707
|
eq14(deviceAuthorizations.userId, userId),
|
|
8623
8708
|
inArray2(deviceAuthorizations.status, ["pending", "approved"])
|
|
8624
8709
|
)
|
|
8625
8710
|
).returning();
|
|
8711
|
+
announceDeviceAuthAnswered(denied.map((record) => record.id));
|
|
8712
|
+
return denied;
|
|
8626
8713
|
}
|
|
8627
8714
|
/**
|
|
8628
8715
|
* Spend an approved record, but only from `approved`, and address it by the
|
|
@@ -8645,6 +8732,13 @@ var init_device_authorizations_repository = __esm({
|
|
|
8645
8732
|
).returning();
|
|
8646
8733
|
return result[0] ?? null;
|
|
8647
8734
|
}
|
|
8735
|
+
/** Wake the polls parked on a record this call moved, and hand the row back. */
|
|
8736
|
+
answered(record) {
|
|
8737
|
+
if (record) {
|
|
8738
|
+
announceDeviceAuthAnswered([record.id]);
|
|
8739
|
+
}
|
|
8740
|
+
return record;
|
|
8741
|
+
}
|
|
8648
8742
|
};
|
|
8649
8743
|
deviceAuthorizationsRepository = new DeviceAuthorizationsRepository();
|
|
8650
8744
|
}
|
|
@@ -11587,7 +11681,7 @@ import { InvalidKeyFingerprintError, KeyIdAlreadyRegisteredError } from "@spfn/a
|
|
|
11587
11681
|
import { ValidationError as ValidationError3 } from "@spfn/core/errors";
|
|
11588
11682
|
|
|
11589
11683
|
// src/server/services/device-registration.service.ts
|
|
11590
|
-
import { onAfterCommit } from "@spfn/core/db";
|
|
11684
|
+
import { onAfterCommit as onAfterCommit2 } from "@spfn/core/db";
|
|
11591
11685
|
|
|
11592
11686
|
// src/server/events/index.ts
|
|
11593
11687
|
init_esm();
|
|
@@ -11739,7 +11833,7 @@ init_repositories();
|
|
|
11739
11833
|
var DEVICE_EVENT_FINGERPRINT_PREFIX_LENGTH = 12;
|
|
11740
11834
|
async function emitDeviceRegistered(row, channel) {
|
|
11741
11835
|
const mfaEnrolled = await mfaEnrolmentRepository.isEnrolled(row.userId);
|
|
11742
|
-
|
|
11836
|
+
onAfterCommit2(() => authDeviceRegisteredEvent.emit({
|
|
11743
11837
|
userId: String(row.userId),
|
|
11744
11838
|
keyId: row.keyId,
|
|
11745
11839
|
algorithm: row.algorithm,
|
|
@@ -11757,7 +11851,7 @@ async function emitDeviceRegistered(row, channel) {
|
|
|
11757
11851
|
// src/server/services/mfa.service.ts
|
|
11758
11852
|
init_logger();
|
|
11759
11853
|
init_config();
|
|
11760
|
-
import { onAfterCommit as
|
|
11854
|
+
import { onAfterCommit as onAfterCommit3, runInTransaction as runInTransaction2 } from "@spfn/core/db";
|
|
11761
11855
|
import { ValidationError as ValidationError2 } from "@spfn/core/errors";
|
|
11762
11856
|
import {
|
|
11763
11857
|
MfaAlreadyEnrolledError,
|
|
@@ -12230,7 +12324,7 @@ async function releaseDeferredAnnouncements(row, key) {
|
|
|
12230
12324
|
return;
|
|
12231
12325
|
}
|
|
12232
12326
|
const mfaEnrolled = await mfaEnrolledForUser(row.userId);
|
|
12233
|
-
|
|
12327
|
+
onAfterCommit3(() => authLoginEvent.emit({ ...row.loginEvent, userId: String(row.userId), mfaEnrolled }));
|
|
12234
12328
|
}
|
|
12235
12329
|
async function verifyMfaChallengeService(params) {
|
|
12236
12330
|
const challengeHash = hashCredential(params.challenge);
|
|
@@ -12324,7 +12418,7 @@ async function countConfirmFailure(userId) {
|
|
|
12324
12418
|
function readSecret(secretEnc, userId) {
|
|
12325
12419
|
const { value, needsRotation } = decryptMfaSecret(secretEnc, userId);
|
|
12326
12420
|
if (needsRotation) {
|
|
12327
|
-
|
|
12421
|
+
onAfterCommit3(() => mfaTotpRepository.updateSecret(userId, encryptMfaSecret(value, userId)));
|
|
12328
12422
|
}
|
|
12329
12423
|
return value;
|
|
12330
12424
|
}
|
|
@@ -12633,7 +12727,7 @@ init_key_policy();
|
|
|
12633
12727
|
// src/server/services/account-deletion.service.ts
|
|
12634
12728
|
init_repositories();
|
|
12635
12729
|
import { ValidationError as ValidationError4, NotFoundError as NotFoundError2 } from "@spfn/core/errors";
|
|
12636
|
-
import { runInTransaction as runInTransaction3, onAfterCommit as
|
|
12730
|
+
import { runInTransaction as runInTransaction3, onAfterCommit as onAfterCommit4 } from "@spfn/core/db";
|
|
12637
12731
|
import { sendEmail as sendEmail3 } from "@spfn/notification/server";
|
|
12638
12732
|
import {
|
|
12639
12733
|
InvalidCredentialsError,
|
|
@@ -12790,13 +12884,13 @@ async function requestAccountDeletionService(userId, params) {
|
|
|
12790
12884
|
await keysRepository.revokeAllActiveByUserId(user.id, "Account deletion requested");
|
|
12791
12885
|
await deviceAuthorizationsRepository.denyAllActiveByUserId(user.id);
|
|
12792
12886
|
await revokeAllOAuth2GrantsForUser(user.id);
|
|
12793
|
-
|
|
12887
|
+
onAfterCommit4(() => authDeletionRequestedEvent.emit({
|
|
12794
12888
|
userId: String(user.id),
|
|
12795
12889
|
userPublicId: user.publicId,
|
|
12796
12890
|
purgeScheduledAt: purgeScheduledAt.toISOString(),
|
|
12797
12891
|
requestedBy
|
|
12798
12892
|
}));
|
|
12799
|
-
|
|
12893
|
+
onAfterCommit4(() => notifyDeletionRequested(user, purgeScheduledAt));
|
|
12800
12894
|
if (gracePeriodDays === 0) {
|
|
12801
12895
|
await purgePendingRequest(request);
|
|
12802
12896
|
}
|
|
@@ -12828,11 +12922,11 @@ async function cancelAccountDeletionService(params) {
|
|
|
12828
12922
|
throw new DeletionNotRequestedError();
|
|
12829
12923
|
}
|
|
12830
12924
|
await usersRepository.reactivateFromPendingDeletion(user.id);
|
|
12831
|
-
|
|
12925
|
+
onAfterCommit4(() => authDeletionCancelledEvent.emit({
|
|
12832
12926
|
userId: String(user.id),
|
|
12833
12927
|
userPublicId: user.publicId
|
|
12834
12928
|
}));
|
|
12835
|
-
|
|
12929
|
+
onAfterCommit4(() => notifyDeletionCancelled(user));
|
|
12836
12930
|
return { userId: String(user.id) };
|
|
12837
12931
|
}
|
|
12838
12932
|
async function anonymizeUser(user) {
|
|
@@ -12919,9 +13013,9 @@ async function purgePendingRequest(request) {
|
|
|
12919
13013
|
}
|
|
12920
13014
|
const { email, publicId } = purgedUser;
|
|
12921
13015
|
if (email) {
|
|
12922
|
-
|
|
13016
|
+
onAfterCommit4(() => notifyPurgeFinal(email));
|
|
12923
13017
|
}
|
|
12924
|
-
|
|
13018
|
+
onAfterCommit4(() => authDeletionCompletedEvent.emit({
|
|
12925
13019
|
userPublicId: publicId,
|
|
12926
13020
|
purgeStrategy
|
|
12927
13021
|
}));
|
|
@@ -13275,7 +13369,7 @@ init_repositories();
|
|
|
13275
13369
|
import { env as env11 } from "@spfn/auth/config";
|
|
13276
13370
|
import { PasswordResetLinkError, PasswordResetSessionError } from "@spfn/auth/errors";
|
|
13277
13371
|
import { ValidationError as ValidationError6 } from "@spfn/core/errors";
|
|
13278
|
-
import { onAfterCommit as
|
|
13372
|
+
import { onAfterCommit as onAfterCommit5 } from "@spfn/core/db";
|
|
13279
13373
|
init_key_policy();
|
|
13280
13374
|
async function activeUserOf(userId) {
|
|
13281
13375
|
const user = await usersRepository.findByIdOnPrimary(userId);
|
|
@@ -13376,7 +13470,7 @@ async function completePasswordResetService(params) {
|
|
|
13376
13470
|
throw new PasswordResetSessionError();
|
|
13377
13471
|
}
|
|
13378
13472
|
const registered = await replaceCredentials(row, user, params);
|
|
13379
|
-
|
|
13473
|
+
onAfterCommit5(() => authPasswordResetEvent.emit({
|
|
13380
13474
|
userId: String(user.id),
|
|
13381
13475
|
email: row.email
|
|
13382
13476
|
}));
|
|
@@ -13468,21 +13562,26 @@ import {
|
|
|
13468
13562
|
DeviceAuthDeniedError,
|
|
13469
13563
|
InvalidKeyFingerprintError as InvalidKeyFingerprintError2
|
|
13470
13564
|
} from "@spfn/auth/errors";
|
|
13471
|
-
import { onAfterCommit as
|
|
13565
|
+
import { onAfterCommit as onAfterCommit6 } from "@spfn/core/db";
|
|
13566
|
+
import { getShutdownManager } from "@spfn/core/server";
|
|
13472
13567
|
|
|
13473
13568
|
// src/server/lib/device-auth-config.ts
|
|
13474
13569
|
var DEFAULT_DEVICE_AUTH_TTL_MS = 10 * 60 * 1e3;
|
|
13475
13570
|
var DEFAULT_DEVICE_AUTH_INTERVAL_MS = 5 * 1e3;
|
|
13571
|
+
var DEFAULT_DEVICE_AUTH_MAX_WAIT_MS = 20 * 1e3;
|
|
13476
13572
|
var config2 = {
|
|
13477
13573
|
ttlMs: DEFAULT_DEVICE_AUTH_TTL_MS,
|
|
13478
|
-
intervalMs: DEFAULT_DEVICE_AUTH_INTERVAL_MS
|
|
13574
|
+
intervalMs: DEFAULT_DEVICE_AUTH_INTERVAL_MS,
|
|
13575
|
+
maxWaitMs: DEFAULT_DEVICE_AUTH_MAX_WAIT_MS
|
|
13479
13576
|
};
|
|
13480
13577
|
function configureDeviceAuth(options) {
|
|
13481
13578
|
const ttlMs = options?.ttlMs ?? DEFAULT_DEVICE_AUTH_TTL_MS;
|
|
13482
13579
|
const intervalMs = options?.intervalMs ?? DEFAULT_DEVICE_AUTH_INTERVAL_MS;
|
|
13580
|
+
const maxWaitMs = options?.maxWaitMs ?? DEFAULT_DEVICE_AUTH_MAX_WAIT_MS;
|
|
13483
13581
|
assertWholeMillis("ttlMs", ttlMs);
|
|
13484
13582
|
assertWholeMillis("intervalMs", intervalMs);
|
|
13485
|
-
|
|
13583
|
+
assertWholeMillis("maxWaitMs", maxWaitMs);
|
|
13584
|
+
config2 = { ttlMs, intervalMs, maxWaitMs };
|
|
13486
13585
|
}
|
|
13487
13586
|
function assertWholeMillis(name, value) {
|
|
13488
13587
|
if (!Number.isInteger(value) || value <= 0) {
|
|
@@ -13495,6 +13594,9 @@ function getDeviceAuthConfig() {
|
|
|
13495
13594
|
return config2;
|
|
13496
13595
|
}
|
|
13497
13596
|
|
|
13597
|
+
// src/server/services/device-auth.service.ts
|
|
13598
|
+
init_device_auth_waiters();
|
|
13599
|
+
|
|
13498
13600
|
// src/server/lib/device-code.ts
|
|
13499
13601
|
import { createHash, randomBytes, randomInt } from "crypto";
|
|
13500
13602
|
var USER_CODE_ALPHABET = "ABCDEFGHJKMNPQRSTUVWXYZ23456789";
|
|
@@ -13524,6 +13626,8 @@ function hashDeviceCode(deviceCode) {
|
|
|
13524
13626
|
// src/server/services/device-auth.service.ts
|
|
13525
13627
|
init_key_policy();
|
|
13526
13628
|
var USER_CODE_ATTEMPTS = 3;
|
|
13629
|
+
var WAIT_RECHECK_MS = 1e3;
|
|
13630
|
+
var MAX_WAITERS_PER_RECORD = 3;
|
|
13527
13631
|
function assertActionable(record) {
|
|
13528
13632
|
if (!record || record.status === "consumed") {
|
|
13529
13633
|
throw new DeviceAuthNotFoundError();
|
|
@@ -13623,6 +13727,37 @@ async function denyDeviceAuthService(params) {
|
|
|
13623
13727
|
);
|
|
13624
13728
|
}
|
|
13625
13729
|
}
|
|
13730
|
+
async function waitForDeviceAuthAnswerService(params) {
|
|
13731
|
+
const requested = Math.min(params.waitMillis, getDeviceAuthConfig().maxWaitMs);
|
|
13732
|
+
const deviceCodeHash = hashDeviceCode(params.deviceCode);
|
|
13733
|
+
const record = requested > 0 ? await readWaitable(deviceCodeHash) : null;
|
|
13734
|
+
if (!record || waitingOnDeviceAuth(record.id) >= MAX_WAITERS_PER_RECORD) {
|
|
13735
|
+
return 0;
|
|
13736
|
+
}
|
|
13737
|
+
const startedAt = Date.now();
|
|
13738
|
+
const deadline = Math.min(startedAt + requested, record.expiresAt.getTime());
|
|
13739
|
+
await holdDeviceAuthWait(record.id, () => waitUntil(record.id, deviceCodeHash, deadline, params.signal));
|
|
13740
|
+
return Date.now() - startedAt;
|
|
13741
|
+
}
|
|
13742
|
+
async function waitUntil(id26, deviceCodeHash, deadline, signal) {
|
|
13743
|
+
while (!signal?.aborted && !getShutdownManager().isShuttingDown()) {
|
|
13744
|
+
const remaining = deadline - Date.now();
|
|
13745
|
+
if (remaining <= 0) {
|
|
13746
|
+
return;
|
|
13747
|
+
}
|
|
13748
|
+
await waitForDeviceAuthAnswer(id26, Math.min(remaining, WAIT_RECHECK_MS), signal);
|
|
13749
|
+
if (!await readWaitable(deviceCodeHash)) {
|
|
13750
|
+
return;
|
|
13751
|
+
}
|
|
13752
|
+
}
|
|
13753
|
+
}
|
|
13754
|
+
async function readWaitable(deviceCodeHash) {
|
|
13755
|
+
const record = await deviceAuthorizationsRepository.findByDeviceCodeHashOnPrimary(deviceCodeHash).catch(() => null);
|
|
13756
|
+
return isWaitable(record) ? record : null;
|
|
13757
|
+
}
|
|
13758
|
+
function isWaitable(record) {
|
|
13759
|
+
return record?.status === "pending" && record.expiresAt.getTime() > Date.now();
|
|
13760
|
+
}
|
|
13626
13761
|
async function pollDeviceAuthService(params) {
|
|
13627
13762
|
const deviceCodeHash = hashDeviceCode(params.deviceCode);
|
|
13628
13763
|
const record = assertActionable(
|
|
@@ -13632,7 +13767,10 @@ async function pollDeviceAuthService(params) {
|
|
|
13632
13767
|
throw new DeviceAuthDeniedError();
|
|
13633
13768
|
}
|
|
13634
13769
|
if (record.status === "pending") {
|
|
13635
|
-
return {
|
|
13770
|
+
return {
|
|
13771
|
+
status: "pending",
|
|
13772
|
+
intervalMillis: Math.max(0, getDeviceAuthConfig().intervalMs - (params.waitedMillis ?? 0))
|
|
13773
|
+
};
|
|
13636
13774
|
}
|
|
13637
13775
|
const consumed = await deviceAuthorizationsRepository.consumeApproved(deviceCodeHash);
|
|
13638
13776
|
if (!consumed) {
|
|
@@ -13688,7 +13826,7 @@ async function completeDeviceLogin(record, provenance) {
|
|
|
13688
13826
|
...loginBindingFields(registeredBinding(registered))
|
|
13689
13827
|
};
|
|
13690
13828
|
const mfaEnrolled = await mfaEnrolledForUser(user.id);
|
|
13691
|
-
|
|
13829
|
+
onAfterCommit6(() => authLoginEvent.emit({
|
|
13692
13830
|
userId: String(user.id),
|
|
13693
13831
|
provider: "device",
|
|
13694
13832
|
email: result.email,
|
|
@@ -13701,7 +13839,7 @@ async function completeDeviceLogin(record, provenance) {
|
|
|
13701
13839
|
// src/server/services/passkey.service.ts
|
|
13702
13840
|
init_logger();
|
|
13703
13841
|
init_config();
|
|
13704
|
-
import { onAfterCommit as
|
|
13842
|
+
import { onAfterCommit as onAfterCommit7, runInTransaction as runInTransaction4 } from "@spfn/core/db";
|
|
13705
13843
|
import { ValidationError as ValidationError8 } from "@spfn/core/errors";
|
|
13706
13844
|
import {
|
|
13707
13845
|
AccountDisabledError as AccountDisabledError3,
|
|
@@ -13819,7 +13957,7 @@ async function finishPasskeyEnrollmentService(params) {
|
|
|
13819
13957
|
aaguid: verified.aaguid,
|
|
13820
13958
|
label: params.label ?? null
|
|
13821
13959
|
});
|
|
13822
|
-
|
|
13960
|
+
onAfterCommit7(() => passkeyEnrolledEvent.emit({
|
|
13823
13961
|
userId: String(params.userId),
|
|
13824
13962
|
passkeyId: String(row.id),
|
|
13825
13963
|
label: row.label ?? void 0
|
|
@@ -13919,7 +14057,7 @@ async function startSession(user, params) {
|
|
|
13919
14057
|
...loginBindingFields(registeredBinding(registered))
|
|
13920
14058
|
};
|
|
13921
14059
|
const mfaEnrolled = await mfaEnrolledForUser(user.id);
|
|
13922
|
-
|
|
14060
|
+
onAfterCommit7(() => authLoginEvent.emit({
|
|
13923
14061
|
userId: String(user.id),
|
|
13924
14062
|
provider: "passkey",
|
|
13925
14063
|
email: result.email,
|
|
@@ -14002,7 +14140,7 @@ async function revokePasskeyService(params) {
|
|
|
14002
14140
|
if (!revoked) {
|
|
14003
14141
|
throw new PasskeyNotFoundError2();
|
|
14004
14142
|
}
|
|
14005
|
-
|
|
14143
|
+
onAfterCommit7(() => passkeyRevokedEvent.emit({
|
|
14006
14144
|
userId: String(params.userId),
|
|
14007
14145
|
passkeyId: String(revoked.id),
|
|
14008
14146
|
reason: "user"
|
|
@@ -15830,7 +15968,7 @@ async function oauthUnlinkNotifyService(provider, notification) {
|
|
|
15830
15968
|
}
|
|
15831
15969
|
|
|
15832
15970
|
// src/server/services/oauth-native.service.ts
|
|
15833
|
-
import { runInTransaction as runInTransaction5, onAfterCommit as
|
|
15971
|
+
import { runInTransaction as runInTransaction5, onAfterCommit as onAfterCommit8 } from "@spfn/core/db";
|
|
15834
15972
|
import {
|
|
15835
15973
|
InvalidKeyFingerprintError as InvalidKeyFingerprintError3,
|
|
15836
15974
|
NativeSignInUnsupportedError as NativeSignInUnsupportedError5,
|
|
@@ -15903,7 +16041,7 @@ async function persistNativeLogin(identity, params) {
|
|
|
15903
16041
|
}
|
|
15904
16042
|
await updateLastLoginService(userId);
|
|
15905
16043
|
const mfaEnrolled = isNewUser ? false : await mfaEnrolledForUser(userId);
|
|
15906
|
-
|
|
16044
|
+
onAfterCommit8(() => isNewUser ? authRegisterEvent.emit(eventPayload) : authLoginEvent.emit({ ...eventPayload, mfaEnrolled }));
|
|
15907
16045
|
return { mfaRequired: false, userId: String(userId), keyId: params.keyId, isNewUser };
|
|
15908
16046
|
}, { context: "auth:oauth-native" });
|
|
15909
16047
|
}
|
|
@@ -16937,6 +17075,31 @@ function attestedClientIp(c) {
|
|
|
16937
17075
|
return provenance.webProxy ? provenance.ip ?? null : null;
|
|
16938
17076
|
}
|
|
16939
17077
|
|
|
17078
|
+
// src/server/middleware/device-auth-long-poll.ts
|
|
17079
|
+
var DEVICE_AUTH_WAITED_MILLIS = "deviceAuthWaitedMillis";
|
|
17080
|
+
function deviceAuthLongPoll() {
|
|
17081
|
+
return async (c, next) => {
|
|
17082
|
+
const target = waitTarget(await c.req.json().catch(() => null));
|
|
17083
|
+
if (!target) {
|
|
17084
|
+
return next();
|
|
17085
|
+
}
|
|
17086
|
+
const signal = c.req.raw.signal;
|
|
17087
|
+
const waitedMillis = await waitForDeviceAuthAnswerService({ ...target, signal });
|
|
17088
|
+
if (signal.aborted) {
|
|
17089
|
+
return c.body(null, 204);
|
|
17090
|
+
}
|
|
17091
|
+
c.set(DEVICE_AUTH_WAITED_MILLIS, waitedMillis);
|
|
17092
|
+
return next();
|
|
17093
|
+
};
|
|
17094
|
+
}
|
|
17095
|
+
function waitTarget(body) {
|
|
17096
|
+
const { deviceCode, waitMillis } = body ?? {};
|
|
17097
|
+
if (typeof deviceCode !== "string" || !Number.isInteger(waitMillis) || waitMillis <= 0) {
|
|
17098
|
+
return null;
|
|
17099
|
+
}
|
|
17100
|
+
return { deviceCode, waitMillis };
|
|
17101
|
+
}
|
|
17102
|
+
|
|
16940
17103
|
// src/server/routes/auth/index.ts
|
|
16941
17104
|
var sendVerificationCode = route.post("/_auth/codes").input({
|
|
16942
17105
|
body: Type.Object({
|
|
@@ -17095,11 +17258,23 @@ var startDeviceAuth = route.post("/_auth/device/start").input({
|
|
|
17095
17258
|
});
|
|
17096
17259
|
var pollDeviceAuth = route.post("/_auth/device/poll").input({
|
|
17097
17260
|
body: Type.Object({
|
|
17098
|
-
deviceCode: Type.String({ description: "Device code returned by /_auth/device/start" })
|
|
17261
|
+
deviceCode: Type.String({ description: "Device code returned by /_auth/device/start" }),
|
|
17262
|
+
waitMillis: Type.Optional(Type.Integer({
|
|
17263
|
+
minimum: 0,
|
|
17264
|
+
description: "Longest to hold the request while nobody has answered; capped by the server"
|
|
17265
|
+
}))
|
|
17099
17266
|
})
|
|
17100
|
-
}).use([
|
|
17267
|
+
}).use([
|
|
17268
|
+
rateLimitPolicy("auth-device-poll", { limit: 30, windowMs: 6e4 }),
|
|
17269
|
+
deviceAuthLongPoll(),
|
|
17270
|
+
Transactional()
|
|
17271
|
+
]).skip(["auth"]).handler(async (c) => {
|
|
17101
17272
|
const { body } = await c.data();
|
|
17102
|
-
return await pollDeviceAuthService({
|
|
17273
|
+
return await pollDeviceAuthService({
|
|
17274
|
+
deviceCode: body.deviceCode,
|
|
17275
|
+
...deviceProvenance(c.raw),
|
|
17276
|
+
waitedMillis: Number(c.raw.get(DEVICE_AUTH_WAITED_MILLIS) ?? 0)
|
|
17277
|
+
});
|
|
17103
17278
|
});
|
|
17104
17279
|
var getDeviceAuthInfo = route.post("/_auth/device/info").input({
|
|
17105
17280
|
body: Type.Object({
|
|
@@ -18176,7 +18351,7 @@ var CORE_PREREQUISITE_OPERATIONS = [
|
|
|
18176
18351
|
|
|
18177
18352
|
// src/server/client-proof/contract-bundle.ts
|
|
18178
18353
|
init_wire_headers();
|
|
18179
|
-
var CONTRACT_VERSION = "0.13.
|
|
18354
|
+
var CONTRACT_VERSION = "0.13.1";
|
|
18180
18355
|
var CONTRACT_SUPPORTED_RANGE = ">=0.13.0 <0.14.0";
|
|
18181
18356
|
function required(name, type) {
|
|
18182
18357
|
return { name, type, optional: false };
|
|
@@ -18510,7 +18685,8 @@ var CONTRACT_TYPES = [
|
|
|
18510
18685
|
{
|
|
18511
18686
|
name: "PollDeviceAuthRequest",
|
|
18512
18687
|
fields: [
|
|
18513
|
-
required("deviceCode", "string")
|
|
18688
|
+
required("deviceCode", "string"),
|
|
18689
|
+
optional("waitMillis", "integer")
|
|
18514
18690
|
]
|
|
18515
18691
|
},
|
|
18516
18692
|
/**
|
|
@@ -21479,6 +21655,7 @@ export {
|
|
|
21479
21655
|
DEFAULT_DELETION_PURGE_STRATEGY,
|
|
21480
21656
|
DEFAULT_DELETION_SEND_NOTIFICATIONS,
|
|
21481
21657
|
DEFAULT_DEVICE_AUTH_INTERVAL_MS,
|
|
21658
|
+
DEFAULT_DEVICE_AUTH_MAX_WAIT_MS,
|
|
21482
21659
|
DEFAULT_DEVICE_AUTH_TTL_MS,
|
|
21483
21660
|
DEFAULT_REFRESH_TOKEN_TTL_MS,
|
|
21484
21661
|
DEFAULT_REVOKE_ALL_TOKEN_PURGE_CRON,
|