@atproto/oauth-provider 0.19.6 → 0.19.8

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 (165) hide show
  1. package/CHANGELOG.md +33 -0
  2. package/dist/errors/error-parser.js +5 -5
  3. package/dist/errors/error-parser.js.map +1 -1
  4. package/package.json +22 -18
  5. package/src/access-token/access-token-mode.ts +0 -4
  6. package/src/account/account-manager.ts +0 -591
  7. package/src/account/account-store.ts +0 -305
  8. package/src/account/sign-in-data.ts +0 -15
  9. package/src/account/sign-up-input.ts +0 -20
  10. package/src/client/client-auth.ts +0 -64
  11. package/src/client/client-data.ts +0 -9
  12. package/src/client/client-id.ts +0 -4
  13. package/src/client/client-info.ts +0 -13
  14. package/src/client/client-manager.ts +0 -772
  15. package/src/client/client-store.ts +0 -35
  16. package/src/client/client-utils.ts +0 -37
  17. package/src/client/client.ts +0 -394
  18. package/src/constants.ts +0 -80
  19. package/src/customization/branding.ts +0 -12
  20. package/src/customization/build-customization-css.ts +0 -55
  21. package/src/customization/build-customization-data.ts +0 -24
  22. package/src/customization/colors.ts +0 -48
  23. package/src/customization/customization.ts +0 -29
  24. package/src/customization/links.ts +0 -10
  25. package/src/device/device-data.ts +0 -11
  26. package/src/device/device-id.ts +0 -27
  27. package/src/device/device-manager.ts +0 -292
  28. package/src/device/device-store.ts +0 -31
  29. package/src/device/session-id.ts +0 -21
  30. package/src/dpop/dpop-manager.ts +0 -214
  31. package/src/dpop/dpop-nonce.ts +0 -121
  32. package/src/dpop/dpop-proof.ts +0 -6
  33. package/src/errors/access-denied-error.ts +0 -12
  34. package/src/errors/account-selection-required-error.ts +0 -12
  35. package/src/errors/authorization-error.ts +0 -45
  36. package/src/errors/consent-required-error.ts +0 -12
  37. package/src/errors/error-parser.ts +0 -147
  38. package/src/errors/handle-unavailable-error.ts +0 -23
  39. package/src/errors/invalid-authorization-details-error.ts +0 -27
  40. package/src/errors/invalid-client-error.ts +0 -20
  41. package/src/errors/invalid-client-id-error.ts +0 -31
  42. package/src/errors/invalid-client-metadata-error.ts +0 -68
  43. package/src/errors/invalid-credentials-error.ts +0 -29
  44. package/src/errors/invalid-dpop-key-binding-error.ts +0 -21
  45. package/src/errors/invalid-dpop-proof-error.ts +0 -13
  46. package/src/errors/invalid-grant-error.ts +0 -21
  47. package/src/errors/invalid-invite-code-error.ts +0 -10
  48. package/src/errors/invalid-redirect-uri-error.ts +0 -17
  49. package/src/errors/invalid-request-error.ts +0 -32
  50. package/src/errors/invalid-scope-error.ts +0 -15
  51. package/src/errors/invalid-token-error.ts +0 -60
  52. package/src/errors/login-required-error.ts +0 -12
  53. package/src/errors/oauth-error.ts +0 -28
  54. package/src/errors/second-authentication-factor-required-error.ts +0 -25
  55. package/src/errors/unauthorized-client-error.ts +0 -20
  56. package/src/errors/use-dpop-nonce-error.ts +0 -32
  57. package/src/errors/www-authenticate-error.ts +0 -64
  58. package/src/index.ts +0 -16
  59. package/src/lexicon/lexicon-data.ts +0 -11
  60. package/src/lexicon/lexicon-getter.ts +0 -55
  61. package/src/lexicon/lexicon-manager.ts +0 -116
  62. package/src/lexicon/lexicon-store.ts +0 -35
  63. package/src/lib/csp/index.ts +0 -101
  64. package/src/lib/hcaptcha.ts +0 -228
  65. package/src/lib/html/README.md +0 -9
  66. package/src/lib/html/build-document.ts +0 -151
  67. package/src/lib/html/escapers.ts +0 -66
  68. package/src/lib/html/html.ts +0 -56
  69. package/src/lib/html/hydration-data.ts +0 -19
  70. package/src/lib/html/index.ts +0 -5
  71. package/src/lib/html/tags.ts +0 -67
  72. package/src/lib/html/util.ts +0 -17
  73. package/src/lib/http/README.md +0 -11
  74. package/src/lib/http/accept.ts +0 -90
  75. package/src/lib/http/context.ts +0 -42
  76. package/src/lib/http/headers.ts +0 -15
  77. package/src/lib/http/index.ts +0 -10
  78. package/src/lib/http/method.ts +0 -18
  79. package/src/lib/http/middleware.ts +0 -169
  80. package/src/lib/http/parser.ts +0 -101
  81. package/src/lib/http/path.ts +0 -82
  82. package/src/lib/http/request.ts +0 -256
  83. package/src/lib/http/response.ts +0 -122
  84. package/src/lib/http/route.ts +0 -60
  85. package/src/lib/http/router.ts +0 -117
  86. package/src/lib/http/security-headers.ts +0 -100
  87. package/src/lib/http/stream.ts +0 -57
  88. package/src/lib/http/types.ts +0 -16
  89. package/src/lib/http/url.ts +0 -23
  90. package/src/lib/nsid.ts +0 -10
  91. package/src/lib/redis.ts +0 -25
  92. package/src/lib/util/authorization-header.ts +0 -28
  93. package/src/lib/util/cast.ts +0 -18
  94. package/src/lib/util/color.ts +0 -168
  95. package/src/lib/util/crypto.ts +0 -32
  96. package/src/lib/util/date.ts +0 -7
  97. package/src/lib/util/error.ts +0 -7
  98. package/src/lib/util/function.ts +0 -39
  99. package/src/lib/util/locale.ts +0 -12
  100. package/src/lib/util/object.ts +0 -23
  101. package/src/lib/util/redirect-uri.ts +0 -46
  102. package/src/lib/util/time.ts +0 -49
  103. package/src/lib/util/type.ts +0 -182
  104. package/src/lib/util/ui8.ts +0 -14
  105. package/src/lib/util/well-known.ts +0 -8
  106. package/src/lib/util/zod-error.ts +0 -26
  107. package/src/lib/write-form-redirect.ts +0 -58
  108. package/src/lib/write-html.ts +0 -70
  109. package/src/metadata/build-metadata.ts +0 -141
  110. package/src/oauth-client.ts +0 -3
  111. package/src/oauth-dpop.ts +0 -2
  112. package/src/oauth-errors.ts +0 -26
  113. package/src/oauth-hooks.ts +0 -519
  114. package/src/oauth-middleware.ts +0 -53
  115. package/src/oauth-provider.ts +0 -1110
  116. package/src/oauth-store.ts +0 -12
  117. package/src/oauth-verifier.ts +0 -260
  118. package/src/replay/replay-manager.ts +0 -51
  119. package/src/replay/replay-store-memory.ts +0 -36
  120. package/src/replay/replay-store-redis.ts +0 -30
  121. package/src/replay/replay-store.ts +0 -44
  122. package/src/request/code.ts +0 -23
  123. package/src/request/request-data.ts +0 -36
  124. package/src/request/request-id.ts +0 -22
  125. package/src/request/request-manager.ts +0 -521
  126. package/src/request/request-store.ts +0 -60
  127. package/src/request/request-uri.ts +0 -42
  128. package/src/result/authorization-redirect-parameters.ts +0 -24
  129. package/src/result/authorization-result-authorize-page.ts +0 -16
  130. package/src/result/authorization-result-redirect.ts +0 -8
  131. package/src/router/assets/assets-manifest.ts +0 -117
  132. package/src/router/assets/assets.ts +0 -124
  133. package/src/router/assets/csrf.ts +0 -79
  134. package/src/router/assets/send-account-page.ts +0 -23
  135. package/src/router/assets/send-authorization-page.ts +0 -42
  136. package/src/router/assets/send-cookie-error-page.ts +0 -21
  137. package/src/router/assets/send-error-page.ts +0 -25
  138. package/src/router/assets/send-redirect.ts +0 -140
  139. package/src/router/create-account-page-middleware.ts +0 -88
  140. package/src/router/create-api-middleware.ts +0 -1051
  141. package/src/router/create-authorization-page-middleware.ts +0 -281
  142. package/src/router/create-oauth-middleware.ts +0 -257
  143. package/src/router/error-handler.ts +0 -6
  144. package/src/router/middleware-options.ts +0 -9
  145. package/src/signer/access-token-payload.ts +0 -25
  146. package/src/signer/api-token-payload.ts +0 -18
  147. package/src/signer/signer.ts +0 -121
  148. package/src/token/refresh-token.ts +0 -30
  149. package/src/token/token-claims.ts +0 -22
  150. package/src/token/token-data.ts +0 -40
  151. package/src/token/token-id.ts +0 -25
  152. package/src/token/token-manager.ts +0 -427
  153. package/src/token/token-store.ts +0 -88
  154. package/src/types/authorization-response-error.ts +0 -27
  155. package/src/types/color-hue.ts +0 -3
  156. package/src/types/email-otp.ts +0 -3
  157. package/src/types/email.ts +0 -26
  158. package/src/types/handle.ts +0 -23
  159. package/src/types/invite-code.ts +0 -4
  160. package/src/types/par-response-error.ts +0 -25
  161. package/src/types/password.ts +0 -4
  162. package/src/types/rgb-color.ts +0 -21
  163. package/tsconfig.build.json +0 -8
  164. package/tsconfig.build.tsbuildinfo +0 -1
  165. package/tsconfig.json +0 -4
@@ -1,591 +0,0 @@
1
- import { Did } from '@atproto/did'
2
- import {
3
- OAuthIssuerIdentifier,
4
- isOAuthClientIdLoopback,
5
- } from '@atproto/oauth-types'
6
- import { ClientId } from '../client/client-id.js'
7
- import { Client } from '../client/client.js'
8
- import { DeviceId } from '../device/device-id.js'
9
- import { InvalidCredentialsError } from '../errors/invalid-credentials-error.js'
10
- import { InvalidRequestError } from '../errors/invalid-request-error.js'
11
- import { HCaptchaClient, HcaptchaVerifyResult } from '../lib/hcaptcha.js'
12
- import { callAsync } from '../lib/util/function.js'
13
- import { constantTime } from '../lib/util/time.js'
14
- import { OAuthHooks, RequestMetadata } from '../oauth-hooks.js'
15
- import { Customization } from '../oauth-provider.js'
16
- import {
17
- Account,
18
- AccountStore,
19
- AuthorizedClientData,
20
- DeleteAccountConfirmInput,
21
- DeleteAccountRequestInput,
22
- DeviceAccount,
23
- HandleString,
24
- ResetPasswordConfirmInput,
25
- ResetPasswordRequestInput,
26
- SignUpData,
27
- UpdateEmailConfirmInput,
28
- UpdateEmailRequestInput,
29
- UpdateHandleData,
30
- VerifyEmailConfirmInput,
31
- VerifyEmailRequestInput,
32
- } from './account-store.js'
33
- import { SignInData } from './sign-in-data.js'
34
- import { SignUpInput } from './sign-up-input.js'
35
-
36
- const TIMING_ATTACK_MITIGATION_DELAY = 400
37
- const BRUTE_FORCE_MITIGATION_DELAY = 300
38
-
39
- // @TODO Add rate limit to all the OAuth routes.
40
-
41
- export class AccountManager {
42
- protected readonly inviteCodeRequired: boolean
43
- protected readonly hcaptchaClient?: HCaptchaClient
44
-
45
- constructor(
46
- issuer: OAuthIssuerIdentifier,
47
- protected readonly store: AccountStore,
48
- protected readonly hooks: OAuthHooks,
49
- customization: Customization,
50
- ) {
51
- this.inviteCodeRequired = customization.inviteCodeRequired !== false
52
- this.hcaptchaClient = customization.hcaptcha
53
- ? new HCaptchaClient(new URL(issuer).hostname, customization.hcaptcha)
54
- : undefined
55
- }
56
-
57
- protected async processHcaptchaToken(
58
- input: SignUpInput,
59
- deviceId: DeviceId,
60
- deviceMetadata: RequestMetadata,
61
- ): Promise<HcaptchaVerifyResult | undefined> {
62
- if (!this.hcaptchaClient) {
63
- return undefined
64
- }
65
-
66
- if (!input.hcaptchaToken) {
67
- throw new InvalidRequestError('hCaptcha token is required')
68
- }
69
-
70
- const tokens = this.hcaptchaClient.buildClientTokens(
71
- deviceMetadata.ipAddress,
72
- input.handle,
73
- deviceMetadata.userAgent,
74
- )
75
-
76
- const result = await this.hcaptchaClient
77
- .verify('signup', input.hcaptchaToken, deviceMetadata.ipAddress, tokens)
78
- .catch((err) => {
79
- throw InvalidRequestError.from(err, 'hCaptcha verification failed')
80
- })
81
-
82
- await this.hooks.onHcaptchaResult?.call(null, {
83
- input,
84
- deviceId,
85
- deviceMetadata,
86
- tokens,
87
- result,
88
- })
89
-
90
- try {
91
- this.hcaptchaClient.checkVerifyResult(result, tokens)
92
- } catch (err) {
93
- throw InvalidRequestError.from(err, 'hCaptcha verification failed')
94
- }
95
-
96
- return result
97
- }
98
-
99
- protected async enforceInviteCode(
100
- input: SignUpInput,
101
- _deviceId: DeviceId,
102
- _deviceMetadata: RequestMetadata,
103
- ): Promise<string | undefined> {
104
- if (!this.inviteCodeRequired) {
105
- return undefined
106
- }
107
-
108
- if (!input.inviteCode) {
109
- throw new InvalidRequestError('Invite code is required')
110
- }
111
-
112
- return input.inviteCode
113
- }
114
-
115
- protected async buildSignupData(
116
- input: SignUpInput,
117
- deviceId: DeviceId,
118
- deviceMetadata: RequestMetadata,
119
- ): Promise<SignUpData> {
120
- const [hcaptchaResult, inviteCode] = await Promise.all([
121
- this.processHcaptchaToken(input, deviceId, deviceMetadata),
122
- this.enforceInviteCode(input, deviceId, deviceMetadata),
123
- ])
124
-
125
- return { ...input, hcaptchaResult, inviteCode }
126
- }
127
-
128
- public async createAccount(
129
- deviceId: DeviceId,
130
- deviceMetadata: RequestMetadata,
131
- input: SignUpInput,
132
- ): Promise<Account> {
133
- return constantTime(BRUTE_FORCE_MITIGATION_DELAY, async () => {
134
- await this.hooks.onSignUpAttempt?.call(null, {
135
- input,
136
- deviceId,
137
- deviceMetadata,
138
- })
139
-
140
- const data = await this.buildSignupData(input, deviceId, deviceMetadata)
141
-
142
- const account = await callAsync(() =>
143
- this.store.createAccount(data),
144
- ).catch((err) => {
145
- throw InvalidRequestError.from(err, 'Account creation failed')
146
- })
147
-
148
- try {
149
- await this.hooks.onSignedUp?.call(null, {
150
- data,
151
- account,
152
- deviceId,
153
- deviceMetadata,
154
- })
155
-
156
- return account
157
- } catch (err) {
158
- await this.removeDeviceAccount(deviceId, account.did)
159
-
160
- throw InvalidRequestError.from(
161
- err,
162
- 'The account was successfully created but something went wrong, try signing-in.',
163
- )
164
- }
165
- })
166
- }
167
-
168
- public async authenticateAccount(
169
- deviceId: DeviceId,
170
- deviceMetadata: RequestMetadata,
171
- data: SignInData,
172
- clientId?: ClientId,
173
- ): Promise<Account> {
174
- return constantTime(TIMING_ATTACK_MITIGATION_DELAY, async () => {
175
- await this.hooks.onSignInAttempt?.call(null, {
176
- data,
177
- deviceId,
178
- deviceMetadata,
179
- clientId,
180
- })
181
-
182
- const account = await callAsync(() =>
183
- this.store.authenticateAccount(data),
184
- ).catch(async (err) => {
185
- // Only notify for credential failures (e.g. unknown identifier, wrong
186
- // password). Server errors and flows that require an additional factor
187
- // (e.g. SecondAuthenticationFactorRequiredError) are not "failed
188
- // sign-ins" and do not trigger the hook.
189
- if (err instanceof InvalidRequestError) {
190
- // Stores that throw the more specific `InvalidCredentialsError`
191
- // can attach the matched subject identifier to distinguish
192
- // "identifier known, password wrong" from "identifier unknown".
193
- // This information is only exposed to the hook and is never
194
- // surfaced to the client.
195
- const isCredentialsError = err instanceof InvalidCredentialsError
196
- const did = isCredentialsError ? err.did ?? null : null
197
-
198
- // Swallow any error from the hook itself so that it does not mask
199
- // the underlying authentication failure being reported.
200
- try {
201
- await this.hooks.onSignInFailed?.call(null, {
202
- data,
203
- error: err,
204
- did,
205
- deviceId,
206
- deviceMetadata,
207
- clientId,
208
- })
209
- } catch {
210
- // noop
211
- }
212
-
213
- if (isCredentialsError) {
214
- // Defensively downgrade to a plain InvalidRequestError
215
- throw new InvalidRequestError(err.error_description)
216
- }
217
- }
218
-
219
- throw err
220
- })
221
-
222
- await this.hooks.onSignedIn?.call(null, {
223
- data,
224
- account,
225
- deviceId,
226
- deviceMetadata,
227
- clientId,
228
- })
229
-
230
- return account
231
- }).catch((err) => {
232
- throw InvalidRequestError.from(
233
- err,
234
- 'Unable to sign-in due to an unexpected server error',
235
- )
236
- })
237
- }
238
-
239
- public async upsertDeviceAccount(
240
- deviceId: DeviceId,
241
- did: Did,
242
- ): Promise<void> {
243
- await this.store.upsertDeviceAccount(deviceId, did)
244
- }
245
-
246
- public async getDeviceAccount(
247
- deviceId: DeviceId,
248
- did: Did,
249
- ): Promise<DeviceAccount> {
250
- const deviceAccount = await this.store.getDeviceAccount(deviceId, did)
251
- if (!deviceAccount) throw new InvalidRequestError(`Account not found`)
252
-
253
- return deviceAccount
254
- }
255
-
256
- public async setAuthorizedClient(
257
- account: Account,
258
- client: Client,
259
- data: AuthorizedClientData,
260
- ): Promise<void> {
261
- // "Loopback" clients are not distinguishable from one another.
262
- if (isOAuthClientIdLoopback(client.id)) return
263
-
264
- await this.store.setAuthorizedClient(account.did, client.id, data)
265
- }
266
-
267
- public async getAccount(did: Did) {
268
- return this.store.getAccount(did)
269
- }
270
-
271
- public async removeDeviceAccount(deviceId: DeviceId, did: Did) {
272
- return this.store.removeDeviceAccount(deviceId, did)
273
- }
274
-
275
- public async listDeviceAccounts(
276
- deviceId: DeviceId,
277
- ): Promise<DeviceAccount[]> {
278
- const deviceAccounts = await this.store.listDeviceAccounts({
279
- deviceId,
280
- })
281
-
282
- return deviceAccounts // Fool proof
283
- .filter((deviceAccount) => deviceAccount.deviceId === deviceId)
284
- }
285
-
286
- public async listAccountDevices(did: Did): Promise<DeviceAccount[]> {
287
- const deviceAccounts = await this.store.listDeviceAccounts({
288
- did,
289
- })
290
-
291
- return deviceAccounts // Fool proof
292
- .filter((deviceAccount) => deviceAccount.account.did === did)
293
- }
294
-
295
- public async resetPasswordRequest(
296
- deviceId: DeviceId,
297
- deviceMetadata: RequestMetadata,
298
- input: ResetPasswordRequestInput,
299
- ) {
300
- return constantTime(TIMING_ATTACK_MITIGATION_DELAY, async () => {
301
- await this.hooks.onResetPasswordRequest?.call(null, {
302
- input,
303
- deviceId,
304
- deviceMetadata,
305
- })
306
-
307
- const account = await this.store.resetPasswordRequest(input)
308
-
309
- // @NOTE Do not throw here, to prevent user enumeration
310
-
311
- await this.hooks.onResetPasswordRequested?.call(null, {
312
- input,
313
- deviceId,
314
- deviceMetadata,
315
- account,
316
- })
317
- })
318
- }
319
-
320
- public async resetPasswordConfirm(
321
- deviceId: DeviceId,
322
- deviceMetadata: RequestMetadata,
323
- input: ResetPasswordConfirmInput,
324
- ) {
325
- return constantTime(TIMING_ATTACK_MITIGATION_DELAY, async () => {
326
- await this.hooks.onResetPasswordConfirm?.call(null, {
327
- input,
328
- deviceId,
329
- deviceMetadata,
330
- })
331
-
332
- const account = await this.store.resetPasswordConfirm(input)
333
-
334
- if (!account) {
335
- throw new InvalidRequestError('Invalid token')
336
- }
337
-
338
- await this.hooks.onResetPasswordConfirmed?.call(null, {
339
- input,
340
- deviceId,
341
- deviceMetadata,
342
- account,
343
- })
344
-
345
- return account
346
- })
347
- }
348
-
349
- public async verifyHandleAvailability(handle: HandleString): Promise<void> {
350
- return constantTime(TIMING_ATTACK_MITIGATION_DELAY, async () => {
351
- return this.store.verifyHandleAvailability(handle)
352
- })
353
- }
354
-
355
- public async updateEmailRequest(
356
- deviceId: DeviceId,
357
- deviceMetadata: RequestMetadata,
358
- input: UpdateEmailRequestInput,
359
- account: Account,
360
- ): Promise<{ tokenRequired: boolean }> {
361
- await this.hooks.onChangeEmailRequest?.call(null, {
362
- deviceId,
363
- deviceMetadata,
364
- input,
365
- account,
366
- })
367
-
368
- const { tokenRequired } = await this.store.updateEmailRequest(input)
369
-
370
- await this.hooks.onChangeEmailRequested?.call(null, {
371
- deviceId,
372
- deviceMetadata,
373
- input,
374
- account,
375
- })
376
-
377
- return { tokenRequired: tokenRequired === true }
378
- }
379
-
380
- public async updateEmailConfirm(
381
- deviceId: DeviceId,
382
- deviceMetadata: RequestMetadata,
383
- input: UpdateEmailConfirmInput,
384
- account: Account,
385
- ): Promise<Account> {
386
- await this.hooks.onUpdateEmailConfirm?.call(null, {
387
- deviceId,
388
- deviceMetadata,
389
- input,
390
- account,
391
- })
392
-
393
- const updatedAccount = await this.store.updateEmailConfirm(input)
394
-
395
- if (!updatedAccount) {
396
- throw new InvalidRequestError('Invalid token')
397
- }
398
-
399
- await this.hooks.onUpdateEmailConfirmed?.call(null, {
400
- deviceId,
401
- deviceMetadata,
402
- input,
403
- account: updatedAccount,
404
- prevAccount: account,
405
- })
406
-
407
- return updatedAccount
408
- }
409
-
410
- public async verifyEmailRequest(
411
- deviceId: DeviceId,
412
- deviceMetadata: RequestMetadata,
413
- input: VerifyEmailRequestInput,
414
- account: Account,
415
- ): Promise<void> {
416
- await this.hooks.onVerifyEmailRequest?.call(null, {
417
- deviceId,
418
- deviceMetadata,
419
- account,
420
- input,
421
- })
422
-
423
- await this.store.verifyEmailRequest(input)
424
-
425
- await this.hooks.onVerifyEmailRequested?.call(null, {
426
- deviceId,
427
- deviceMetadata,
428
- account,
429
- input,
430
- })
431
- }
432
-
433
- public async verifyEmailConfirm(
434
- deviceId: DeviceId,
435
- deviceMetadata: RequestMetadata,
436
- input: VerifyEmailConfirmInput,
437
- account: Account,
438
- ): Promise<Account> {
439
- await this.hooks.onVerifyEmailConfirm?.call(null, {
440
- deviceId,
441
- deviceMetadata,
442
- account,
443
- input,
444
- })
445
-
446
- const updatedAccount = await this.store.verifyEmailConfirm(input)
447
-
448
- if (!updatedAccount) {
449
- throw new InvalidRequestError('Invalid token')
450
- }
451
-
452
- await this.hooks.onVerifyEmailConfirmed?.call(null, {
453
- deviceId,
454
- deviceMetadata,
455
- account: updatedAccount,
456
- input,
457
- })
458
-
459
- return updatedAccount
460
- }
461
-
462
- public async updateHandle(
463
- deviceId: DeviceId,
464
- deviceMetadata: RequestMetadata,
465
- input: UpdateHandleData,
466
- account: Account,
467
- ): Promise<Account> {
468
- await this.hooks.onUpdateHandle?.call(null, {
469
- deviceId,
470
- deviceMetadata,
471
- input,
472
- account,
473
- })
474
-
475
- const updatedAccount = await this.store.updateHandle(input)
476
-
477
- await this.hooks.onUpdatedHandle?.call(null, {
478
- deviceId,
479
- deviceMetadata,
480
- input,
481
- account: updatedAccount,
482
- })
483
-
484
- return updatedAccount
485
- }
486
-
487
- public async deactivateAccount(
488
- deviceId: DeviceId,
489
- deviceMetadata: RequestMetadata,
490
- account: Account,
491
- ): Promise<Account> {
492
- await this.hooks.onDeactivateAccount?.call(null, {
493
- deviceId,
494
- deviceMetadata,
495
- account,
496
- })
497
-
498
- const updatedAccount = await callAsync(() =>
499
- this.store.deactivateAccount({
500
- did: account.did,
501
- // @TODO support setting this from the UI/API
502
- deleteAfter: undefined,
503
- }),
504
- ).catch((err) => {
505
- throw InvalidRequestError.from(err, 'Account deactivation failed')
506
- })
507
-
508
- await this.hooks.onDeactivatedAccount?.call(null, {
509
- deviceId,
510
- deviceMetadata,
511
- account: updatedAccount,
512
- })
513
-
514
- return updatedAccount
515
- }
516
-
517
- public async reactivateAccount(
518
- deviceId: DeviceId,
519
- deviceMetadata: RequestMetadata,
520
- account: Account,
521
- ): Promise<Account> {
522
- await this.hooks.onReactivateAccount?.call(null, {
523
- deviceId,
524
- deviceMetadata,
525
- account,
526
- })
527
-
528
- const updatedAccount = await callAsync(() =>
529
- this.store.reactivateAccount({ did: account.did }),
530
- ).catch((err) => {
531
- throw InvalidRequestError.from(err, 'Account reactivation failed')
532
- })
533
-
534
- await this.hooks.onReactivatedAccount?.call(null, {
535
- deviceId,
536
- deviceMetadata,
537
- account: updatedAccount,
538
- })
539
-
540
- return updatedAccount
541
- }
542
-
543
- public async deleteAccountRequest(
544
- deviceId: DeviceId,
545
- deviceMetadata: RequestMetadata,
546
- input: DeleteAccountRequestInput,
547
- account: Account,
548
- ): Promise<void> {
549
- await this.hooks.onDeleteAccountRequest?.call(null, {
550
- deviceId,
551
- deviceMetadata,
552
- account,
553
- })
554
-
555
- await this.store.deleteAccountRequest(input)
556
-
557
- await this.hooks.onDeleteAccountRequested?.call(null, {
558
- deviceId,
559
- deviceMetadata,
560
- account,
561
- })
562
- }
563
-
564
- public async deleteAccountConfirm(
565
- deviceId: DeviceId,
566
- deviceMetadata: RequestMetadata,
567
- input: DeleteAccountConfirmInput,
568
- account: Account,
569
- ): Promise<void> {
570
- return constantTime(BRUTE_FORCE_MITIGATION_DELAY, async () => {
571
- await this.hooks.onDeleteAccountConfirm?.call(null, {
572
- deviceId,
573
- deviceMetadata,
574
- account,
575
- })
576
-
577
- await callAsync(() => this.store.deleteAccountConfirm(input)).catch(
578
- (err) => {
579
- throw InvalidRequestError.from(err, 'Account deletion failed')
580
- },
581
- )
582
-
583
- await this.hooks.onDeleteAccountConfirmed?.call(null, {
584
- deviceId,
585
- deviceMetadata,
586
- account,
587
- input,
588
- })
589
- })
590
- }
591
- }