@atproto/oauth-provider 0.18.1 → 0.18.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/dist/account/account-manager.d.ts +2 -1
  3. package/dist/account/account-manager.d.ts.map +1 -1
  4. package/dist/account/account-manager.js +16 -0
  5. package/dist/account/account-manager.js.map +1 -1
  6. package/dist/account/account-store.d.ts +8 -1
  7. package/dist/account/account-store.d.ts.map +1 -1
  8. package/dist/account/account-store.js +1 -0
  9. package/dist/account/account-store.js.map +1 -1
  10. package/dist/customization/build-customization-data.d.ts +1 -1
  11. package/dist/customization/build-customization-data.d.ts.map +1 -1
  12. package/dist/customization/build-customization-data.js +2 -1
  13. package/dist/customization/build-customization-data.js.map +1 -1
  14. package/dist/customization/customization.d.ts +6 -0
  15. package/dist/customization/customization.d.ts.map +1 -1
  16. package/dist/customization/customization.js +4 -0
  17. package/dist/customization/customization.js.map +1 -1
  18. package/dist/errors/handle-unavailable-error.d.ts +5 -3
  19. package/dist/errors/handle-unavailable-error.d.ts.map +1 -1
  20. package/dist/errors/handle-unavailable-error.js.map +1 -1
  21. package/dist/oauth-hooks.d.ts +23 -2
  22. package/dist/oauth-hooks.d.ts.map +1 -1
  23. package/dist/oauth-hooks.js.map +1 -1
  24. package/dist/oauth-middleware.js +3 -2
  25. package/dist/oauth-middleware.js.map +1 -1
  26. package/dist/router/create-api-middleware.d.ts.map +1 -1
  27. package/dist/router/create-api-middleware.js +16 -1
  28. package/dist/router/create-api-middleware.js.map +1 -1
  29. package/package.json +5 -5
  30. package/src/account/account-manager.ts +26 -0
  31. package/src/account/account-store.ts +10 -0
  32. package/src/customization/build-customization-data.ts +2 -0
  33. package/src/customization/customization.ts +4 -0
  34. package/src/errors/handle-unavailable-error.ts +6 -1
  35. package/src/oauth-hooks.ts +25 -0
  36. package/src/oauth-middleware.ts +9 -9
  37. package/src/router/create-api-middleware.ts +26 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,15 @@
1
1
  # @atproto/oauth-provider
2
2
 
3
+ ## 0.18.2
4
+
5
+ ### Patch Changes
6
+
7
+ - [#4986](https://github.com/bluesky-social/atproto/pull/4986) [`6c63f7d`](https://github.com/bluesky-social/atproto/commit/6c63f7dca6d37c22a8dd5d579ad6a72e532fc372) Thanks [@matthieusieben](https://github.com/matthieusieben)! - Add ability to change the user handle through the account manager interface
8
+
9
+ - Updated dependencies [[`6c63f7d`](https://github.com/bluesky-social/atproto/commit/6c63f7dca6d37c22a8dd5d579ad6a72e532fc372), [`6c63f7d`](https://github.com/bluesky-social/atproto/commit/6c63f7dca6d37c22a8dd5d579ad6a72e532fc372), [`6c63f7d`](https://github.com/bluesky-social/atproto/commit/6c63f7dca6d37c22a8dd5d579ad6a72e532fc372), [`6c63f7d`](https://github.com/bluesky-social/atproto/commit/6c63f7dca6d37c22a8dd5d579ad6a72e532fc372), [`6c63f7d`](https://github.com/bluesky-social/atproto/commit/6c63f7dca6d37c22a8dd5d579ad6a72e532fc372)]:
10
+ - @atproto/oauth-provider-ui@0.7.2
11
+ - @atproto/oauth-provider-api@0.6.1
12
+
3
13
  ## 0.18.1
4
14
 
5
15
  ### Patch Changes
@@ -6,7 +6,7 @@ import { HCaptchaClient, HcaptchaVerifyResult } from '../lib/hcaptcha.js';
6
6
  import { OAuthHooks, RequestMetadata } from '../oauth-hooks.js';
7
7
  import { Customization } from '../oauth-provider.js';
8
8
  import { Sub } from '../oidc/sub.js';
9
- import { Account, AccountStore, AuthorizedClientData, DeviceAccount, ResetPasswordConfirmInput, ResetPasswordRequestInput, SignUpData, UpdateEmailConfirmInput, UpdateEmailRequestInput, VerifyEmailConfirmInput, VerifyEmailRequestInput } from './account-store.js';
9
+ import { Account, AccountStore, AuthorizedClientData, DeviceAccount, ResetPasswordConfirmInput, ResetPasswordRequestInput, SignUpData, UpdateEmailConfirmInput, UpdateEmailRequestInput, UpdateHandleData, VerifyEmailConfirmInput, VerifyEmailRequestInput } from './account-store.js';
10
10
  import { SignInData } from './sign-in-data.js';
11
11
  import { SignUpInput } from './sign-up-input.js';
12
12
  export declare class AccountManager {
@@ -39,5 +39,6 @@ export declare class AccountManager {
39
39
  updateEmailConfirm(deviceId: DeviceId, deviceMetadata: RequestMetadata, input: UpdateEmailConfirmInput, account: Account): Promise<Account>;
40
40
  verifyEmailRequest(deviceId: DeviceId, deviceMetadata: RequestMetadata, input: VerifyEmailRequestInput, account: Account): Promise<void>;
41
41
  verifyEmailConfirm(deviceId: DeviceId, deviceMetadata: RequestMetadata, input: VerifyEmailConfirmInput, account: Account): Promise<Account>;
42
+ updateHandle(deviceId: DeviceId, deviceMetadata: RequestMetadata, input: UpdateHandleData, account: Account): Promise<Account>;
42
43
  }
43
44
  //# sourceMappingURL=account-manager.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"account-manager.d.ts","sourceRoot":"","sources":["../../src/account/account-manager.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"account-manager.d.ts","sourceRoot":"","sources":["../../src/account/account-manager.ts"],"names":[],"mappings":"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"}
@@ -287,5 +287,21 @@ export class AccountManager {
287
287
  });
288
288
  return updatedAccount;
289
289
  }
290
+ async updateHandle(deviceId, deviceMetadata, input, account) {
291
+ await this.hooks.onUpdateHandle?.call(null, {
292
+ deviceId,
293
+ deviceMetadata,
294
+ input,
295
+ account,
296
+ });
297
+ const updatedAccount = await this.store.updateHandle(input);
298
+ await this.hooks.onUpdatedHandle?.call(null, {
299
+ deviceId,
300
+ deviceMetadata,
301
+ input,
302
+ account: updatedAccount,
303
+ });
304
+ return updatedAccount;
305
+ }
290
306
  }
291
307
  //# sourceMappingURL=account-manager.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"account-manager.js","sourceRoot":"","sources":["../../src/account/account-manager.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n OAuthIssuerIdentifier,\n isOAuthClientIdLoopback,\n} from '@atproto/oauth-types'\nimport { ClientId } from '../client/client-id.js'\nimport { Client } from '../client/client.js'\nimport { DeviceId } from '../device/device-id.js'\nimport { InvalidCredentialsError } from '../errors/invalid-credentials-error.js'\nimport { InvalidRequestError } from '../errors/invalid-request-error.js'\nimport { HCaptchaClient, HcaptchaVerifyResult } from '../lib/hcaptcha.js'\nimport { callAsync } from '../lib/util/function.js'\nimport { constantTime } from '../lib/util/time.js'\nimport { OAuthHooks, RequestMetadata } from '../oauth-hooks.js'\nimport { Customization } from '../oauth-provider.js'\nimport { Sub } from '../oidc/sub.js'\nimport {\n Account,\n AccountStore,\n AuthorizedClientData,\n DeviceAccount,\n ResetPasswordConfirmInput,\n ResetPasswordRequestInput,\n SignUpData,\n UpdateEmailConfirmInput,\n UpdateEmailRequestInput,\n VerifyEmailConfirmInput,\n VerifyEmailRequestInput,\n} from './account-store.js'\nimport { SignInData } from './sign-in-data.js'\nimport { SignUpInput } from './sign-up-input.js'\n\nconst TIMING_ATTACK_MITIGATION_DELAY = 400\nconst BRUTE_FORCE_MITIGATION_DELAY = 300\n\n// @TODO Add rate limit to all the OAuth routes.\n\nexport class AccountManager {\n protected readonly inviteCodeRequired: boolean\n protected readonly hcaptchaClient?: HCaptchaClient\n\n constructor(\n issuer: OAuthIssuerIdentifier,\n protected readonly store: AccountStore,\n protected readonly hooks: OAuthHooks,\n customization: Customization,\n ) {\n this.inviteCodeRequired = customization.inviteCodeRequired !== false\n this.hcaptchaClient = customization.hcaptcha\n ? new HCaptchaClient(new URL(issuer).hostname, customization.hcaptcha)\n : undefined\n }\n\n protected async processHcaptchaToken(\n input: SignUpInput,\n deviceId: DeviceId,\n deviceMetadata: RequestMetadata,\n ): Promise<HcaptchaVerifyResult | undefined> {\n if (!this.hcaptchaClient) {\n return undefined\n }\n\n if (!input.hcaptchaToken) {\n throw new InvalidRequestError('hCaptcha token is required')\n }\n\n const tokens = this.hcaptchaClient.buildClientTokens(\n deviceMetadata.ipAddress,\n input.handle,\n deviceMetadata.userAgent,\n )\n\n const result = await this.hcaptchaClient\n .verify('signup', input.hcaptchaToken, deviceMetadata.ipAddress, tokens)\n .catch((err) => {\n throw InvalidRequestError.from(err, 'hCaptcha verification failed')\n })\n\n await this.hooks.onHcaptchaResult?.call(null, {\n input,\n deviceId,\n deviceMetadata,\n tokens,\n result,\n })\n\n try {\n this.hcaptchaClient.checkVerifyResult(result, tokens)\n } catch (err) {\n throw InvalidRequestError.from(err, 'hCaptcha verification failed')\n }\n\n return result\n }\n\n protected async enforceInviteCode(\n input: SignUpInput,\n _deviceId: DeviceId,\n _deviceMetadata: RequestMetadata,\n ): Promise<string | undefined> {\n if (!this.inviteCodeRequired) {\n return undefined\n }\n\n if (!input.inviteCode) {\n throw new InvalidRequestError('Invite code is required')\n }\n\n return input.inviteCode\n }\n\n protected async buildSignupData(\n input: SignUpInput,\n deviceId: DeviceId,\n deviceMetadata: RequestMetadata,\n ): Promise<SignUpData> {\n const [hcaptchaResult, inviteCode] = await Promise.all([\n this.processHcaptchaToken(input, deviceId, deviceMetadata),\n this.enforceInviteCode(input, deviceId, deviceMetadata),\n ])\n\n return { ...input, hcaptchaResult, inviteCode }\n }\n\n public async createAccount(\n deviceId: DeviceId,\n deviceMetadata: RequestMetadata,\n input: SignUpInput,\n ): Promise<Account> {\n return constantTime(BRUTE_FORCE_MITIGATION_DELAY, async () => {\n await this.hooks.onSignUpAttempt?.call(null, {\n input,\n deviceId,\n deviceMetadata,\n })\n\n const data = await this.buildSignupData(input, deviceId, deviceMetadata)\n\n const account = await callAsync(() =>\n this.store.createAccount(data),\n ).catch((err) => {\n throw InvalidRequestError.from(err, 'Account creation failed')\n })\n\n try {\n await this.hooks.onSignedUp?.call(null, {\n data,\n account,\n deviceId,\n deviceMetadata,\n })\n\n return account\n } catch (err) {\n await this.removeDeviceAccount(deviceId, account.sub)\n\n throw InvalidRequestError.from(\n err,\n 'The account was successfully created but something went wrong, try signing-in.',\n )\n }\n })\n }\n\n public async authenticateAccount(\n deviceId: DeviceId,\n deviceMetadata: RequestMetadata,\n data: SignInData,\n clientId?: ClientId,\n ): Promise<Account> {\n return constantTime(TIMING_ATTACK_MITIGATION_DELAY, async () => {\n await this.hooks.onSignInAttempt?.call(null, {\n data,\n deviceId,\n deviceMetadata,\n clientId,\n })\n\n const account = await callAsync(() =>\n this.store.authenticateAccount(data),\n ).catch(async (err) => {\n // Only notify for credential failures (e.g. unknown identifier, wrong\n // password). Server errors and flows that require an additional factor\n // (e.g. SecondAuthenticationFactorRequiredError) are not \"failed\n // sign-ins\" and do not trigger the hook.\n if (err instanceof InvalidRequestError) {\n // Stores that throw the more specific `InvalidCredentialsError`\n // can attach the matched subject identifier to distinguish\n // \"identifier known, password wrong\" from \"identifier unknown\".\n // This information is only exposed to the hook and is never\n // surfaced to the client.\n const isCredentialsError = err instanceof InvalidCredentialsError\n const sub = isCredentialsError ? err.sub ?? null : null\n\n // Swallow any error from the hook itself so that it does not mask\n // the underlying authentication failure being reported.\n try {\n await this.hooks.onSignInFailed?.call(null, {\n data,\n error: err,\n sub,\n deviceId,\n deviceMetadata,\n clientId,\n })\n } catch {\n // noop\n }\n\n if (isCredentialsError) {\n // Defensively downgrade to a plain InvalidRequestError\n throw new InvalidRequestError(err.error_description)\n }\n }\n\n throw err\n })\n\n await this.hooks.onSignedIn?.call(null, {\n data,\n account,\n deviceId,\n deviceMetadata,\n clientId,\n })\n\n return account\n }).catch((err) => {\n throw InvalidRequestError.from(\n err,\n 'Unable to sign-in due to an unexpected server error',\n )\n })\n }\n\n public async upsertDeviceAccount(\n deviceId: DeviceId,\n sub: Sub,\n ): Promise<void> {\n await this.store.upsertDeviceAccount(deviceId, sub)\n }\n\n public async getDeviceAccount(\n deviceId: DeviceId,\n sub: Sub,\n ): Promise<DeviceAccount> {\n const deviceAccount = await this.store.getDeviceAccount(deviceId, sub)\n if (!deviceAccount) throw new InvalidRequestError(`Account not found`)\n\n return deviceAccount\n }\n\n public async setAuthorizedClient(\n account: Account,\n client: Client,\n data: AuthorizedClientData,\n ): Promise<void> {\n // \"Loopback\" clients are not distinguishable from one another.\n if (isOAuthClientIdLoopback(client.id)) return\n\n await this.store.setAuthorizedClient(account.sub, client.id, data)\n }\n\n public async getAccount(sub: Sub) {\n return this.store.getAccount(sub)\n }\n\n public async removeDeviceAccount(deviceId: DeviceId, sub: Sub) {\n return this.store.removeDeviceAccount(deviceId, sub)\n }\n\n public async listDeviceAccounts(\n deviceId: DeviceId,\n ): Promise<DeviceAccount[]> {\n const deviceAccounts = await this.store.listDeviceAccounts({\n deviceId,\n })\n\n return deviceAccounts // Fool proof\n .filter((deviceAccount) => deviceAccount.deviceId === deviceId)\n }\n\n public async listAccountDevices(sub: Sub): Promise<DeviceAccount[]> {\n const deviceAccounts = await this.store.listDeviceAccounts({\n sub,\n })\n\n return deviceAccounts // Fool proof\n .filter((deviceAccount) => deviceAccount.account.sub === sub)\n }\n\n public async resetPasswordRequest(\n deviceId: DeviceId,\n deviceMetadata: RequestMetadata,\n input: ResetPasswordRequestInput,\n ) {\n return constantTime(TIMING_ATTACK_MITIGATION_DELAY, async () => {\n await this.hooks.onResetPasswordRequest?.call(null, {\n input,\n deviceId,\n deviceMetadata,\n })\n\n const account = await this.store.resetPasswordRequest(input)\n\n // @NOTE Do not throw here, to prevent user enumeration\n\n await this.hooks.onResetPasswordRequested?.call(null, {\n input,\n deviceId,\n deviceMetadata,\n account,\n })\n })\n }\n\n public async resetPasswordConfirm(\n deviceId: DeviceId,\n deviceMetadata: RequestMetadata,\n input: ResetPasswordConfirmInput,\n ) {\n return constantTime(TIMING_ATTACK_MITIGATION_DELAY, async () => {\n await this.hooks.onResetPasswordConfirm?.call(null, {\n input,\n deviceId,\n deviceMetadata,\n })\n\n const account = await this.store.resetPasswordConfirm(input)\n\n if (!account) {\n throw new InvalidRequestError('Invalid token')\n }\n\n await this.hooks.onResetPasswordConfirmed?.call(null, {\n input,\n deviceId,\n deviceMetadata,\n account,\n })\n\n return account\n })\n }\n\n public async verifyHandleAvailability(handle: string): Promise<void> {\n return constantTime(TIMING_ATTACK_MITIGATION_DELAY, async () => {\n return this.store.verifyHandleAvailability(handle)\n })\n }\n\n public async updateEmailRequest(\n deviceId: DeviceId,\n deviceMetadata: RequestMetadata,\n input: UpdateEmailRequestInput,\n account: Account,\n ): Promise<{ tokenRequired: boolean }> {\n await this.hooks.onChangeEmailRequest?.call(null, {\n deviceId,\n deviceMetadata,\n input,\n account,\n })\n\n const { tokenRequired } = await this.store.updateEmailRequest(input)\n\n await this.hooks.onChangeEmailRequested?.call(null, {\n deviceId,\n deviceMetadata,\n input,\n account,\n })\n\n return { tokenRequired: tokenRequired === true }\n }\n\n public async updateEmailConfirm(\n deviceId: DeviceId,\n deviceMetadata: RequestMetadata,\n input: UpdateEmailConfirmInput,\n account: Account,\n ): Promise<Account> {\n await this.hooks.onUpdateEmailConfirm?.call(null, {\n deviceId,\n deviceMetadata,\n input,\n account,\n })\n\n const updatedAccount = await this.store.updateEmailConfirm(input)\n\n if (!updatedAccount) {\n throw new InvalidRequestError('Invalid token')\n }\n\n await this.hooks.onUpdateEmailConfirmed?.call(null, {\n deviceId,\n deviceMetadata,\n input,\n account: updatedAccount,\n })\n\n return updatedAccount\n }\n\n public async verifyEmailRequest(\n deviceId: DeviceId,\n deviceMetadata: RequestMetadata,\n input: VerifyEmailRequestInput,\n account: Account,\n ): Promise<void> {\n await this.hooks.onVerifyEmailRequest?.call(null, {\n deviceId,\n deviceMetadata,\n input,\n account,\n })\n\n await this.store.verifyEmailRequest(input)\n\n await this.hooks.onVerifyEmailRequested?.call(null, {\n deviceId,\n deviceMetadata,\n input,\n account,\n })\n }\n\n public async verifyEmailConfirm(\n deviceId: DeviceId,\n deviceMetadata: RequestMetadata,\n input: VerifyEmailConfirmInput,\n account: Account,\n ): Promise<Account> {\n await this.hooks.onVerifyEmailConfirm?.call(null, {\n deviceId,\n deviceMetadata,\n input,\n account,\n })\n\n const updatedAccount = await this.store.verifyEmailConfirm(input)\n\n if (!updatedAccount) {\n throw new InvalidRequestError('Invalid token')\n }\n\n await this.hooks.onVerifyEmailConfirmed?.call(null, {\n deviceId,\n deviceMetadata,\n input,\n account: updatedAccount,\n })\n\n return updatedAccount\n }\n}\n"]}
1
+ {"version":3,"file":"account-manager.js","sourceRoot":"","sources":["../../src/account/account-manager.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n OAuthIssuerIdentifier,\n isOAuthClientIdLoopback,\n} from '@atproto/oauth-types'\nimport { ClientId } from '../client/client-id.js'\nimport { Client } from '../client/client.js'\nimport { DeviceId } from '../device/device-id.js'\nimport { InvalidCredentialsError } from '../errors/invalid-credentials-error.js'\nimport { InvalidRequestError } from '../errors/invalid-request-error.js'\nimport { HCaptchaClient, HcaptchaVerifyResult } from '../lib/hcaptcha.js'\nimport { callAsync } from '../lib/util/function.js'\nimport { constantTime } from '../lib/util/time.js'\nimport { OAuthHooks, RequestMetadata } from '../oauth-hooks.js'\nimport { Customization } from '../oauth-provider.js'\nimport { Sub } from '../oidc/sub.js'\nimport {\n Account,\n AccountStore,\n AuthorizedClientData,\n DeviceAccount,\n ResetPasswordConfirmInput,\n ResetPasswordRequestInput,\n SignUpData,\n UpdateEmailConfirmInput,\n UpdateEmailRequestInput,\n UpdateHandleData,\n VerifyEmailConfirmInput,\n VerifyEmailRequestInput,\n} from './account-store.js'\nimport { SignInData } from './sign-in-data.js'\nimport { SignUpInput } from './sign-up-input.js'\n\nconst TIMING_ATTACK_MITIGATION_DELAY = 400\nconst BRUTE_FORCE_MITIGATION_DELAY = 300\n\n// @TODO Add rate limit to all the OAuth routes.\n\nexport class AccountManager {\n protected readonly inviteCodeRequired: boolean\n protected readonly hcaptchaClient?: HCaptchaClient\n\n constructor(\n issuer: OAuthIssuerIdentifier,\n protected readonly store: AccountStore,\n protected readonly hooks: OAuthHooks,\n customization: Customization,\n ) {\n this.inviteCodeRequired = customization.inviteCodeRequired !== false\n this.hcaptchaClient = customization.hcaptcha\n ? new HCaptchaClient(new URL(issuer).hostname, customization.hcaptcha)\n : undefined\n }\n\n protected async processHcaptchaToken(\n input: SignUpInput,\n deviceId: DeviceId,\n deviceMetadata: RequestMetadata,\n ): Promise<HcaptchaVerifyResult | undefined> {\n if (!this.hcaptchaClient) {\n return undefined\n }\n\n if (!input.hcaptchaToken) {\n throw new InvalidRequestError('hCaptcha token is required')\n }\n\n const tokens = this.hcaptchaClient.buildClientTokens(\n deviceMetadata.ipAddress,\n input.handle,\n deviceMetadata.userAgent,\n )\n\n const result = await this.hcaptchaClient\n .verify('signup', input.hcaptchaToken, deviceMetadata.ipAddress, tokens)\n .catch((err) => {\n throw InvalidRequestError.from(err, 'hCaptcha verification failed')\n })\n\n await this.hooks.onHcaptchaResult?.call(null, {\n input,\n deviceId,\n deviceMetadata,\n tokens,\n result,\n })\n\n try {\n this.hcaptchaClient.checkVerifyResult(result, tokens)\n } catch (err) {\n throw InvalidRequestError.from(err, 'hCaptcha verification failed')\n }\n\n return result\n }\n\n protected async enforceInviteCode(\n input: SignUpInput,\n _deviceId: DeviceId,\n _deviceMetadata: RequestMetadata,\n ): Promise<string | undefined> {\n if (!this.inviteCodeRequired) {\n return undefined\n }\n\n if (!input.inviteCode) {\n throw new InvalidRequestError('Invite code is required')\n }\n\n return input.inviteCode\n }\n\n protected async buildSignupData(\n input: SignUpInput,\n deviceId: DeviceId,\n deviceMetadata: RequestMetadata,\n ): Promise<SignUpData> {\n const [hcaptchaResult, inviteCode] = await Promise.all([\n this.processHcaptchaToken(input, deviceId, deviceMetadata),\n this.enforceInviteCode(input, deviceId, deviceMetadata),\n ])\n\n return { ...input, hcaptchaResult, inviteCode }\n }\n\n public async createAccount(\n deviceId: DeviceId,\n deviceMetadata: RequestMetadata,\n input: SignUpInput,\n ): Promise<Account> {\n return constantTime(BRUTE_FORCE_MITIGATION_DELAY, async () => {\n await this.hooks.onSignUpAttempt?.call(null, {\n input,\n deviceId,\n deviceMetadata,\n })\n\n const data = await this.buildSignupData(input, deviceId, deviceMetadata)\n\n const account = await callAsync(() =>\n this.store.createAccount(data),\n ).catch((err) => {\n throw InvalidRequestError.from(err, 'Account creation failed')\n })\n\n try {\n await this.hooks.onSignedUp?.call(null, {\n data,\n account,\n deviceId,\n deviceMetadata,\n })\n\n return account\n } catch (err) {\n await this.removeDeviceAccount(deviceId, account.sub)\n\n throw InvalidRequestError.from(\n err,\n 'The account was successfully created but something went wrong, try signing-in.',\n )\n }\n })\n }\n\n public async authenticateAccount(\n deviceId: DeviceId,\n deviceMetadata: RequestMetadata,\n data: SignInData,\n clientId?: ClientId,\n ): Promise<Account> {\n return constantTime(TIMING_ATTACK_MITIGATION_DELAY, async () => {\n await this.hooks.onSignInAttempt?.call(null, {\n data,\n deviceId,\n deviceMetadata,\n clientId,\n })\n\n const account = await callAsync(() =>\n this.store.authenticateAccount(data),\n ).catch(async (err) => {\n // Only notify for credential failures (e.g. unknown identifier, wrong\n // password). Server errors and flows that require an additional factor\n // (e.g. SecondAuthenticationFactorRequiredError) are not \"failed\n // sign-ins\" and do not trigger the hook.\n if (err instanceof InvalidRequestError) {\n // Stores that throw the more specific `InvalidCredentialsError`\n // can attach the matched subject identifier to distinguish\n // \"identifier known, password wrong\" from \"identifier unknown\".\n // This information is only exposed to the hook and is never\n // surfaced to the client.\n const isCredentialsError = err instanceof InvalidCredentialsError\n const sub = isCredentialsError ? err.sub ?? null : null\n\n // Swallow any error from the hook itself so that it does not mask\n // the underlying authentication failure being reported.\n try {\n await this.hooks.onSignInFailed?.call(null, {\n data,\n error: err,\n sub,\n deviceId,\n deviceMetadata,\n clientId,\n })\n } catch {\n // noop\n }\n\n if (isCredentialsError) {\n // Defensively downgrade to a plain InvalidRequestError\n throw new InvalidRequestError(err.error_description)\n }\n }\n\n throw err\n })\n\n await this.hooks.onSignedIn?.call(null, {\n data,\n account,\n deviceId,\n deviceMetadata,\n clientId,\n })\n\n return account\n }).catch((err) => {\n throw InvalidRequestError.from(\n err,\n 'Unable to sign-in due to an unexpected server error',\n )\n })\n }\n\n public async upsertDeviceAccount(\n deviceId: DeviceId,\n sub: Sub,\n ): Promise<void> {\n await this.store.upsertDeviceAccount(deviceId, sub)\n }\n\n public async getDeviceAccount(\n deviceId: DeviceId,\n sub: Sub,\n ): Promise<DeviceAccount> {\n const deviceAccount = await this.store.getDeviceAccount(deviceId, sub)\n if (!deviceAccount) throw new InvalidRequestError(`Account not found`)\n\n return deviceAccount\n }\n\n public async setAuthorizedClient(\n account: Account,\n client: Client,\n data: AuthorizedClientData,\n ): Promise<void> {\n // \"Loopback\" clients are not distinguishable from one another.\n if (isOAuthClientIdLoopback(client.id)) return\n\n await this.store.setAuthorizedClient(account.sub, client.id, data)\n }\n\n public async getAccount(sub: Sub) {\n return this.store.getAccount(sub)\n }\n\n public async removeDeviceAccount(deviceId: DeviceId, sub: Sub) {\n return this.store.removeDeviceAccount(deviceId, sub)\n }\n\n public async listDeviceAccounts(\n deviceId: DeviceId,\n ): Promise<DeviceAccount[]> {\n const deviceAccounts = await this.store.listDeviceAccounts({\n deviceId,\n })\n\n return deviceAccounts // Fool proof\n .filter((deviceAccount) => deviceAccount.deviceId === deviceId)\n }\n\n public async listAccountDevices(sub: Sub): Promise<DeviceAccount[]> {\n const deviceAccounts = await this.store.listDeviceAccounts({\n sub,\n })\n\n return deviceAccounts // Fool proof\n .filter((deviceAccount) => deviceAccount.account.sub === sub)\n }\n\n public async resetPasswordRequest(\n deviceId: DeviceId,\n deviceMetadata: RequestMetadata,\n input: ResetPasswordRequestInput,\n ) {\n return constantTime(TIMING_ATTACK_MITIGATION_DELAY, async () => {\n await this.hooks.onResetPasswordRequest?.call(null, {\n input,\n deviceId,\n deviceMetadata,\n })\n\n const account = await this.store.resetPasswordRequest(input)\n\n // @NOTE Do not throw here, to prevent user enumeration\n\n await this.hooks.onResetPasswordRequested?.call(null, {\n input,\n deviceId,\n deviceMetadata,\n account,\n })\n })\n }\n\n public async resetPasswordConfirm(\n deviceId: DeviceId,\n deviceMetadata: RequestMetadata,\n input: ResetPasswordConfirmInput,\n ) {\n return constantTime(TIMING_ATTACK_MITIGATION_DELAY, async () => {\n await this.hooks.onResetPasswordConfirm?.call(null, {\n input,\n deviceId,\n deviceMetadata,\n })\n\n const account = await this.store.resetPasswordConfirm(input)\n\n if (!account) {\n throw new InvalidRequestError('Invalid token')\n }\n\n await this.hooks.onResetPasswordConfirmed?.call(null, {\n input,\n deviceId,\n deviceMetadata,\n account,\n })\n\n return account\n })\n }\n\n public async verifyHandleAvailability(handle: string): Promise<void> {\n return constantTime(TIMING_ATTACK_MITIGATION_DELAY, async () => {\n return this.store.verifyHandleAvailability(handle)\n })\n }\n\n public async updateEmailRequest(\n deviceId: DeviceId,\n deviceMetadata: RequestMetadata,\n input: UpdateEmailRequestInput,\n account: Account,\n ): Promise<{ tokenRequired: boolean }> {\n await this.hooks.onChangeEmailRequest?.call(null, {\n deviceId,\n deviceMetadata,\n input,\n account,\n })\n\n const { tokenRequired } = await this.store.updateEmailRequest(input)\n\n await this.hooks.onChangeEmailRequested?.call(null, {\n deviceId,\n deviceMetadata,\n input,\n account,\n })\n\n return { tokenRequired: tokenRequired === true }\n }\n\n public async updateEmailConfirm(\n deviceId: DeviceId,\n deviceMetadata: RequestMetadata,\n input: UpdateEmailConfirmInput,\n account: Account,\n ): Promise<Account> {\n await this.hooks.onUpdateEmailConfirm?.call(null, {\n deviceId,\n deviceMetadata,\n input,\n account,\n })\n\n const updatedAccount = await this.store.updateEmailConfirm(input)\n\n if (!updatedAccount) {\n throw new InvalidRequestError('Invalid token')\n }\n\n await this.hooks.onUpdateEmailConfirmed?.call(null, {\n deviceId,\n deviceMetadata,\n input,\n account: updatedAccount,\n })\n\n return updatedAccount\n }\n\n public async verifyEmailRequest(\n deviceId: DeviceId,\n deviceMetadata: RequestMetadata,\n input: VerifyEmailRequestInput,\n account: Account,\n ): Promise<void> {\n await this.hooks.onVerifyEmailRequest?.call(null, {\n deviceId,\n deviceMetadata,\n input,\n account,\n })\n\n await this.store.verifyEmailRequest(input)\n\n await this.hooks.onVerifyEmailRequested?.call(null, {\n deviceId,\n deviceMetadata,\n input,\n account,\n })\n }\n\n public async verifyEmailConfirm(\n deviceId: DeviceId,\n deviceMetadata: RequestMetadata,\n input: VerifyEmailConfirmInput,\n account: Account,\n ): Promise<Account> {\n await this.hooks.onVerifyEmailConfirm?.call(null, {\n deviceId,\n deviceMetadata,\n input,\n account,\n })\n\n const updatedAccount = await this.store.verifyEmailConfirm(input)\n\n if (!updatedAccount) {\n throw new InvalidRequestError('Invalid token')\n }\n\n await this.hooks.onVerifyEmailConfirmed?.call(null, {\n deviceId,\n deviceMetadata,\n input,\n account: updatedAccount,\n })\n\n return updatedAccount\n }\n\n public async updateHandle(\n deviceId: DeviceId,\n deviceMetadata: RequestMetadata,\n input: UpdateHandleData,\n account: Account,\n ): Promise<Account> {\n await this.hooks.onUpdateHandle?.call(null, {\n deviceId,\n deviceMetadata,\n input,\n account,\n })\n\n const updatedAccount = await this.store.updateHandle(input)\n\n await this.hooks.onUpdatedHandle?.call(null, {\n deviceId,\n deviceMetadata,\n input,\n account: updatedAccount,\n })\n\n return updatedAccount\n }\n}\n"]}
@@ -1,4 +1,4 @@
1
- import type { Account, ConfirmEmailUpdateInput, ConfirmEmailVerificationInput, ConfirmResetPasswordInput, InitiateEmailUpdateInput, InitiateEmailUpdateOutput, InitiateEmailVerificationInput, InitiatePasswordResetInput } from '@atproto/oauth-provider-api';
1
+ import type { Account, ConfirmEmailUpdateInput, ConfirmEmailVerificationInput, ConfirmResetPasswordInput, InitiateEmailUpdateInput, InitiateEmailUpdateOutput, InitiateEmailVerificationInput, InitiatePasswordResetInput, UpdateHandleInput } from '@atproto/oauth-provider-api';
2
2
  import { OAuthScope } from '@atproto/oauth-types';
3
3
  import { ClientId } from '../client/client-id.js';
4
4
  import { DeviceId } from '../device/device-id.js';
@@ -23,6 +23,7 @@ export type UpdateEmailRequestOutput = InitiateEmailUpdateOutput;
23
23
  export type UpdateEmailConfirmInput = ConfirmEmailUpdateInput;
24
24
  export type VerifyEmailRequestInput = InitiateEmailVerificationInput;
25
25
  export type VerifyEmailConfirmInput = ConfirmEmailVerificationInput;
26
+ export type UpdateHandleData = UpdateHandleInput;
26
27
  export type CreateAccountData = {
27
28
  locale: string;
28
29
  email: string;
@@ -152,6 +153,12 @@ export interface AccountStore {
152
153
  * @throws {HandleUnavailableError} - To indicate that the handle is already taken
153
154
  */
154
155
  verifyHandleAvailability(handle: string): Awaitable<void>;
156
+ /**
157
+ * @throws {HandleUnavailableError} - To indicate that the handle is already taken
158
+ * @throws {InvalidRequestError} - To indicate that the handle is invalid or
159
+ * cannot be used
160
+ */
161
+ updateHandle(data: UpdateHandleData): Awaitable<Account>;
155
162
  }
156
163
  export declare const isAccountStore: <V extends Partial<AccountStore>>(value: V) => value is V & import("../lib/util/type.js").RequiredDefined<AccountStore>;
157
164
  export declare function asAccountStore<V>(implementation: V): V & AccountStore;
@@ -1 +1 @@
1
- {"version":3,"file":"account-store.d.ts","sourceRoot":"","sources":["../../src/account/account-store.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"account-store.d.ts","sourceRoot":"","sources":["../../src/account/account-store.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,OAAO,EACP,uBAAuB,EACvB,6BAA6B,EAC7B,yBAAyB,EACzB,wBAAwB,EACxB,yBAAyB,EACzB,8BAA8B,EAC9B,0BAA0B,EAC1B,iBAAiB,EAClB,MAAM,6BAA6B,CAAA;AACpC,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAA;AACjD,OAAO,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAA;AACjD,OAAO,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAA;AACjD,OAAO,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAA;AACtD,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAA;AACzD,OAAO,EAAE,SAAS,EAAyB,MAAM,qBAAqB,CAAA;AACtE,OAAO,EACL,sBAAsB,EACtB,uBAAuB,EACvB,mBAAmB,EACnB,uCAAuC,EACxC,MAAM,oBAAoB,CAAA;AAC3B,OAAO,EAAE,GAAG,EAAE,MAAM,gBAAgB,CAAA;AACpC,OAAO,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAA;AACpD,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;AAIhD,cAAc,wBAAwB,CAAA;AACtC,cAAc,0BAA0B,CAAA;AACxC,cAAc,wBAAwB,CAAA;AACtC,cAAc,gBAAgB,CAAA;AAC9B,cAAc,0BAA0B,CAAA;AAExC,YAAY,EACV,OAAO,EACP,oBAAoB,EACpB,UAAU,EACV,UAAU,EACV,WAAW,GACZ,CAAA;AAED,OAAO,EACL,sBAAsB,EACtB,uBAAuB,EACvB,mBAAmB,EACnB,uCAAuC,GACxC,CAAA;AAED,MAAM,MAAM,yBAAyB,GAAG,0BAA0B,CAAA;AAClE,MAAM,MAAM,yBAAyB,GAAG,yBAAyB,CAAA;AAEjE,MAAM,MAAM,uBAAuB,GAAG,wBAAwB,CAAA;AAC9D,MAAM,MAAM,wBAAwB,GAAG,yBAAyB,CAAA;AAChE,MAAM,MAAM,uBAAuB,GAAG,uBAAuB,CAAA;AAC7D,MAAM,MAAM,uBAAuB,GAAG,8BAA8B,CAAA;AACpE,MAAM,MAAM,uBAAuB,GAAG,6BAA6B,CAAA;AACnE,MAAM,MAAM,gBAAgB,GAAG,iBAAiB,CAAA;AAEhD,MAAM,MAAM,iBAAiB,GAAG;IAC9B,MAAM,EAAE,MAAM,CAAA;IACd,KAAK,EAAE,MAAM,CAAA;IACb,QAAQ,EAAE,MAAM,CAAA;IAChB,MAAM,EAAE,MAAM,CAAA;IACd,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;CAChC,CAAA;AAED,MAAM,MAAM,uBAAuB,GAAG;IACpC,MAAM,EAAE,MAAM,CAAA;IACd,QAAQ,EAAE,MAAM,CAAA;IAChB,QAAQ,EAAE,MAAM,CAAA;IAChB,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;CAC9B,CAAA;AAED,MAAM,MAAM,oBAAoB,GAAG;IAAE,gBAAgB,EAAE,SAAS,MAAM,EAAE,CAAA;CAAE,CAAA;AAC1E,MAAM,MAAM,iBAAiB,GAAG,GAAG,CAAC,QAAQ,EAAE,oBAAoB,CAAC,CAAA;AAEnE,MAAM,MAAM,aAAa,GAAG;IAC1B,QAAQ,EAAE,QAAQ,CAAA;IAElB;;;;OAIG;IACH,UAAU,EAAE,UAAU,CAAA;IAEtB;;OAEG;IACH,OAAO,EAAE,OAAO,CAAA;IAEhB;;;OAGG;IACH,iBAAiB,EAAE,iBAAiB,CAAA;IAEpC;;;OAGG;IACH,SAAS,EAAE,IAAI,CAAA;IAEf;;;OAGG;IACH,SAAS,EAAE,IAAI,CAAA;CAChB,CAAA;AAED,MAAM,MAAM,UAAU,GAAG,WAAW,GAAG;IACrC,cAAc,CAAC,EAAE,oBAAoB,CAAA;IACrC,UAAU,CAAC,EAAE,UAAU,CAAA;CACxB,CAAA;AAED,MAAM,WAAW,YAAY;IAC3B;;;OAGG;IACH,aAAa,CAAC,IAAI,EAAE,iBAAiB,GAAG,SAAS,CAAC,OAAO,CAAC,CAAA;IAE1D;;;;;;;;;OASG;IACH,mBAAmB,CAAC,IAAI,EAAE,uBAAuB,GAAG,SAAS,CAAC,OAAO,CAAC,CAAA;IAEtE;;OAEG;IACH,mBAAmB,CACjB,GAAG,EAAE,GAAG,EACR,QAAQ,EAAE,QAAQ,EAClB,IAAI,EAAE,oBAAoB,GACzB,SAAS,CAAC,IAAI,CAAC,CAAA;IAElB;;OAEG;IACH,UAAU,CAAC,GAAG,EAAE,GAAG,GAAG,SAAS,CAAC;QAC9B,OAAO,EAAE,OAAO,CAAA;QAChB,iBAAiB,EAAE,iBAAiB,CAAA;KACrC,CAAC,CAAA;IAEF;;;;;;;;;;OAUG;IACH,mBAAmB,CAAC,QAAQ,EAAE,QAAQ,EAAE,GAAG,EAAE,GAAG,GAAG,SAAS,CAAC,IAAI,CAAC,CAAA;IAElE;;;;;;OAMG;IACH,gBAAgB,CACd,QAAQ,EAAE,QAAQ,EAClB,GAAG,EAAE,GAAG,GACP,SAAS,CAAC,aAAa,GAAG,IAAI,CAAC,CAAA;IAElC;;;;;OAKG;IACH,mBAAmB,CAAC,QAAQ,EAAE,QAAQ,EAAE,GAAG,EAAE,GAAG,GAAG,SAAS,CAAC,IAAI,CAAC,CAAA;IAElE;;;OAGG;IACH,kBAAkB,CAChB,MAAM,EAAE;QAAE,GAAG,EAAE,GAAG,CAAA;KAAE,GAAG;QAAE,QAAQ,EAAE,QAAQ,CAAA;KAAE,GAC5C,SAAS,CAAC,aAAa,EAAE,CAAC,CAAA;IAE7B,oBAAoB,CAClB,IAAI,EAAE,yBAAyB,GAC9B,SAAS,CAAC,IAAI,GAAG,OAAO,CAAC,CAAA;IAE5B,oBAAoB,CAClB,IAAI,EAAE,yBAAyB,GAC9B,SAAS,CAAC,IAAI,GAAG,OAAO,CAAC,CAAA;IAE5B,kBAAkB,CAChB,IAAI,EAAE,uBAAuB,GAC5B,SAAS,CAAC,wBAAwB,CAAC,CAAA;IACtC;;;;;OAKG;IACH,kBAAkB,CAAC,IAAI,EAAE,uBAAuB,GAAG,SAAS,CAAC,OAAO,GAAG,IAAI,CAAC,CAAA;IAE5E,kBAAkB,CAAC,IAAI,EAAE,uBAAuB,GAAG,SAAS,CAAC,IAAI,CAAC,CAAA;IAClE,kBAAkB,CAAC,IAAI,EAAE,uBAAuB,GAAG,SAAS,CAAC,OAAO,GAAG,IAAI,CAAC,CAAA;IAE5E;;OAEG;IACH,wBAAwB,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,IAAI,CAAC,CAAA;IAEzD;;;;OAIG;IACH,YAAY,CAAC,IAAI,EAAE,gBAAgB,GAAG,SAAS,CAAC,OAAO,CAAC,CAAA;CACzD;AAED,eAAO,MAAM,cAAc,yHAiBzB,CAAA;AAEF,wBAAgB,cAAc,CAAC,CAAC,EAAE,cAAc,EAAE,CAAC,GAAG,CAAC,GAAG,YAAY,CAKrE"}
@@ -23,6 +23,7 @@ export const isAccountStore = buildInterfaceChecker([
23
23
  'verifyEmailRequest',
24
24
  'verifyEmailConfirm',
25
25
  'verifyHandleAvailability',
26
+ 'updateHandle',
26
27
  ]);
27
28
  export function asAccountStore(implementation) {
28
29
  if (!implementation || !isAccountStore(implementation)) {
@@ -1 +1 @@
1
- {"version":3,"file":"account-store.js","sourceRoot":"","sources":["../../src/account/account-store.ts"],"names":[],"mappings":"AAeA,OAAO,EAAa,qBAAqB,EAAE,MAAM,qBAAqB,CAAA;AACtE,OAAO,EACL,sBAAsB,EACtB,uBAAuB,EACvB,mBAAmB,EACnB,uCAAuC,GACxC,MAAM,oBAAoB,CAAA;AAK3B,kEAAkE;AAElE,cAAc,wBAAwB,CAAA;AACtC,cAAc,0BAA0B,CAAA;AACxC,cAAc,wBAAwB,CAAA;AACtC,cAAc,gBAAgB,CAAA;AAC9B,cAAc,0BAA0B,CAAA;AAUxC,OAAO,EACL,sBAAsB,EACtB,uBAAuB,EACvB,mBAAmB,EACnB,uCAAuC,GACxC,CAAA;AA6KD,MAAM,CAAC,MAAM,cAAc,GAAG,qBAAqB,CAAe;IAChE,eAAe;IACf,qBAAqB;IACrB,qBAAqB;IACrB,YAAY;IACZ,qBAAqB;IACrB,kBAAkB;IAClB,qBAAqB;IACrB,oBAAoB;IACpB,sBAAsB;IACtB,sBAAsB;IACtB,oBAAoB;IACpB,oBAAoB;IACpB,oBAAoB;IACpB,oBAAoB;IACpB,0BAA0B;CAC3B,CAAC,CAAA;AAEF,MAAM,UAAU,cAAc,CAAI,cAAiB;IACjD,IAAI,CAAC,cAAc,IAAI,CAAC,cAAc,CAAC,cAAc,CAAC,EAAE,CAAC;QACvD,MAAM,IAAI,KAAK,CAAC,qCAAqC,CAAC,CAAA;IACxD,CAAC;IACD,OAAO,cAAc,CAAA;AACvB,CAAC","sourcesContent":["import type {\n Account,\n ConfirmEmailUpdateInput,\n ConfirmEmailVerificationInput,\n ConfirmResetPasswordInput,\n InitiateEmailUpdateInput,\n InitiateEmailUpdateOutput,\n InitiateEmailVerificationInput,\n InitiatePasswordResetInput,\n} from '@atproto/oauth-provider-api'\nimport { OAuthScope } from '@atproto/oauth-types'\nimport { ClientId } from '../client/client-id.js'\nimport { DeviceId } from '../device/device-id.js'\nimport { DeviceData } from '../device/device-store.js'\nimport { HcaptchaVerifyResult } from '../lib/hcaptcha.js'\nimport { Awaitable, buildInterfaceChecker } from '../lib/util/type.js'\nimport {\n HandleUnavailableError,\n InvalidCredentialsError,\n InvalidRequestError,\n SecondAuthenticationFactorRequiredError,\n} from '../oauth-errors.js'\nimport { Sub } from '../oidc/sub.js'\nimport { InviteCode } from '../types/invite-code.js'\nimport { SignUpInput } from './sign-up-input.js'\n\n// Export all types needed to implement the AccountStore interface\n\nexport * from '../client/client-id.js'\nexport * from '../device/device-data.js'\nexport * from '../device/device-id.js'\nexport * from '../oidc/sub.js'\nexport * from '../request/request-id.js'\n\nexport type {\n Account,\n HcaptchaVerifyResult,\n InviteCode,\n OAuthScope,\n SignUpInput,\n}\n\nexport {\n HandleUnavailableError,\n InvalidCredentialsError,\n InvalidRequestError,\n SecondAuthenticationFactorRequiredError,\n}\n\nexport type ResetPasswordRequestInput = InitiatePasswordResetInput\nexport type ResetPasswordConfirmInput = ConfirmResetPasswordInput\n\nexport type UpdateEmailRequestInput = InitiateEmailUpdateInput\nexport type UpdateEmailRequestOutput = InitiateEmailUpdateOutput\nexport type UpdateEmailConfirmInput = ConfirmEmailUpdateInput\nexport type VerifyEmailRequestInput = InitiateEmailVerificationInput\nexport type VerifyEmailConfirmInput = ConfirmEmailVerificationInput\n\nexport type CreateAccountData = {\n locale: string\n email: string\n password: string\n handle: string\n inviteCode?: string | undefined\n}\n\nexport type AuthenticateAccountData = {\n locale: string\n password: string\n username: string\n emailOtp?: string | undefined\n}\n\nexport type AuthorizedClientData = { authorizedScopes: readonly string[] }\nexport type AuthorizedClients = Map<ClientId, AuthorizedClientData>\n\nexport type DeviceAccount = {\n deviceId: DeviceId\n\n /**\n * The data associated with the device, created through the\n * {@link DeviceStore}. This data is used to identify devices on which a user\n * has logged in.\n */\n deviceData: DeviceData\n\n /**\n * The account associated with the device account.\n */\n account: Account\n\n /**\n * The list of clients that are authorized by the account, as created through\n * the {@link AccountStore.setAuthorizedClient} method.\n */\n authorizedClients: AuthorizedClients\n\n /**\n * The date at which the device account was created. This value is currently\n * not used.\n */\n createdAt: Date\n\n /**\n * The date at which the device account was last updated. This value is used\n * to determine the date at which the user last authenticated on a device\n */\n updatedAt: Date\n}\n\nexport type SignUpData = SignUpInput & {\n hcaptchaResult?: HcaptchaVerifyResult\n inviteCode?: InviteCode\n}\n\nexport interface AccountStore {\n /**\n * @throws {HandleUnavailableError} - To indicate that the handle is already taken\n * @throws {InvalidRequestError} - To indicate that some data is invalid\n */\n createAccount(data: CreateAccountData): Awaitable<Account>\n\n /**\n * @throws {InvalidCredentialsError} - When the credentials are not valid.\n * Populate {@link InvalidCredentialsError.sub} with the subject identifier\n * when the identifier matched an existing account (e.g. wrong password for\n * a known user); omit it when the identifier was not found. Throwing the\n * generic {@link InvalidRequestError} is also accepted for backward\n * compatibility but prevents the `onSignInFailed` hook from distinguishing\n * the two cases.\n * @throws {SecondAuthenticationFactorRequiredError} - To indicate that an {@link SecondAuthenticationFactorRequiredError.type} is required in the credentials\n */\n authenticateAccount(data: AuthenticateAccountData): Awaitable<Account>\n\n /**\n * Add a client & scopes to the list of authorized clients for the given account.\n */\n setAuthorizedClient(\n sub: Sub,\n clientId: ClientId,\n data: AuthorizedClientData,\n ): Awaitable<void>\n\n /**\n * @throws {InvalidRequestError} - When the credentials are not valid\n */\n getAccount(sub: Sub): Awaitable<{\n account: Account\n authorizedClients: AuthorizedClients\n }>\n\n /**\n * @param data.requestId - If provided, the inserted account must be bound to\n * that particular requestId.\n *\n * @note Whenever a particular device account is created, all **unbound**\n * device accounts for the same `deviceId` & `sub` should be deleted.\n *\n * @note When a particular request is deleted (through\n * {@link RequestStore.deleteRequest}), all accounts bound to that request\n * should be deleted as well.\n */\n upsertDeviceAccount(deviceId: DeviceId, sub: Sub): Awaitable<void>\n\n /**\n * @param requestId - If provided, the result must either have the same\n * requestId, or not be bound to a particular requestId. If `null`, the\n * result must not be bound to a particular requestId.\n * @throws {InvalidRequestError} - Instead of returning `null` in order to\n * provide a custom error message\n */\n getDeviceAccount(\n deviceId: DeviceId,\n sub: Sub,\n ): Awaitable<DeviceAccount | null>\n\n /**\n * Removes *all* the unbound device-accounts associated with the given device\n * & account.\n *\n * @note Noop if the device-account is not found.\n */\n removeDeviceAccount(deviceId: DeviceId, sub: Sub): Awaitable<void>\n\n /**\n * @returns **all** the device accounts that match the {@link requestId}\n * criteria and given {@link filter}.\n */\n listDeviceAccounts(\n filter: { sub: Sub } | { deviceId: DeviceId },\n ): Awaitable<DeviceAccount[]>\n\n resetPasswordRequest(\n data: ResetPasswordRequestInput,\n ): Awaitable<null | Account>\n\n resetPasswordConfirm(\n data: ResetPasswordConfirmInput,\n ): Awaitable<null | Account>\n\n updateEmailRequest(\n data: UpdateEmailRequestInput,\n ): Awaitable<UpdateEmailRequestOutput>\n /**\n * Must trigger a verification email to be sent to the new email address, that\n * will then be confirmed through {@link updateEmailConfirm}. The account's\n * `email_verified` field is expected to become `false` until the new email is\n * confirmed.\n */\n updateEmailConfirm(data: UpdateEmailConfirmInput): Awaitable<Account | null>\n\n verifyEmailRequest(data: VerifyEmailRequestInput): Awaitable<void>\n verifyEmailConfirm(data: VerifyEmailConfirmInput): Awaitable<Account | null>\n\n /**\n * @throws {HandleUnavailableError} - To indicate that the handle is already taken\n */\n verifyHandleAvailability(handle: string): Awaitable<void>\n}\n\nexport const isAccountStore = buildInterfaceChecker<AccountStore>([\n 'createAccount',\n 'authenticateAccount',\n 'setAuthorizedClient',\n 'getAccount',\n 'upsertDeviceAccount',\n 'getDeviceAccount',\n 'removeDeviceAccount',\n 'listDeviceAccounts',\n 'resetPasswordRequest',\n 'resetPasswordConfirm',\n 'updateEmailRequest',\n 'updateEmailConfirm',\n 'verifyEmailRequest',\n 'verifyEmailConfirm',\n 'verifyHandleAvailability',\n])\n\nexport function asAccountStore<V>(implementation: V): V & AccountStore {\n if (!implementation || !isAccountStore(implementation)) {\n throw new Error('Invalid AccountStore implementation')\n }\n return implementation\n}\n"]}
1
+ {"version":3,"file":"account-store.js","sourceRoot":"","sources":["../../src/account/account-store.ts"],"names":[],"mappings":"AAgBA,OAAO,EAAa,qBAAqB,EAAE,MAAM,qBAAqB,CAAA;AACtE,OAAO,EACL,sBAAsB,EACtB,uBAAuB,EACvB,mBAAmB,EACnB,uCAAuC,GACxC,MAAM,oBAAoB,CAAA;AAK3B,kEAAkE;AAElE,cAAc,wBAAwB,CAAA;AACtC,cAAc,0BAA0B,CAAA;AACxC,cAAc,wBAAwB,CAAA;AACtC,cAAc,gBAAgB,CAAA;AAC9B,cAAc,0BAA0B,CAAA;AAUxC,OAAO,EACL,sBAAsB,EACtB,uBAAuB,EACvB,mBAAmB,EACnB,uCAAuC,GACxC,CAAA;AAqLD,MAAM,CAAC,MAAM,cAAc,GAAG,qBAAqB,CAAe;IAChE,eAAe;IACf,qBAAqB;IACrB,qBAAqB;IACrB,YAAY;IACZ,qBAAqB;IACrB,kBAAkB;IAClB,qBAAqB;IACrB,oBAAoB;IACpB,sBAAsB;IACtB,sBAAsB;IACtB,oBAAoB;IACpB,oBAAoB;IACpB,oBAAoB;IACpB,oBAAoB;IACpB,0BAA0B;IAC1B,cAAc;CACf,CAAC,CAAA;AAEF,MAAM,UAAU,cAAc,CAAI,cAAiB;IACjD,IAAI,CAAC,cAAc,IAAI,CAAC,cAAc,CAAC,cAAc,CAAC,EAAE,CAAC;QACvD,MAAM,IAAI,KAAK,CAAC,qCAAqC,CAAC,CAAA;IACxD,CAAC;IACD,OAAO,cAAc,CAAA;AACvB,CAAC","sourcesContent":["import type {\n Account,\n ConfirmEmailUpdateInput,\n ConfirmEmailVerificationInput,\n ConfirmResetPasswordInput,\n InitiateEmailUpdateInput,\n InitiateEmailUpdateOutput,\n InitiateEmailVerificationInput,\n InitiatePasswordResetInput,\n UpdateHandleInput,\n} from '@atproto/oauth-provider-api'\nimport { OAuthScope } from '@atproto/oauth-types'\nimport { ClientId } from '../client/client-id.js'\nimport { DeviceId } from '../device/device-id.js'\nimport { DeviceData } from '../device/device-store.js'\nimport { HcaptchaVerifyResult } from '../lib/hcaptcha.js'\nimport { Awaitable, buildInterfaceChecker } from '../lib/util/type.js'\nimport {\n HandleUnavailableError,\n InvalidCredentialsError,\n InvalidRequestError,\n SecondAuthenticationFactorRequiredError,\n} from '../oauth-errors.js'\nimport { Sub } from '../oidc/sub.js'\nimport { InviteCode } from '../types/invite-code.js'\nimport { SignUpInput } from './sign-up-input.js'\n\n// Export all types needed to implement the AccountStore interface\n\nexport * from '../client/client-id.js'\nexport * from '../device/device-data.js'\nexport * from '../device/device-id.js'\nexport * from '../oidc/sub.js'\nexport * from '../request/request-id.js'\n\nexport type {\n Account,\n HcaptchaVerifyResult,\n InviteCode,\n OAuthScope,\n SignUpInput,\n}\n\nexport {\n HandleUnavailableError,\n InvalidCredentialsError,\n InvalidRequestError,\n SecondAuthenticationFactorRequiredError,\n}\n\nexport type ResetPasswordRequestInput = InitiatePasswordResetInput\nexport type ResetPasswordConfirmInput = ConfirmResetPasswordInput\n\nexport type UpdateEmailRequestInput = InitiateEmailUpdateInput\nexport type UpdateEmailRequestOutput = InitiateEmailUpdateOutput\nexport type UpdateEmailConfirmInput = ConfirmEmailUpdateInput\nexport type VerifyEmailRequestInput = InitiateEmailVerificationInput\nexport type VerifyEmailConfirmInput = ConfirmEmailVerificationInput\nexport type UpdateHandleData = UpdateHandleInput\n\nexport type CreateAccountData = {\n locale: string\n email: string\n password: string\n handle: string\n inviteCode?: string | undefined\n}\n\nexport type AuthenticateAccountData = {\n locale: string\n password: string\n username: string\n emailOtp?: string | undefined\n}\n\nexport type AuthorizedClientData = { authorizedScopes: readonly string[] }\nexport type AuthorizedClients = Map<ClientId, AuthorizedClientData>\n\nexport type DeviceAccount = {\n deviceId: DeviceId\n\n /**\n * The data associated with the device, created through the\n * {@link DeviceStore}. This data is used to identify devices on which a user\n * has logged in.\n */\n deviceData: DeviceData\n\n /**\n * The account associated with the device account.\n */\n account: Account\n\n /**\n * The list of clients that are authorized by the account, as created through\n * the {@link AccountStore.setAuthorizedClient} method.\n */\n authorizedClients: AuthorizedClients\n\n /**\n * The date at which the device account was created. This value is currently\n * not used.\n */\n createdAt: Date\n\n /**\n * The date at which the device account was last updated. This value is used\n * to determine the date at which the user last authenticated on a device\n */\n updatedAt: Date\n}\n\nexport type SignUpData = SignUpInput & {\n hcaptchaResult?: HcaptchaVerifyResult\n inviteCode?: InviteCode\n}\n\nexport interface AccountStore {\n /**\n * @throws {HandleUnavailableError} - To indicate that the handle is already taken\n * @throws {InvalidRequestError} - To indicate that some data is invalid\n */\n createAccount(data: CreateAccountData): Awaitable<Account>\n\n /**\n * @throws {InvalidCredentialsError} - When the credentials are not valid.\n * Populate {@link InvalidCredentialsError.sub} with the subject identifier\n * when the identifier matched an existing account (e.g. wrong password for\n * a known user); omit it when the identifier was not found. Throwing the\n * generic {@link InvalidRequestError} is also accepted for backward\n * compatibility but prevents the `onSignInFailed` hook from distinguishing\n * the two cases.\n * @throws {SecondAuthenticationFactorRequiredError} - To indicate that an {@link SecondAuthenticationFactorRequiredError.type} is required in the credentials\n */\n authenticateAccount(data: AuthenticateAccountData): Awaitable<Account>\n\n /**\n * Add a client & scopes to the list of authorized clients for the given account.\n */\n setAuthorizedClient(\n sub: Sub,\n clientId: ClientId,\n data: AuthorizedClientData,\n ): Awaitable<void>\n\n /**\n * @throws {InvalidRequestError} - When the credentials are not valid\n */\n getAccount(sub: Sub): Awaitable<{\n account: Account\n authorizedClients: AuthorizedClients\n }>\n\n /**\n * @param data.requestId - If provided, the inserted account must be bound to\n * that particular requestId.\n *\n * @note Whenever a particular device account is created, all **unbound**\n * device accounts for the same `deviceId` & `sub` should be deleted.\n *\n * @note When a particular request is deleted (through\n * {@link RequestStore.deleteRequest}), all accounts bound to that request\n * should be deleted as well.\n */\n upsertDeviceAccount(deviceId: DeviceId, sub: Sub): Awaitable<void>\n\n /**\n * @param requestId - If provided, the result must either have the same\n * requestId, or not be bound to a particular requestId. If `null`, the\n * result must not be bound to a particular requestId.\n * @throws {InvalidRequestError} - Instead of returning `null` in order to\n * provide a custom error message\n */\n getDeviceAccount(\n deviceId: DeviceId,\n sub: Sub,\n ): Awaitable<DeviceAccount | null>\n\n /**\n * Removes *all* the unbound device-accounts associated with the given device\n * & account.\n *\n * @note Noop if the device-account is not found.\n */\n removeDeviceAccount(deviceId: DeviceId, sub: Sub): Awaitable<void>\n\n /**\n * @returns **all** the device accounts that match the {@link requestId}\n * criteria and given {@link filter}.\n */\n listDeviceAccounts(\n filter: { sub: Sub } | { deviceId: DeviceId },\n ): Awaitable<DeviceAccount[]>\n\n resetPasswordRequest(\n data: ResetPasswordRequestInput,\n ): Awaitable<null | Account>\n\n resetPasswordConfirm(\n data: ResetPasswordConfirmInput,\n ): Awaitable<null | Account>\n\n updateEmailRequest(\n data: UpdateEmailRequestInput,\n ): Awaitable<UpdateEmailRequestOutput>\n /**\n * Must trigger a verification email to be sent to the new email address, that\n * will then be confirmed through {@link updateEmailConfirm}. The account's\n * `email_verified` field is expected to become `false` until the new email is\n * confirmed.\n */\n updateEmailConfirm(data: UpdateEmailConfirmInput): Awaitable<Account | null>\n\n verifyEmailRequest(data: VerifyEmailRequestInput): Awaitable<void>\n verifyEmailConfirm(data: VerifyEmailConfirmInput): Awaitable<Account | null>\n\n /**\n * @throws {HandleUnavailableError} - To indicate that the handle is already taken\n */\n verifyHandleAvailability(handle: string): Awaitable<void>\n\n /**\n * @throws {HandleUnavailableError} - To indicate that the handle is already taken\n * @throws {InvalidRequestError} - To indicate that the handle is invalid or\n * cannot be used\n */\n updateHandle(data: UpdateHandleData): Awaitable<Account>\n}\n\nexport const isAccountStore = buildInterfaceChecker<AccountStore>([\n 'createAccount',\n 'authenticateAccount',\n 'setAuthorizedClient',\n 'getAccount',\n 'upsertDeviceAccount',\n 'getDeviceAccount',\n 'removeDeviceAccount',\n 'listDeviceAccounts',\n 'resetPasswordRequest',\n 'resetPasswordConfirm',\n 'updateEmailRequest',\n 'updateEmailConfirm',\n 'verifyEmailRequest',\n 'verifyEmailConfirm',\n 'verifyHandleAvailability',\n 'updateHandle',\n])\n\nexport function asAccountStore<V>(implementation: V): V & AccountStore {\n if (!implementation || !isAccountStore(implementation)) {\n throw new Error('Invalid AccountStore implementation')\n }\n return implementation\n}\n"]}
@@ -1,4 +1,4 @@
1
1
  import type { CustomizationData } from '@atproto/oauth-provider-api';
2
2
  import type { Customization } from './customization.js';
3
- export declare function buildCustomizationData({ branding, availableUserDomains, inviteCodeRequired, hcaptcha, }: Customization): CustomizationData;
3
+ export declare function buildCustomizationData({ branding, availableUserDomains, inviteCodeRequired, show2FaWarningOnEmailUpdate, hcaptcha, }: Customization): CustomizationData;
4
4
  //# sourceMappingURL=build-customization-data.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"build-customization-data.d.ts","sourceRoot":"","sources":["../../src/customization/build-customization-data.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAA;AACpE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;AAEvD,wBAAgB,sBAAsB,CAAC,EACrC,QAAQ,EACR,oBAAoB,EACpB,kBAAkB,EAClB,QAAQ,GACT,EAAE,aAAa,GAAG,iBAAiB,CAanC"}
1
+ {"version":3,"file":"build-customization-data.d.ts","sourceRoot":"","sources":["../../src/customization/build-customization-data.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAA;AACpE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;AAEvD,wBAAgB,sBAAsB,CAAC,EACrC,QAAQ,EACR,oBAAoB,EACpB,kBAAkB,EAClB,2BAA2B,EAC3B,QAAQ,GACT,EAAE,aAAa,GAAG,iBAAiB,CAcnC"}
@@ -1,4 +1,4 @@
1
- export function buildCustomizationData({ branding, availableUserDomains, inviteCodeRequired, hcaptcha, }) {
1
+ export function buildCustomizationData({ branding, availableUserDomains, inviteCodeRequired, show2FaWarningOnEmailUpdate, hcaptcha, }) {
2
2
  // @NOTE the front end does not need colors here as they will be injected as
3
3
  // CSS variables.
4
4
  // @NOTE We only copy the values explicitly needed to avoid leaking sensitive
@@ -6,6 +6,7 @@ export function buildCustomizationData({ branding, availableUserDomains, inviteC
6
6
  return {
7
7
  availableUserDomains,
8
8
  inviteCodeRequired,
9
+ show2FaWarningOnEmailUpdate,
9
10
  hcaptchaSiteKey: hcaptcha?.siteKey,
10
11
  name: branding?.name,
11
12
  logo: branding?.logo,
@@ -1 +1 @@
1
- {"version":3,"file":"build-customization-data.js","sourceRoot":"","sources":["../../src/customization/build-customization-data.ts"],"names":[],"mappings":"AAGA,MAAM,UAAU,sBAAsB,CAAC,EACrC,QAAQ,EACR,oBAAoB,EACpB,kBAAkB,EAClB,QAAQ,GACM;IACd,4EAA4E;IAC5E,iBAAiB;IACjB,6EAA6E;IAC7E,6DAA6D;IAC7D,OAAO;QACL,oBAAoB;QACpB,kBAAkB;QAClB,eAAe,EAAE,QAAQ,EAAE,OAAO;QAClC,IAAI,EAAE,QAAQ,EAAE,IAAI;QACpB,IAAI,EAAE,QAAQ,EAAE,IAAI;QACpB,KAAK,EAAE,QAAQ,EAAE,KAAK;KACvB,CAAA;AACH,CAAC","sourcesContent":["import type { CustomizationData } from '@atproto/oauth-provider-api'\nimport type { Customization } from './customization.js'\n\nexport function buildCustomizationData({\n branding,\n availableUserDomains,\n inviteCodeRequired,\n hcaptcha,\n}: Customization): CustomizationData {\n // @NOTE the front end does not need colors here as they will be injected as\n // CSS variables.\n // @NOTE We only copy the values explicitly needed to avoid leaking sensitive\n // data (in case the caller passed more than what we expect).\n return {\n availableUserDomains,\n inviteCodeRequired,\n hcaptchaSiteKey: hcaptcha?.siteKey,\n name: branding?.name,\n logo: branding?.logo,\n links: branding?.links,\n }\n}\n"]}
1
+ {"version":3,"file":"build-customization-data.js","sourceRoot":"","sources":["../../src/customization/build-customization-data.ts"],"names":[],"mappings":"AAGA,MAAM,UAAU,sBAAsB,CAAC,EACrC,QAAQ,EACR,oBAAoB,EACpB,kBAAkB,EAClB,2BAA2B,EAC3B,QAAQ,GACM;IACd,4EAA4E;IAC5E,iBAAiB;IACjB,6EAA6E;IAC7E,6DAA6D;IAC7D,OAAO;QACL,oBAAoB;QACpB,kBAAkB;QAClB,2BAA2B;QAC3B,eAAe,EAAE,QAAQ,EAAE,OAAO;QAClC,IAAI,EAAE,QAAQ,EAAE,IAAI;QACpB,IAAI,EAAE,QAAQ,EAAE,IAAI;QACpB,KAAK,EAAE,QAAQ,EAAE,KAAK;KACvB,CAAA;AACH,CAAC","sourcesContent":["import type { CustomizationData } from '@atproto/oauth-provider-api'\nimport type { Customization } from './customization.js'\n\nexport function buildCustomizationData({\n branding,\n availableUserDomains,\n inviteCodeRequired,\n show2FaWarningOnEmailUpdate,\n hcaptcha,\n}: Customization): CustomizationData {\n // @NOTE the front end does not need colors here as they will be injected as\n // CSS variables.\n // @NOTE We only copy the values explicitly needed to avoid leaking sensitive\n // data (in case the caller passed more than what we expect).\n return {\n availableUserDomains,\n inviteCodeRequired,\n show2FaWarningOnEmailUpdate,\n hcaptchaSiteKey: hcaptcha?.siteKey,\n name: branding?.name,\n logo: branding?.logo,\n links: branding?.links,\n }\n}\n"]}
@@ -128,6 +128,10 @@ export declare const customizationSchema: z.ZodObject<{
128
128
  * Is an invite code required to sign up?
129
129
  */
130
130
  inviteCodeRequired: z.ZodOptional<z.ZodBoolean>;
131
+ /**
132
+ * Show a warning about 2FA being disabled when updating email address
133
+ */
134
+ show2FaWarningOnEmailUpdate: z.ZodOptional<z.ZodBoolean>;
131
135
  /**
132
136
  * Enables hCaptcha during sign-up.
133
137
  */
@@ -179,6 +183,7 @@ export declare const customizationSchema: z.ZodObject<{
179
183
  }[] | undefined;
180
184
  } | undefined;
181
185
  inviteCodeRequired?: boolean | undefined;
186
+ show2FaWarningOnEmailUpdate?: boolean | undefined;
182
187
  hcaptcha?: {
183
188
  siteKey: string;
184
189
  secretKey: string;
@@ -217,6 +222,7 @@ export declare const customizationSchema: z.ZodObject<{
217
222
  }[] | undefined;
218
223
  } | undefined;
219
224
  inviteCodeRequired?: boolean | undefined;
225
+ show2FaWarningOnEmailUpdate?: boolean | undefined;
220
226
  hcaptcha?: {
221
227
  siteKey: string;
222
228
  secretKey: string;
@@ -1 +1 @@
1
- {"version":3,"file":"customization.d.ts","sourceRoot":"","sources":["../../src/customization/customization.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAIvB,eAAO,MAAM,mBAAmB;IAC9B;;;OAGG;;IAEH;;OAEG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAEH;;OAEG;;IAEH;;OAEG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAEH,CAAA;AACF,MAAM,MAAM,kBAAkB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAA;AACpE,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAA"}
1
+ {"version":3,"file":"customization.d.ts","sourceRoot":"","sources":["../../src/customization/customization.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAIvB,eAAO,MAAM,mBAAmB;IAC9B;;;OAGG;;IAEH;;OAEG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAEH;;OAEG;;IAEH;;OAEG;;IAEH;;OAEG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAEH,CAAA;AACF,MAAM,MAAM,kBAAkB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAA;AACpE,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAA"}
@@ -15,6 +15,10 @@ export const customizationSchema = z.object({
15
15
  * Is an invite code required to sign up?
16
16
  */
17
17
  inviteCodeRequired: z.boolean().optional(),
18
+ /**
19
+ * Show a warning about 2FA being disabled when updating email address
20
+ */
21
+ show2FaWarningOnEmailUpdate: z.boolean().optional(),
18
22
  /**
19
23
  * Enables hCaptcha during sign-up.
20
24
  */
@@ -1 +1 @@
1
- {"version":3,"file":"customization.js","sourceRoot":"","sources":["../../src/customization/customization.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AACvB,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAA;AACzD,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAA;AAE9C,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC1C;;;OAGG;IACH,oBAAoB,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,QAAQ,EAAE;IACpD;;OAEG;IACH,QAAQ,EAAE,cAAc,CAAC,QAAQ,EAAE;IACnC;;OAEG;IACH,kBAAkB,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE;IAC1C;;OAEG;IACH,QAAQ,EAAE,oBAAoB,CAAC,QAAQ,EAAE;CAC1C,CAAC,CAAA","sourcesContent":["import { z } from 'zod'\nimport { hcaptchaConfigSchema } from '../lib/hcaptcha.js'\nimport { brandingSchema } from './branding.js'\n\nexport const customizationSchema = z.object({\n /**\n * Available user domains that can be used to sign up. A non-empty array\n * is required to enable the sign-up feature.\n */\n availableUserDomains: z.array(z.string()).optional(),\n /**\n * UI customizations\n */\n branding: brandingSchema.optional(),\n /**\n * Is an invite code required to sign up?\n */\n inviteCodeRequired: z.boolean().optional(),\n /**\n * Enables hCaptcha during sign-up.\n */\n hcaptcha: hcaptchaConfigSchema.optional(),\n})\nexport type CustomizationInput = z.input<typeof customizationSchema>\nexport type Customization = z.infer<typeof customizationSchema>\n"]}
1
+ {"version":3,"file":"customization.js","sourceRoot":"","sources":["../../src/customization/customization.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AACvB,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAA;AACzD,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAA;AAE9C,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC1C;;;OAGG;IACH,oBAAoB,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,QAAQ,EAAE;IACpD;;OAEG;IACH,QAAQ,EAAE,cAAc,CAAC,QAAQ,EAAE;IACnC;;OAEG;IACH,kBAAkB,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE;IAC1C;;OAEG;IACH,2BAA2B,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE;IACnD;;OAEG;IACH,QAAQ,EAAE,oBAAoB,CAAC,QAAQ,EAAE;CAC1C,CAAC,CAAA","sourcesContent":["import { z } from 'zod'\nimport { hcaptchaConfigSchema } from '../lib/hcaptcha.js'\nimport { brandingSchema } from './branding.js'\n\nexport const customizationSchema = z.object({\n /**\n * Available user domains that can be used to sign up. A non-empty array\n * is required to enable the sign-up feature.\n */\n availableUserDomains: z.array(z.string()).optional(),\n /**\n * UI customizations\n */\n branding: brandingSchema.optional(),\n /**\n * Is an invite code required to sign up?\n */\n inviteCodeRequired: z.boolean().optional(),\n /**\n * Show a warning about 2FA being disabled when updating email address\n */\n show2FaWarningOnEmailUpdate: z.boolean().optional(),\n /**\n * Enables hCaptcha during sign-up.\n */\n hcaptcha: hcaptchaConfigSchema.optional(),\n})\nexport type CustomizationInput = z.input<typeof customizationSchema>\nexport type Customization = z.infer<typeof customizationSchema>\n"]}
@@ -1,9 +1,11 @@
1
+ import { HandleUnavailableReason } from '@atproto/oauth-provider-api';
1
2
  import { OAuthError } from './oauth-error.js';
3
+ export type { HandleUnavailableReason };
2
4
  export declare class HandleUnavailableError extends OAuthError {
3
- readonly reason: 'syntax' | 'domain' | 'slur' | 'taken';
4
- constructor(reason: 'syntax' | 'domain' | 'slur' | 'taken', details?: string, cause?: unknown);
5
+ readonly reason: HandleUnavailableReason;
6
+ constructor(reason: HandleUnavailableReason, details?: string, cause?: unknown);
5
7
  toJSON(): {
6
- readonly reason: "syntax" | "domain" | "slur" | "taken";
8
+ readonly reason: "syntax" | "domain" | "slur" | "taken" | "reserved" | "resolution" | "unsupported";
7
9
  readonly error: string;
8
10
  readonly error_description: string;
9
11
  };
@@ -1 +1 @@
1
- {"version":3,"file":"handle-unavailable-error.d.ts","sourceRoot":"","sources":["../../src/errors/handle-unavailable-error.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAE7C,qBAAa,sBAAuB,SAAQ,UAAU;IAElD,QAAQ,CAAC,MAAM,EAAE,QAAQ,GAAG,QAAQ,GAAG,MAAM,GAAG,OAAO;gBAA9C,MAAM,EAAE,QAAQ,GAAG,QAAQ,GAAG,MAAM,GAAG,OAAO,EACvD,OAAO,GAAE,MAAuC,EAChD,KAAK,CAAC,EAAE,OAAO;IAKjB,MAAM;;;;;CAMP"}
1
+ {"version":3,"file":"handle-unavailable-error.d.ts","sourceRoot":"","sources":["../../src/errors/handle-unavailable-error.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,uBAAuB,EAAE,MAAM,6BAA6B,CAAA;AACrE,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAI7C,YAAY,EAAE,uBAAuB,EAAE,CAAA;AAEvC,qBAAa,sBAAuB,SAAQ,UAAU;IAElD,QAAQ,CAAC,MAAM,EAAE,uBAAuB;gBAA/B,MAAM,EAAE,uBAAuB,EACxC,OAAO,GAAE,MAAuC,EAChD,KAAK,CAAC,EAAE,OAAO;IAKjB,MAAM;;;;;CAMP"}
@@ -1 +1 @@
1
- {"version":3,"file":"handle-unavailable-error.js","sourceRoot":"","sources":["../../src/errors/handle-unavailable-error.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAE7C,MAAM,OAAO,sBAAuB,SAAQ,UAAU;IACpD,YACW,MAA8C,EACvD,UAAkB,8BAA8B,EAChD,KAAe;QAEf,KAAK,CAAC,oBAAoB,EAAE,OAAO,EAAE,GAAG,EAAE,KAAK,CAAC,CAAA;QAJvC,WAAM,GAAN,MAAM,CAAwC;IAKzD,CAAC;IAED,MAAM;QACJ,OAAO;YACL,GAAG,KAAK,CAAC,MAAM,EAAE;YACjB,MAAM,EAAE,IAAI,CAAC,MAAM;SACX,CAAA;IACZ,CAAC;CACF","sourcesContent":["import { OAuthError } from './oauth-error.js'\n\nexport class HandleUnavailableError extends OAuthError {\n constructor(\n readonly reason: 'syntax' | 'domain' | 'slur' | 'taken',\n details: string = 'That handle is not available',\n cause?: unknown,\n ) {\n super('handle_unavailable', details, 400, cause)\n }\n\n toJSON() {\n return {\n ...super.toJSON(),\n reason: this.reason,\n } as const\n }\n}\n"]}
1
+ {"version":3,"file":"handle-unavailable-error.js","sourceRoot":"","sources":["../../src/errors/handle-unavailable-error.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAM7C,MAAM,OAAO,sBAAuB,SAAQ,UAAU;IACpD,YACW,MAA+B,EACxC,UAAkB,8BAA8B,EAChD,KAAe;QAEf,KAAK,CAAC,oBAAoB,EAAE,OAAO,EAAE,GAAG,EAAE,KAAK,CAAC,CAAA;QAJvC,WAAM,GAAN,MAAM,CAAyB;IAK1C,CAAC;IAED,MAAM;QACJ,OAAO;YACL,GAAG,KAAK,CAAC,MAAM,EAAE;YACjB,MAAM,EAAE,IAAI,CAAC,MAAM;SACX,CAAA;IACZ,CAAC;CACF","sourcesContent":["import { HandleUnavailableReason } from '@atproto/oauth-provider-api'\nimport { OAuthError } from './oauth-error.js'\n\n// @TODO this is *not* and \"OAuthError\" error but rather an ApiError.\n\nexport type { HandleUnavailableReason }\n\nexport class HandleUnavailableError extends OAuthError {\n constructor(\n readonly reason: HandleUnavailableReason,\n details: string = 'That handle is not available',\n cause?: unknown,\n ) {\n super('handle_unavailable', details, 400, cause)\n }\n\n toJSON() {\n return {\n ...super.toJSON(),\n reason: this.reason,\n } as const\n }\n}\n"]}
@@ -1,7 +1,7 @@
1
1
  import { Jwks } from '@atproto/jwk';
2
2
  import type { Account } from '@atproto/oauth-provider-api';
3
3
  import { OAuthAccessToken, OAuthAuthorizationDetails, OAuthAuthorizationRequestParameters, OAuthClientMetadata, OAuthTokenResponse, OAuthTokenType } from '@atproto/oauth-types';
4
- import { ResetPasswordConfirmInput, ResetPasswordRequestInput, SignUpData, UpdateEmailConfirmInput, UpdateEmailRequestInput, VerifyEmailConfirmInput, VerifyEmailRequestInput } from './account/account-store.js';
4
+ import { ResetPasswordConfirmInput, ResetPasswordRequestInput, SignUpData, UpdateEmailConfirmInput, UpdateEmailRequestInput, UpdateHandleData, VerifyEmailConfirmInput, VerifyEmailRequestInput } from './account/account-store.js';
5
5
  import { SignInData } from './account/sign-in-data.js';
6
6
  import { SignUpInput } from './account/sign-up-input.js';
7
7
  import { ClientAuth } from './client/client-auth.js';
@@ -22,7 +22,7 @@ import { Sub } from './oidc/sub.js';
22
22
  import { RequestId } from './request/request-id.js';
23
23
  import { AccessTokenPayload } from './signer/access-token-payload.js';
24
24
  import { TokenClaims } from './token/token-claims.js';
25
- export { AccessDeniedError, type AccessTokenPayload, type Account, AuthorizationError, type Awaitable, Client, type ClientAuth, type ClientId, type ClientInfo, type DeviceId, type DpopProof, type HcaptchaClientTokens, type HcaptchaConfig, type HcaptchaVerifyResult, InvalidCredentialsError, InvalidRequestError, type Jwks, type OAuthAccessToken, type OAuthAuthorizationDetails, type OAuthAuthorizationRequestParameters, type OAuthClientMetadata, OAuthError, type OAuthTokenResponse, type OAuthTokenType, type RequestMetadata, type ResetPasswordConfirmInput, type ResetPasswordRequestInput, type SignInData, type SignUpData, type SignUpInput, type Sub, type TokenClaims, };
25
+ export { AccessDeniedError, type AccessTokenPayload, type Account, AuthorizationError, type Awaitable, Client, type ClientAuth, type ClientId, type ClientInfo, type DeviceId, type DpopProof, type HcaptchaClientTokens, type HcaptchaConfig, type HcaptchaVerifyResult, InvalidCredentialsError, InvalidRequestError, type Jwks, type OAuthAccessToken, type OAuthAuthorizationDetails, type OAuthAuthorizationRequestParameters, type OAuthClientMetadata, OAuthError, type OAuthTokenResponse, type OAuthTokenType, type RequestMetadata, type ResetPasswordConfirmInput, type ResetPasswordRequestInput, type SignInData, type SignUpData, type SignUpInput, type Sub, type TokenClaims, type UpdateHandleData, };
26
26
  export type OAuthHooks = {
27
27
  /**
28
28
  * Use this to alter, override or validate the client metadata & jwks returned
@@ -119,6 +119,27 @@ export type OAuthHooks = {
119
119
  deviceMetadata: RequestMetadata;
120
120
  account: Account;
121
121
  }) => Awaitable<void>;
122
+ /**
123
+ * This hook is called when a user requests a handle change, before the change
124
+ * is performed on the account store. Only triggered with authenticated
125
+ * sessions, so the `account` is always available.
126
+ */
127
+ onUpdateHandle?: (data: {
128
+ input: UpdateHandleData;
129
+ deviceId: DeviceId;
130
+ deviceMetadata: RequestMetadata;
131
+ account: Account;
132
+ }) => Awaitable<void>;
133
+ /**
134
+ * This hook is called after a user successfully changed their handle on the
135
+ * account store.
136
+ */
137
+ onUpdatedHandle?: (data: {
138
+ input: UpdateHandleData;
139
+ deviceId: DeviceId;
140
+ deviceMetadata: RequestMetadata;
141
+ account: Account;
142
+ }) => Awaitable<void>;
122
143
  /**
123
144
  * This hook is called when a user attempts to sign up, after every validation
124
145
  * has passed (including hcaptcha).
@@ -1 +1 @@
1
- {"version":3,"file":"oauth-hooks.d.ts","sourceRoot":"","sources":["../src/oauth-hooks.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"oauth-hooks.d.ts","sourceRoot":"","sources":["../src/oauth-hooks.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"oauth-hooks.js","sourceRoot":"","sources":["../src/oauth-hooks.ts"],"names":[],"mappings":"AAwBA,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAA;AAG3C,OAAO,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAA;AACnE,OAAO,EAAE,kBAAkB,EAAE,MAAM,iCAAiC,CAAA;AACpE,OAAO,EAAE,uBAAuB,EAAE,MAAM,uCAAuC,CAAA;AAC/E,OAAO,EAAE,mBAAmB,EAAE,MAAM,mCAAmC,CAAA;AACvE,OAAO,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAA;AAapD,sEAAsE;AACtE,OAAO,EACL,iBAAiB,EAGjB,kBAAkB,EAElB,MAAM,EASN,uBAAuB,EACvB,mBAAmB,EAMnB,UAAU,GAWX,CAAA","sourcesContent":["import { Jwks } from '@atproto/jwk'\nimport type { Account } from '@atproto/oauth-provider-api'\nimport {\n OAuthAccessToken,\n OAuthAuthorizationDetails,\n OAuthAuthorizationRequestParameters,\n OAuthClientMetadata,\n OAuthTokenResponse,\n OAuthTokenType,\n} from '@atproto/oauth-types'\nimport {\n ResetPasswordConfirmInput,\n ResetPasswordRequestInput,\n SignUpData,\n UpdateEmailConfirmInput,\n UpdateEmailRequestInput,\n VerifyEmailConfirmInput,\n VerifyEmailRequestInput,\n} from './account/account-store.js'\nimport { SignInData } from './account/sign-in-data.js'\nimport { SignUpInput } from './account/sign-up-input.js'\nimport { ClientAuth } from './client/client-auth.js'\nimport { ClientId } from './client/client-id.js'\nimport { ClientInfo } from './client/client-info.js'\nimport { Client } from './client/client.js'\nimport { DeviceId } from './device/device-id.js'\nimport { DpopProof } from './dpop/dpop-proof.js'\nimport { AccessDeniedError } from './errors/access-denied-error.js'\nimport { AuthorizationError } from './errors/authorization-error.js'\nimport { InvalidCredentialsError } from './errors/invalid-credentials-error.js'\nimport { InvalidRequestError } from './errors/invalid-request-error.js'\nimport { OAuthError } from './errors/oauth-error.js'\nimport {\n HcaptchaClientTokens,\n HcaptchaConfig,\n HcaptchaVerifyResult,\n} from './lib/hcaptcha.js'\nimport { RequestMetadata } from './lib/http/request.js'\nimport { Awaitable, OmitKey } from './lib/util/type.js'\nimport { Sub } from './oidc/sub.js'\nimport { RequestId } from './request/request-id.js'\nimport { AccessTokenPayload } from './signer/access-token-payload.js'\nimport { TokenClaims } from './token/token-claims.js'\n\n// Make sure all types needed to implement the OAuthHooks are exported\nexport {\n AccessDeniedError,\n type AccessTokenPayload,\n type Account,\n AuthorizationError,\n type Awaitable,\n Client,\n type ClientAuth,\n type ClientId,\n type ClientInfo,\n type DeviceId,\n type DpopProof,\n type HcaptchaClientTokens,\n type HcaptchaConfig,\n type HcaptchaVerifyResult,\n InvalidCredentialsError,\n InvalidRequestError,\n type Jwks,\n type OAuthAccessToken,\n type OAuthAuthorizationDetails,\n type OAuthAuthorizationRequestParameters,\n type OAuthClientMetadata,\n OAuthError,\n type OAuthTokenResponse,\n type OAuthTokenType,\n type RequestMetadata,\n type ResetPasswordConfirmInput,\n type ResetPasswordRequestInput,\n type SignInData,\n type SignUpData,\n type SignUpInput,\n type Sub,\n type TokenClaims,\n}\n\nexport type OAuthHooks = {\n /**\n * Use this to alter, override or validate the client metadata & jwks returned\n * by the client store.\n *\n * @throws {InvalidClientMetadataError} if the metadata is invalid\n * @see {@link InvalidClientMetadataError}\n */\n getClientInfo?: (\n clientId: ClientId,\n data: { metadata: OAuthClientMetadata; jwks?: Jwks },\n ) => Awaitable<undefined | Partial<ClientInfo>>\n\n /**\n * This hook is called when a user requests an email change, before the email\n * change request is triggered on the account store. Only triggered with\n * authenticated sessions, so the `account` is always available.\n */\n onChangeEmailRequest?: (data: {\n input: UpdateEmailRequestInput\n deviceId: DeviceId\n deviceMetadata: RequestMetadata\n account: Account\n }) => Awaitable<void>\n\n /**\n * This hook is called after a user requests an email change, and the email\n * change request was successfully triggered on the account store.\n */\n onChangeEmailRequested?: (data: {\n input: UpdateEmailRequestInput\n deviceId: DeviceId\n deviceMetadata: RequestMetadata\n account: Account\n }) => Awaitable<void>\n\n /**\n * This hook is called when a user confirms an email change, before the email\n * change is actually confirmed on the account store. Only triggered with\n * authenticated sessions, so the `account` is always available.\n */\n onUpdateEmailConfirm?: (data: {\n input: UpdateEmailConfirmInput\n deviceId: DeviceId\n deviceMetadata: RequestMetadata\n account: Account\n }) => Awaitable<void>\n\n /**\n * This hook is called after a user confirms an email change, and the email\n * change was successfully confirmed on the account store.\n */\n onUpdateEmailConfirmed?: (data: {\n input: UpdateEmailConfirmInput\n deviceId: DeviceId\n deviceMetadata: RequestMetadata\n account: Account\n }) => Awaitable<void>\n\n /**\n * This hook is called when a user requests an email verification, before the\n * verification request is triggered on the account store. Only triggered with\n * authenticated sessions, so the `account` is always available.\n */\n onVerifyEmailRequest?: (data: {\n input: VerifyEmailRequestInput\n deviceId: DeviceId\n deviceMetadata: RequestMetadata\n account: Account\n }) => Awaitable<void>\n\n /**\n * This hook is called after a user requests an email verification, and the\n * verification request was successfully triggered on the account store.\n */\n onVerifyEmailRequested?: (data: {\n input: VerifyEmailRequestInput\n deviceId: DeviceId\n deviceMetadata: RequestMetadata\n account: Account\n }) => Awaitable<void>\n\n /**\n * This hook is called when a user confirms an email verification, before the\n * verification is actually confirmed on the account store. Only triggered\n * with authenticated sessions, so the `account` is always available.\n */\n onVerifyEmailConfirm?: (data: {\n input: VerifyEmailConfirmInput\n deviceId: DeviceId\n deviceMetadata: RequestMetadata\n account: Account\n }) => Awaitable<void>\n\n /**\n * This hook is called after a user confirms an email verification, and the\n * verification was successfully confirmed on the account store.\n */\n onVerifyEmailConfirmed?: (data: {\n input: VerifyEmailConfirmInput\n deviceId: DeviceId\n deviceMetadata: RequestMetadata\n account: Account\n }) => Awaitable<void>\n\n /**\n * This hook is called when a user attempts to sign up, after every validation\n * has passed (including hcaptcha).\n */\n onSignUpAttempt?: (data: {\n input: SignUpInput\n deviceId: DeviceId\n deviceMetadata: RequestMetadata\n }) => Awaitable<void>\n\n /**\n * This hook is called when a user attempts to sign up, after the hcaptcha\n * `/siteverify` request has been made (and before the result is validated).\n */\n onHcaptchaResult?: (data: {\n input: SignUpInput\n deviceId: DeviceId\n deviceMetadata: RequestMetadata\n tokens: HcaptchaClientTokens\n result: HcaptchaVerifyResult\n }) => Awaitable<void>\n\n /**\n * This hook is called when a user requests a password reset, before the\n * reset password request is triggered on the account store. Use this to\n * potentially cancel the password reset.\n */\n onResetPasswordRequest?: (data: {\n input: ResetPasswordRequestInput\n deviceId: DeviceId\n deviceMetadata: RequestMetadata\n }) => Awaitable<void>\n\n /**\n * This hook is called when a user requests a password reset, before the\n * reset password request is triggered on the account store. If not account\n * was found for the provided identifier, the `account` field will be `null`.\n */\n onResetPasswordRequested?: (data: {\n input: ResetPasswordRequestInput\n deviceId: DeviceId\n deviceMetadata: RequestMetadata\n account: Account | null\n }) => Awaitable<void>\n\n /**\n * This hook is called when a user confirms a password reset, before the\n * password is actually reset on the account store.\n */\n onResetPasswordConfirm?: (data: {\n input: ResetPasswordConfirmInput\n deviceId: DeviceId\n deviceMetadata: RequestMetadata\n }) => Awaitable<void>\n\n /**\n * This hook is called after a user confirms a password reset, and the\n * password was successfully reset on the account store.\n */\n onResetPasswordConfirmed?: (data: {\n input: ResetPasswordConfirmInput\n deviceId: DeviceId\n deviceMetadata: RequestMetadata\n account: Account\n }) => Awaitable<void>\n\n /**\n * This hook is called when a user successfully signs up.\n *\n * @throws {AccessDeniedError} to deny the sign-up\n */\n onSignedUp?: (data: {\n data: SignUpData\n account: Account\n deviceId: DeviceId\n deviceMetadata: RequestMetadata\n }) => Awaitable<void>\n\n /**\n * `clientId` is populated when the sign-in is submitted in the context of\n * an OAuth authorization request (i.e. the user is logging in to approve a\n * client); it is omitted for first-party sign-ins that happen outside any\n * authorization flow.\n */\n onSignInAttempt?: (data: {\n data: SignInData\n deviceId: DeviceId\n deviceMetadata: RequestMetadata\n clientId?: ClientId\n }) => Awaitable<void>\n\n /**\n * This hook is called when a user successfully signs in.\n *\n * `clientId` is populated when the sign-in is submitted in the context of\n * an OAuth authorization request; see {@link OAuthHooks.onSignInAttempt}.\n *\n * @throws {InvalidRequestError} when the sing-in should be denied\n */\n onSignedIn?: (data: {\n data: SignInData\n account: Account\n deviceId: DeviceId\n deviceMetadata: RequestMetadata\n clientId?: ClientId\n }) => Awaitable<void>\n\n /**\n * This hook is called when a sign-in attempt is rejected by the account\n * store due to invalid credentials (e.g. unknown identifier, wrong\n * password). It is *not* called for unexpected server errors, nor for flows\n * that require an additional authentication factor.\n *\n * `sub` is populated when the store throws an\n * {@link InvalidCredentialsError} that carries the matched subject\n * identifier (i.e. identifier known, credentials wrong). It is `null` when\n * the identifier was unknown or when the store threw a plain\n * {@link InvalidRequestError} without distinguishing the two cases.\n *\n * `clientId` is populated when the sign-in is submitted in the context of\n * an OAuth authorization request; see {@link OAuthHooks.onSignInAttempt}.\n *\n * Errors thrown from this hook are caught and ignored so that they do not\n * mask the original authentication failure.\n */\n onSignInFailed?: (data: {\n data: SignInData\n error: InvalidRequestError\n sub: Sub | null\n deviceId: DeviceId\n deviceMetadata: RequestMetadata\n clientId?: ClientId\n }) => Awaitable<void>\n\n /**\n * Allows validating an authorization request (typically the requested scopes)\n * before it is created. Note that the validity against the client metadata is\n * already enforced by the OAuth provider.\n *\n * @throws {AuthorizationError}\n */\n onAuthorizationRequest?: (data: {\n client: Client\n clientAuth: null | ClientAuth\n parameters: Readonly<OAuthAuthorizationRequestParameters>\n }) => Awaitable<void>\n\n /**\n * This hook is called when a client is authorized.\n *\n * @throws {AuthorizationError} to deny the authorization request and redirect\n * the user to the client with an OAuth error (other errors will result in an\n * internal server error being displayed to the user)\n *\n * @note We use `deviceMetadata` instead of `clientMetadata` to make it clear\n * that this metadata is from the user device, which might be different from\n * the client metadata (because the OAuth client could live in a backend).\n */\n onAuthorized?: (data: {\n client: Client\n account: Account\n parameters: OAuthAuthorizationRequestParameters\n deviceId: DeviceId\n deviceMetadata: RequestMetadata\n requestId: RequestId\n }) => Awaitable<void>\n\n /**\n * This hook is called whenever a token is about to be created. You can use\n * it to modify the token claims or perform additional validation.\n *\n * This hook should never throw an error.\n */\n onCreateToken?: (data: {\n client: Client\n account: Account\n parameters: OAuthAuthorizationRequestParameters\n claims: TokenClaims\n }) => Awaitable<void | OmitKey<AccessTokenPayload, 'iss'>>\n\n /**\n * This hook is called whenever a token was just decoded, and basic validation\n * was performed (signature, expiration, not-before).\n *\n * It can be used to modify the payload (e.g., to add custom claims), or to\n * perform additional validation.\n *\n * This hook is called when authenticating requests through the\n * `authenticateRequest()` method in `OAuthVerifier` and `OAuthProvider`.\n *\n * Any error thrown here will be propagated.\n */\n onDecodeToken?: (data: {\n tokenType: OAuthTokenType\n token: OAuthAccessToken\n payload: AccessTokenPayload\n dpopProof: null | DpopProof\n }) => Promise<AccessTokenPayload | void>\n\n /**\n * This hook is called when an authorized client exchanges an authorization\n * code for an access token.\n *\n * @throws {OAuthError} to cancel the token creation and revoke the session\n */\n onTokenCreated?: (data: {\n client: Client\n clientAuth: ClientAuth\n clientMetadata: RequestMetadata\n account: Account\n parameters: OAuthAuthorizationRequestParameters\n }) => Awaitable<void>\n\n /**\n * This hook is called when an authorized client refreshes an access token.\n *\n * @throws {OAuthError} to cancel the token refresh and revoke the session\n */\n onTokenRefreshed?: (data: {\n client: Client\n clientAuth: ClientAuth\n clientMetadata: RequestMetadata\n account: Account\n parameters: OAuthAuthorizationRequestParameters\n }) => Awaitable<void>\n}\n"]}
1
+ {"version":3,"file":"oauth-hooks.js","sourceRoot":"","sources":["../src/oauth-hooks.ts"],"names":[],"mappings":"AAyBA,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAA;AAG3C,OAAO,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAA;AACnE,OAAO,EAAE,kBAAkB,EAAE,MAAM,iCAAiC,CAAA;AACpE,OAAO,EAAE,uBAAuB,EAAE,MAAM,uCAAuC,CAAA;AAC/E,OAAO,EAAE,mBAAmB,EAAE,MAAM,mCAAmC,CAAA;AACvE,OAAO,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAA;AAapD,sEAAsE;AACtE,OAAO,EACL,iBAAiB,EAGjB,kBAAkB,EAElB,MAAM,EASN,uBAAuB,EACvB,mBAAmB,EAMnB,UAAU,GAYX,CAAA","sourcesContent":["import { Jwks } from '@atproto/jwk'\nimport type { Account } from '@atproto/oauth-provider-api'\nimport {\n OAuthAccessToken,\n OAuthAuthorizationDetails,\n OAuthAuthorizationRequestParameters,\n OAuthClientMetadata,\n OAuthTokenResponse,\n OAuthTokenType,\n} from '@atproto/oauth-types'\nimport {\n ResetPasswordConfirmInput,\n ResetPasswordRequestInput,\n SignUpData,\n UpdateEmailConfirmInput,\n UpdateEmailRequestInput,\n UpdateHandleData,\n VerifyEmailConfirmInput,\n VerifyEmailRequestInput,\n} from './account/account-store.js'\nimport { SignInData } from './account/sign-in-data.js'\nimport { SignUpInput } from './account/sign-up-input.js'\nimport { ClientAuth } from './client/client-auth.js'\nimport { ClientId } from './client/client-id.js'\nimport { ClientInfo } from './client/client-info.js'\nimport { Client } from './client/client.js'\nimport { DeviceId } from './device/device-id.js'\nimport { DpopProof } from './dpop/dpop-proof.js'\nimport { AccessDeniedError } from './errors/access-denied-error.js'\nimport { AuthorizationError } from './errors/authorization-error.js'\nimport { InvalidCredentialsError } from './errors/invalid-credentials-error.js'\nimport { InvalidRequestError } from './errors/invalid-request-error.js'\nimport { OAuthError } from './errors/oauth-error.js'\nimport {\n HcaptchaClientTokens,\n HcaptchaConfig,\n HcaptchaVerifyResult,\n} from './lib/hcaptcha.js'\nimport { RequestMetadata } from './lib/http/request.js'\nimport { Awaitable, OmitKey } from './lib/util/type.js'\nimport { Sub } from './oidc/sub.js'\nimport { RequestId } from './request/request-id.js'\nimport { AccessTokenPayload } from './signer/access-token-payload.js'\nimport { TokenClaims } from './token/token-claims.js'\n\n// Make sure all types needed to implement the OAuthHooks are exported\nexport {\n AccessDeniedError,\n type AccessTokenPayload,\n type Account,\n AuthorizationError,\n type Awaitable,\n Client,\n type ClientAuth,\n type ClientId,\n type ClientInfo,\n type DeviceId,\n type DpopProof,\n type HcaptchaClientTokens,\n type HcaptchaConfig,\n type HcaptchaVerifyResult,\n InvalidCredentialsError,\n InvalidRequestError,\n type Jwks,\n type OAuthAccessToken,\n type OAuthAuthorizationDetails,\n type OAuthAuthorizationRequestParameters,\n type OAuthClientMetadata,\n OAuthError,\n type OAuthTokenResponse,\n type OAuthTokenType,\n type RequestMetadata,\n type ResetPasswordConfirmInput,\n type ResetPasswordRequestInput,\n type SignInData,\n type SignUpData,\n type SignUpInput,\n type Sub,\n type TokenClaims,\n type UpdateHandleData,\n}\n\nexport type OAuthHooks = {\n /**\n * Use this to alter, override or validate the client metadata & jwks returned\n * by the client store.\n *\n * @throws {InvalidClientMetadataError} if the metadata is invalid\n * @see {@link InvalidClientMetadataError}\n */\n getClientInfo?: (\n clientId: ClientId,\n data: { metadata: OAuthClientMetadata; jwks?: Jwks },\n ) => Awaitable<undefined | Partial<ClientInfo>>\n\n /**\n * This hook is called when a user requests an email change, before the email\n * change request is triggered on the account store. Only triggered with\n * authenticated sessions, so the `account` is always available.\n */\n onChangeEmailRequest?: (data: {\n input: UpdateEmailRequestInput\n deviceId: DeviceId\n deviceMetadata: RequestMetadata\n account: Account\n }) => Awaitable<void>\n\n /**\n * This hook is called after a user requests an email change, and the email\n * change request was successfully triggered on the account store.\n */\n onChangeEmailRequested?: (data: {\n input: UpdateEmailRequestInput\n deviceId: DeviceId\n deviceMetadata: RequestMetadata\n account: Account\n }) => Awaitable<void>\n\n /**\n * This hook is called when a user confirms an email change, before the email\n * change is actually confirmed on the account store. Only triggered with\n * authenticated sessions, so the `account` is always available.\n */\n onUpdateEmailConfirm?: (data: {\n input: UpdateEmailConfirmInput\n deviceId: DeviceId\n deviceMetadata: RequestMetadata\n account: Account\n }) => Awaitable<void>\n\n /**\n * This hook is called after a user confirms an email change, and the email\n * change was successfully confirmed on the account store.\n */\n onUpdateEmailConfirmed?: (data: {\n input: UpdateEmailConfirmInput\n deviceId: DeviceId\n deviceMetadata: RequestMetadata\n account: Account\n }) => Awaitable<void>\n\n /**\n * This hook is called when a user requests an email verification, before the\n * verification request is triggered on the account store. Only triggered with\n * authenticated sessions, so the `account` is always available.\n */\n onVerifyEmailRequest?: (data: {\n input: VerifyEmailRequestInput\n deviceId: DeviceId\n deviceMetadata: RequestMetadata\n account: Account\n }) => Awaitable<void>\n\n /**\n * This hook is called after a user requests an email verification, and the\n * verification request was successfully triggered on the account store.\n */\n onVerifyEmailRequested?: (data: {\n input: VerifyEmailRequestInput\n deviceId: DeviceId\n deviceMetadata: RequestMetadata\n account: Account\n }) => Awaitable<void>\n\n /**\n * This hook is called when a user confirms an email verification, before the\n * verification is actually confirmed on the account store. Only triggered\n * with authenticated sessions, so the `account` is always available.\n */\n onVerifyEmailConfirm?: (data: {\n input: VerifyEmailConfirmInput\n deviceId: DeviceId\n deviceMetadata: RequestMetadata\n account: Account\n }) => Awaitable<void>\n\n /**\n * This hook is called after a user confirms an email verification, and the\n * verification was successfully confirmed on the account store.\n */\n onVerifyEmailConfirmed?: (data: {\n input: VerifyEmailConfirmInput\n deviceId: DeviceId\n deviceMetadata: RequestMetadata\n account: Account\n }) => Awaitable<void>\n\n /**\n * This hook is called when a user requests a handle change, before the change\n * is performed on the account store. Only triggered with authenticated\n * sessions, so the `account` is always available.\n */\n onUpdateHandle?: (data: {\n input: UpdateHandleData\n deviceId: DeviceId\n deviceMetadata: RequestMetadata\n account: Account\n }) => Awaitable<void>\n\n /**\n * This hook is called after a user successfully changed their handle on the\n * account store.\n */\n onUpdatedHandle?: (data: {\n input: UpdateHandleData\n deviceId: DeviceId\n deviceMetadata: RequestMetadata\n account: Account\n }) => Awaitable<void>\n\n /**\n * This hook is called when a user attempts to sign up, after every validation\n * has passed (including hcaptcha).\n */\n onSignUpAttempt?: (data: {\n input: SignUpInput\n deviceId: DeviceId\n deviceMetadata: RequestMetadata\n }) => Awaitable<void>\n\n /**\n * This hook is called when a user attempts to sign up, after the hcaptcha\n * `/siteverify` request has been made (and before the result is validated).\n */\n onHcaptchaResult?: (data: {\n input: SignUpInput\n deviceId: DeviceId\n deviceMetadata: RequestMetadata\n tokens: HcaptchaClientTokens\n result: HcaptchaVerifyResult\n }) => Awaitable<void>\n\n /**\n * This hook is called when a user requests a password reset, before the\n * reset password request is triggered on the account store. Use this to\n * potentially cancel the password reset.\n */\n onResetPasswordRequest?: (data: {\n input: ResetPasswordRequestInput\n deviceId: DeviceId\n deviceMetadata: RequestMetadata\n }) => Awaitable<void>\n\n /**\n * This hook is called when a user requests a password reset, before the\n * reset password request is triggered on the account store. If not account\n * was found for the provided identifier, the `account` field will be `null`.\n */\n onResetPasswordRequested?: (data: {\n input: ResetPasswordRequestInput\n deviceId: DeviceId\n deviceMetadata: RequestMetadata\n account: Account | null\n }) => Awaitable<void>\n\n /**\n * This hook is called when a user confirms a password reset, before the\n * password is actually reset on the account store.\n */\n onResetPasswordConfirm?: (data: {\n input: ResetPasswordConfirmInput\n deviceId: DeviceId\n deviceMetadata: RequestMetadata\n }) => Awaitable<void>\n\n /**\n * This hook is called after a user confirms a password reset, and the\n * password was successfully reset on the account store.\n */\n onResetPasswordConfirmed?: (data: {\n input: ResetPasswordConfirmInput\n deviceId: DeviceId\n deviceMetadata: RequestMetadata\n account: Account\n }) => Awaitable<void>\n\n /**\n * This hook is called when a user successfully signs up.\n *\n * @throws {AccessDeniedError} to deny the sign-up\n */\n onSignedUp?: (data: {\n data: SignUpData\n account: Account\n deviceId: DeviceId\n deviceMetadata: RequestMetadata\n }) => Awaitable<void>\n\n /**\n * `clientId` is populated when the sign-in is submitted in the context of\n * an OAuth authorization request (i.e. the user is logging in to approve a\n * client); it is omitted for first-party sign-ins that happen outside any\n * authorization flow.\n */\n onSignInAttempt?: (data: {\n data: SignInData\n deviceId: DeviceId\n deviceMetadata: RequestMetadata\n clientId?: ClientId\n }) => Awaitable<void>\n\n /**\n * This hook is called when a user successfully signs in.\n *\n * `clientId` is populated when the sign-in is submitted in the context of\n * an OAuth authorization request; see {@link OAuthHooks.onSignInAttempt}.\n *\n * @throws {InvalidRequestError} when the sing-in should be denied\n */\n onSignedIn?: (data: {\n data: SignInData\n account: Account\n deviceId: DeviceId\n deviceMetadata: RequestMetadata\n clientId?: ClientId\n }) => Awaitable<void>\n\n /**\n * This hook is called when a sign-in attempt is rejected by the account\n * store due to invalid credentials (e.g. unknown identifier, wrong\n * password). It is *not* called for unexpected server errors, nor for flows\n * that require an additional authentication factor.\n *\n * `sub` is populated when the store throws an\n * {@link InvalidCredentialsError} that carries the matched subject\n * identifier (i.e. identifier known, credentials wrong). It is `null` when\n * the identifier was unknown or when the store threw a plain\n * {@link InvalidRequestError} without distinguishing the two cases.\n *\n * `clientId` is populated when the sign-in is submitted in the context of\n * an OAuth authorization request; see {@link OAuthHooks.onSignInAttempt}.\n *\n * Errors thrown from this hook are caught and ignored so that they do not\n * mask the original authentication failure.\n */\n onSignInFailed?: (data: {\n data: SignInData\n error: InvalidRequestError\n sub: Sub | null\n deviceId: DeviceId\n deviceMetadata: RequestMetadata\n clientId?: ClientId\n }) => Awaitable<void>\n\n /**\n * Allows validating an authorization request (typically the requested scopes)\n * before it is created. Note that the validity against the client metadata is\n * already enforced by the OAuth provider.\n *\n * @throws {AuthorizationError}\n */\n onAuthorizationRequest?: (data: {\n client: Client\n clientAuth: null | ClientAuth\n parameters: Readonly<OAuthAuthorizationRequestParameters>\n }) => Awaitable<void>\n\n /**\n * This hook is called when a client is authorized.\n *\n * @throws {AuthorizationError} to deny the authorization request and redirect\n * the user to the client with an OAuth error (other errors will result in an\n * internal server error being displayed to the user)\n *\n * @note We use `deviceMetadata` instead of `clientMetadata` to make it clear\n * that this metadata is from the user device, which might be different from\n * the client metadata (because the OAuth client could live in a backend).\n */\n onAuthorized?: (data: {\n client: Client\n account: Account\n parameters: OAuthAuthorizationRequestParameters\n deviceId: DeviceId\n deviceMetadata: RequestMetadata\n requestId: RequestId\n }) => Awaitable<void>\n\n /**\n * This hook is called whenever a token is about to be created. You can use\n * it to modify the token claims or perform additional validation.\n *\n * This hook should never throw an error.\n */\n onCreateToken?: (data: {\n client: Client\n account: Account\n parameters: OAuthAuthorizationRequestParameters\n claims: TokenClaims\n }) => Awaitable<void | OmitKey<AccessTokenPayload, 'iss'>>\n\n /**\n * This hook is called whenever a token was just decoded, and basic validation\n * was performed (signature, expiration, not-before).\n *\n * It can be used to modify the payload (e.g., to add custom claims), or to\n * perform additional validation.\n *\n * This hook is called when authenticating requests through the\n * `authenticateRequest()` method in `OAuthVerifier` and `OAuthProvider`.\n *\n * Any error thrown here will be propagated.\n */\n onDecodeToken?: (data: {\n tokenType: OAuthTokenType\n token: OAuthAccessToken\n payload: AccessTokenPayload\n dpopProof: null | DpopProof\n }) => Promise<AccessTokenPayload | void>\n\n /**\n * This hook is called when an authorized client exchanges an authorization\n * code for an access token.\n *\n * @throws {OAuthError} to cancel the token creation and revoke the session\n */\n onTokenCreated?: (data: {\n client: Client\n clientAuth: ClientAuth\n clientMetadata: RequestMetadata\n account: Account\n parameters: OAuthAuthorizationRequestParameters\n }) => Awaitable<void>\n\n /**\n * This hook is called when an authorized client refreshes an access token.\n *\n * @throws {OAuthError} to cancel the token refresh and revoke the session\n */\n onTokenRefreshed?: (data: {\n client: Client\n clientAuth: ClientAuth\n clientMetadata: RequestMetadata\n account: Account\n parameters: OAuthAuthorizationRequestParameters\n }) => Awaitable<void>\n}\n"]}
@@ -18,12 +18,13 @@ export function oauthMiddleware(server, { ...options } = {}) {
18
18
  return onError?.(req, res, err, msg);
19
19
  }
20
20
  : onError;
21
- return asHandler(combineMiddlewares([
21
+ const middleware = combineMiddlewares([
22
22
  assetsMiddleware,
23
23
  createOAuthMiddleware(server, options),
24
24
  createApiMiddleware(server, options),
25
25
  createAuthorizationPageMiddleware(server, options),
26
26
  createAccountPageMiddleware(server, options),
27
- ]));
27
+ ]);
28
+ return asHandler(middleware);
28
29
  }
29
30
  //# sourceMappingURL=oauth-middleware.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"oauth-middleware.js","sourceRoot":"","sources":["../src/oauth-middleware.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAA;AAGxE,OAAO,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAA;AAC5D,OAAO,EAAE,2BAA2B,EAAE,MAAM,4CAA4C,CAAA;AACxF,OAAO,EAAE,mBAAmB,EAAE,MAAM,mCAAmC,CAAA;AACvE,OAAO,EAAE,iCAAiC,EAAE,MAAM,kDAAkD,CAAA;AACpG,OAAO,EAAE,qBAAqB,EAAE,MAAM,qCAAqC,CAAA;AAa3E;;;GAGG;AACH,MAAM,UAAU,eAAe,CAI7B,MAAqB,EACrB,EAAE,GAAG,OAAO,KAAkC,EAAE;IAEhD,MAAM,EAAE,OAAO,EAAE,GAAG,OAAO,CAAA;IAE3B,sDAAsD;IACtD,OAAO,CAAC,OAAO;QACb,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,KAAK,aAAa;YACvC,CAAC,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE;gBACrB,OAAO,CAAC,KAAK,CAAC,wBAAwB,GAAG,IAAI,EAAE,GAAG,CAAC,CAAA;gBACnD,OAAO,OAAO,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAA;YACtC,CAAC;YACH,CAAC,CAAC,OAAO,CAAA;IAEb,OAAO,SAAS,CACd,kBAAkB,CAAC;QACjB,gBAAgB;QAChB,qBAAqB,CAAC,MAAM,EAAE,OAAO,CAAC;QACtC,mBAAmB,CAAC,MAAM,EAAE,OAAO,CAAC;QACpC,iCAAiC,CAAC,MAAM,EAAE,OAAO,CAAC;QAClD,2BAA2B,CAAC,MAAM,EAAE,OAAO,CAAC;KAC7C,CAAC,CACH,CAAA;AACH,CAAC","sourcesContent":["import type { IncomingMessage, ServerResponse } from 'node:http'\nimport { asHandler, combineMiddlewares } from './lib/http/middleware.js'\nimport { Handler } from './lib/http/types.js'\nimport { OAuthProvider } from './oauth-provider.js'\nimport { assetsMiddleware } from './router/assets/assets.js'\nimport { createAccountPageMiddleware } from './router/create-account-page-middleware.js'\nimport { createApiMiddleware } from './router/create-api-middleware.js'\nimport { createAuthorizationPageMiddleware } from './router/create-authorization-page-middleware.js'\nimport { createOAuthMiddleware } from './router/create-oauth-middleware.js'\nimport { ErrorHandler } from './router/error-handler.js'\nimport { MiddlewareOptions } from './router/middleware-options.js'\n\n// Export all the types exposed\nexport type {\n ErrorHandler,\n Handler,\n IncomingMessage,\n MiddlewareOptions,\n ServerResponse,\n}\n\n/**\n * @returns An http request handler that can be used with node's http server\n * or as a middleware with express / connect.\n */\nexport function oauthMiddleware<\n Req extends IncomingMessage = IncomingMessage,\n Res extends ServerResponse = ServerResponse,\n>(\n server: OAuthProvider,\n { ...options }: MiddlewareOptions<Req, Res> = {},\n): Handler<void, Req, Res> {\n const { onError } = options\n\n // options is shallow cloned so it's fine to mutate it\n options.onError =\n process.env['NODE_ENV'] === 'development'\n ? (req, res, err, msg) => {\n console.error(`OAuthProvider error (${msg}):`, err)\n return onError?.(req, res, err, msg)\n }\n : onError\n\n return asHandler(\n combineMiddlewares([\n assetsMiddleware,\n createOAuthMiddleware(server, options),\n createApiMiddleware(server, options),\n createAuthorizationPageMiddleware(server, options),\n createAccountPageMiddleware(server, options),\n ]),\n )\n}\n"]}
1
+ {"version":3,"file":"oauth-middleware.js","sourceRoot":"","sources":["../src/oauth-middleware.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAA;AAGxE,OAAO,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAA;AAC5D,OAAO,EAAE,2BAA2B,EAAE,MAAM,4CAA4C,CAAA;AACxF,OAAO,EAAE,mBAAmB,EAAE,MAAM,mCAAmC,CAAA;AACvE,OAAO,EAAE,iCAAiC,EAAE,MAAM,kDAAkD,CAAA;AACpG,OAAO,EAAE,qBAAqB,EAAE,MAAM,qCAAqC,CAAA;AAa3E;;;GAGG;AACH,MAAM,UAAU,eAAe,CAI7B,MAAqB,EACrB,EAAE,GAAG,OAAO,KAAkC,EAAE;IAEhD,MAAM,EAAE,OAAO,EAAE,GAAG,OAAO,CAAA;IAE3B,sDAAsD;IACtD,OAAO,CAAC,OAAO;QACb,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,KAAK,aAAa;YACvC,CAAC,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE;gBACrB,OAAO,CAAC,KAAK,CAAC,wBAAwB,GAAG,IAAI,EAAE,GAAG,CAAC,CAAA;gBACnD,OAAO,OAAO,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAA;YACtC,CAAC;YACH,CAAC,CAAC,OAAO,CAAA;IAEb,MAAM,UAAU,GAAG,kBAAkB,CAAC;QACpC,gBAAgB;QAChB,qBAAqB,CAAC,MAAM,EAAE,OAAO,CAAC;QACtC,mBAAmB,CAAC,MAAM,EAAE,OAAO,CAAC;QACpC,iCAAiC,CAAC,MAAM,EAAE,OAAO,CAAC;QAClD,2BAA2B,CAAC,MAAM,EAAE,OAAO,CAAC;KAC7C,CAAC,CAAA;IAEF,OAAO,SAAS,CAAC,UAAU,CAAC,CAAA;AAC9B,CAAC","sourcesContent":["import type { IncomingMessage, ServerResponse } from 'node:http'\nimport { asHandler, combineMiddlewares } from './lib/http/middleware.js'\nimport { Handler } from './lib/http/types.js'\nimport { OAuthProvider } from './oauth-provider.js'\nimport { assetsMiddleware } from './router/assets/assets.js'\nimport { createAccountPageMiddleware } from './router/create-account-page-middleware.js'\nimport { createApiMiddleware } from './router/create-api-middleware.js'\nimport { createAuthorizationPageMiddleware } from './router/create-authorization-page-middleware.js'\nimport { createOAuthMiddleware } from './router/create-oauth-middleware.js'\nimport { ErrorHandler } from './router/error-handler.js'\nimport { MiddlewareOptions } from './router/middleware-options.js'\n\n// Export all the types exposed\nexport type {\n ErrorHandler,\n Handler,\n IncomingMessage,\n MiddlewareOptions,\n ServerResponse,\n}\n\n/**\n * @returns An http request handler that can be used with node's http server\n * or as a middleware with express / connect.\n */\nexport function oauthMiddleware<\n Req extends IncomingMessage = IncomingMessage,\n Res extends ServerResponse = ServerResponse,\n>(\n server: OAuthProvider,\n { ...options }: MiddlewareOptions<Req, Res> = {},\n): Handler<void, Req, Res> {\n const { onError } = options\n\n // options is shallow cloned so it's fine to mutate it\n options.onError =\n process.env['NODE_ENV'] === 'development'\n ? (req, res, err, msg) => {\n console.error(`OAuthProvider error (${msg}):`, err)\n return onError?.(req, res, err, msg)\n }\n : onError\n\n const middleware = combineMiddlewares([\n assetsMiddleware,\n createOAuthMiddleware(server, options),\n createApiMiddleware(server, options),\n createAuthorizationPageMiddleware(server, options),\n createAccountPageMiddleware(server, options),\n ])\n\n return asHandler(middleware)\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"create-api-middleware.d.ts","sourceRoot":"","sources":["../../src/router/create-api-middleware.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,WAAW,CAAA;AA8BhE,OAAO,EAEL,UAAU,EAaX,MAAM,sBAAsB,CAAA;AAK7B,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAA;AAUzD,OAAO,EAEL,oBAAoB,EAMrB,MAAM,2BAA2B,CAAA;AAClC,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAA;AAIhE,wBAAgB,mBAAmB,CACjC,GAAG,SAAS,MAAM,GAAG,IAAI,GAAG,IAAI,EAChC,GAAG,SAAS,eAAe,GAAG,eAAe,EAC7C,GAAG,SAAS,cAAc,GAAG,cAAc,EAE3C,MAAM,EAAE,aAAa,EACrB,EAAE,OAAO,EAAE,EAAE,iBAAiB,CAAC,GAAG,EAAE,GAAG,CAAC,GACvC,UAAU,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CA6yB3B;AA2BD,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,GAAG,GAAG,oBAAoB,CA4C/D"}
1
+ {"version":3,"file":"create-api-middleware.d.ts","sourceRoot":"","sources":["../../src/router/create-api-middleware.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,WAAW,CAAA;AA8BhE,OAAO,EAEL,UAAU,EAaX,MAAM,sBAAsB,CAAA;AAK7B,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAA;AAUzD,OAAO,EAEL,oBAAoB,EAMrB,MAAM,2BAA2B,CAAA;AAClC,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAA;AAIhE,wBAAgB,mBAAmB,CACjC,GAAG,SAAS,MAAM,GAAG,IAAI,GAAG,IAAI,EAChC,GAAG,SAAS,eAAe,GAAG,eAAe,EAC7C,GAAG,SAAS,cAAc,GAAG,cAAc,EAE3C,MAAM,EAAE,aAAa,EACrB,EAAE,OAAO,EAAE,EAAE,iBAAiB,CAAC,GAAG,EAAE,GAAG,CAAC,GACvC,UAAU,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAs0B3B;AA2BD,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,GAAG,GAAG,oBAAoB,CA4C/D"}
@@ -175,8 +175,8 @@ export function createApiMiddleware(server, { onError }) {
175
175
  schema: z
176
176
  .object({
177
177
  sub: subSchema,
178
- token: emailOtpSchema,
179
178
  email: emailSchema,
179
+ token: emailOtpSchema.optional(),
180
180
  locale: localeSchema.optional(),
181
181
  })
182
182
  .strict(),
@@ -217,6 +217,21 @@ export function createApiMiddleware(server, { onError }) {
217
217
  return { json: { success: true } };
218
218
  },
219
219
  }));
220
+ router.use(apiRoute({
221
+ method: 'POST',
222
+ endpoint: '/update-handle',
223
+ schema: z
224
+ .object({
225
+ sub: subSchema,
226
+ handle: handleSchema,
227
+ })
228
+ .strict(),
229
+ async handler(req, res) {
230
+ const { account } = await authenticate.call(this, req, res);
231
+ await server.accountManager.updateHandle(this.deviceId, this.deviceMetadata, this.input, account);
232
+ return { json: { success: true } };
233
+ },
234
+ }));
220
235
  router.use(apiRoute({
221
236
  method: 'GET',
222
237
  endpoint: '/device-sessions',
@@ -1 +1 @@
1
- {"version":3,"file":"create-api-middleware.js","sourceRoot":"","sources":["../../src/router/create-api-middleware.ts"],"names":[],"mappings":"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","sourcesContent":["import type { IncomingMessage, ServerResponse } from 'node:http'\nimport createHttpError from 'http-errors'\nimport { z } from 'zod'\nimport { signedJwtSchema } from '@atproto/jwk'\nimport {\n API_ENDPOINT_PREFIX,\n ActiveAccountSession,\n ActiveDeviceSession,\n ActiveOAuthSession,\n ApiEndpoints,\n ISODateString,\n} from '@atproto/oauth-provider-api'\nimport {\n OAuthAuthorizationRequestParameters,\n OAuthRedirectUri,\n OAuthResponseMode,\n oauthRedirectUriSchema,\n oauthResponseModeSchema,\n} from '@atproto/oauth-types'\nimport { signInDataSchema } from '../account/sign-in-data.js'\nimport { signUpInputSchema } from '../account/sign-up-input.js'\nimport { DeviceId, deviceIdSchema } from '../device/device-id.js'\nimport { AuthorizationError } from '../errors/authorization-error.js'\nimport {\n ErrorPayload,\n buildErrorPayload,\n buildErrorStatus,\n} from '../errors/error-parser.js'\nimport { InvalidRequestError } from '../errors/invalid-request-error.js'\nimport { WWWAuthenticateError } from '../errors/www-authenticate-error.js'\nimport {\n JsonResponse,\n Middleware,\n RequestMetadata,\n Router,\n RouterCtx,\n SubCtx,\n flushStream,\n jsonHandler,\n parseHttpRequest,\n subCtx,\n validateFetchMode,\n validateFetchSite,\n validateOrigin,\n validateReferrer,\n} from '../lib/http/index.js'\nimport { RouteCtx, createRoute } from '../lib/http/route.js'\nimport { asArray } from '../lib/util/cast.js'\nimport { localeSchema } from '../lib/util/locale.js'\nimport type { Awaitable } from '../lib/util/type.js'\nimport type { OAuthProvider } from '../oauth-provider.js'\nimport { Sub, subSchema } from '../oidc/sub.js'\nimport { RequestUri, requestUriSchema } from '../request/request-uri.js'\nimport { AuthorizationRedirectParameters } from '../result/authorization-redirect-parameters.js'\nimport { tokenIdSchema } from '../token/token-id.js'\nimport { emailOtpSchema } from '../types/email-otp.js'\nimport { emailSchema } from '../types/email.js'\nimport { handleSchema } from '../types/handle.js'\nimport { newPasswordSchema } from '../types/password.js'\nimport { validateCsrfToken } from './assets/csrf.js'\nimport {\n ERROR_REDIRECT_KEYS,\n OAuthRedirectOptions,\n OAuthRedirectQueryParameter,\n SUCCESS_REDIRECT_KEYS,\n buildRedirectMode,\n buildRedirectParams,\n buildRedirectUri,\n} from './assets/send-redirect.js'\nimport type { MiddlewareOptions } from './middleware-options.js'\n\nconst verifyHandleSchema = z.object({ handle: handleSchema }).strict()\n\nexport function createApiMiddleware<\n Ctx extends object | void = void,\n Req extends IncomingMessage = IncomingMessage,\n Res extends ServerResponse = ServerResponse,\n>(\n server: OAuthProvider,\n { onError }: MiddlewareOptions<Req, Res>,\n): Middleware<Ctx, Req, Res> {\n const issuerUrl = new URL(server.issuer)\n const issuerOrigin = issuerUrl.origin\n const router = new Router<Ctx, Req, Res>(issuerUrl)\n\n router.use(\n apiRoute({\n method: 'POST',\n endpoint: '/verify-handle-availability',\n schema: verifyHandleSchema,\n async handler() {\n await server.accountManager.verifyHandleAvailability(this.input.handle)\n return { json: { available: true } }\n },\n }),\n )\n\n router.use(\n apiRoute({\n method: 'POST',\n endpoint: '/sign-up',\n schema: signUpInputSchema,\n rotateDeviceCookies: true,\n async handler() {\n const { deviceId, deviceMetadata, input, requestUri } = this\n\n const account = await server.accountManager.createAccount(\n deviceId,\n deviceMetadata,\n input,\n )\n\n // Remember when not in the context of a request by default\n const remember = requestUri == null\n\n // Only \"remember\" the newly created account if it was not created during an\n // OAuth flow.\n if (remember) {\n await server.accountManager.upsertDeviceAccount(deviceId, account.sub)\n }\n\n const ephemeralToken = remember\n ? undefined\n : await server.signer.createEphemeralToken({\n sub: account.sub,\n deviceId,\n requestUri: this.requestUri,\n })\n\n const json = { account, ephemeralToken }\n return { json }\n },\n }),\n )\n\n router.use(\n apiRoute({\n method: 'POST',\n endpoint: '/sign-in',\n schema: signInDataSchema.extend({ remember: z.boolean().optional() }),\n rotateDeviceCookies: true,\n async handler() {\n const { deviceId, deviceMetadata, requestUri } = this\n\n // Remember when not in the context of a request by default\n const { remember = requestUri == null, ...input } = this.input\n\n // Look up the client identifier associated with the pending OAuth\n // request, if any, so it can be surfaced to the sign-in hooks.\n const clientId = requestUri\n ? await server.requestManager.peekClientId(requestUri)\n : undefined\n\n const account = await server.accountManager.authenticateAccount(\n deviceId,\n deviceMetadata,\n input,\n clientId,\n )\n\n if (remember) {\n await server.accountManager.upsertDeviceAccount(deviceId, account.sub)\n } else {\n // In case the user was already signed in, and signed in again, this\n // time without \"remember me\", let's sign them off of the device.\n await server.accountManager.removeDeviceAccount(deviceId, account.sub)\n }\n\n const ephemeralToken = remember\n ? undefined\n : await server.signer.createEphemeralToken({\n sub: account.sub,\n deviceId,\n requestUri,\n })\n\n if (requestUri) {\n // Check if a consent is required for the client, but only if this\n // call is made within the context of an oauth request.\n\n const { clientId, parameters } = await server.requestManager.get(\n requestUri,\n deviceId,\n )\n\n const { authorizedClients } = await server.accountManager.getAccount(\n account.sub,\n )\n\n const json = {\n account,\n ephemeralToken,\n consentRequired: server.checkConsentRequired(\n parameters,\n authorizedClients.get(clientId),\n ),\n }\n\n return { json }\n }\n\n const json = { account, ephemeralToken }\n return { json }\n },\n }),\n )\n\n router.use(\n apiRoute({\n method: 'POST',\n endpoint: '/sign-out',\n schema: z\n .object({\n sub: z.union([subSchema, z.array(subSchema)]),\n })\n .strict(),\n rotateDeviceCookies: true,\n async handler() {\n const uniqueSubs = new Set(asArray(this.input.sub))\n\n for (const sub of uniqueSubs) {\n await server.accountManager.removeDeviceAccount(this.deviceId, sub)\n }\n\n return { json: { success: true as const } }\n },\n }),\n )\n\n router.use(\n apiRoute({\n method: 'POST',\n endpoint: '/reset-password-request',\n schema: z\n .object({\n locale: localeSchema,\n email: emailSchema,\n })\n .strict(),\n async handler() {\n await server.accountManager.resetPasswordRequest(\n this.deviceId,\n this.deviceMetadata,\n this.input,\n )\n return { json: { success: true } }\n },\n }),\n )\n\n router.use(\n apiRoute({\n method: 'POST',\n endpoint: '/reset-password-confirm',\n schema: z\n .object({\n token: emailOtpSchema,\n password: newPasswordSchema,\n })\n .strict(),\n async handler() {\n await server.accountManager.resetPasswordConfirm(\n this.deviceId,\n this.deviceMetadata,\n this.input,\n )\n return { json: { success: true } }\n },\n }),\n )\n\n router.use(\n apiRoute({\n method: 'POST',\n endpoint: '/update-email-request',\n schema: z\n .object({\n sub: subSchema,\n locale: localeSchema.optional(),\n })\n .strict(),\n async handler(req, res) {\n const { account } = await authenticate.call(this, req, res)\n\n const { tokenRequired } =\n await server.accountManager.updateEmailRequest(\n this.deviceId,\n this.deviceMetadata,\n this.input,\n account,\n )\n\n return { json: { tokenRequired } }\n },\n }),\n )\n\n router.use(\n apiRoute({\n method: 'POST',\n endpoint: '/update-email-confirm',\n schema: z\n .object({\n sub: subSchema,\n token: emailOtpSchema,\n email: emailSchema,\n locale: localeSchema.optional(),\n })\n .strict(),\n async handler(req, res) {\n const { account } = await authenticate.call(this, req, res)\n\n await server.accountManager.updateEmailConfirm(\n this.deviceId,\n this.deviceMetadata,\n this.input,\n account,\n )\n\n return { json: { success: true } }\n },\n }),\n )\n\n router.use(\n apiRoute({\n method: 'POST',\n endpoint: '/verify-email-request',\n schema: z\n .object({\n sub: subSchema,\n locale: localeSchema.optional(),\n })\n .strict(),\n async handler(req, res) {\n const { account } = await authenticate.call(this, req, res)\n\n await server.accountManager.verifyEmailRequest(\n this.deviceId,\n this.deviceMetadata,\n this.input,\n account,\n )\n\n return { json: { success: true } }\n },\n }),\n )\n\n router.use(\n apiRoute({\n method: 'POST',\n endpoint: '/verify-email-confirm',\n schema: z\n .object({\n sub: subSchema,\n token: emailOtpSchema,\n email: emailSchema,\n })\n .strict(),\n async handler(req, res) {\n const { account } = await authenticate.call(this, req, res)\n\n await server.accountManager.verifyEmailConfirm(\n this.deviceId,\n this.deviceMetadata,\n this.input,\n account,\n )\n\n return { json: { success: true } }\n },\n }),\n )\n\n router.use(\n apiRoute({\n method: 'GET',\n endpoint: '/device-sessions',\n schema: undefined,\n async handler() {\n const deviceAccounts = await server.accountManager.listDeviceAccounts(\n this.deviceId,\n )\n\n const json = deviceAccounts.map(\n (deviceAccount): ActiveDeviceSession => ({\n account: deviceAccount.account,\n loginRequired: server.checkLoginRequired(deviceAccount),\n }),\n )\n\n return { json }\n },\n }),\n )\n\n router.use(\n apiRoute({\n method: 'GET',\n endpoint: '/oauth-sessions',\n schema: z.object({ sub: subSchema }).strict(),\n async handler(req, res) {\n const { account } = await authenticate.call(this, req, res)\n\n const tokenInfos = await server.tokenManager.listAccountTokens(\n account.sub,\n )\n\n const clientIds = tokenInfos.map((tokenInfo) => tokenInfo.data.clientId)\n\n const clients = await server.clientManager.loadClients(clientIds, {\n onError: (err, clientId) => {\n onError?.(req, res, err, `Failed to load client ${clientId}`)\n return undefined // metadata won't be available in the UI\n },\n })\n\n // @TODO: We should ideally filter sessions that are expired (or even\n // expose the expiration date). This requires a change to the way\n // TokenInfo are stored (see TokenManager#isTokenExpired and\n // TokenManager#isTokenInactive).\n const json = tokenInfos.map(({ id, data }): ActiveOAuthSession => {\n return {\n tokenId: id,\n\n createdAt: data.createdAt.toISOString() as ISODateString,\n updatedAt: data.updatedAt.toISOString() as ISODateString,\n\n clientId: data.clientId,\n clientMetadata: clients.get(data.clientId)?.metadata,\n\n scope: data.parameters.scope,\n }\n })\n\n return { json }\n },\n }),\n )\n\n router.use(\n apiRoute({\n method: 'GET',\n endpoint: '/account-sessions',\n schema: z.object({ sub: subSchema }).strict(),\n async handler(req, res) {\n const { account } = await authenticate.call(this, req, res)\n\n const deviceAccounts = await server.accountManager.listAccountDevices(\n account.sub,\n )\n\n const json = deviceAccounts.map(\n (accountSession): ActiveAccountSession => ({\n deviceId: accountSession.deviceId,\n deviceMetadata: {\n ipAddress: accountSession.deviceData.ipAddress,\n userAgent: accountSession.deviceData.userAgent,\n lastSeenAt:\n accountSession.deviceData.lastSeenAt.toISOString() as ISODateString,\n },\n\n isCurrentDevice: accountSession.deviceId === this.deviceId,\n }),\n )\n\n return { json }\n },\n }),\n )\n\n router.use(\n apiRoute({\n method: 'POST',\n endpoint: '/revoke-account-session',\n schema: z.object({ sub: subSchema, deviceId: deviceIdSchema }).strict(),\n async handler() {\n // @NOTE This route is not authenticated. If a user is able to steal\n // another user's session cookie, we allow them to revoke the device\n // session.\n\n await server.accountManager.removeDeviceAccount(\n this.input.deviceId,\n this.input.sub,\n )\n\n return { json: { success: true } }\n },\n }),\n )\n\n router.use(\n apiRoute({\n method: 'POST',\n endpoint: '/revoke-oauth-session',\n schema: z.object({ sub: subSchema, tokenId: tokenIdSchema }).strict(),\n async handler(req, res) {\n const { account } = await authenticate.call(this, req, res)\n\n const tokenInfo = await server.tokenManager.getTokenInfo(\n this.input.tokenId,\n )\n\n if (!tokenInfo || tokenInfo.account.sub !== account.sub) {\n // report this as though the token was not found\n throw new InvalidRequestError(`Invalid token`)\n }\n\n await server.tokenManager.deleteToken(tokenInfo.id)\n\n return { json: { success: true } }\n },\n }),\n )\n\n router.use(\n apiRoute({\n method: 'POST',\n endpoint: '/consent',\n schema: z\n .object({\n sub: z.union([subSchema, signedJwtSchema]),\n scope: z.string().optional(),\n })\n .strict(),\n async handler(req, res) {\n if (!this.requestUri) {\n throw new InvalidRequestError(\n 'This endpoint can only be used in the context of an OAuth request',\n )\n }\n\n // Any AuthorizationError caught in this block will result in a redirect\n // to the client's redirect_uri with an error.\n try {\n const { clientId, parameters } = await server.requestManager.get(\n this.requestUri,\n this.deviceId,\n )\n\n // Any error thrown in this block will be transformed into an\n // AuthorizationError.\n try {\n const { account, authorizedClients } = await authenticate.call(\n this,\n req,\n res,\n )\n\n const client = await server.clientManager.getClient(clientId)\n\n const code = await server.requestManager.setAuthorized(\n this.requestUri,\n client,\n account,\n this.deviceId,\n this.deviceMetadata,\n this.input.scope,\n )\n\n const clientData = authorizedClients.get(clientId)\n if (server.checkConsentRequired(parameters, clientData)) {\n const scopes = new Set(clientData?.authorizedScopes)\n\n // Add the newly accepted scopes to the authorized scopes\n\n // @NOTE `oauthScopeSchema` ensures that `scope` contains no\n // leading/trailing/duplicate spaces.\n for (const s of parameters.scope?.split(' ') ?? []) scopes.add(s)\n\n await server.accountManager.setAuthorizedClient(account, client, {\n ...clientData,\n authorizedScopes: [...scopes],\n })\n }\n\n const url = buildRedirectUrl(server.issuer, parameters, { code })\n\n return { json: { url } }\n } catch (err) {\n // Since we have access to the parameters, we can re-throw an\n // AuthorizationError with the redirect_uri parameter.\n throw AuthorizationError.from(parameters, err)\n }\n } catch (err) {\n onError?.(req, res, err, 'Failed to consent authorization request')\n\n // If any error happened (unauthenticated, invalid request, etc.),\n // lets make sure the request can no longer be used.\n try {\n await server.requestManager.delete(this.requestUri)\n } catch (err) {\n onError?.(req, res, err, 'Failed to delete request')\n }\n\n if (err instanceof AuthorizationError) {\n try {\n const url = buildRedirectUrl(\n server.issuer,\n err.parameters,\n err.toJSON(),\n )\n\n return { json: { url } }\n } catch {\n // Unable to build redirect URL, ignore\n }\n }\n\n // @NOTE Not re-throwing the error here, as the error was already\n // handled by the `onError` callback, and apiRoute (`apiMiddleware`)\n // would call `onError` again.\n return buildErrorJsonResponse(err)\n }\n },\n }),\n )\n\n router.use(\n apiRoute({\n method: 'POST',\n endpoint: '/reject',\n schema: z.object({}).strict(),\n rotateDeviceCookies: true,\n async handler(req, res) {\n const { requestUri } = this\n if (!requestUri) {\n throw new InvalidRequestError(\n 'This endpoint can only be used in the context of an OAuth request',\n )\n }\n\n // Once this endpoint is called, the request will definitely be\n // rejected.\n try {\n // No need to authenticate the user here as they are not authorizing a\n // particular account (CSRF protection is enough).\n\n // @NOTE that the client could *technically* trigger this endpoint while\n // the user is on the authorize page by forging the request (because the\n // client knows the RequestURI from PAR and has all the info needed to\n // forge the request, including CSRF). This cannot be used as DoS attack\n // as the request ID is not guessable and would only result in a bad UX\n // for misbehaving clients, only for the users of those clients.\n\n const { parameters } = await server.requestManager.get(\n requestUri,\n this.deviceId,\n )\n\n const url = buildRedirectUrl(server.issuer, parameters, {\n error: 'access_denied',\n error_description: 'The user rejected the request',\n })\n\n return { json: { url } }\n } catch (err) {\n onError?.(req, res, err, 'Failed to reject authorization request')\n\n if (err instanceof AuthorizationError) {\n try {\n const url = buildRedirectUrl(\n server.issuer,\n err.parameters,\n err.toJSON(),\n )\n\n return { json: { url } }\n } catch {\n // Unable to build redirect URL, ignore\n }\n }\n\n return buildErrorJsonResponse(err)\n } finally {\n await server.requestManager.delete(requestUri).catch((err) => {\n onError?.(req, res, err, 'Failed to delete request')\n })\n }\n },\n }),\n )\n\n return router.buildMiddleware()\n\n async function authenticate(\n this: ApiContext<void, { sub: Sub }>,\n req: Req,\n _res: Res,\n ) {\n if (req.headers.authorization?.startsWith('Bearer ')) {\n try {\n // If there is an authorization header, verify that the ephemeral token it\n // contains is a jwt bound to the right [sub, device, request].\n const bearer = req.headers.authorization.slice(7)\n const ephemeralToken = signedJwtSchema.parse(bearer)\n const { payload } =\n await server.signer.verifyEphemeralToken(ephemeralToken)\n\n if (\n payload.sub === this.input.sub &&\n payload.deviceId === this.deviceId &&\n payload.requestUri === this.requestUri\n ) {\n return await server.accountManager.getAccount(payload.sub)\n }\n } catch (err) {\n throw new WWWAuthenticateError(\n 'unauthorized',\n `Invalid or expired bearer token`,\n { Bearer: {} },\n err,\n )\n }\n }\n\n try {\n // Ensures the \"sub\" has an active session on the device\n const deviceAccount = await server.accountManager.getDeviceAccount(\n this.deviceId,\n this.input.sub,\n )\n\n // The session exists but was created too long ago\n if (server.checkLoginRequired(deviceAccount)) {\n throw new InvalidRequestError('Login required')\n }\n\n return deviceAccount\n } catch (err) {\n throw new WWWAuthenticateError(\n 'unauthorized',\n `User ${this.input.sub} not authenticated on this device`,\n { Bearer: {} },\n err,\n )\n }\n }\n\n type ApiContext<T extends object | void, I = void> = SubCtx<\n T,\n {\n deviceId: DeviceId\n deviceMetadata: RequestMetadata\n\n /**\n * The parsed input data (json payload if \"POST\", query params if \"GET\").\n */\n input: I\n\n /**\n * When defined, the request originated from the authorize page.\n */\n requestUri?: RequestUri\n }\n >\n\n type InferValidation<S extends void | z.ZodTypeAny> = S extends z.ZodTypeAny\n ? z.infer<S>\n : void\n\n /**\n * The main purpose of this function is to ensure that the endpoint\n * implementation matches its type definition from {@link ApiEndpoints}.\n * @private\n */\n function apiRoute<\n C extends RouterCtx<Ctx>,\n M extends 'GET' | 'POST',\n E extends `/${string}` &\n // Extract all the endpoint path that match the method (allows for\n // auto-complete & better error reporting)\n {\n [E in keyof ApiEndpoints]: ApiEndpoints[E] extends { method: M }\n ? E\n : never\n }[keyof ApiEndpoints],\n S extends // A schema that validates the POST input or GET params\n ApiEndpoints[E] extends { method: 'POST'; input: infer I }\n ? z.ZodType<I>\n : ApiEndpoints[E] extends { method: 'GET'; params: infer P }\n ? z.ZodType<P>\n : void,\n >(options: {\n method: M\n endpoint: E\n schema: S\n rotateDeviceCookies?: boolean\n handler: (\n this: ApiContext<RouteCtx<C>, InferValidation<S>>,\n req: Req,\n res: Res,\n ) => Awaitable<JsonResponse<ErrorPayload | ApiEndpoints[E]['output']>>\n }): Middleware<C, Req, Res> {\n return createRoute(\n options.method,\n `${API_ENDPOINT_PREFIX}${options.endpoint}`,\n apiMiddleware(options),\n )\n }\n\n function apiMiddleware<C extends RouterCtx, S extends void | z.ZodTypeAny>({\n method,\n schema,\n rotateDeviceCookies,\n handler,\n }: {\n method: 'GET' | 'POST'\n schema: S\n rotateDeviceCookies?: boolean\n handler: (\n this: ApiContext<C, InferValidation<S>>,\n req: Req,\n res: Res,\n ) => Awaitable<JsonResponse>\n }): Middleware<C, Req, Res> {\n const parseInput: (this: C, req: Req) => Promise<InferValidation<S>> =\n schema == null // No schema means endpoint doesn't accept any input\n ? async function (req) {\n await flushStream(req)\n return undefined\n }\n : method === 'POST'\n ? async function (req) {\n const body = await parseHttpRequest(req, ['json'])\n return schema.parseAsync(body, { path: ['body'] })\n }\n : async function (req) {\n await flushStream(req)\n const query = Object.fromEntries(this.url.searchParams)\n return schema.parseAsync(query, { path: ['query'] })\n }\n\n return jsonHandler<C, Req, Res>(async function (req, res) {\n try {\n // Prevent caching of API routes\n res.setHeader('Cache-Control', 'no-store')\n res.setHeader('Pragma', 'no-cache')\n\n // Prevent CORS requests\n validateFetchMode(req, ['same-origin'])\n validateFetchSite(req, ['same-origin'])\n validateOrigin(req, issuerOrigin)\n const referrer = validateReferrer(req, { origin: issuerOrigin })\n\n // Ensure we are one the right page\n if (\n // trailing slashes are not allowed\n referrer.pathname !== '/oauth/authorize' &&\n referrer.pathname !== '/account' &&\n !referrer.pathname.startsWith(`/account/`)\n ) {\n throw createHttpError(400, `Invalid referrer ${referrer}`)\n }\n\n // Check if the request originated from the authorize page\n const requestUri =\n referrer.pathname === '/oauth/authorize'\n ? await requestUriSchema.parseAsync(\n referrer.searchParams.get('request_uri'),\n )\n : undefined\n\n // Validate CSRF token\n await validateCsrfToken(req, res)\n\n // Parse and validate the input data\n const input = await parseInput.call(this, req)\n\n // Load session data, rotating the session cookie if needed\n const { deviceId, deviceMetadata } = await server.deviceManager.load(\n req,\n res,\n rotateDeviceCookies,\n )\n\n const context: ApiContext<C, InferValidation<S>> = subCtx(this, {\n input,\n requestUri,\n deviceId,\n deviceMetadata,\n })\n\n return await handler.call(context, req, res)\n } catch (err) {\n onError?.(req, res, err, `Failed to handle API request`)\n\n // Make sore to always return a JSON response\n return buildErrorJsonResponse(err)\n }\n })\n }\n}\n\nfunction buildErrorJsonResponse(err: unknown) {\n // @TODO Rework the API error responses (relying on codes)\n const json = buildErrorPayload(err)\n const status = buildErrorStatus(err)\n\n return { json, status }\n}\n\nfunction buildRedirectUrl(\n iss: string,\n parameters: OAuthAuthorizationRequestParameters,\n redirect: AuthorizationRedirectParameters,\n): string {\n const url = new URL('/oauth/authorize/redirect', iss)\n\n url.searchParams.set('redirect_mode', buildRedirectMode(parameters))\n url.searchParams.set('redirect_uri', buildRedirectUri(parameters))\n\n for (const [key, value] of buildRedirectParams(iss, parameters, redirect)) {\n url.searchParams.set(key, value)\n }\n\n return url.href\n}\n\nexport function parseRedirectUrl(url: URL): OAuthRedirectOptions {\n if (url.pathname !== '/oauth/authorize/redirect') {\n throw new InvalidRequestError(\n `Invalid redirect URL: ${url.pathname} is not a valid path`,\n )\n }\n\n const params: [OAuthRedirectQueryParameter, string][] = []\n\n const state = url.searchParams.get('state')\n if (state) params.push(['state', state])\n\n const iss = url.searchParams.get('iss')\n if (iss) params.push(['iss', iss])\n\n if (url.searchParams.has('code')) {\n for (const key of SUCCESS_REDIRECT_KEYS) {\n const value = url.searchParams.get(key)\n if (value != null) params.push([key, value])\n }\n } else if (url.searchParams.has('error')) {\n for (const key of ERROR_REDIRECT_KEYS) {\n const value = url.searchParams.get(key)\n if (value != null) params.push([key, value])\n }\n } else {\n throw new InvalidRequestError(\n 'Invalid redirect URL: neither code nor error found',\n )\n }\n\n try {\n const mode: OAuthResponseMode = oauthResponseModeSchema.parse(\n url.searchParams.get('redirect_mode'),\n )\n\n const redirectUri: OAuthRedirectUri = oauthRedirectUriSchema.parse(\n url.searchParams.get('redirect_uri'),\n )\n\n return { mode, redirectUri, params }\n } catch (err) {\n throw InvalidRequestError.from(err, 'Invalid redirect URL')\n }\n}\n"]}
1
+ {"version":3,"file":"create-api-middleware.js","sourceRoot":"","sources":["../../src/router/create-api-middleware.ts"],"names":[],"mappings":"AACA,OAAO,eAAe,MAAM,aAAa,CAAA;AACzC,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AACvB,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAA;AAC9C,OAAO,EACL,mBAAmB,GAMpB,MAAM,6BAA6B,CAAA;AACpC,OAAO,EAIL,sBAAsB,EACtB,uBAAuB,GACxB,MAAM,sBAAsB,CAAA;AAC7B,OAAO,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAA;AAC7D,OAAO,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAA;AAC/D,OAAO,EAAY,cAAc,EAAE,MAAM,wBAAwB,CAAA;AACjE,OAAO,EAAE,kBAAkB,EAAE,MAAM,kCAAkC,CAAA;AACrE,OAAO,EAEL,iBAAiB,EACjB,gBAAgB,GACjB,MAAM,2BAA2B,CAAA;AAClC,OAAO,EAAE,mBAAmB,EAAE,MAAM,oCAAoC,CAAA;AACxE,OAAO,EAAE,oBAAoB,EAAE,MAAM,qCAAqC,CAAA;AAC1E,OAAO,EAIL,MAAM,EAGN,WAAW,EACX,WAAW,EACX,gBAAgB,EAChB,MAAM,EACN,iBAAiB,EACjB,iBAAiB,EACjB,cAAc,EACd,gBAAgB,GACjB,MAAM,sBAAsB,CAAA;AAC7B,OAAO,EAAY,WAAW,EAAE,MAAM,sBAAsB,CAAA;AAC5D,OAAO,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAC7C,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAA;AAGpD,OAAO,EAAO,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAC/C,OAAO,EAAc,gBAAgB,EAAE,MAAM,2BAA2B,CAAA;AAExE,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAA;AACpD,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAA;AACtD,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAC/C,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AACjD,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAA;AACxD,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAA;AACpD,OAAO,EACL,mBAAmB,EAGnB,qBAAqB,EACrB,iBAAiB,EACjB,mBAAmB,EACnB,gBAAgB,GACjB,MAAM,2BAA2B,CAAA;AAGlC,MAAM,kBAAkB,GAAG,CAAC,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,YAAY,EAAE,CAAC,CAAC,MAAM,EAAE,CAAA;AAEtE,MAAM,UAAU,mBAAmB,CAKjC,MAAqB,EACrB,EAAE,OAAO,EAA+B;IAExC,MAAM,SAAS,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,CAAA;IACxC,MAAM,YAAY,GAAG,SAAS,CAAC,MAAM,CAAA;IACrC,MAAM,MAAM,GAAG,IAAI,MAAM,CAAgB,SAAS,CAAC,CAAA;IAEnD,MAAM,CAAC,GAAG,CACR,QAAQ,CAAC;QACP,MAAM,EAAE,MAAM;QACd,QAAQ,EAAE,6BAA6B;QACvC,MAAM,EAAE,kBAAkB;QAC1B,KAAK,CAAC,OAAO;YACX,MAAM,MAAM,CAAC,cAAc,CAAC,wBAAwB,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAA;YACvE,OAAO,EAAE,IAAI,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,EAAE,CAAA;QACtC,CAAC;KACF,CAAC,CACH,CAAA;IAED,MAAM,CAAC,GAAG,CACR,QAAQ,CAAC;QACP,MAAM,EAAE,MAAM;QACd,QAAQ,EAAE,UAAU;QACpB,MAAM,EAAE,iBAAiB;QACzB,mBAAmB,EAAE,IAAI;QACzB,KAAK,CAAC,OAAO;YACX,MAAM,EAAE,QAAQ,EAAE,cAAc,EAAE,KAAK,EAAE,UAAU,EAAE,GAAG,IAAI,CAAA;YAE5D,MAAM,OAAO,GAAG,MAAM,MAAM,CAAC,cAAc,CAAC,aAAa,CACvD,QAAQ,EACR,cAAc,EACd,KAAK,CACN,CAAA;YAED,2DAA2D;YAC3D,MAAM,QAAQ,GAAG,UAAU,IAAI,IAAI,CAAA;YAEnC,4EAA4E;YAC5E,cAAc;YACd,IAAI,QAAQ,EAAE,CAAC;gBACb,MAAM,MAAM,CAAC,cAAc,CAAC,mBAAmB,CAAC,QAAQ,EAAE,OAAO,CAAC,GAAG,CAAC,CAAA;YACxE,CAAC;YAED,MAAM,cAAc,GAAG,QAAQ;gBAC7B,CAAC,CAAC,SAAS;gBACX,CAAC,CAAC,MAAM,MAAM,CAAC,MAAM,CAAC,oBAAoB,CAAC;oBACvC,GAAG,EAAE,OAAO,CAAC,GAAG;oBAChB,QAAQ;oBACR,UAAU,EAAE,IAAI,CAAC,UAAU;iBAC5B,CAAC,CAAA;YAEN,MAAM,IAAI,GAAG,EAAE,OAAO,EAAE,cAAc,EAAE,CAAA;YACxC,OAAO,EAAE,IAAI,EAAE,CAAA;QACjB,CAAC;KACF,CAAC,CACH,CAAA;IAED,MAAM,CAAC,GAAG,CACR,QAAQ,CAAC;QACP,MAAM,EAAE,MAAM;QACd,QAAQ,EAAE,UAAU;QACpB,MAAM,EAAE,gBAAgB,CAAC,MAAM,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE,EAAE,CAAC;QACrE,mBAAmB,EAAE,IAAI;QACzB,KAAK,CAAC,OAAO;YACX,MAAM,EAAE,QAAQ,EAAE,cAAc,EAAE,UAAU,EAAE,GAAG,IAAI,CAAA;YAErD,2DAA2D;YAC3D,MAAM,EAAE,QAAQ,GAAG,UAAU,IAAI,IAAI,EAAE,GAAG,KAAK,EAAE,GAAG,IAAI,CAAC,KAAK,CAAA;YAE9D,kEAAkE;YAClE,+DAA+D;YAC/D,MAAM,QAAQ,GAAG,UAAU;gBACzB,CAAC,CAAC,MAAM,MAAM,CAAC,cAAc,CAAC,YAAY,CAAC,UAAU,CAAC;gBACtD,CAAC,CAAC,SAAS,CAAA;YAEb,MAAM,OAAO,GAAG,MAAM,MAAM,CAAC,cAAc,CAAC,mBAAmB,CAC7D,QAAQ,EACR,cAAc,EACd,KAAK,EACL,QAAQ,CACT,CAAA;YAED,IAAI,QAAQ,EAAE,CAAC;gBACb,MAAM,MAAM,CAAC,cAAc,CAAC,mBAAmB,CAAC,QAAQ,EAAE,OAAO,CAAC,GAAG,CAAC,CAAA;YACxE,CAAC;iBAAM,CAAC;gBACN,oEAAoE;gBACpE,iEAAiE;gBACjE,MAAM,MAAM,CAAC,cAAc,CAAC,mBAAmB,CAAC,QAAQ,EAAE,OAAO,CAAC,GAAG,CAAC,CAAA;YACxE,CAAC;YAED,MAAM,cAAc,GAAG,QAAQ;gBAC7B,CAAC,CAAC,SAAS;gBACX,CAAC,CAAC,MAAM,MAAM,CAAC,MAAM,CAAC,oBAAoB,CAAC;oBACvC,GAAG,EAAE,OAAO,CAAC,GAAG;oBAChB,QAAQ;oBACR,UAAU;iBACX,CAAC,CAAA;YAEN,IAAI,UAAU,EAAE,CAAC;gBACf,kEAAkE;gBAClE,uDAAuD;gBAEvD,MAAM,EAAE,QAAQ,EAAE,UAAU,EAAE,GAAG,MAAM,MAAM,CAAC,cAAc,CAAC,GAAG,CAC9D,UAAU,EACV,QAAQ,CACT,CAAA;gBAED,MAAM,EAAE,iBAAiB,EAAE,GAAG,MAAM,MAAM,CAAC,cAAc,CAAC,UAAU,CAClE,OAAO,CAAC,GAAG,CACZ,CAAA;gBAED,MAAM,IAAI,GAAG;oBACX,OAAO;oBACP,cAAc;oBACd,eAAe,EAAE,MAAM,CAAC,oBAAoB,CAC1C,UAAU,EACV,iBAAiB,CAAC,GAAG,CAAC,QAAQ,CAAC,CAChC;iBACF,CAAA;gBAED,OAAO,EAAE,IAAI,EAAE,CAAA;YACjB,CAAC;YAED,MAAM,IAAI,GAAG,EAAE,OAAO,EAAE,cAAc,EAAE,CAAA;YACxC,OAAO,EAAE,IAAI,EAAE,CAAA;QACjB,CAAC;KACF,CAAC,CACH,CAAA;IAED,MAAM,CAAC,GAAG,CACR,QAAQ,CAAC;QACP,MAAM,EAAE,MAAM;QACd,QAAQ,EAAE,WAAW;QACrB,MAAM,EAAE,CAAC;aACN,MAAM,CAAC;YACN,GAAG,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC;SAC9C,CAAC;aACD,MAAM,EAAE;QACX,mBAAmB,EAAE,IAAI;QACzB,KAAK,CAAC,OAAO;YACX,MAAM,UAAU,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAA;YAEnD,KAAK,MAAM,GAAG,IAAI,UAAU,EAAE,CAAC;gBAC7B,MAAM,MAAM,CAAC,cAAc,CAAC,mBAAmB,CAAC,IAAI,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAA;YACrE,CAAC;YAED,OAAO,EAAE,IAAI,EAAE,EAAE,OAAO,EAAE,IAAa,EAAE,EAAE,CAAA;QAC7C,CAAC;KACF,CAAC,CACH,CAAA;IAED,MAAM,CAAC,GAAG,CACR,QAAQ,CAAC;QACP,MAAM,EAAE,MAAM;QACd,QAAQ,EAAE,yBAAyB;QACnC,MAAM,EAAE,CAAC;aACN,MAAM,CAAC;YACN,MAAM,EAAE,YAAY;YACpB,KAAK,EAAE,WAAW;SACnB,CAAC;aACD,MAAM,EAAE;QACX,KAAK,CAAC,OAAO;YACX,MAAM,MAAM,CAAC,cAAc,CAAC,oBAAoB,CAC9C,IAAI,CAAC,QAAQ,EACb,IAAI,CAAC,cAAc,EACnB,IAAI,CAAC,KAAK,CACX,CAAA;YACD,OAAO,EAAE,IAAI,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE,CAAA;QACpC,CAAC;KACF,CAAC,CACH,CAAA;IAED,MAAM,CAAC,GAAG,CACR,QAAQ,CAAC;QACP,MAAM,EAAE,MAAM;QACd,QAAQ,EAAE,yBAAyB;QACnC,MAAM,EAAE,CAAC;aACN,MAAM,CAAC;YACN,KAAK,EAAE,cAAc;YACrB,QAAQ,EAAE,iBAAiB;SAC5B,CAAC;aACD,MAAM,EAAE;QACX,KAAK,CAAC,OAAO;YACX,MAAM,MAAM,CAAC,cAAc,CAAC,oBAAoB,CAC9C,IAAI,CAAC,QAAQ,EACb,IAAI,CAAC,cAAc,EACnB,IAAI,CAAC,KAAK,CACX,CAAA;YACD,OAAO,EAAE,IAAI,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE,CAAA;QACpC,CAAC;KACF,CAAC,CACH,CAAA;IAED,MAAM,CAAC,GAAG,CACR,QAAQ,CAAC;QACP,MAAM,EAAE,MAAM;QACd,QAAQ,EAAE,uBAAuB;QACjC,MAAM,EAAE,CAAC;aACN,MAAM,CAAC;YACN,GAAG,EAAE,SAAS;YACd,MAAM,EAAE,YAAY,CAAC,QAAQ,EAAE;SAChC,CAAC;aACD,MAAM,EAAE;QACX,KAAK,CAAC,OAAO,CAAC,GAAG,EAAE,GAAG;YACpB,MAAM,EAAE,OAAO,EAAE,GAAG,MAAM,YAAY,CAAC,IAAI,CAAC,IAAI,EAAE,GAAG,EAAE,GAAG,CAAC,CAAA;YAE3D,MAAM,EAAE,aAAa,EAAE,GACrB,MAAM,MAAM,CAAC,cAAc,CAAC,kBAAkB,CAC5C,IAAI,CAAC,QAAQ,EACb,IAAI,CAAC,cAAc,EACnB,IAAI,CAAC,KAAK,EACV,OAAO,CACR,CAAA;YAEH,OAAO,EAAE,IAAI,EAAE,EAAE,aAAa,EAAE,EAAE,CAAA;QACpC,CAAC;KACF,CAAC,CACH,CAAA;IAED,MAAM,CAAC,GAAG,CACR,QAAQ,CAAC;QACP,MAAM,EAAE,MAAM;QACd,QAAQ,EAAE,uBAAuB;QACjC,MAAM,EAAE,CAAC;aACN,MAAM,CAAC;YACN,GAAG,EAAE,SAAS;YACd,KAAK,EAAE,WAAW;YAClB,KAAK,EAAE,cAAc,CAAC,QAAQ,EAAE;YAChC,MAAM,EAAE,YAAY,CAAC,QAAQ,EAAE;SAChC,CAAC;aACD,MAAM,EAAE;QACX,KAAK,CAAC,OAAO,CAAC,GAAG,EAAE,GAAG;YACpB,MAAM,EAAE,OAAO,EAAE,GAAG,MAAM,YAAY,CAAC,IAAI,CAAC,IAAI,EAAE,GAAG,EAAE,GAAG,CAAC,CAAA;YAE3D,MAAM,MAAM,CAAC,cAAc,CAAC,kBAAkB,CAC5C,IAAI,CAAC,QAAQ,EACb,IAAI,CAAC,cAAc,EACnB,IAAI,CAAC,KAAK,EACV,OAAO,CACR,CAAA;YAED,OAAO,EAAE,IAAI,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE,CAAA;QACpC,CAAC;KACF,CAAC,CACH,CAAA;IAED,MAAM,CAAC,GAAG,CACR,QAAQ,CAAC;QACP,MAAM,EAAE,MAAM;QACd,QAAQ,EAAE,uBAAuB;QACjC,MAAM,EAAE,CAAC;aACN,MAAM,CAAC;YACN,GAAG,EAAE,SAAS;YACd,MAAM,EAAE,YAAY,CAAC,QAAQ,EAAE;SAChC,CAAC;aACD,MAAM,EAAE;QACX,KAAK,CAAC,OAAO,CAAC,GAAG,EAAE,GAAG;YACpB,MAAM,EAAE,OAAO,EAAE,GAAG,MAAM,YAAY,CAAC,IAAI,CAAC,IAAI,EAAE,GAAG,EAAE,GAAG,CAAC,CAAA;YAE3D,MAAM,MAAM,CAAC,cAAc,CAAC,kBAAkB,CAC5C,IAAI,CAAC,QAAQ,EACb,IAAI,CAAC,cAAc,EACnB,IAAI,CAAC,KAAK,EACV,OAAO,CACR,CAAA;YAED,OAAO,EAAE,IAAI,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE,CAAA;QACpC,CAAC;KACF,CAAC,CACH,CAAA;IAED,MAAM,CAAC,GAAG,CACR,QAAQ,CAAC;QACP,MAAM,EAAE,MAAM;QACd,QAAQ,EAAE,uBAAuB;QACjC,MAAM,EAAE,CAAC;aACN,MAAM,CAAC;YACN,GAAG,EAAE,SAAS;YACd,KAAK,EAAE,cAAc;YACrB,KAAK,EAAE,WAAW;SACnB,CAAC;aACD,MAAM,EAAE;QACX,KAAK,CAAC,OAAO,CAAC,GAAG,EAAE,GAAG;YACpB,MAAM,EAAE,OAAO,EAAE,GAAG,MAAM,YAAY,CAAC,IAAI,CAAC,IAAI,EAAE,GAAG,EAAE,GAAG,CAAC,CAAA;YAE3D,MAAM,MAAM,CAAC,cAAc,CAAC,kBAAkB,CAC5C,IAAI,CAAC,QAAQ,EACb,IAAI,CAAC,cAAc,EACnB,IAAI,CAAC,KAAK,EACV,OAAO,CACR,CAAA;YAED,OAAO,EAAE,IAAI,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE,CAAA;QACpC,CAAC;KACF,CAAC,CACH,CAAA;IAED,MAAM,CAAC,GAAG,CACR,QAAQ,CAAC;QACP,MAAM,EAAE,MAAM;QACd,QAAQ,EAAE,gBAAgB;QAC1B,MAAM,EAAE,CAAC;aACN,MAAM,CAAC;YACN,GAAG,EAAE,SAAS;YACd,MAAM,EAAE,YAAY;SACrB,CAAC;aACD,MAAM,EAAE;QACX,KAAK,CAAC,OAAO,CAAC,GAAG,EAAE,GAAG;YACpB,MAAM,EAAE,OAAO,EAAE,GAAG,MAAM,YAAY,CAAC,IAAI,CAAC,IAAI,EAAE,GAAG,EAAE,GAAG,CAAC,CAAA;YAE3D,MAAM,MAAM,CAAC,cAAc,CAAC,YAAY,CACtC,IAAI,CAAC,QAAQ,EACb,IAAI,CAAC,cAAc,EACnB,IAAI,CAAC,KAAK,EACV,OAAO,CACR,CAAA;YAED,OAAO,EAAE,IAAI,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE,CAAA;QACpC,CAAC;KACF,CAAC,CACH,CAAA;IAED,MAAM,CAAC,GAAG,CACR,QAAQ,CAAC;QACP,MAAM,EAAE,KAAK;QACb,QAAQ,EAAE,kBAAkB;QAC5B,MAAM,EAAE,SAAS;QACjB,KAAK,CAAC,OAAO;YACX,MAAM,cAAc,GAAG,MAAM,MAAM,CAAC,cAAc,CAAC,kBAAkB,CACnE,IAAI,CAAC,QAAQ,CACd,CAAA;YAED,MAAM,IAAI,GAAG,cAAc,CAAC,GAAG,CAC7B,CAAC,aAAa,EAAuB,EAAE,CAAC,CAAC;gBACvC,OAAO,EAAE,aAAa,CAAC,OAAO;gBAC9B,aAAa,EAAE,MAAM,CAAC,kBAAkB,CAAC,aAAa,CAAC;aACxD,CAAC,CACH,CAAA;YAED,OAAO,EAAE,IAAI,EAAE,CAAA;QACjB,CAAC;KACF,CAAC,CACH,CAAA;IAED,MAAM,CAAC,GAAG,CACR,QAAQ,CAAC;QACP,MAAM,EAAE,KAAK;QACb,QAAQ,EAAE,iBAAiB;QAC3B,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,EAAE,GAAG,EAAE,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE;QAC7C,KAAK,CAAC,OAAO,CAAC,GAAG,EAAE,GAAG;YACpB,MAAM,EAAE,OAAO,EAAE,GAAG,MAAM,YAAY,CAAC,IAAI,CAAC,IAAI,EAAE,GAAG,EAAE,GAAG,CAAC,CAAA;YAE3D,MAAM,UAAU,GAAG,MAAM,MAAM,CAAC,YAAY,CAAC,iBAAiB,CAC5D,OAAO,CAAC,GAAG,CACZ,CAAA;YAED,MAAM,SAAS,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;YAExE,MAAM,OAAO,GAAG,MAAM,MAAM,CAAC,aAAa,CAAC,WAAW,CAAC,SAAS,EAAE;gBAChE,OAAO,EAAE,CAAC,GAAG,EAAE,QAAQ,EAAE,EAAE;oBACzB,OAAO,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,yBAAyB,QAAQ,EAAE,CAAC,CAAA;oBAC7D,OAAO,SAAS,CAAA,CAAC,wCAAwC;gBAC3D,CAAC;aACF,CAAC,CAAA;YAEF,qEAAqE;YACrE,iEAAiE;YACjE,4DAA4D;YAC5D,iCAAiC;YACjC,MAAM,IAAI,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,EAAsB,EAAE;gBAC/D,OAAO;oBACL,OAAO,EAAE,EAAE;oBAEX,SAAS,EAAE,IAAI,CAAC,SAAS,CAAC,WAAW,EAAmB;oBACxD,SAAS,EAAE,IAAI,CAAC,SAAS,CAAC,WAAW,EAAmB;oBAExD,QAAQ,EAAE,IAAI,CAAC,QAAQ;oBACvB,cAAc,EAAE,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,QAAQ;oBAEpD,KAAK,EAAE,IAAI,CAAC,UAAU,CAAC,KAAK;iBAC7B,CAAA;YACH,CAAC,CAAC,CAAA;YAEF,OAAO,EAAE,IAAI,EAAE,CAAA;QACjB,CAAC;KACF,CAAC,CACH,CAAA;IAED,MAAM,CAAC,GAAG,CACR,QAAQ,CAAC;QACP,MAAM,EAAE,KAAK;QACb,QAAQ,EAAE,mBAAmB;QAC7B,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,EAAE,GAAG,EAAE,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE;QAC7C,KAAK,CAAC,OAAO,CAAC,GAAG,EAAE,GAAG;YACpB,MAAM,EAAE,OAAO,EAAE,GAAG,MAAM,YAAY,CAAC,IAAI,CAAC,IAAI,EAAE,GAAG,EAAE,GAAG,CAAC,CAAA;YAE3D,MAAM,cAAc,GAAG,MAAM,MAAM,CAAC,cAAc,CAAC,kBAAkB,CACnE,OAAO,CAAC,GAAG,CACZ,CAAA;YAED,MAAM,IAAI,GAAG,cAAc,CAAC,GAAG,CAC7B,CAAC,cAAc,EAAwB,EAAE,CAAC,CAAC;gBACzC,QAAQ,EAAE,cAAc,CAAC,QAAQ;gBACjC,cAAc,EAAE;oBACd,SAAS,EAAE,cAAc,CAAC,UAAU,CAAC,SAAS;oBAC9C,SAAS,EAAE,cAAc,CAAC,UAAU,CAAC,SAAS;oBAC9C,UAAU,EACR,cAAc,CAAC,UAAU,CAAC,UAAU,CAAC,WAAW,EAAmB;iBACtE;gBAED,eAAe,EAAE,cAAc,CAAC,QAAQ,KAAK,IAAI,CAAC,QAAQ;aAC3D,CAAC,CACH,CAAA;YAED,OAAO,EAAE,IAAI,EAAE,CAAA;QACjB,CAAC;KACF,CAAC,CACH,CAAA;IAED,MAAM,CAAC,GAAG,CACR,QAAQ,CAAC;QACP,MAAM,EAAE,MAAM;QACd,QAAQ,EAAE,yBAAyB;QACnC,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,EAAE,GAAG,EAAE,SAAS,EAAE,QAAQ,EAAE,cAAc,EAAE,CAAC,CAAC,MAAM,EAAE;QACvE,KAAK,CAAC,OAAO;YACX,oEAAoE;YACpE,oEAAoE;YACpE,WAAW;YAEX,MAAM,MAAM,CAAC,cAAc,CAAC,mBAAmB,CAC7C,IAAI,CAAC,KAAK,CAAC,QAAQ,EACnB,IAAI,CAAC,KAAK,CAAC,GAAG,CACf,CAAA;YAED,OAAO,EAAE,IAAI,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE,CAAA;QACpC,CAAC;KACF,CAAC,CACH,CAAA;IAED,MAAM,CAAC,GAAG,CACR,QAAQ,CAAC;QACP,MAAM,EAAE,MAAM;QACd,QAAQ,EAAE,uBAAuB;QACjC,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,EAAE,GAAG,EAAE,SAAS,EAAE,OAAO,EAAE,aAAa,EAAE,CAAC,CAAC,MAAM,EAAE;QACrE,KAAK,CAAC,OAAO,CAAC,GAAG,EAAE,GAAG;YACpB,MAAM,EAAE,OAAO,EAAE,GAAG,MAAM,YAAY,CAAC,IAAI,CAAC,IAAI,EAAE,GAAG,EAAE,GAAG,CAAC,CAAA;YAE3D,MAAM,SAAS,GAAG,MAAM,MAAM,CAAC,YAAY,CAAC,YAAY,CACtD,IAAI,CAAC,KAAK,CAAC,OAAO,CACnB,CAAA;YAED,IAAI,CAAC,SAAS,IAAI,SAAS,CAAC,OAAO,CAAC,GAAG,KAAK,OAAO,CAAC,GAAG,EAAE,CAAC;gBACxD,gDAAgD;gBAChD,MAAM,IAAI,mBAAmB,CAAC,eAAe,CAAC,CAAA;YAChD,CAAC;YAED,MAAM,MAAM,CAAC,YAAY,CAAC,WAAW,CAAC,SAAS,CAAC,EAAE,CAAC,CAAA;YAEnD,OAAO,EAAE,IAAI,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE,CAAA;QACpC,CAAC;KACF,CAAC,CACH,CAAA;IAED,MAAM,CAAC,GAAG,CACR,QAAQ,CAAC;QACP,MAAM,EAAE,MAAM;QACd,QAAQ,EAAE,UAAU;QACpB,MAAM,EAAE,CAAC;aACN,MAAM,CAAC;YACN,GAAG,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,SAAS,EAAE,eAAe,CAAC,CAAC;YAC1C,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;SAC7B,CAAC;aACD,MAAM,EAAE;QACX,KAAK,CAAC,OAAO,CAAC,GAAG,EAAE,GAAG;YACpB,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC;gBACrB,MAAM,IAAI,mBAAmB,CAC3B,mEAAmE,CACpE,CAAA;YACH,CAAC;YAED,wEAAwE;YACxE,8CAA8C;YAC9C,IAAI,CAAC;gBACH,MAAM,EAAE,QAAQ,EAAE,UAAU,EAAE,GAAG,MAAM,MAAM,CAAC,cAAc,CAAC,GAAG,CAC9D,IAAI,CAAC,UAAU,EACf,IAAI,CAAC,QAAQ,CACd,CAAA;gBAED,6DAA6D;gBAC7D,sBAAsB;gBACtB,IAAI,CAAC;oBACH,MAAM,EAAE,OAAO,EAAE,iBAAiB,EAAE,GAAG,MAAM,YAAY,CAAC,IAAI,CAC5D,IAAI,EACJ,GAAG,EACH,GAAG,CACJ,CAAA;oBAED,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,aAAa,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAA;oBAE7D,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,cAAc,CAAC,aAAa,CACpD,IAAI,CAAC,UAAU,EACf,MAAM,EACN,OAAO,EACP,IAAI,CAAC,QAAQ,EACb,IAAI,CAAC,cAAc,EACnB,IAAI,CAAC,KAAK,CAAC,KAAK,CACjB,CAAA;oBAED,MAAM,UAAU,GAAG,iBAAiB,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAA;oBAClD,IAAI,MAAM,CAAC,oBAAoB,CAAC,UAAU,EAAE,UAAU,CAAC,EAAE,CAAC;wBACxD,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,UAAU,EAAE,gBAAgB,CAAC,CAAA;wBAEpD,yDAAyD;wBAEzD,4DAA4D;wBAC5D,qCAAqC;wBACrC,KAAK,MAAM,CAAC,IAAI,UAAU,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,IAAI,EAAE;4BAAE,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAA;wBAEjE,MAAM,MAAM,CAAC,cAAc,CAAC,mBAAmB,CAAC,OAAO,EAAE,MAAM,EAAE;4BAC/D,GAAG,UAAU;4BACb,gBAAgB,EAAE,CAAC,GAAG,MAAM,CAAC;yBAC9B,CAAC,CAAA;oBACJ,CAAC;oBAED,MAAM,GAAG,GAAG,gBAAgB,CAAC,MAAM,CAAC,MAAM,EAAE,UAAU,EAAE,EAAE,IAAI,EAAE,CAAC,CAAA;oBAEjE,OAAO,EAAE,IAAI,EAAE,EAAE,GAAG,EAAE,EAAE,CAAA;gBAC1B,CAAC;gBAAC,OAAO,GAAG,EAAE,CAAC;oBACb,6DAA6D;oBAC7D,sDAAsD;oBACtD,MAAM,kBAAkB,CAAC,IAAI,CAAC,UAAU,EAAE,GAAG,CAAC,CAAA;gBAChD,CAAC;YACH,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,OAAO,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,yCAAyC,CAAC,CAAA;gBAEnE,kEAAkE;gBAClE,oDAAoD;gBACpD,IAAI,CAAC;oBACH,MAAM,MAAM,CAAC,cAAc,CAAC,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,CAAA;gBACrD,CAAC;gBAAC,OAAO,GAAG,EAAE,CAAC;oBACb,OAAO,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,0BAA0B,CAAC,CAAA;gBACtD,CAAC;gBAED,IAAI,GAAG,YAAY,kBAAkB,EAAE,CAAC;oBACtC,IAAI,CAAC;wBACH,MAAM,GAAG,GAAG,gBAAgB,CAC1B,MAAM,CAAC,MAAM,EACb,GAAG,CAAC,UAAU,EACd,GAAG,CAAC,MAAM,EAAE,CACb,CAAA;wBAED,OAAO,EAAE,IAAI,EAAE,EAAE,GAAG,EAAE,EAAE,CAAA;oBAC1B,CAAC;oBAAC,MAAM,CAAC;wBACP,uCAAuC;oBACzC,CAAC;gBACH,CAAC;gBAED,iEAAiE;gBACjE,oEAAoE;gBACpE,8BAA8B;gBAC9B,OAAO,sBAAsB,CAAC,GAAG,CAAC,CAAA;YACpC,CAAC;QACH,CAAC;KACF,CAAC,CACH,CAAA;IAED,MAAM,CAAC,GAAG,CACR,QAAQ,CAAC;QACP,MAAM,EAAE,MAAM;QACd,QAAQ,EAAE,SAAS;QACnB,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,MAAM,EAAE;QAC7B,mBAAmB,EAAE,IAAI;QACzB,KAAK,CAAC,OAAO,CAAC,GAAG,EAAE,GAAG;YACpB,MAAM,EAAE,UAAU,EAAE,GAAG,IAAI,CAAA;YAC3B,IAAI,CAAC,UAAU,EAAE,CAAC;gBAChB,MAAM,IAAI,mBAAmB,CAC3B,mEAAmE,CACpE,CAAA;YACH,CAAC;YAED,+DAA+D;YAC/D,YAAY;YACZ,IAAI,CAAC;gBACH,sEAAsE;gBACtE,kDAAkD;gBAElD,wEAAwE;gBACxE,wEAAwE;gBACxE,sEAAsE;gBACtE,wEAAwE;gBACxE,uEAAuE;gBACvE,gEAAgE;gBAEhE,MAAM,EAAE,UAAU,EAAE,GAAG,MAAM,MAAM,CAAC,cAAc,CAAC,GAAG,CACpD,UAAU,EACV,IAAI,CAAC,QAAQ,CACd,CAAA;gBAED,MAAM,GAAG,GAAG,gBAAgB,CAAC,MAAM,CAAC,MAAM,EAAE,UAAU,EAAE;oBACtD,KAAK,EAAE,eAAe;oBACtB,iBAAiB,EAAE,+BAA+B;iBACnD,CAAC,CAAA;gBAEF,OAAO,EAAE,IAAI,EAAE,EAAE,GAAG,EAAE,EAAE,CAAA;YAC1B,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,OAAO,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,wCAAwC,CAAC,CAAA;gBAElE,IAAI,GAAG,YAAY,kBAAkB,EAAE,CAAC;oBACtC,IAAI,CAAC;wBACH,MAAM,GAAG,GAAG,gBAAgB,CAC1B,MAAM,CAAC,MAAM,EACb,GAAG,CAAC,UAAU,EACd,GAAG,CAAC,MAAM,EAAE,CACb,CAAA;wBAED,OAAO,EAAE,IAAI,EAAE,EAAE,GAAG,EAAE,EAAE,CAAA;oBAC1B,CAAC;oBAAC,MAAM,CAAC;wBACP,uCAAuC;oBACzC,CAAC;gBACH,CAAC;gBAED,OAAO,sBAAsB,CAAC,GAAG,CAAC,CAAA;YACpC,CAAC;oBAAS,CAAC;gBACT,MAAM,MAAM,CAAC,cAAc,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;oBAC3D,OAAO,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,0BAA0B,CAAC,CAAA;gBACtD,CAAC,CAAC,CAAA;YACJ,CAAC;QACH,CAAC;KACF,CAAC,CACH,CAAA;IAED,OAAO,MAAM,CAAC,eAAe,EAAE,CAAA;IAE/B,KAAK,UAAU,YAAY,CAEzB,GAAQ,EACR,IAAS;QAET,IAAI,GAAG,CAAC,OAAO,CAAC,aAAa,EAAE,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;YACrD,IAAI,CAAC;gBACH,0EAA0E;gBAC1E,+DAA+D;gBAC/D,MAAM,MAAM,GAAG,GAAG,CAAC,OAAO,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,CAAC,CAAA;gBACjD,MAAM,cAAc,GAAG,eAAe,CAAC,KAAK,CAAC,MAAM,CAAC,CAAA;gBACpD,MAAM,EAAE,OAAO,EAAE,GACf,MAAM,MAAM,CAAC,MAAM,CAAC,oBAAoB,CAAC,cAAc,CAAC,CAAA;gBAE1D,IACE,OAAO,CAAC,GAAG,KAAK,IAAI,CAAC,KAAK,CAAC,GAAG;oBAC9B,OAAO,CAAC,QAAQ,KAAK,IAAI,CAAC,QAAQ;oBAClC,OAAO,CAAC,UAAU,KAAK,IAAI,CAAC,UAAU,EACtC,CAAC;oBACD,OAAO,MAAM,MAAM,CAAC,cAAc,CAAC,UAAU,CAAC,OAAO,CAAC,GAAG,CAAC,CAAA;gBAC5D,CAAC;YACH,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,MAAM,IAAI,oBAAoB,CAC5B,cAAc,EACd,iCAAiC,EACjC,EAAE,MAAM,EAAE,EAAE,EAAE,EACd,GAAG,CACJ,CAAA;YACH,CAAC;QACH,CAAC;QAED,IAAI,CAAC;YACH,wDAAwD;YACxD,MAAM,aAAa,GAAG,MAAM,MAAM,CAAC,cAAc,CAAC,gBAAgB,CAChE,IAAI,CAAC,QAAQ,EACb,IAAI,CAAC,KAAK,CAAC,GAAG,CACf,CAAA;YAED,kDAAkD;YAClD,IAAI,MAAM,CAAC,kBAAkB,CAAC,aAAa,CAAC,EAAE,CAAC;gBAC7C,MAAM,IAAI,mBAAmB,CAAC,gBAAgB,CAAC,CAAA;YACjD,CAAC;YAED,OAAO,aAAa,CAAA;QACtB,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,IAAI,oBAAoB,CAC5B,cAAc,EACd,QAAQ,IAAI,CAAC,KAAK,CAAC,GAAG,mCAAmC,EACzD,EAAE,MAAM,EAAE,EAAE,EAAE,EACd,GAAG,CACJ,CAAA;QACH,CAAC;IACH,CAAC;IAwBD;;;;OAIG;IACH,SAAS,QAAQ,CAiBf,OAUD;QACC,OAAO,WAAW,CAChB,OAAO,CAAC,MAAM,EACd,GAAG,mBAAmB,GAAG,OAAO,CAAC,QAAQ,EAAE,EAC3C,aAAa,CAAC,OAAO,CAAC,CACvB,CAAA;IACH,CAAC;IAED,SAAS,aAAa,CAAqD,EACzE,MAAM,EACN,MAAM,EACN,mBAAmB,EACnB,OAAO,GAUR;QACC,MAAM,UAAU,GACd,MAAM,IAAI,IAAI,CAAC,oDAAoD;YACjE,CAAC,CAAC,KAAK,WAAW,GAAG;gBACjB,MAAM,WAAW,CAAC,GAAG,CAAC,CAAA;gBACtB,OAAO,SAAS,CAAA;YAClB,CAAC;YACH,CAAC,CAAC,MAAM,KAAK,MAAM;gBACjB,CAAC,CAAC,KAAK,WAAW,GAAG;oBACjB,MAAM,IAAI,GAAG,MAAM,gBAAgB,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,CAAC,CAAA;oBAClD,OAAO,MAAM,CAAC,UAAU,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,CAAA;gBACpD,CAAC;gBACH,CAAC,CAAC,KAAK,WAAW,GAAG;oBACjB,MAAM,WAAW,CAAC,GAAG,CAAC,CAAA;oBACtB,MAAM,KAAK,GAAG,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC,YAAY,CAAC,CAAA;oBACvD,OAAO,MAAM,CAAC,UAAU,CAAC,KAAK,EAAE,EAAE,IAAI,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,CAAA;gBACtD,CAAC,CAAA;QAET,OAAO,WAAW,CAAc,KAAK,WAAW,GAAG,EAAE,GAAG;YACtD,IAAI,CAAC;gBACH,gCAAgC;gBAChC,GAAG,CAAC,SAAS,CAAC,eAAe,EAAE,UAAU,CAAC,CAAA;gBAC1C,GAAG,CAAC,SAAS,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAA;gBAEnC,wBAAwB;gBACxB,iBAAiB,CAAC,GAAG,EAAE,CAAC,aAAa,CAAC,CAAC,CAAA;gBACvC,iBAAiB,CAAC,GAAG,EAAE,CAAC,aAAa,CAAC,CAAC,CAAA;gBACvC,cAAc,CAAC,GAAG,EAAE,YAAY,CAAC,CAAA;gBACjC,MAAM,QAAQ,GAAG,gBAAgB,CAAC,GAAG,EAAE,EAAE,MAAM,EAAE,YAAY,EAAE,CAAC,CAAA;gBAEhE,mCAAmC;gBACnC;gBACE,mCAAmC;gBACnC,QAAQ,CAAC,QAAQ,KAAK,kBAAkB;oBACxC,QAAQ,CAAC,QAAQ,KAAK,UAAU;oBAChC,CAAC,QAAQ,CAAC,QAAQ,CAAC,UAAU,CAAC,WAAW,CAAC,EAC1C,CAAC;oBACD,MAAM,eAAe,CAAC,GAAG,EAAE,oBAAoB,QAAQ,EAAE,CAAC,CAAA;gBAC5D,CAAC;gBAED,0DAA0D;gBAC1D,MAAM,UAAU,GACd,QAAQ,CAAC,QAAQ,KAAK,kBAAkB;oBACtC,CAAC,CAAC,MAAM,gBAAgB,CAAC,UAAU,CAC/B,QAAQ,CAAC,YAAY,CAAC,GAAG,CAAC,aAAa,CAAC,CACzC;oBACH,CAAC,CAAC,SAAS,CAAA;gBAEf,sBAAsB;gBACtB,MAAM,iBAAiB,CAAC,GAAG,EAAE,GAAG,CAAC,CAAA;gBAEjC,oCAAoC;gBACpC,MAAM,KAAK,GAAG,MAAM,UAAU,CAAC,IAAI,CAAC,IAAI,EAAE,GAAG,CAAC,CAAA;gBAE9C,2DAA2D;gBAC3D,MAAM,EAAE,QAAQ,EAAE,cAAc,EAAE,GAAG,MAAM,MAAM,CAAC,aAAa,CAAC,IAAI,CAClE,GAAG,EACH,GAAG,EACH,mBAAmB,CACpB,CAAA;gBAED,MAAM,OAAO,GAAsC,MAAM,CAAC,IAAI,EAAE;oBAC9D,KAAK;oBACL,UAAU;oBACV,QAAQ;oBACR,cAAc;iBACf,CAAC,CAAA;gBAEF,OAAO,MAAM,OAAO,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,EAAE,GAAG,CAAC,CAAA;YAC9C,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,OAAO,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,8BAA8B,CAAC,CAAA;gBAExD,6CAA6C;gBAC7C,OAAO,sBAAsB,CAAC,GAAG,CAAC,CAAA;YACpC,CAAC;QACH,CAAC,CAAC,CAAA;IACJ,CAAC;AACH,CAAC;AAED,SAAS,sBAAsB,CAAC,GAAY;IAC1C,0DAA0D;IAC1D,MAAM,IAAI,GAAG,iBAAiB,CAAC,GAAG,CAAC,CAAA;IACnC,MAAM,MAAM,GAAG,gBAAgB,CAAC,GAAG,CAAC,CAAA;IAEpC,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,CAAA;AACzB,CAAC;AAED,SAAS,gBAAgB,CACvB,GAAW,EACX,UAA+C,EAC/C,QAAyC;IAEzC,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,2BAA2B,EAAE,GAAG,CAAC,CAAA;IAErD,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,eAAe,EAAE,iBAAiB,CAAC,UAAU,CAAC,CAAC,CAAA;IACpE,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,cAAc,EAAE,gBAAgB,CAAC,UAAU,CAAC,CAAC,CAAA;IAElE,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,mBAAmB,CAAC,GAAG,EAAE,UAAU,EAAE,QAAQ,CAAC,EAAE,CAAC;QAC1E,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAA;IAClC,CAAC;IAED,OAAO,GAAG,CAAC,IAAI,CAAA;AACjB,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,GAAQ;IACvC,IAAI,GAAG,CAAC,QAAQ,KAAK,2BAA2B,EAAE,CAAC;QACjD,MAAM,IAAI,mBAAmB,CAC3B,yBAAyB,GAAG,CAAC,QAAQ,sBAAsB,CAC5D,CAAA;IACH,CAAC;IAED,MAAM,MAAM,GAA4C,EAAE,CAAA;IAE1D,MAAM,KAAK,GAAG,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC,CAAA;IAC3C,IAAI,KAAK;QAAE,MAAM,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC,CAAA;IAExC,MAAM,GAAG,GAAG,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,KAAK,CAAC,CAAA;IACvC,IAAI,GAAG;QAAE,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,CAAA;IAElC,IAAI,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC;QACjC,KAAK,MAAM,GAAG,IAAI,qBAAqB,EAAE,CAAC;YACxC,MAAM,KAAK,GAAG,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;YACvC,IAAI,KAAK,IAAI,IAAI;gBAAE,MAAM,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC,CAAA;QAC9C,CAAC;IACH,CAAC;SAAM,IAAI,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC;QACzC,KAAK,MAAM,GAAG,IAAI,mBAAmB,EAAE,CAAC;YACtC,MAAM,KAAK,GAAG,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;YACvC,IAAI,KAAK,IAAI,IAAI;gBAAE,MAAM,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC,CAAA;QAC9C,CAAC;IACH,CAAC;SAAM,CAAC;QACN,MAAM,IAAI,mBAAmB,CAC3B,oDAAoD,CACrD,CAAA;IACH,CAAC;IAED,IAAI,CAAC;QACH,MAAM,IAAI,GAAsB,uBAAuB,CAAC,KAAK,CAC3D,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,eAAe,CAAC,CACtC,CAAA;QAED,MAAM,WAAW,GAAqB,sBAAsB,CAAC,KAAK,CAChE,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,cAAc,CAAC,CACrC,CAAA;QAED,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,CAAA;IACtC,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,mBAAmB,CAAC,IAAI,CAAC,GAAG,EAAE,sBAAsB,CAAC,CAAA;IAC7D,CAAC;AACH,CAAC","sourcesContent":["import type { IncomingMessage, ServerResponse } from 'node:http'\nimport createHttpError from 'http-errors'\nimport { z } from 'zod'\nimport { signedJwtSchema } from '@atproto/jwk'\nimport {\n API_ENDPOINT_PREFIX,\n ActiveAccountSession,\n ActiveDeviceSession,\n ActiveOAuthSession,\n ApiEndpoints,\n ISODateString,\n} from '@atproto/oauth-provider-api'\nimport {\n OAuthAuthorizationRequestParameters,\n OAuthRedirectUri,\n OAuthResponseMode,\n oauthRedirectUriSchema,\n oauthResponseModeSchema,\n} from '@atproto/oauth-types'\nimport { signInDataSchema } from '../account/sign-in-data.js'\nimport { signUpInputSchema } from '../account/sign-up-input.js'\nimport { DeviceId, deviceIdSchema } from '../device/device-id.js'\nimport { AuthorizationError } from '../errors/authorization-error.js'\nimport {\n ErrorPayload,\n buildErrorPayload,\n buildErrorStatus,\n} from '../errors/error-parser.js'\nimport { InvalidRequestError } from '../errors/invalid-request-error.js'\nimport { WWWAuthenticateError } from '../errors/www-authenticate-error.js'\nimport {\n JsonResponse,\n Middleware,\n RequestMetadata,\n Router,\n RouterCtx,\n SubCtx,\n flushStream,\n jsonHandler,\n parseHttpRequest,\n subCtx,\n validateFetchMode,\n validateFetchSite,\n validateOrigin,\n validateReferrer,\n} from '../lib/http/index.js'\nimport { RouteCtx, createRoute } from '../lib/http/route.js'\nimport { asArray } from '../lib/util/cast.js'\nimport { localeSchema } from '../lib/util/locale.js'\nimport type { Awaitable } from '../lib/util/type.js'\nimport type { OAuthProvider } from '../oauth-provider.js'\nimport { Sub, subSchema } from '../oidc/sub.js'\nimport { RequestUri, requestUriSchema } from '../request/request-uri.js'\nimport { AuthorizationRedirectParameters } from '../result/authorization-redirect-parameters.js'\nimport { tokenIdSchema } from '../token/token-id.js'\nimport { emailOtpSchema } from '../types/email-otp.js'\nimport { emailSchema } from '../types/email.js'\nimport { handleSchema } from '../types/handle.js'\nimport { newPasswordSchema } from '../types/password.js'\nimport { validateCsrfToken } from './assets/csrf.js'\nimport {\n ERROR_REDIRECT_KEYS,\n OAuthRedirectOptions,\n OAuthRedirectQueryParameter,\n SUCCESS_REDIRECT_KEYS,\n buildRedirectMode,\n buildRedirectParams,\n buildRedirectUri,\n} from './assets/send-redirect.js'\nimport type { MiddlewareOptions } from './middleware-options.js'\n\nconst verifyHandleSchema = z.object({ handle: handleSchema }).strict()\n\nexport function createApiMiddleware<\n Ctx extends object | void = void,\n Req extends IncomingMessage = IncomingMessage,\n Res extends ServerResponse = ServerResponse,\n>(\n server: OAuthProvider,\n { onError }: MiddlewareOptions<Req, Res>,\n): Middleware<Ctx, Req, Res> {\n const issuerUrl = new URL(server.issuer)\n const issuerOrigin = issuerUrl.origin\n const router = new Router<Ctx, Req, Res>(issuerUrl)\n\n router.use(\n apiRoute({\n method: 'POST',\n endpoint: '/verify-handle-availability',\n schema: verifyHandleSchema,\n async handler() {\n await server.accountManager.verifyHandleAvailability(this.input.handle)\n return { json: { available: true } }\n },\n }),\n )\n\n router.use(\n apiRoute({\n method: 'POST',\n endpoint: '/sign-up',\n schema: signUpInputSchema,\n rotateDeviceCookies: true,\n async handler() {\n const { deviceId, deviceMetadata, input, requestUri } = this\n\n const account = await server.accountManager.createAccount(\n deviceId,\n deviceMetadata,\n input,\n )\n\n // Remember when not in the context of a request by default\n const remember = requestUri == null\n\n // Only \"remember\" the newly created account if it was not created during an\n // OAuth flow.\n if (remember) {\n await server.accountManager.upsertDeviceAccount(deviceId, account.sub)\n }\n\n const ephemeralToken = remember\n ? undefined\n : await server.signer.createEphemeralToken({\n sub: account.sub,\n deviceId,\n requestUri: this.requestUri,\n })\n\n const json = { account, ephemeralToken }\n return { json }\n },\n }),\n )\n\n router.use(\n apiRoute({\n method: 'POST',\n endpoint: '/sign-in',\n schema: signInDataSchema.extend({ remember: z.boolean().optional() }),\n rotateDeviceCookies: true,\n async handler() {\n const { deviceId, deviceMetadata, requestUri } = this\n\n // Remember when not in the context of a request by default\n const { remember = requestUri == null, ...input } = this.input\n\n // Look up the client identifier associated with the pending OAuth\n // request, if any, so it can be surfaced to the sign-in hooks.\n const clientId = requestUri\n ? await server.requestManager.peekClientId(requestUri)\n : undefined\n\n const account = await server.accountManager.authenticateAccount(\n deviceId,\n deviceMetadata,\n input,\n clientId,\n )\n\n if (remember) {\n await server.accountManager.upsertDeviceAccount(deviceId, account.sub)\n } else {\n // In case the user was already signed in, and signed in again, this\n // time without \"remember me\", let's sign them off of the device.\n await server.accountManager.removeDeviceAccount(deviceId, account.sub)\n }\n\n const ephemeralToken = remember\n ? undefined\n : await server.signer.createEphemeralToken({\n sub: account.sub,\n deviceId,\n requestUri,\n })\n\n if (requestUri) {\n // Check if a consent is required for the client, but only if this\n // call is made within the context of an oauth request.\n\n const { clientId, parameters } = await server.requestManager.get(\n requestUri,\n deviceId,\n )\n\n const { authorizedClients } = await server.accountManager.getAccount(\n account.sub,\n )\n\n const json = {\n account,\n ephemeralToken,\n consentRequired: server.checkConsentRequired(\n parameters,\n authorizedClients.get(clientId),\n ),\n }\n\n return { json }\n }\n\n const json = { account, ephemeralToken }\n return { json }\n },\n }),\n )\n\n router.use(\n apiRoute({\n method: 'POST',\n endpoint: '/sign-out',\n schema: z\n .object({\n sub: z.union([subSchema, z.array(subSchema)]),\n })\n .strict(),\n rotateDeviceCookies: true,\n async handler() {\n const uniqueSubs = new Set(asArray(this.input.sub))\n\n for (const sub of uniqueSubs) {\n await server.accountManager.removeDeviceAccount(this.deviceId, sub)\n }\n\n return { json: { success: true as const } }\n },\n }),\n )\n\n router.use(\n apiRoute({\n method: 'POST',\n endpoint: '/reset-password-request',\n schema: z\n .object({\n locale: localeSchema,\n email: emailSchema,\n })\n .strict(),\n async handler() {\n await server.accountManager.resetPasswordRequest(\n this.deviceId,\n this.deviceMetadata,\n this.input,\n )\n return { json: { success: true } }\n },\n }),\n )\n\n router.use(\n apiRoute({\n method: 'POST',\n endpoint: '/reset-password-confirm',\n schema: z\n .object({\n token: emailOtpSchema,\n password: newPasswordSchema,\n })\n .strict(),\n async handler() {\n await server.accountManager.resetPasswordConfirm(\n this.deviceId,\n this.deviceMetadata,\n this.input,\n )\n return { json: { success: true } }\n },\n }),\n )\n\n router.use(\n apiRoute({\n method: 'POST',\n endpoint: '/update-email-request',\n schema: z\n .object({\n sub: subSchema,\n locale: localeSchema.optional(),\n })\n .strict(),\n async handler(req, res) {\n const { account } = await authenticate.call(this, req, res)\n\n const { tokenRequired } =\n await server.accountManager.updateEmailRequest(\n this.deviceId,\n this.deviceMetadata,\n this.input,\n account,\n )\n\n return { json: { tokenRequired } }\n },\n }),\n )\n\n router.use(\n apiRoute({\n method: 'POST',\n endpoint: '/update-email-confirm',\n schema: z\n .object({\n sub: subSchema,\n email: emailSchema,\n token: emailOtpSchema.optional(),\n locale: localeSchema.optional(),\n })\n .strict(),\n async handler(req, res) {\n const { account } = await authenticate.call(this, req, res)\n\n await server.accountManager.updateEmailConfirm(\n this.deviceId,\n this.deviceMetadata,\n this.input,\n account,\n )\n\n return { json: { success: true } }\n },\n }),\n )\n\n router.use(\n apiRoute({\n method: 'POST',\n endpoint: '/verify-email-request',\n schema: z\n .object({\n sub: subSchema,\n locale: localeSchema.optional(),\n })\n .strict(),\n async handler(req, res) {\n const { account } = await authenticate.call(this, req, res)\n\n await server.accountManager.verifyEmailRequest(\n this.deviceId,\n this.deviceMetadata,\n this.input,\n account,\n )\n\n return { json: { success: true } }\n },\n }),\n )\n\n router.use(\n apiRoute({\n method: 'POST',\n endpoint: '/verify-email-confirm',\n schema: z\n .object({\n sub: subSchema,\n token: emailOtpSchema,\n email: emailSchema,\n })\n .strict(),\n async handler(req, res) {\n const { account } = await authenticate.call(this, req, res)\n\n await server.accountManager.verifyEmailConfirm(\n this.deviceId,\n this.deviceMetadata,\n this.input,\n account,\n )\n\n return { json: { success: true } }\n },\n }),\n )\n\n router.use(\n apiRoute({\n method: 'POST',\n endpoint: '/update-handle',\n schema: z\n .object({\n sub: subSchema,\n handle: handleSchema,\n })\n .strict(),\n async handler(req, res) {\n const { account } = await authenticate.call(this, req, res)\n\n await server.accountManager.updateHandle(\n this.deviceId,\n this.deviceMetadata,\n this.input,\n account,\n )\n\n return { json: { success: true } }\n },\n }),\n )\n\n router.use(\n apiRoute({\n method: 'GET',\n endpoint: '/device-sessions',\n schema: undefined,\n async handler() {\n const deviceAccounts = await server.accountManager.listDeviceAccounts(\n this.deviceId,\n )\n\n const json = deviceAccounts.map(\n (deviceAccount): ActiveDeviceSession => ({\n account: deviceAccount.account,\n loginRequired: server.checkLoginRequired(deviceAccount),\n }),\n )\n\n return { json }\n },\n }),\n )\n\n router.use(\n apiRoute({\n method: 'GET',\n endpoint: '/oauth-sessions',\n schema: z.object({ sub: subSchema }).strict(),\n async handler(req, res) {\n const { account } = await authenticate.call(this, req, res)\n\n const tokenInfos = await server.tokenManager.listAccountTokens(\n account.sub,\n )\n\n const clientIds = tokenInfos.map((tokenInfo) => tokenInfo.data.clientId)\n\n const clients = await server.clientManager.loadClients(clientIds, {\n onError: (err, clientId) => {\n onError?.(req, res, err, `Failed to load client ${clientId}`)\n return undefined // metadata won't be available in the UI\n },\n })\n\n // @TODO: We should ideally filter sessions that are expired (or even\n // expose the expiration date). This requires a change to the way\n // TokenInfo are stored (see TokenManager#isTokenExpired and\n // TokenManager#isTokenInactive).\n const json = tokenInfos.map(({ id, data }): ActiveOAuthSession => {\n return {\n tokenId: id,\n\n createdAt: data.createdAt.toISOString() as ISODateString,\n updatedAt: data.updatedAt.toISOString() as ISODateString,\n\n clientId: data.clientId,\n clientMetadata: clients.get(data.clientId)?.metadata,\n\n scope: data.parameters.scope,\n }\n })\n\n return { json }\n },\n }),\n )\n\n router.use(\n apiRoute({\n method: 'GET',\n endpoint: '/account-sessions',\n schema: z.object({ sub: subSchema }).strict(),\n async handler(req, res) {\n const { account } = await authenticate.call(this, req, res)\n\n const deviceAccounts = await server.accountManager.listAccountDevices(\n account.sub,\n )\n\n const json = deviceAccounts.map(\n (accountSession): ActiveAccountSession => ({\n deviceId: accountSession.deviceId,\n deviceMetadata: {\n ipAddress: accountSession.deviceData.ipAddress,\n userAgent: accountSession.deviceData.userAgent,\n lastSeenAt:\n accountSession.deviceData.lastSeenAt.toISOString() as ISODateString,\n },\n\n isCurrentDevice: accountSession.deviceId === this.deviceId,\n }),\n )\n\n return { json }\n },\n }),\n )\n\n router.use(\n apiRoute({\n method: 'POST',\n endpoint: '/revoke-account-session',\n schema: z.object({ sub: subSchema, deviceId: deviceIdSchema }).strict(),\n async handler() {\n // @NOTE This route is not authenticated. If a user is able to steal\n // another user's session cookie, we allow them to revoke the device\n // session.\n\n await server.accountManager.removeDeviceAccount(\n this.input.deviceId,\n this.input.sub,\n )\n\n return { json: { success: true } }\n },\n }),\n )\n\n router.use(\n apiRoute({\n method: 'POST',\n endpoint: '/revoke-oauth-session',\n schema: z.object({ sub: subSchema, tokenId: tokenIdSchema }).strict(),\n async handler(req, res) {\n const { account } = await authenticate.call(this, req, res)\n\n const tokenInfo = await server.tokenManager.getTokenInfo(\n this.input.tokenId,\n )\n\n if (!tokenInfo || tokenInfo.account.sub !== account.sub) {\n // report this as though the token was not found\n throw new InvalidRequestError(`Invalid token`)\n }\n\n await server.tokenManager.deleteToken(tokenInfo.id)\n\n return { json: { success: true } }\n },\n }),\n )\n\n router.use(\n apiRoute({\n method: 'POST',\n endpoint: '/consent',\n schema: z\n .object({\n sub: z.union([subSchema, signedJwtSchema]),\n scope: z.string().optional(),\n })\n .strict(),\n async handler(req, res) {\n if (!this.requestUri) {\n throw new InvalidRequestError(\n 'This endpoint can only be used in the context of an OAuth request',\n )\n }\n\n // Any AuthorizationError caught in this block will result in a redirect\n // to the client's redirect_uri with an error.\n try {\n const { clientId, parameters } = await server.requestManager.get(\n this.requestUri,\n this.deviceId,\n )\n\n // Any error thrown in this block will be transformed into an\n // AuthorizationError.\n try {\n const { account, authorizedClients } = await authenticate.call(\n this,\n req,\n res,\n )\n\n const client = await server.clientManager.getClient(clientId)\n\n const code = await server.requestManager.setAuthorized(\n this.requestUri,\n client,\n account,\n this.deviceId,\n this.deviceMetadata,\n this.input.scope,\n )\n\n const clientData = authorizedClients.get(clientId)\n if (server.checkConsentRequired(parameters, clientData)) {\n const scopes = new Set(clientData?.authorizedScopes)\n\n // Add the newly accepted scopes to the authorized scopes\n\n // @NOTE `oauthScopeSchema` ensures that `scope` contains no\n // leading/trailing/duplicate spaces.\n for (const s of parameters.scope?.split(' ') ?? []) scopes.add(s)\n\n await server.accountManager.setAuthorizedClient(account, client, {\n ...clientData,\n authorizedScopes: [...scopes],\n })\n }\n\n const url = buildRedirectUrl(server.issuer, parameters, { code })\n\n return { json: { url } }\n } catch (err) {\n // Since we have access to the parameters, we can re-throw an\n // AuthorizationError with the redirect_uri parameter.\n throw AuthorizationError.from(parameters, err)\n }\n } catch (err) {\n onError?.(req, res, err, 'Failed to consent authorization request')\n\n // If any error happened (unauthenticated, invalid request, etc.),\n // lets make sure the request can no longer be used.\n try {\n await server.requestManager.delete(this.requestUri)\n } catch (err) {\n onError?.(req, res, err, 'Failed to delete request')\n }\n\n if (err instanceof AuthorizationError) {\n try {\n const url = buildRedirectUrl(\n server.issuer,\n err.parameters,\n err.toJSON(),\n )\n\n return { json: { url } }\n } catch {\n // Unable to build redirect URL, ignore\n }\n }\n\n // @NOTE Not re-throwing the error here, as the error was already\n // handled by the `onError` callback, and apiRoute (`apiMiddleware`)\n // would call `onError` again.\n return buildErrorJsonResponse(err)\n }\n },\n }),\n )\n\n router.use(\n apiRoute({\n method: 'POST',\n endpoint: '/reject',\n schema: z.object({}).strict(),\n rotateDeviceCookies: true,\n async handler(req, res) {\n const { requestUri } = this\n if (!requestUri) {\n throw new InvalidRequestError(\n 'This endpoint can only be used in the context of an OAuth request',\n )\n }\n\n // Once this endpoint is called, the request will definitely be\n // rejected.\n try {\n // No need to authenticate the user here as they are not authorizing a\n // particular account (CSRF protection is enough).\n\n // @NOTE that the client could *technically* trigger this endpoint while\n // the user is on the authorize page by forging the request (because the\n // client knows the RequestURI from PAR and has all the info needed to\n // forge the request, including CSRF). This cannot be used as DoS attack\n // as the request ID is not guessable and would only result in a bad UX\n // for misbehaving clients, only for the users of those clients.\n\n const { parameters } = await server.requestManager.get(\n requestUri,\n this.deviceId,\n )\n\n const url = buildRedirectUrl(server.issuer, parameters, {\n error: 'access_denied',\n error_description: 'The user rejected the request',\n })\n\n return { json: { url } }\n } catch (err) {\n onError?.(req, res, err, 'Failed to reject authorization request')\n\n if (err instanceof AuthorizationError) {\n try {\n const url = buildRedirectUrl(\n server.issuer,\n err.parameters,\n err.toJSON(),\n )\n\n return { json: { url } }\n } catch {\n // Unable to build redirect URL, ignore\n }\n }\n\n return buildErrorJsonResponse(err)\n } finally {\n await server.requestManager.delete(requestUri).catch((err) => {\n onError?.(req, res, err, 'Failed to delete request')\n })\n }\n },\n }),\n )\n\n return router.buildMiddleware()\n\n async function authenticate(\n this: ApiContext<void, { sub: Sub }>,\n req: Req,\n _res: Res,\n ) {\n if (req.headers.authorization?.startsWith('Bearer ')) {\n try {\n // If there is an authorization header, verify that the ephemeral token it\n // contains is a jwt bound to the right [sub, device, request].\n const bearer = req.headers.authorization.slice(7)\n const ephemeralToken = signedJwtSchema.parse(bearer)\n const { payload } =\n await server.signer.verifyEphemeralToken(ephemeralToken)\n\n if (\n payload.sub === this.input.sub &&\n payload.deviceId === this.deviceId &&\n payload.requestUri === this.requestUri\n ) {\n return await server.accountManager.getAccount(payload.sub)\n }\n } catch (err) {\n throw new WWWAuthenticateError(\n 'unauthorized',\n `Invalid or expired bearer token`,\n { Bearer: {} },\n err,\n )\n }\n }\n\n try {\n // Ensures the \"sub\" has an active session on the device\n const deviceAccount = await server.accountManager.getDeviceAccount(\n this.deviceId,\n this.input.sub,\n )\n\n // The session exists but was created too long ago\n if (server.checkLoginRequired(deviceAccount)) {\n throw new InvalidRequestError('Login required')\n }\n\n return deviceAccount\n } catch (err) {\n throw new WWWAuthenticateError(\n 'unauthorized',\n `User ${this.input.sub} not authenticated on this device`,\n { Bearer: {} },\n err,\n )\n }\n }\n\n type ApiContext<T extends object | void, I = void> = SubCtx<\n T,\n {\n deviceId: DeviceId\n deviceMetadata: RequestMetadata\n\n /**\n * The parsed input data (json payload if \"POST\", query params if \"GET\").\n */\n input: I\n\n /**\n * When defined, the request originated from the authorize page.\n */\n requestUri?: RequestUri\n }\n >\n\n type InferValidation<S extends void | z.ZodTypeAny> = S extends z.ZodTypeAny\n ? z.infer<S>\n : void\n\n /**\n * The main purpose of this function is to ensure that the endpoint\n * implementation matches its type definition from {@link ApiEndpoints}.\n * @private\n */\n function apiRoute<\n C extends RouterCtx<Ctx>,\n M extends 'GET' | 'POST',\n E extends `/${string}` &\n // Extract all the endpoint path that match the method (allows for\n // auto-complete & better error reporting)\n {\n [E in keyof ApiEndpoints]: ApiEndpoints[E] extends { method: M }\n ? E\n : never\n }[keyof ApiEndpoints],\n S extends // A schema that validates the POST input or GET params\n ApiEndpoints[E] extends { method: 'POST'; input: infer I }\n ? z.ZodType<I>\n : ApiEndpoints[E] extends { method: 'GET'; params: infer P }\n ? z.ZodType<P>\n : void,\n >(options: {\n method: M\n endpoint: E\n schema: S\n rotateDeviceCookies?: boolean\n handler: (\n this: ApiContext<RouteCtx<C>, InferValidation<S>>,\n req: Req,\n res: Res,\n ) => Awaitable<JsonResponse<ErrorPayload | ApiEndpoints[E]['output']>>\n }): Middleware<C, Req, Res> {\n return createRoute(\n options.method,\n `${API_ENDPOINT_PREFIX}${options.endpoint}`,\n apiMiddleware(options),\n )\n }\n\n function apiMiddleware<C extends RouterCtx, S extends void | z.ZodTypeAny>({\n method,\n schema,\n rotateDeviceCookies,\n handler,\n }: {\n method: 'GET' | 'POST'\n schema: S\n rotateDeviceCookies?: boolean\n handler: (\n this: ApiContext<C, InferValidation<S>>,\n req: Req,\n res: Res,\n ) => Awaitable<JsonResponse>\n }): Middleware<C, Req, Res> {\n const parseInput: (this: C, req: Req) => Promise<InferValidation<S>> =\n schema == null // No schema means endpoint doesn't accept any input\n ? async function (req) {\n await flushStream(req)\n return undefined\n }\n : method === 'POST'\n ? async function (req) {\n const body = await parseHttpRequest(req, ['json'])\n return schema.parseAsync(body, { path: ['body'] })\n }\n : async function (req) {\n await flushStream(req)\n const query = Object.fromEntries(this.url.searchParams)\n return schema.parseAsync(query, { path: ['query'] })\n }\n\n return jsonHandler<C, Req, Res>(async function (req, res) {\n try {\n // Prevent caching of API routes\n res.setHeader('Cache-Control', 'no-store')\n res.setHeader('Pragma', 'no-cache')\n\n // Prevent CORS requests\n validateFetchMode(req, ['same-origin'])\n validateFetchSite(req, ['same-origin'])\n validateOrigin(req, issuerOrigin)\n const referrer = validateReferrer(req, { origin: issuerOrigin })\n\n // Ensure we are one the right page\n if (\n // trailing slashes are not allowed\n referrer.pathname !== '/oauth/authorize' &&\n referrer.pathname !== '/account' &&\n !referrer.pathname.startsWith(`/account/`)\n ) {\n throw createHttpError(400, `Invalid referrer ${referrer}`)\n }\n\n // Check if the request originated from the authorize page\n const requestUri =\n referrer.pathname === '/oauth/authorize'\n ? await requestUriSchema.parseAsync(\n referrer.searchParams.get('request_uri'),\n )\n : undefined\n\n // Validate CSRF token\n await validateCsrfToken(req, res)\n\n // Parse and validate the input data\n const input = await parseInput.call(this, req)\n\n // Load session data, rotating the session cookie if needed\n const { deviceId, deviceMetadata } = await server.deviceManager.load(\n req,\n res,\n rotateDeviceCookies,\n )\n\n const context: ApiContext<C, InferValidation<S>> = subCtx(this, {\n input,\n requestUri,\n deviceId,\n deviceMetadata,\n })\n\n return await handler.call(context, req, res)\n } catch (err) {\n onError?.(req, res, err, `Failed to handle API request`)\n\n // Make sore to always return a JSON response\n return buildErrorJsonResponse(err)\n }\n })\n }\n}\n\nfunction buildErrorJsonResponse(err: unknown) {\n // @TODO Rework the API error responses (relying on codes)\n const json = buildErrorPayload(err)\n const status = buildErrorStatus(err)\n\n return { json, status }\n}\n\nfunction buildRedirectUrl(\n iss: string,\n parameters: OAuthAuthorizationRequestParameters,\n redirect: AuthorizationRedirectParameters,\n): string {\n const url = new URL('/oauth/authorize/redirect', iss)\n\n url.searchParams.set('redirect_mode', buildRedirectMode(parameters))\n url.searchParams.set('redirect_uri', buildRedirectUri(parameters))\n\n for (const [key, value] of buildRedirectParams(iss, parameters, redirect)) {\n url.searchParams.set(key, value)\n }\n\n return url.href\n}\n\nexport function parseRedirectUrl(url: URL): OAuthRedirectOptions {\n if (url.pathname !== '/oauth/authorize/redirect') {\n throw new InvalidRequestError(\n `Invalid redirect URL: ${url.pathname} is not a valid path`,\n )\n }\n\n const params: [OAuthRedirectQueryParameter, string][] = []\n\n const state = url.searchParams.get('state')\n if (state) params.push(['state', state])\n\n const iss = url.searchParams.get('iss')\n if (iss) params.push(['iss', iss])\n\n if (url.searchParams.has('code')) {\n for (const key of SUCCESS_REDIRECT_KEYS) {\n const value = url.searchParams.get(key)\n if (value != null) params.push([key, value])\n }\n } else if (url.searchParams.has('error')) {\n for (const key of ERROR_REDIRECT_KEYS) {\n const value = url.searchParams.get(key)\n if (value != null) params.push([key, value])\n }\n } else {\n throw new InvalidRequestError(\n 'Invalid redirect URL: neither code nor error found',\n )\n }\n\n try {\n const mode: OAuthResponseMode = oauthResponseModeSchema.parse(\n url.searchParams.get('redirect_mode'),\n )\n\n const redirectUri: OAuthRedirectUri = oauthRedirectUriSchema.parse(\n url.searchParams.get('redirect_uri'),\n )\n\n return { mode, redirectUri, params }\n } catch (err) {\n throw InvalidRequestError.from(err, 'Invalid redirect URL')\n }\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atproto/oauth-provider",
3
- "version": "0.18.1",
3
+ "version": "0.18.2",
4
4
  "license": "MIT",
5
5
  "description": "Generic OAuth2 and OpenID Connect provider for Node.js. Currently only supports features needed for Atproto.",
6
6
  "keywords": [
@@ -41,7 +41,6 @@
41
41
  "jose": "^5.2.0",
42
42
  "zod": "^3.23.8",
43
43
  "@atproto-labs/fetch": "^0.3.0",
44
- "@atproto-labs/fetch-node": "^0.3.0",
45
44
  "@atproto-labs/pipe": "^0.2.0",
46
45
  "@atproto-labs/simple-store": "^0.4.0",
47
46
  "@atproto-labs/simple-store-memory": "^0.2.0",
@@ -52,10 +51,11 @@
52
51
  "@atproto/lex-document": "^0.1.0",
53
52
  "@atproto/lex-resolver": "^0.1.0",
54
53
  "@atproto/oauth-types": "^0.7.1",
55
- "@atproto/oauth-provider-api": "0.6.0",
56
- "@atproto/oauth-provider-ui": "0.7.1",
54
+ "@atproto/oauth-provider-api": "0.6.1",
55
+ "@atproto/oauth-provider-ui": "0.7.2",
57
56
  "@atproto/oauth-scopes": "^0.5.0",
58
- "@atproto/syntax": "^0.6.1"
57
+ "@atproto/syntax": "^0.6.1",
58
+ "@atproto-labs/fetch-node": "^0.3.0"
59
59
  },
60
60
  "devDependencies": {
61
61
  "@types/cookie": "^0.6.0",
@@ -23,6 +23,7 @@ import {
23
23
  SignUpData,
24
24
  UpdateEmailConfirmInput,
25
25
  UpdateEmailRequestInput,
26
+ UpdateHandleData,
26
27
  VerifyEmailConfirmInput,
27
28
  VerifyEmailRequestInput,
28
29
  } from './account-store.js'
@@ -453,4 +454,29 @@ export class AccountManager {
453
454
 
454
455
  return updatedAccount
455
456
  }
457
+
458
+ public async updateHandle(
459
+ deviceId: DeviceId,
460
+ deviceMetadata: RequestMetadata,
461
+ input: UpdateHandleData,
462
+ account: Account,
463
+ ): Promise<Account> {
464
+ await this.hooks.onUpdateHandle?.call(null, {
465
+ deviceId,
466
+ deviceMetadata,
467
+ input,
468
+ account,
469
+ })
470
+
471
+ const updatedAccount = await this.store.updateHandle(input)
472
+
473
+ await this.hooks.onUpdatedHandle?.call(null, {
474
+ deviceId,
475
+ deviceMetadata,
476
+ input,
477
+ account: updatedAccount,
478
+ })
479
+
480
+ return updatedAccount
481
+ }
456
482
  }
@@ -7,6 +7,7 @@ import type {
7
7
  InitiateEmailUpdateOutput,
8
8
  InitiateEmailVerificationInput,
9
9
  InitiatePasswordResetInput,
10
+ UpdateHandleInput,
10
11
  } from '@atproto/oauth-provider-api'
11
12
  import { OAuthScope } from '@atproto/oauth-types'
12
13
  import { ClientId } from '../client/client-id.js'
@@ -55,6 +56,7 @@ export type UpdateEmailRequestOutput = InitiateEmailUpdateOutput
55
56
  export type UpdateEmailConfirmInput = ConfirmEmailUpdateInput
56
57
  export type VerifyEmailRequestInput = InitiateEmailVerificationInput
57
58
  export type VerifyEmailConfirmInput = ConfirmEmailVerificationInput
59
+ export type UpdateHandleData = UpdateHandleInput
58
60
 
59
61
  export type CreateAccountData = {
60
62
  locale: string
@@ -216,6 +218,13 @@ export interface AccountStore {
216
218
  * @throws {HandleUnavailableError} - To indicate that the handle is already taken
217
219
  */
218
220
  verifyHandleAvailability(handle: string): Awaitable<void>
221
+
222
+ /**
223
+ * @throws {HandleUnavailableError} - To indicate that the handle is already taken
224
+ * @throws {InvalidRequestError} - To indicate that the handle is invalid or
225
+ * cannot be used
226
+ */
227
+ updateHandle(data: UpdateHandleData): Awaitable<Account>
219
228
  }
220
229
 
221
230
  export const isAccountStore = buildInterfaceChecker<AccountStore>([
@@ -234,6 +243,7 @@ export const isAccountStore = buildInterfaceChecker<AccountStore>([
234
243
  'verifyEmailRequest',
235
244
  'verifyEmailConfirm',
236
245
  'verifyHandleAvailability',
246
+ 'updateHandle',
237
247
  ])
238
248
 
239
249
  export function asAccountStore<V>(implementation: V): V & AccountStore {
@@ -5,6 +5,7 @@ export function buildCustomizationData({
5
5
  branding,
6
6
  availableUserDomains,
7
7
  inviteCodeRequired,
8
+ show2FaWarningOnEmailUpdate,
8
9
  hcaptcha,
9
10
  }: Customization): CustomizationData {
10
11
  // @NOTE the front end does not need colors here as they will be injected as
@@ -14,6 +15,7 @@ export function buildCustomizationData({
14
15
  return {
15
16
  availableUserDomains,
16
17
  inviteCodeRequired,
18
+ show2FaWarningOnEmailUpdate,
17
19
  hcaptchaSiteKey: hcaptcha?.siteKey,
18
20
  name: branding?.name,
19
21
  logo: branding?.logo,
@@ -16,6 +16,10 @@ export const customizationSchema = z.object({
16
16
  * Is an invite code required to sign up?
17
17
  */
18
18
  inviteCodeRequired: z.boolean().optional(),
19
+ /**
20
+ * Show a warning about 2FA being disabled when updating email address
21
+ */
22
+ show2FaWarningOnEmailUpdate: z.boolean().optional(),
19
23
  /**
20
24
  * Enables hCaptcha during sign-up.
21
25
  */
@@ -1,8 +1,13 @@
1
+ import { HandleUnavailableReason } from '@atproto/oauth-provider-api'
1
2
  import { OAuthError } from './oauth-error.js'
2
3
 
4
+ // @TODO this is *not* and "OAuthError" error but rather an ApiError.
5
+
6
+ export type { HandleUnavailableReason }
7
+
3
8
  export class HandleUnavailableError extends OAuthError {
4
9
  constructor(
5
- readonly reason: 'syntax' | 'domain' | 'slur' | 'taken',
10
+ readonly reason: HandleUnavailableReason,
6
11
  details: string = 'That handle is not available',
7
12
  cause?: unknown,
8
13
  ) {
@@ -14,6 +14,7 @@ import {
14
14
  SignUpData,
15
15
  UpdateEmailConfirmInput,
16
16
  UpdateEmailRequestInput,
17
+ UpdateHandleData,
17
18
  VerifyEmailConfirmInput,
18
19
  VerifyEmailRequestInput,
19
20
  } from './account/account-store.js'
@@ -76,6 +77,7 @@ export {
76
77
  type SignUpInput,
77
78
  type Sub,
78
79
  type TokenClaims,
80
+ type UpdateHandleData,
79
81
  }
80
82
 
81
83
  export type OAuthHooks = {
@@ -183,6 +185,29 @@ export type OAuthHooks = {
183
185
  account: Account
184
186
  }) => Awaitable<void>
185
187
 
188
+ /**
189
+ * This hook is called when a user requests a handle change, before the change
190
+ * is performed on the account store. Only triggered with authenticated
191
+ * sessions, so the `account` is always available.
192
+ */
193
+ onUpdateHandle?: (data: {
194
+ input: UpdateHandleData
195
+ deviceId: DeviceId
196
+ deviceMetadata: RequestMetadata
197
+ account: Account
198
+ }) => Awaitable<void>
199
+
200
+ /**
201
+ * This hook is called after a user successfully changed their handle on the
202
+ * account store.
203
+ */
204
+ onUpdatedHandle?: (data: {
205
+ input: UpdateHandleData
206
+ deviceId: DeviceId
207
+ deviceMetadata: RequestMetadata
208
+ account: Account
209
+ }) => Awaitable<void>
210
+
186
211
  /**
187
212
  * This hook is called when a user attempts to sign up, after every validation
188
213
  * has passed (including hcaptcha).
@@ -41,13 +41,13 @@ export function oauthMiddleware<
41
41
  }
42
42
  : onError
43
43
 
44
- return asHandler(
45
- combineMiddlewares([
46
- assetsMiddleware,
47
- createOAuthMiddleware(server, options),
48
- createApiMiddleware(server, options),
49
- createAuthorizationPageMiddleware(server, options),
50
- createAccountPageMiddleware(server, options),
51
- ]),
52
- )
44
+ const middleware = combineMiddlewares([
45
+ assetsMiddleware,
46
+ createOAuthMiddleware(server, options),
47
+ createApiMiddleware(server, options),
48
+ createAuthorizationPageMiddleware(server, options),
49
+ createAccountPageMiddleware(server, options),
50
+ ])
51
+
52
+ return asHandler(middleware)
53
53
  }
@@ -302,8 +302,8 @@ export function createApiMiddleware<
302
302
  schema: z
303
303
  .object({
304
304
  sub: subSchema,
305
- token: emailOtpSchema,
306
305
  email: emailSchema,
306
+ token: emailOtpSchema.optional(),
307
307
  locale: localeSchema.optional(),
308
308
  })
309
309
  .strict(),
@@ -373,6 +373,31 @@ export function createApiMiddleware<
373
373
  }),
374
374
  )
375
375
 
376
+ router.use(
377
+ apiRoute({
378
+ method: 'POST',
379
+ endpoint: '/update-handle',
380
+ schema: z
381
+ .object({
382
+ sub: subSchema,
383
+ handle: handleSchema,
384
+ })
385
+ .strict(),
386
+ async handler(req, res) {
387
+ const { account } = await authenticate.call(this, req, res)
388
+
389
+ await server.accountManager.updateHandle(
390
+ this.deviceId,
391
+ this.deviceMetadata,
392
+ this.input,
393
+ account,
394
+ )
395
+
396
+ return { json: { success: true } }
397
+ },
398
+ }),
399
+ )
400
+
376
401
  router.use(
377
402
  apiRoute({
378
403
  method: 'GET',