@atproto/pds 0.5.35 → 0.5.37

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 (201) hide show
  1. package/CHANGELOG.md +59 -0
  2. package/dist/account-manager/account-manager.d.ts +59 -8
  3. package/dist/account-manager/account-manager.d.ts.map +1 -1
  4. package/dist/account-manager/account-manager.js +154 -21
  5. package/dist/account-manager/account-manager.js.map +1 -1
  6. package/dist/account-manager/db/migrations/008-account-email-auth-factor.d.ts +9 -0
  7. package/dist/account-manager/db/migrations/008-account-email-auth-factor.d.ts.map +1 -0
  8. package/dist/account-manager/db/migrations/008-account-email-auth-factor.js +16 -0
  9. package/dist/account-manager/db/migrations/008-account-email-auth-factor.js.map +1 -0
  10. package/dist/account-manager/db/migrations/index.d.ts +2 -0
  11. package/dist/account-manager/db/migrations/index.d.ts.map +1 -1
  12. package/dist/account-manager/db/migrations/index.js +2 -0
  13. package/dist/account-manager/db/migrations/index.js.map +1 -1
  14. package/dist/account-manager/db/schema/account-email-auth-factor.d.ts +20 -0
  15. package/dist/account-manager/db/schema/account-email-auth-factor.d.ts.map +1 -0
  16. package/dist/account-manager/db/schema/account-email-auth-factor.js +2 -0
  17. package/dist/account-manager/db/schema/account-email-auth-factor.js.map +1 -0
  18. package/dist/account-manager/db/schema/email-token.d.ts +1 -1
  19. package/dist/account-manager/db/schema/email-token.d.ts.map +1 -1
  20. package/dist/account-manager/db/schema/email-token.js.map +1 -1
  21. package/dist/account-manager/db/schema/index.d.ts +2 -1
  22. package/dist/account-manager/db/schema/index.d.ts.map +1 -1
  23. package/dist/account-manager/db/schema/index.js.map +1 -1
  24. package/dist/account-manager/helpers/account-device.d.ts +4 -2
  25. package/dist/account-manager/helpers/account-device.d.ts.map +1 -1
  26. package/dist/account-manager/helpers/account.d.ts +4 -1
  27. package/dist/account-manager/helpers/account.d.ts.map +1 -1
  28. package/dist/account-manager/helpers/account.js +4 -1
  29. package/dist/account-manager/helpers/account.js.map +1 -1
  30. package/dist/account-manager/helpers/email-auth-factor.d.ts +46 -0
  31. package/dist/account-manager/helpers/email-auth-factor.d.ts.map +1 -0
  32. package/dist/account-manager/helpers/email-auth-factor.js +77 -0
  33. package/dist/account-manager/helpers/email-auth-factor.js.map +1 -0
  34. package/dist/account-manager/helpers/invite.d.ts +1 -0
  35. package/dist/account-manager/helpers/invite.d.ts.map +1 -1
  36. package/dist/account-manager/helpers/token.d.ts +4 -2
  37. package/dist/account-manager/helpers/token.d.ts.map +1 -1
  38. package/dist/account-manager/oauth-store.d.ts +4 -2
  39. package/dist/account-manager/oauth-store.d.ts.map +1 -1
  40. package/dist/account-manager/oauth-store.js +48 -14
  41. package/dist/account-manager/oauth-store.js.map +1 -1
  42. package/dist/actor-store/actor-store-reader.d.ts +3 -1
  43. package/dist/actor-store/actor-store-reader.d.ts.map +1 -1
  44. package/dist/actor-store/actor-store-reader.js +72 -5
  45. package/dist/actor-store/actor-store-reader.js.map +1 -1
  46. package/dist/actor-store/actor-store-transactor.d.ts +3 -1
  47. package/dist/actor-store/actor-store-transactor.d.ts.map +1 -1
  48. package/dist/actor-store/actor-store-transactor.js +6 -3
  49. package/dist/actor-store/actor-store-transactor.js.map +1 -1
  50. package/dist/actor-store/actor-store-writer.js +67 -3
  51. package/dist/actor-store/actor-store-writer.js.map +1 -1
  52. package/dist/actor-store/actor-store.d.ts +2 -2
  53. package/dist/actor-store/actor-store.d.ts.map +1 -1
  54. package/dist/actor-store/actor-store.js +125 -25
  55. package/dist/actor-store/actor-store.js.map +1 -1
  56. package/dist/api/com/atproto/admin/updateAccountEmail.d.ts.map +1 -1
  57. package/dist/api/com/atproto/admin/updateAccountEmail.js +1 -4
  58. package/dist/api/com/atproto/admin/updateAccountEmail.js.map +1 -1
  59. package/dist/api/com/atproto/repo/importRepo.d.ts.map +1 -1
  60. package/dist/api/com/atproto/repo/importRepo.js +7 -2
  61. package/dist/api/com/atproto/repo/importRepo.js.map +1 -1
  62. package/dist/api/com/atproto/server/createAccount.js +7 -2
  63. package/dist/api/com/atproto/server/createAccount.js.map +1 -1
  64. package/dist/api/com/atproto/server/createSession.d.ts.map +1 -1
  65. package/dist/api/com/atproto/server/createSession.js +8 -1
  66. package/dist/api/com/atproto/server/createSession.js.map +1 -1
  67. package/dist/api/com/atproto/server/getSession.d.ts.map +1 -1
  68. package/dist/api/com/atproto/server/getSession.js +1 -0
  69. package/dist/api/com/atproto/server/getSession.js.map +1 -1
  70. package/dist/api/com/atproto/server/refreshSession.d.ts.map +1 -1
  71. package/dist/api/com/atproto/server/refreshSession.js +1 -0
  72. package/dist/api/com/atproto/server/refreshSession.js.map +1 -1
  73. package/dist/api/com/atproto/server/updateEmail.d.ts.map +1 -1
  74. package/dist/api/com/atproto/server/updateEmail.js +45 -1
  75. package/dist/api/com/atproto/server/updateEmail.js.map +1 -1
  76. package/dist/api/com/atproto/sync/getRecord.d.ts.map +1 -1
  77. package/dist/api/com/atproto/sync/getRecord.js +4 -2
  78. package/dist/api/com/atproto/sync/getRecord.js.map +1 -1
  79. package/dist/api/com/atproto/sync/getRepo.d.ts.map +1 -1
  80. package/dist/api/com/atproto/sync/getRepo.js +3 -1
  81. package/dist/api/com/atproto/sync/getRepo.js.map +1 -1
  82. package/dist/auth-verifier.d.ts +1 -0
  83. package/dist/auth-verifier.d.ts.map +1 -1
  84. package/dist/auth-verifier.js +1 -0
  85. package/dist/auth-verifier.js.map +1 -1
  86. package/dist/config/secrets.d.ts +2 -1
  87. package/dist/config/secrets.d.ts.map +1 -1
  88. package/dist/config/secrets.js +25 -18
  89. package/dist/config/secrets.js.map +1 -1
  90. package/dist/context.d.ts +4 -4
  91. package/dist/context.d.ts.map +1 -1
  92. package/dist/context.js +42 -20
  93. package/dist/context.js.map +1 -1
  94. package/dist/db/db.d.ts +5 -3
  95. package/dist/db/db.d.ts.map +1 -1
  96. package/dist/db/db.js +13 -7
  97. package/dist/db/db.js.map +1 -1
  98. package/dist/disk-blobstore.d.ts +3 -2
  99. package/dist/disk-blobstore.d.ts.map +1 -1
  100. package/dist/disk-blobstore.js +13 -4
  101. package/dist/disk-blobstore.js.map +1 -1
  102. package/dist/index.d.ts +3 -3
  103. package/dist/index.d.ts.map +1 -1
  104. package/dist/index.js +2 -2
  105. package/dist/index.js.map +1 -1
  106. package/dist/lexicons/app/bsky/authFullApp.defs.d.ts.map +1 -1
  107. package/dist/lexicons/app/bsky/authFullApp.defs.js +10 -0
  108. package/dist/lexicons/app/bsky/authFullApp.defs.js.map +1 -1
  109. package/dist/lexicons/app/bsky/authManageNotifications.defs.d.ts.map +1 -1
  110. package/dist/lexicons/app/bsky/authManageNotifications.defs.js +1 -0
  111. package/dist/lexicons/app/bsky/authManageNotifications.defs.js.map +1 -1
  112. package/dist/lexicons/app/bsky/feed/defs.defs.d.ts +8 -0
  113. package/dist/lexicons/app/bsky/feed/defs.defs.d.ts.map +1 -1
  114. package/dist/lexicons/app/bsky/feed/defs.defs.js +2 -0
  115. package/dist/lexicons/app/bsky/feed/defs.defs.js.map +1 -1
  116. package/dist/lexicons/app/bsky/feed/getListFeed.defs.d.ts +4 -0
  117. package/dist/lexicons/app/bsky/feed/getListFeed.defs.d.ts.map +1 -1
  118. package/dist/lexicons/app/bsky/feed/getListFeed.defs.js +2 -0
  119. package/dist/lexicons/app/bsky/feed/getListFeed.defs.js.map +1 -1
  120. package/dist/lexicons/app/bsky/feed/getQuotes.defs.d.ts +6 -0
  121. package/dist/lexicons/app/bsky/feed/getQuotes.defs.d.ts.map +1 -1
  122. package/dist/lexicons/app/bsky/feed/getQuotes.defs.js +2 -0
  123. package/dist/lexicons/app/bsky/feed/getQuotes.defs.js.map +1 -1
  124. package/dist/lexicons/app/bsky/feed/getTimeline.defs.d.ts +4 -0
  125. package/dist/lexicons/app/bsky/feed/getTimeline.defs.d.ts.map +1 -1
  126. package/dist/lexicons/app/bsky/feed/getTimeline.defs.js +2 -0
  127. package/dist/lexicons/app/bsky/feed/getTimeline.defs.js.map +1 -1
  128. package/dist/lexicons/app/bsky/notification/getGroupedNotifications.d.ts +3 -0
  129. package/dist/lexicons/app/bsky/notification/getGroupedNotifications.d.ts.map +1 -0
  130. package/dist/lexicons/app/bsky/notification/getGroupedNotifications.defs.d.ts +299 -0
  131. package/dist/lexicons/app/bsky/notification/getGroupedNotifications.defs.d.ts.map +1 -0
  132. package/dist/lexicons/app/bsky/notification/getGroupedNotifications.defs.js +231 -0
  133. package/dist/lexicons/app/bsky/notification/getGroupedNotifications.defs.js.map +1 -0
  134. package/dist/lexicons/app/bsky/notification/getGroupedNotifications.js +6 -0
  135. package/dist/lexicons/app/bsky/notification/getGroupedNotifications.js.map +1 -0
  136. package/dist/lexicons/app/bsky/notification.d.ts +1 -0
  137. package/dist/lexicons/app/bsky/notification.d.ts.map +1 -1
  138. package/dist/lexicons/app/bsky/notification.js +1 -0
  139. package/dist/lexicons/app/bsky/notification.js.map +1 -1
  140. package/dist/lexicons/tools/ozone/inbox/appealActionedSubject.d.ts +3 -0
  141. package/dist/lexicons/tools/ozone/inbox/appealActionedSubject.d.ts.map +1 -0
  142. package/dist/lexicons/tools/ozone/inbox/appealActionedSubject.defs.d.ts +65 -0
  143. package/dist/lexicons/tools/ozone/inbox/appealActionedSubject.defs.d.ts.map +1 -0
  144. package/dist/lexicons/tools/ozone/inbox/appealActionedSubject.defs.js +49 -0
  145. package/dist/lexicons/tools/ozone/inbox/appealActionedSubject.defs.js.map +1 -0
  146. package/dist/lexicons/tools/ozone/inbox/appealActionedSubject.js +6 -0
  147. package/dist/lexicons/tools/ozone/inbox/appealActionedSubject.js.map +1 -0
  148. package/dist/lexicons/tools/ozone/inbox/defs.d.ts +2 -0
  149. package/dist/lexicons/tools/ozone/inbox/defs.d.ts.map +1 -0
  150. package/dist/lexicons/tools/ozone/inbox/defs.defs.d.ts +89 -0
  151. package/dist/lexicons/tools/ozone/inbox/defs.defs.d.ts.map +1 -0
  152. package/dist/lexicons/tools/ozone/inbox/defs.defs.js +73 -0
  153. package/dist/lexicons/tools/ozone/inbox/defs.defs.js.map +1 -0
  154. package/dist/lexicons/tools/ozone/inbox/defs.js +5 -0
  155. package/dist/lexicons/tools/ozone/inbox/defs.js.map +1 -0
  156. package/dist/lexicons/tools/ozone/inbox.d.ts +3 -0
  157. package/dist/lexicons/tools/ozone/inbox.d.ts.map +1 -0
  158. package/dist/lexicons/tools/ozone/inbox.js +6 -0
  159. package/dist/lexicons/tools/ozone/inbox.js.map +1 -0
  160. package/dist/lexicons/tools/ozone/queue/createQueue.defs.d.ts +2 -0
  161. package/dist/lexicons/tools/ozone/queue/createQueue.defs.d.ts.map +1 -1
  162. package/dist/lexicons/tools/ozone/queue/createQueue.defs.js +2 -0
  163. package/dist/lexicons/tools/ozone/queue/createQueue.defs.js.map +1 -1
  164. package/dist/lexicons/tools/ozone/queue/defs.defs.d.ts +4 -0
  165. package/dist/lexicons/tools/ozone/queue/defs.defs.d.ts.map +1 -1
  166. package/dist/lexicons/tools/ozone/queue/defs.defs.js +2 -0
  167. package/dist/lexicons/tools/ozone/queue/defs.defs.js.map +1 -1
  168. package/dist/lexicons/tools/ozone/queue/updateQueue.defs.d.ts +3 -1
  169. package/dist/lexicons/tools/ozone/queue/updateQueue.defs.d.ts.map +1 -1
  170. package/dist/lexicons/tools/ozone/queue/updateQueue.defs.js +3 -0
  171. package/dist/lexicons/tools/ozone/queue/updateQueue.defs.js.map +1 -1
  172. package/dist/lexicons/tools/ozone/report/defs.defs.d.ts +89 -9
  173. package/dist/lexicons/tools/ozone/report/defs.defs.d.ts.map +1 -1
  174. package/dist/lexicons/tools/ozone/report/defs.defs.js +20 -0
  175. package/dist/lexicons/tools/ozone/report/defs.defs.js.map +1 -1
  176. package/dist/lexicons/tools/ozone/report/getLiveStats.defs.d.ts +1 -1
  177. package/dist/lexicons/tools/ozone/report/getLiveStats.defs.d.ts.map +1 -1
  178. package/dist/lexicons/tools/ozone/report/getLiveStats.defs.js +1 -1
  179. package/dist/lexicons/tools/ozone/report/getLiveStats.defs.js.map +1 -1
  180. package/dist/lexicons/tools/ozone/report/refreshStats.defs.d.ts +1 -1
  181. package/dist/lexicons/tools/ozone/report/refreshStats.defs.d.ts.map +1 -1
  182. package/dist/lexicons/tools/ozone/report/refreshStats.defs.js +1 -1
  183. package/dist/lexicons/tools/ozone/report/refreshStats.defs.js.map +1 -1
  184. package/dist/lexicons/tools/ozone.d.ts +1 -0
  185. package/dist/lexicons/tools/ozone.d.ts.map +1 -1
  186. package/dist/lexicons/tools/ozone.js +1 -0
  187. package/dist/lexicons/tools/ozone.js.map +1 -1
  188. package/dist/mailer/index.d.ts +7 -1
  189. package/dist/mailer/index.d.ts.map +1 -1
  190. package/dist/mailer/index.js +12 -1
  191. package/dist/mailer/index.js.map +1 -1
  192. package/dist/mailer/templates/sign-in-auth-factor.js +43 -0
  193. package/dist/mailer/templates/sign-in-auth-factor.js.map +1 -0
  194. package/dist/mailer/templates.d.ts +2 -0
  195. package/dist/mailer/templates.d.ts.map +1 -1
  196. package/dist/mailer/templates.js +1 -0
  197. package/dist/mailer/templates.js.map +1 -1
  198. package/dist/pipethrough.d.ts.map +1 -1
  199. package/dist/pipethrough.js +9 -2
  200. package/dist/pipethrough.js.map +1 -1
  201. package/package.json +21 -21
package/CHANGELOG.md CHANGED
@@ -1,5 +1,64 @@
1
1
  # @atproto/pds
2
2
 
3
+ ## 0.5.37
4
+
5
+ ### Patch Changes
6
+
7
+ - [#5493](https://github.com/bluesky-social/atproto/pull/5493) [`cd736b3`](https://github.com/bluesky-social/atproto/commit/cd736b3dbbec957cf4eaa7e67fa5b8be8f8ae04e) Thanks [@mozzius](https://github.com/mozzius)! - Add `since` and `startCursor` to `getTimeline` and `getListFeed`, for reading everything strictly newer than a previously returned position.
8
+
9
+ - [#5576](https://github.com/bluesky-social/atproto/pull/5576) [`13b7cb0`](https://github.com/bluesky-social/atproto/commit/13b7cb000d7358a570be46854a93e441c8fa791e) Thanks [@matthieusieben](https://github.com/matthieusieben)! - Improve resource management of actor store
10
+
11
+ - [#5584](https://github.com/bluesky-social/atproto/pull/5584) [`a6561d5`](https://github.com/bluesky-social/atproto/commit/a6561d54227756876a0901e4a87675df17972d32) Thanks [@haileyok](https://github.com/haileyok)! - Reject MSTs that reference the same node more than once. Full-tree traversals and diffs now throw `VisitedCidError` instead of re-walking shared subtrees, bounding their cost by the number of unique blocks. `com.atproto.repo.importRepo` returns `InvalidRequest` for such repos.
12
+ - Updated dependencies [[`13b7cb0`](https://github.com/bluesky-social/atproto/commit/13b7cb000d7358a570be46854a93e441c8fa791e), [`f8ed258`](https://github.com/bluesky-social/atproto/commit/f8ed25853dc91a16639decfaee2e0dcbb60808cd), [`cea6f5c`](https://github.com/bluesky-social/atproto/commit/cea6f5c4a034860c35eda03dbde207f5bdb9387f), [`13b7cb0`](https://github.com/bluesky-social/atproto/commit/13b7cb000d7358a570be46854a93e441c8fa791e), [`0593d81`](https://github.com/bluesky-social/atproto/commit/0593d818bc2b7f8a40c9d0fe036bf39c7a4eecda), [`e8b89ff`](https://github.com/bluesky-social/atproto/commit/e8b89ff4c211a10519b54bd83eb64950035942c3), [`a6561d5`](https://github.com/bluesky-social/atproto/commit/a6561d54227756876a0901e4a87675df17972d32), [`52e51de`](https://github.com/bluesky-social/atproto/commit/52e51de0fc7b27173fe7ecc2c7b47ec476a8c1bf)]:
13
+ - @atproto/repo@0.11.0
14
+ - @atproto/crypto@0.5.7
15
+ - @atproto/oauth-provider@0.23.1
16
+ - @atproto/aws@0.3.19
17
+ - @atproto-labs/opentelemetry-node@0.3.0
18
+ - @atproto/lex-data@0.1.8
19
+ - @atproto/identity@0.5.16
20
+ - @atproto/xrpc-server@0.13.4
21
+ - @atproto/common@0.8.5
22
+ - @atproto/lex@0.3.14
23
+ - @atproto/lex-cbor@0.1.7
24
+ - @atproto/lex-document@0.1.13
25
+ - @atproto/lex-json@0.1.7
26
+ - @atproto-labs/xrpc-utils@0.1.25
27
+
28
+ ## 0.5.36
29
+
30
+ ### Patch Changes
31
+
32
+ - [#5562](https://github.com/bluesky-social/atproto/pull/5562) [`f632a35`](https://github.com/bluesky-social/atproto/commit/f632a35e8641644022bf430c6e3b34b1382cab55) Thanks [@matthieusieben](https://github.com/matthieusieben)! - Remove the need to provide a `plcRotationKey` secret when and override is provided
33
+
34
+ - [#5563](https://github.com/bluesky-social/atproto/pull/5563) [`af8c350`](https://github.com/bluesky-social/atproto/commit/af8c3501cd32e82cf8128683445656aa6708608d) Thanks [@matthieusieben](https://github.com/matthieusieben)! - Report a handle or email belonging to a deactivated or taken down account as an `InvalidRequest` from `com.atproto.server.createAccount`, instead of failing with an `InternalServerError` once the insert hits the unique index.
35
+
36
+ - [#5556](https://github.com/bluesky-social/atproto/pull/5556) [`5019f55`](https://github.com/bluesky-social/atproto/commit/5019f5537317ee75ad4527db212bc27c3085fe67) Thanks [@dependabot](https://github.com/apps/dependabot)! - build(deps-dev): bump the dev-dependencies group across 1 directory with 25 updates
37
+
38
+ - [#5562](https://github.com/bluesky-social/atproto/pull/5562) [`f632a35`](https://github.com/bluesky-social/atproto/commit/f632a35e8641644022bf430c6e3b34b1382cab55) Thanks [@matthieusieben](https://github.com/matthieusieben)! - Honour the `plcRotationKey` override passed to `PDS.create` when updating handles and when creating or tombstoning accounts through OAuth.
39
+
40
+ - [#5563](https://github.com/bluesky-social/atproto/pull/5563) [`af8c350`](https://github.com/bluesky-social/atproto/commit/af8c3501cd32e82cf8128683445656aa6708608d) Thanks [@matthieusieben](https://github.com/matthieusieben)! - Name the handle, rather than the email, when account creation conflicts on the handle.
41
+
42
+ - [#5207](https://github.com/bluesky-social/atproto/pull/5207) [`f5f0aab`](https://github.com/bluesky-social/atproto/commit/f5f0aab4cf3046de3dddd9251a07003d29e3c0be) Thanks [@ThisIsMissEm](https://github.com/ThisIsMissEm)! - Fix email authentication factor toggles, including repeated requests, without treating an omitted setting as a request to disable two-factor authentication.
43
+
44
+ - [#5459](https://github.com/bluesky-social/atproto/pull/5459) [`136e214`](https://github.com/bluesky-social/atproto/commit/136e2145b893773a94e9620df37be5215cdb57a3) Thanks [@gcwill70](https://github.com/gcwill70)! - Allow takendown accounts to file actioned-subject appeals through the PDS.
45
+
46
+ - [#5207](https://github.com/bluesky-social/atproto/pull/5207) [`f5f0aab`](https://github.com/bluesky-social/atproto/commit/f5f0aab4cf3046de3dddd9251a07003d29e3c0be) Thanks [@ThisIsMissEm](https://github.com/ThisIsMissEm)! - Add email-based authentication factor (2FA) for account sign-in
47
+
48
+ - [#5562](https://github.com/bluesky-social/atproto/pull/5562) [`f632a35`](https://github.com/bluesky-social/atproto/commit/f632a35e8641644022bf430c6e3b34b1382cab55) Thanks [@matthieusieben](https://github.com/matthieusieben)! - Add `overrides?: Partial<AppContextOptions>` argument to `PDS.fromEnv`
49
+ - Updated dependencies [[`5019f55`](https://github.com/bluesky-social/atproto/commit/5019f5537317ee75ad4527db212bc27c3085fe67), [`f5f0aab`](https://github.com/bluesky-social/atproto/commit/f5f0aab4cf3046de3dddd9251a07003d29e3c0be)]:
50
+ - @atproto/crypto@0.5.6
51
+ - @atproto/did@0.5.6
52
+ - @atproto/identity@0.5.15
53
+ - @atproto/repo@0.10.15
54
+ - @atproto/xrpc-server@0.13.3
55
+ - @atproto/oauth-provider@0.23.0
56
+ - @atproto/aws@0.3.18
57
+ - @atproto/common@0.8.4
58
+ - @atproto/oauth-scopes@0.5.13
59
+ - @atproto-labs/xrpc-utils@0.1.24
60
+ - @atproto/lex@0.3.13
61
+
3
62
  ## 0.5.35
4
63
 
5
64
  ### Patch Changes
@@ -15,6 +15,10 @@ import * as accountHelpers from './helpers/account.js';
15
15
  import { AccountStatus, type ActorAccount } from './helpers/account.js';
16
16
  import * as password from './helpers/password.js';
17
17
  export { AccountStatus, formatAccountStatus } from './helpers/account.js';
18
+ export type UpdateAccountEmailOptions = {
19
+ sendConfirmationEmail?: boolean;
20
+ locale?: string;
21
+ };
18
22
  /**
19
23
  * Thrown by {@link AccountManager.login} when the identifier resolved to a
20
24
  * known account but the supplied credentials (account password / app
@@ -31,6 +35,26 @@ export declare class InvalidPasswordError extends AuthRequiredError {
31
35
  readonly did: DidString;
32
36
  constructor(did: DidString, errorMessage?: string);
33
37
  }
38
+ /**
39
+ * Thrown by {@link AccountManager.login} when the credentials were valid but
40
+ * the account requires a second authentication factor. A one-time code has
41
+ * already been dispatched by the time this is thrown.
42
+ *
43
+ * XRPC-native like every other error this class raises: `AuthFactorTokenRequired`
44
+ * is the error name `com.atproto.server.createSession` declares, so that path
45
+ * needs no translation. The OAuth boundary ({@link OAuthStore.authenticateAccount})
46
+ * converts it to `SecondAuthenticationFactorRequiredError` — which is why
47
+ * `factor` and `hint` are carried as fields rather than baked into the message.
48
+ *
49
+ * @NOTE Subclasses {@link AuthRequiredError}, so any `instanceof` check against
50
+ * the base class must come *after* this one — see the ordering note in
51
+ * `OAuthStore.authenticateAccount`.
52
+ */
53
+ export declare class AuthFactorRequiredError extends AuthRequiredError {
54
+ readonly factor: 'emailOtp';
55
+ readonly hint: string;
56
+ constructor(factor: 'emailOtp', hint: string, errorMessage?: string);
57
+ }
34
58
  export type AccountManagerDbConfig = {
35
59
  accountDbLoc: string;
36
60
  disableWalAutoCheckpoint: boolean;
@@ -49,7 +73,7 @@ export declare class AccountManager {
49
73
  get serviceDid(): DidString;
50
74
  get serviceHandleDomains(): string[];
51
75
  migrateOrThrow(): Promise<void>;
52
- close(): void;
76
+ close(): Promise<void>;
53
77
  getAccount(handleOrDid: AtIdentifierString, flags?: accountHelpers.AvailabilityFlags): Promise<ActorAccount | null>;
54
78
  getAccounts(dids: DidString[], flags?: accountHelpers.AvailabilityFlags): Promise<Map<string, ActorAccount>>;
55
79
  getAccountByEmail(email: string, flags?: accountHelpers.AvailabilityFlags): Promise<ActorAccount | null>;
@@ -159,9 +183,11 @@ export declare class AccountManager {
159
183
  }>;
160
184
  rotateRefreshToken(id: string): any;
161
185
  revokeRefreshToken(id: string): Promise<boolean>;
162
- login({ identifier, password, }: {
186
+ login({ identifier, password, authFactorToken, locale, }: {
163
187
  identifier: string;
164
188
  password: string;
189
+ authFactorToken?: string | undefined;
190
+ locale?: string | undefined;
165
191
  }): Promise<{
166
192
  user: ActorAccount;
167
193
  appPassword: password.AppPassDescript | null;
@@ -203,17 +229,42 @@ export declare class AccountManager {
203
229
  }): Promise<{
204
230
  tokenRequired: boolean;
205
231
  }>;
232
+ checkUpdateEmail(did: DidString, email: string, token?: string): Promise<ActorAccount>;
206
233
  /**
207
234
  * @throws UserAlreadyExistsError if the new email is already in use by another account
208
235
  */
209
- updateEmail(did: DidString, email: string, token?: string, opts?: {
210
- locale?: string;
211
- sendConfirmationEmail?: boolean;
236
+ updateEmail(did: DidString, email: string, token?: string, opts?: UpdateAccountEmailOptions): Promise<ActorAccount>;
237
+ updateAccountEmail(did: DidString, email: string, opts?: UpdateAccountEmailOptions): Promise<void>;
238
+ /**
239
+ * Enable email-based two-factor authentication. Enabling is immediate: the
240
+ * account must already have a confirmed email matching `email`, since the
241
+ * factor delivers one-time codes to that address. Returns
242
+ * `{ account, tokenRequired }` for symmetry with future factors that require
243
+ * a confirmation step; email-based 2FA never does, so `tokenRequired` is
244
+ * always `false`.
245
+ *
246
+ * @throws InvalidRequestError if the account has no confirmed, matching email
247
+ */
248
+ enableEmailAuthFactor(opts: {
249
+ did: DidString;
212
250
  }): Promise<ActorAccount>;
213
- updateAccountEmail(opts: {
251
+ /**
252
+ * Disable email-based two-factor authentication. This supports a two-phase
253
+ * flow, if a token isn't initially supplied for proving control of the inbox
254
+ * which prevents a hijacked session from silently turning off the factor. The
255
+ * second call (with a valid `token`) actually disables it. Disabling an
256
+ * already-disabled factor is an idempotent no-op.
257
+ *
258
+ * @throws InvalidRequestError if the account has no matching email, or the
259
+ * token is invalid
260
+ * @throws InvalidRequestError with `TokenRequired` error code if a
261
+ * confirmation token is required but not provided
262
+ */
263
+ disableEmailAuthFactor(opts: {
214
264
  did: DidString;
215
- email: string;
216
- }): Promise<void>;
265
+ token?: string;
266
+ locale?: string;
267
+ }): Promise<ActorAccount>;
217
268
  resetPassword(opts: {
218
269
  password: string;
219
270
  token: string;
@@ -1 +1 @@
1
- {"version":3,"file":"account-manager.d.ts","sourceRoot":"","sources":["../../src/account-manager/account-manager.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"account-manager.d.ts","sourceRoot":"","sources":["../../src/account-manager/account-manager.ts"],"names":[],"mappings":"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"}
@@ -1,7 +1,7 @@
1
1
  import assert from 'node:assert';
2
2
  import { isEmailValid } from '@hapi/address';
3
3
  import { isDisposableEmail } from 'disposable-email-domains-js';
4
- import { HOUR, wait } from '@atproto/common';
4
+ import { HOUR, obfuscateEmail, wait } from '@atproto/common';
5
5
  import { isAtIdentifierString, } from '@atproto/lex';
6
6
  import { INVALID_HANDLE, currentDatetimeString, isValidTld, } from '@atproto/syntax';
7
7
  import { AuthRequiredError, InvalidRequestError } from '@atproto/xrpc-server';
@@ -16,6 +16,7 @@ import * as accountHelpers from './helpers/account.js';
16
16
  import { AccountStatus } from './helpers/account.js';
17
17
  import * as auth from './helpers/auth.js';
18
18
  import * as authorizedClientHelper from './helpers/authorized-client.js';
19
+ import * as emailAuthFactor from './helpers/email-auth-factor.js';
19
20
  import * as emailToken from './helpers/email-token.js';
20
21
  import * as invite from './helpers/invite.js';
21
22
  import * as password from './helpers/password.js';
@@ -41,6 +42,28 @@ export class InvalidPasswordError extends AuthRequiredError {
41
42
  this.did = did;
42
43
  }
43
44
  }
45
+ /**
46
+ * Thrown by {@link AccountManager.login} when the credentials were valid but
47
+ * the account requires a second authentication factor. A one-time code has
48
+ * already been dispatched by the time this is thrown.
49
+ *
50
+ * XRPC-native like every other error this class raises: `AuthFactorTokenRequired`
51
+ * is the error name `com.atproto.server.createSession` declares, so that path
52
+ * needs no translation. The OAuth boundary ({@link OAuthStore.authenticateAccount})
53
+ * converts it to `SecondAuthenticationFactorRequiredError` — which is why
54
+ * `factor` and `hint` are carried as fields rather than baked into the message.
55
+ *
56
+ * @NOTE Subclasses {@link AuthRequiredError}, so any `instanceof` check against
57
+ * the base class must come *after* this one — see the ordering note in
58
+ * `OAuthStore.authenticateAccount`.
59
+ */
60
+ export class AuthFactorRequiredError extends AuthRequiredError {
61
+ constructor(factor, hint, errorMessage = 'A sign in code has been sent to your email address') {
62
+ super(errorMessage, 'AuthFactorTokenRequired');
63
+ this.factor = factor;
64
+ this.hint = hint;
65
+ }
66
+ }
44
67
  export class AccountManager {
45
68
  constructor(cfg, actorStore, idResolver, jwtKey, mailer, sequencer, plcClient, plcRotationKey) {
46
69
  this.cfg = cfg;
@@ -63,8 +86,8 @@ export class AccountManager {
63
86
  await this.db.ensureWal();
64
87
  await getMigrator(this.db).migrateToLatestOrThrow();
65
88
  }
66
- close() {
67
- this.db.close();
89
+ async close() {
90
+ await this.db.close();
68
91
  }
69
92
  // Account
70
93
  // ----------
@@ -353,7 +376,7 @@ export class AccountManager {
353
376
  }
354
377
  // Login
355
378
  // ----------
356
- async login({ identifier, password, }) {
379
+ async login({ identifier, password, authFactorToken, locale, }) {
357
380
  const start = Date.now();
358
381
  try {
359
382
  const identifierNormalized = identifier.toLowerCase();
@@ -384,6 +407,17 @@ export class AccountManager {
384
407
  throw new InvalidPasswordError(user.did);
385
408
  }
386
409
  }
410
+ if (authFactorToken) {
411
+ await this.assertValidEmailTokenAndCleanup(user.did, 'auth_factor', authFactorToken);
412
+ // require email factor when not using an app password
413
+ }
414
+ else if (user.email !== null &&
415
+ user.emailAuthFactorAt !== null &&
416
+ appPassword === null) {
417
+ const token = await this.createEmailToken(user.did, 'auth_factor');
418
+ await this.mailer.sendSignInAuthFactor({ token, handle: user.handle, locale }, { to: user.email });
419
+ throw new AuthFactorRequiredError('emailOtp', obfuscateEmail(user.email));
420
+ }
387
421
  return { user, appPassword, isSoftDeleted };
388
422
  }
389
423
  finally {
@@ -512,10 +546,7 @@ export class AccountManager {
512
546
  }
513
547
  return { tokenRequired: !!token };
514
548
  }
515
- /**
516
- * @throws UserAlreadyExistsError if the new email is already in use by another account
517
- */
518
- async updateEmail(did, email, token, opts) {
549
+ async checkUpdateEmail(did, email, token) {
519
550
  if (!isEmailValid(email) || isDisposableEmail(email)) {
520
551
  throw new InvalidRequestError('This email address is not supported, please use a different email.');
521
552
  }
@@ -524,34 +555,136 @@ export class AccountManager {
524
555
  includeTakenDown: true,
525
556
  });
526
557
  if (!account) {
527
- throw new InvalidRequestError('account not found');
558
+ throw new InvalidRequestError(`Could not find user info for account: ${did}`);
528
559
  }
529
560
  const tokenRequired = !!account.emailConfirmedAt;
530
- // require a token if account email is confirmed
531
- if (!token && tokenRequired) {
532
- throw new InvalidRequestError('confirmation token required', 'TokenRequired');
533
- }
534
561
  if (token) {
535
562
  await this.assertValidEmailToken(did, 'update_email', token);
536
563
  }
537
- await this.updateAccountEmail({ did, email });
564
+ else if (tokenRequired) {
565
+ // require a token if account email is confirmed
566
+ throw new InvalidRequestError('confirmation token required', 'TokenRequired');
567
+ }
568
+ return account;
569
+ }
570
+ /**
571
+ * @throws UserAlreadyExistsError if the new email is already in use by another account
572
+ */
573
+ async updateEmail(did, email, token, opts) {
574
+ const account = await this.checkUpdateEmail(did, email, token);
575
+ await this.updateAccountEmail(did, email, opts);
538
576
  account.email = email;
539
577
  account.emailConfirmedAt = null;
578
+ return account;
579
+ }
580
+ async updateAccountEmail(did, email, opts) {
581
+ await this.db.transaction(async (dbTxn) => {
582
+ await accountHelpers.updateEmail(dbTxn, did, email);
583
+ // @NOTE In the same transaction as the email write, deliberately: the
584
+ // new address is unconfirmed, and 2FA against an unconfirmed address can
585
+ // lock the user out. The account-manager UI warns about this, see
586
+ // `show2FaWarningOnEmailUpdate` in context.ts.
587
+ await emailAuthFactor.deleteForDid(dbTxn, did);
588
+ await emailToken.deleteAllEmailTokens(dbTxn, did);
589
+ });
540
590
  // Proactively send a confirmation email so that the user can confirm the
541
591
  // new email immediately.
542
592
  if (opts?.sendConfirmationEmail) {
543
593
  const token = await this.createEmailToken(did, 'confirm_email');
544
- const locale = opts.locale;
594
+ const { locale } = opts;
545
595
  await this.mailer.sendConfirmEmail({ token, locale }, { to: email });
546
596
  }
547
- return account;
548
597
  }
549
- async updateAccountEmail(opts) {
550
- const { did, email } = opts;
551
- await this.db.transaction(async (dbTxn) => {
552
- await accountHelpers.updateEmail(dbTxn, did, email);
553
- await emailToken.deleteAllEmailTokens(dbTxn, did);
598
+ /**
599
+ * Enable email-based two-factor authentication. Enabling is immediate: the
600
+ * account must already have a confirmed email matching `email`, since the
601
+ * factor delivers one-time codes to that address. Returns
602
+ * `{ account, tokenRequired }` for symmetry with future factors that require
603
+ * a confirmation step; email-based 2FA never does, so `tokenRequired` is
604
+ * always `false`.
605
+ *
606
+ * @throws InvalidRequestError if the account has no confirmed, matching email
607
+ */
608
+ async enableEmailAuthFactor(opts) {
609
+ const { did } = opts;
610
+ const account = await this.getAccount(did, {
611
+ includeDeactivated: true,
612
+ includeTakenDown: true,
613
+ });
614
+ if (!account) {
615
+ throw new InvalidRequestError('account not found');
616
+ }
617
+ // Already enabled → nothing to change (idempotent).
618
+ if (account.emailAuthFactorAt) {
619
+ return account;
620
+ }
621
+ // Email confirmed → attempt to enable email-based 2FA.
622
+ if (account.email && account.emailConfirmedAt) {
623
+ const emailAuthFactorAt = await emailAuthFactor.enable(this.db, did, account.email);
624
+ // @NOTE The confirmed-email requirement is enforced in the insert's own
625
+ // SELECT, so a miss here means the address stopped being confirmed (or
626
+ // changed) between that read and this write. Nothing was persisted, so
627
+ // don't hand back an account claiming otherwise.
628
+ if (emailAuthFactorAt) {
629
+ account.emailAuthFactorAt = emailAuthFactorAt;
630
+ return account;
631
+ }
632
+ }
633
+ throw new InvalidRequestError('A confirmed email address is required to enable email-based two-factor authentication');
634
+ }
635
+ /**
636
+ * Disable email-based two-factor authentication. This supports a two-phase
637
+ * flow, if a token isn't initially supplied for proving control of the inbox
638
+ * which prevents a hijacked session from silently turning off the factor. The
639
+ * second call (with a valid `token`) actually disables it. Disabling an
640
+ * already-disabled factor is an idempotent no-op.
641
+ *
642
+ * @throws InvalidRequestError if the account has no matching email, or the
643
+ * token is invalid
644
+ * @throws InvalidRequestError with `TokenRequired` error code if a
645
+ * confirmation token is required but not provided
646
+ */
647
+ async disableEmailAuthFactor(opts) {
648
+ const { did, token, locale } = opts;
649
+ const account = await this.getAccount(did, {
650
+ includeDeactivated: true,
651
+ includeTakenDown: true,
554
652
  });
653
+ if (!account) {
654
+ throw new InvalidRequestError('account not found');
655
+ }
656
+ // Already disabled → idempotent no-op; nothing to confirm, no OTP sent.
657
+ if (!account.emailAuthFactorAt) {
658
+ return account;
659
+ }
660
+ // Fool-proof: account in invalid state
661
+ if (!account.email) {
662
+ throw new Error('account has no email address');
663
+ }
664
+ // Phase one: no token yet, send a one-time code and signal "pending". MUST
665
+ // use `update_email` due to social-app using requestEmailUpdate, not
666
+ // two-step updateEmail:
667
+ if (!token) {
668
+ const otp = await this.createEmailToken(did, 'update_email');
669
+ await this.mailer.sendUpdateEmail({ token: otp, locale: locale }, { to: account.email });
670
+ throw new InvalidRequestError('confirmation token required', 'TokenRequired');
671
+ }
672
+ // Phase two: verify the one-time code, then disable the factor.
673
+ await this.assertValidEmailTokenAndCleanup(did, 'update_email', token);
674
+ // The returned flag is deliberately ignored here, unlike in
675
+ // `enableEmailAuthFactor`. Disabling only conditions the write on `did` and
676
+ // `email` matching, so a miss means no row matched either, leaving nothing
677
+ // worth reporting. A deleted account has no factor left to disable, and a
678
+ // changed email drops the factor row in the same transaction (see
679
+ // `updateAccountEmail`). That second case stops arising once unconfirmed
680
+ // emails get a column of their own, since `account.email` will no longer
681
+ // move mid-flow; the conclusion holds either way.
682
+ //
683
+ // Enabling is the opposite: a miss there leaves the account in the very
684
+ // state the caller asked to change, hence the throw.
685
+ await emailAuthFactor.disable(this.db, did, account.email);
686
+ account.emailAuthFactorAt = null;
687
+ return account;
555
688
  }
556
689
  async resetPassword(opts) {
557
690
  const did = await emailToken.assertValidTokenAndFindDid(this.db, 'reset_password', opts.token);