@atproto/pds 0.4.226 → 0.5.1

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 (113) hide show
  1. package/CHANGELOG.md +27 -0
  2. package/dist/account-manager/account-manager.d.ts +19 -5
  3. package/dist/account-manager/account-manager.d.ts.map +1 -1
  4. package/dist/account-manager/account-manager.js +94 -12
  5. package/dist/account-manager/account-manager.js.map +1 -1
  6. package/dist/account-manager/helpers/account.d.ts +2 -0
  7. package/dist/account-manager/helpers/account.d.ts.map +1 -1
  8. package/dist/account-manager/helpers/account.js +4 -0
  9. package/dist/account-manager/helpers/account.js.map +1 -1
  10. package/dist/account-manager/oauth-store.d.ts +5 -1
  11. package/dist/account-manager/oauth-store.d.ts.map +1 -1
  12. package/dist/account-manager/oauth-store.js +50 -1
  13. package/dist/account-manager/oauth-store.js.map +1 -1
  14. package/dist/api/app/bsky/actor/getPreferences.d.ts.map +1 -1
  15. package/dist/api/app/bsky/actor/getPreferences.js +7 -2
  16. package/dist/api/app/bsky/actor/getPreferences.js.map +1 -1
  17. package/dist/api/app/bsky/actor/putPreferences.d.ts.map +1 -1
  18. package/dist/api/app/bsky/actor/putPreferences.js +7 -2
  19. package/dist/api/app/bsky/actor/putPreferences.js.map +1 -1
  20. package/dist/api/com/atproto/admin/updateAccountEmail.js +1 -1
  21. package/dist/api/com/atproto/admin/updateAccountEmail.js.map +1 -1
  22. package/dist/api/com/atproto/server/confirmEmail.d.ts.map +1 -1
  23. package/dist/api/com/atproto/server/confirmEmail.js +20 -27
  24. package/dist/api/com/atproto/server/confirmEmail.js.map +1 -1
  25. package/dist/api/com/atproto/server/getServiceAuth.d.ts.map +1 -1
  26. package/dist/api/com/atproto/server/getServiceAuth.js +4 -0
  27. package/dist/api/com/atproto/server/getServiceAuth.js.map +1 -1
  28. package/dist/api/com/atproto/server/requestEmailConfirmation.d.ts +3 -1
  29. package/dist/api/com/atproto/server/requestEmailConfirmation.d.ts.map +1 -1
  30. package/dist/api/com/atproto/server/requestEmailConfirmation.js +44 -39
  31. package/dist/api/com/atproto/server/requestEmailConfirmation.js.map +1 -1
  32. package/dist/api/com/atproto/server/requestEmailUpdate.d.ts +3 -1
  33. package/dist/api/com/atproto/server/requestEmailUpdate.d.ts.map +1 -1
  34. package/dist/api/com/atproto/server/requestEmailUpdate.js +51 -47
  35. package/dist/api/com/atproto/server/requestEmailUpdate.js.map +1 -1
  36. package/dist/api/com/atproto/server/updateEmail.d.ts.map +1 -1
  37. package/dist/api/com/atproto/server/updateEmail.js +32 -46
  38. package/dist/api/com/atproto/server/updateEmail.js.map +1 -1
  39. package/dist/config/config.d.ts +5 -2
  40. package/dist/config/config.d.ts.map +1 -1
  41. package/dist/config/config.js +50 -46
  42. package/dist/config/config.js.map +1 -1
  43. package/dist/config/env.d.ts +1 -0
  44. package/dist/config/env.d.ts.map +1 -1
  45. package/dist/config/env.js +1 -0
  46. package/dist/config/env.js.map +1 -1
  47. package/dist/context.d.ts.map +1 -1
  48. package/dist/context.js +2 -2
  49. package/dist/context.js.map +1 -1
  50. package/dist/lexicons/app/bsky/embed/external.defs.d.ts +5 -0
  51. package/dist/lexicons/app/bsky/embed/external.defs.d.ts.map +1 -1
  52. package/dist/lexicons/app/bsky/embed/external.defs.js +4 -0
  53. package/dist/lexicons/app/bsky/embed/external.defs.js.map +1 -1
  54. package/dist/lexicons/chat/bsky/actor/getStatus.defs.d.ts +2 -0
  55. package/dist/lexicons/chat/bsky/actor/getStatus.defs.d.ts.map +1 -1
  56. package/dist/lexicons/chat/bsky/actor/getStatus.defs.js +1 -0
  57. package/dist/lexicons/chat/bsky/actor/getStatus.defs.js.map +1 -1
  58. package/dist/lexicons/chat/bsky/convo/defs.defs.d.ts +4 -0
  59. package/dist/lexicons/chat/bsky/convo/defs.defs.d.ts.map +1 -1
  60. package/dist/lexicons/chat/bsky/convo/defs.defs.js +1 -0
  61. package/dist/lexicons/chat/bsky/convo/defs.defs.js.map +1 -1
  62. package/dist/lexicons/com/atproto/server/getServiceAuth.defs.d.ts +2 -2
  63. package/dist/lexicons/com/atproto/server/getServiceAuth.defs.js +1 -1
  64. package/dist/lexicons/com/atproto/server/getServiceAuth.defs.js.map +1 -1
  65. package/dist/mailer/index.d.ts +5 -3
  66. package/dist/mailer/index.d.ts.map +1 -1
  67. package/dist/mailer/index.js +20 -9
  68. package/dist/mailer/index.js.map +1 -1
  69. package/dist/mailer/templates/confirm-email.js +11 -3
  70. package/dist/mailer/templates/confirm-email.js.map +2 -2
  71. package/dist/mailer/templates/delete-account.js +2 -2
  72. package/dist/mailer/templates/delete-account.js.map +2 -2
  73. package/dist/mailer/templates/plc-operation.js +2 -2
  74. package/dist/mailer/templates/plc-operation.js.map +2 -2
  75. package/dist/mailer/templates/reset-password.js +2 -2
  76. package/dist/mailer/templates/reset-password.js.map +2 -2
  77. package/dist/mailer/templates/update-email.js +2 -2
  78. package/dist/mailer/templates/update-email.js.map +2 -2
  79. package/dist/mailer/templates.d.ts +11 -0
  80. package/dist/mailer/templates.d.ts.map +1 -1
  81. package/dist/mailer/templates.js.map +1 -1
  82. package/dist/pipethrough.d.ts +3 -0
  83. package/dist/pipethrough.d.ts.map +1 -1
  84. package/dist/pipethrough.js +25 -9
  85. package/dist/pipethrough.js.map +1 -1
  86. package/package.json +12 -11
  87. package/src/account-manager/account-manager.ts +136 -15
  88. package/src/account-manager/helpers/account.ts +9 -1
  89. package/src/account-manager/oauth-store.ts +80 -1
  90. package/src/api/app/bsky/actor/getPreferences.ts +11 -2
  91. package/src/api/app/bsky/actor/putPreferences.ts +11 -2
  92. package/src/api/com/atproto/admin/updateAccountEmail.ts +1 -1
  93. package/src/api/com/atproto/server/confirmEmail.ts +24 -29
  94. package/src/api/com/atproto/server/getServiceAuth.ts +7 -0
  95. package/src/api/com/atproto/server/requestEmailConfirmation.ts +55 -48
  96. package/src/api/com/atproto/server/requestEmailUpdate.ts +64 -48
  97. package/src/api/com/atproto/server/updateEmail.ts +32 -62
  98. package/src/config/config.ts +69 -57
  99. package/src/config/env.ts +3 -0
  100. package/src/context.ts +2 -1
  101. package/src/mailer/index.ts +35 -11
  102. package/src/mailer/templates/confirm-email.hbs +18 -17
  103. package/src/mailer/templates/delete-account.hbs +6 -6
  104. package/src/mailer/templates/plc-operation.hbs +6 -6
  105. package/src/mailer/templates/reset-password.hbs +7 -7
  106. package/src/mailer/templates/update-email.hbs +6 -6
  107. package/src/mailer/templates.ts +12 -0
  108. package/src/pipethrough.ts +33 -12
  109. package/tests/account-manager.test.ts +89 -8
  110. package/tests/app-passwords.test.ts +5 -5
  111. package/tests/get-service-auth.test.ts +81 -0
  112. package/tests/proxied/proxy-header.test.ts +1 -0
  113. package/tests/proxied/proxy-oauth-aud.test.ts +175 -0
@@ -1,46 +1,51 @@
1
1
  import { DAY, HOUR } from '@atproto/common';
2
- import { InvalidRequestError } from '@atproto/xrpc-server';
3
2
  import { com } from '../../../../lexicons/index.js';
3
+ // Exposed as a utility to ensure auth in confirmEmail and requestEmailConfirmation
4
+ export function requestEmailConfirmationAuth(ctx) {
5
+ return ctx.authVerifier.authorization({
6
+ checkTakedown: true,
7
+ authorize: (permissions) => {
8
+ permissions.assertAccount({ attr: 'email', action: 'manage' });
9
+ },
10
+ });
11
+ }
12
+ const rateLimit = [
13
+ {
14
+ durationMs: DAY,
15
+ points: 15,
16
+ calcKey: ({ auth }) => auth.credentials.did,
17
+ },
18
+ {
19
+ durationMs: HOUR,
20
+ points: 5,
21
+ calcKey: ({ auth }) => auth.credentials.did,
22
+ },
23
+ ];
4
24
  export default function (server, ctx) {
5
- server.add(com.atproto.server.requestEmailConfirmation, {
6
- rateLimit: [
7
- {
8
- durationMs: DAY,
9
- points: 15,
10
- calcKey: ({ auth }) => auth.credentials.did,
11
- },
12
- {
13
- durationMs: HOUR,
14
- points: 5,
15
- calcKey: ({ auth }) => auth.credentials.did,
25
+ const { entrywayClient } = ctx;
26
+ const auth = requestEmailConfirmationAuth(ctx);
27
+ if (entrywayClient) {
28
+ server.add(com.atproto.server.requestEmailConfirmation, {
29
+ auth,
30
+ rateLimit,
31
+ handler: async ({ auth, req }) => {
32
+ const { headers } = await ctx.entrywayAuthHeaders(req, auth.credentials.did, com.atproto.server.requestEmailConfirmation.$lxm);
33
+ await entrywayClient.xrpc(com.atproto.server.requestEmailConfirmation, {
34
+ headers,
35
+ });
16
36
  },
17
- ],
18
- auth: ctx.authVerifier.authorization({
19
- checkTakedown: true,
20
- authorize: (permissions) => {
21
- permissions.assertAccount({ attr: 'email', action: 'manage' });
37
+ });
38
+ }
39
+ else {
40
+ server.add(com.atproto.server.requestEmailConfirmation, {
41
+ auth,
42
+ rateLimit,
43
+ handler: async ({ auth }) => {
44
+ const did = auth.credentials.did;
45
+ const locale = undefined; // @TODO get the locale somehow
46
+ await ctx.accountManager.requestEmailConfirmation(did, { locale });
22
47
  },
23
- }),
24
- handler: async ({ auth, req }) => {
25
- const did = auth.credentials.did;
26
- const account = await ctx.accountManager.getAccount(did, {
27
- includeDeactivated: true,
28
- includeTakenDown: true,
29
- });
30
- if (!account) {
31
- throw new InvalidRequestError('account not found');
32
- }
33
- if (ctx.entrywayClient) {
34
- const { headers } = await ctx.entrywayAuthHeaders(req, auth.credentials.did, com.atproto.server.requestEmailConfirmation.$lxm);
35
- await ctx.entrywayClient.xrpc(com.atproto.server.requestEmailConfirmation, { headers });
36
- return;
37
- }
38
- if (!account.email) {
39
- throw new InvalidRequestError('account does not have an email address');
40
- }
41
- const token = await ctx.accountManager.createEmailToken(did, 'confirm_email');
42
- await ctx.mailer.sendConfirmEmail({ token }, { to: account.email });
43
- },
44
- });
48
+ });
49
+ }
45
50
  }
46
51
  //# sourceMappingURL=requestEmailConfirmation.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"requestEmailConfirmation.js","sourceRoot":"","sources":["../../../../../src/api/com/atproto/server/requestEmailConfirmation.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAA;AAC3C,OAAO,EAAE,mBAAmB,EAAU,MAAM,sBAAsB,CAAA;AAElE,OAAO,EAAE,GAAG,EAAE,MAAM,+BAA+B,CAAA;AAEnD,MAAM,CAAC,OAAO,WAAW,MAAc,EAAE,GAAe;IACtD,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,wBAAwB,EAAE;QACtD,SAAS,EAAE;YACT;gBACE,UAAU,EAAE,GAAG;gBACf,MAAM,EAAE,EAAE;gBACV,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,IAAI,CAAC,WAAW,CAAC,GAAG;aAC5C;YACD;gBACE,UAAU,EAAE,IAAI;gBAChB,MAAM,EAAE,CAAC;gBACT,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,IAAI,CAAC,WAAW,CAAC,GAAG;aAC5C;SACF;QACD,IAAI,EAAE,GAAG,CAAC,YAAY,CAAC,aAAa,CAAC;YACnC,aAAa,EAAE,IAAI;YACnB,SAAS,EAAE,CAAC,WAAW,EAAE,EAAE;gBACzB,WAAW,CAAC,aAAa,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,CAAA;YAChE,CAAC;SACF,CAAC;QACF,OAAO,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,GAAG,EAAE,EAAE,EAAE;YAC/B,MAAM,GAAG,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,CAAA;YAChC,MAAM,OAAO,GAAG,MAAM,GAAG,CAAC,cAAc,CAAC,UAAU,CAAC,GAAG,EAAE;gBACvD,kBAAkB,EAAE,IAAI;gBACxB,gBAAgB,EAAE,IAAI;aACvB,CAAC,CAAA;YACF,IAAI,CAAC,OAAO,EAAE,CAAC;gBACb,MAAM,IAAI,mBAAmB,CAAC,mBAAmB,CAAC,CAAA;YACpD,CAAC;YAED,IAAI,GAAG,CAAC,cAAc,EAAE,CAAC;gBACvB,MAAM,EAAE,OAAO,EAAE,GAAG,MAAM,GAAG,CAAC,mBAAmB,CAC/C,GAAG,EACH,IAAI,CAAC,WAAW,CAAC,GAAG,EACpB,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,wBAAwB,CAAC,IAAI,CACjD,CAAA;gBAED,MAAM,GAAG,CAAC,cAAc,CAAC,IAAI,CAC3B,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,wBAAwB,EAC3C,EAAE,OAAO,EAAE,CACZ,CAAA;gBAED,OAAM;YACR,CAAC;YAED,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;gBACnB,MAAM,IAAI,mBAAmB,CAAC,wCAAwC,CAAC,CAAA;YACzE,CAAC;YACD,MAAM,KAAK,GAAG,MAAM,GAAG,CAAC,cAAc,CAAC,gBAAgB,CACrD,GAAG,EACH,eAAe,CAChB,CAAA;YACD,MAAM,GAAG,CAAC,MAAM,CAAC,gBAAgB,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,EAAE,OAAO,CAAC,KAAK,EAAE,CAAC,CAAA;QACrE,CAAC;KACF,CAAC,CAAA;AACJ,CAAC","sourcesContent":["import { DAY, HOUR } from '@atproto/common'\nimport { InvalidRequestError, Server } from '@atproto/xrpc-server'\nimport { AppContext } from '../../../../context.js'\nimport { com } from '../../../../lexicons/index.js'\n\nexport default function (server: Server, ctx: AppContext) {\n server.add(com.atproto.server.requestEmailConfirmation, {\n rateLimit: [\n {\n durationMs: DAY,\n points: 15,\n calcKey: ({ auth }) => auth.credentials.did,\n },\n {\n durationMs: HOUR,\n points: 5,\n calcKey: ({ auth }) => auth.credentials.did,\n },\n ],\n auth: ctx.authVerifier.authorization({\n checkTakedown: true,\n authorize: (permissions) => {\n permissions.assertAccount({ attr: 'email', action: 'manage' })\n },\n }),\n handler: async ({ auth, req }) => {\n const did = auth.credentials.did\n const account = await ctx.accountManager.getAccount(did, {\n includeDeactivated: true,\n includeTakenDown: true,\n })\n if (!account) {\n throw new InvalidRequestError('account not found')\n }\n\n if (ctx.entrywayClient) {\n const { headers } = await ctx.entrywayAuthHeaders(\n req,\n auth.credentials.did,\n com.atproto.server.requestEmailConfirmation.$lxm,\n )\n\n await ctx.entrywayClient.xrpc(\n com.atproto.server.requestEmailConfirmation,\n { headers },\n )\n\n return\n }\n\n if (!account.email) {\n throw new InvalidRequestError('account does not have an email address')\n }\n const token = await ctx.accountManager.createEmailToken(\n did,\n 'confirm_email',\n )\n await ctx.mailer.sendConfirmEmail({ token }, { to: account.email })\n },\n })\n}\n"]}
1
+ {"version":3,"file":"requestEmailConfirmation.js","sourceRoot":"","sources":["../../../../../src/api/com/atproto/server/requestEmailConfirmation.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAA;AAQ3C,OAAO,EAAE,GAAG,EAAE,MAAM,+BAA+B,CAAA;AAEnD,mFAAmF;AACnF,MAAM,UAAU,4BAA4B,CAC1C,GAAe;IAEf,OAAO,GAAG,CAAC,YAAY,CAAC,aAAa,CAAC;QACpC,aAAa,EAAE,IAAI;QACnB,SAAS,EAAE,CAAC,WAAW,EAAE,EAAE;YACzB,WAAW,CAAC,aAAa,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,CAAA;QAChE,CAAC;KACF,CAAC,CAAA;AACJ,CAAC;AAED,MAAM,SAAS,GAAgD;IAC7D;QACE,UAAU,EAAE,GAAG;QACf,MAAM,EAAE,EAAE;QACV,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,IAAI,CAAC,WAAW,CAAC,GAAG;KAC5C;IACD;QACE,UAAU,EAAE,IAAI;QAChB,MAAM,EAAE,CAAC;QACT,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,IAAI,CAAC,WAAW,CAAC,GAAG;KAC5C;CACF,CAAA;AAED,MAAM,CAAC,OAAO,WAAW,MAAc,EAAE,GAAe;IACtD,MAAM,EAAE,cAAc,EAAE,GAAG,GAAG,CAAA;IAE9B,MAAM,IAAI,GAAG,4BAA4B,CAAC,GAAG,CAAC,CAAA;IAE9C,IAAI,cAAc,EAAE,CAAC;QACnB,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,wBAAwB,EAAE;YACtD,IAAI;YACJ,SAAS;YACT,OAAO,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,GAAG,EAAE,EAAE,EAAE;gBAC/B,MAAM,EAAE,OAAO,EAAE,GAAG,MAAM,GAAG,CAAC,mBAAmB,CAC/C,GAAG,EACH,IAAI,CAAC,WAAW,CAAC,GAAG,EACpB,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,wBAAwB,CAAC,IAAI,CACjD,CAAA;gBAED,MAAM,cAAc,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,wBAAwB,EAAE;oBACrE,OAAO;iBACR,CAAC,CAAA;YACJ,CAAC;SACF,CAAC,CAAA;IACJ,CAAC;SAAM,CAAC;QACN,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,wBAAwB,EAAE;YACtD,IAAI;YACJ,SAAS;YACT,OAAO,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE;gBAC1B,MAAM,GAAG,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,CAAA;gBAChC,MAAM,MAAM,GAAG,SAAS,CAAA,CAAC,+BAA+B;gBACxD,MAAM,GAAG,CAAC,cAAc,CAAC,wBAAwB,CAAC,GAAG,EAAE,EAAE,MAAM,EAAE,CAAC,CAAA;YACpE,CAAC;SACF,CAAC,CAAA;IACJ,CAAC;AACH,CAAC","sourcesContent":["import { DAY, HOUR } from '@atproto/common'\nimport {\n MethodAuthVerifier,\n MethodRateLimit,\n Server,\n} from '@atproto/xrpc-server'\nimport { AccessOutput, OAuthOutput } from '../../../../auth-output.js'\nimport { AppContext } from '../../../../context.js'\nimport { com } from '../../../../lexicons/index.js'\n\n// Exposed as a utility to ensure auth in confirmEmail and requestEmailConfirmation\nexport function requestEmailConfirmationAuth(\n ctx: AppContext,\n): MethodAuthVerifier<AccessOutput | OAuthOutput> {\n return ctx.authVerifier.authorization({\n checkTakedown: true,\n authorize: (permissions) => {\n permissions.assertAccount({ attr: 'email', action: 'manage' })\n },\n })\n}\n\nconst rateLimit: MethodRateLimit<AccessOutput | OAuthOutput> = [\n {\n durationMs: DAY,\n points: 15,\n calcKey: ({ auth }) => auth.credentials.did,\n },\n {\n durationMs: HOUR,\n points: 5,\n calcKey: ({ auth }) => auth.credentials.did,\n },\n]\n\nexport default function (server: Server, ctx: AppContext) {\n const { entrywayClient } = ctx\n\n const auth = requestEmailConfirmationAuth(ctx)\n\n if (entrywayClient) {\n server.add(com.atproto.server.requestEmailConfirmation, {\n auth,\n rateLimit,\n handler: async ({ auth, req }) => {\n const { headers } = await ctx.entrywayAuthHeaders(\n req,\n auth.credentials.did,\n com.atproto.server.requestEmailConfirmation.$lxm,\n )\n\n await entrywayClient.xrpc(com.atproto.server.requestEmailConfirmation, {\n headers,\n })\n },\n })\n } else {\n server.add(com.atproto.server.requestEmailConfirmation, {\n auth,\n rateLimit,\n handler: async ({ auth }) => {\n const did = auth.credentials.did\n const locale = undefined // @TODO get the locale somehow\n await ctx.accountManager.requestEmailConfirmation(did, { locale })\n },\n })\n }\n}\n"]}
@@ -1,4 +1,6 @@
1
- import { Server } from '@atproto/xrpc-server';
1
+ import { MethodAuthVerifier, Server } from '@atproto/xrpc-server';
2
+ import { AccessOutput, OAuthOutput } from '../../../../auth-output.js';
2
3
  import { AppContext } from '../../../../context.js';
4
+ export declare function requestEmailUpdateAuth(ctx: AppContext): MethodAuthVerifier<AccessOutput | OAuthOutput>;
3
5
  export default function (server: Server, ctx: AppContext): void;
4
6
  //# sourceMappingURL=requestEmailUpdate.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"requestEmailUpdate.d.ts","sourceRoot":"","sources":["../../../../../src/api/com/atproto/server/requestEmailUpdate.ts"],"names":[],"mappings":"AACA,OAAO,EAAuB,MAAM,EAAE,MAAM,sBAAsB,CAAA;AAClE,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAA;AAGnD,MAAM,CAAC,OAAO,WAAW,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,UAAU,QAgEvD"}
1
+ {"version":3,"file":"requestEmailUpdate.d.ts","sourceRoot":"","sources":["../../../../../src/api/com/atproto/server/requestEmailUpdate.ts"],"names":[],"mappings":"AACA,OAAO,EAEL,kBAAkB,EAElB,MAAM,EACP,MAAM,sBAAsB,CAAA;AAC7B,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAA;AAEtE,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAA;AAKnD,wBAAgB,sBAAsB,CACpC,GAAG,EAAE,UAAU,GACd,kBAAkB,CAAC,YAAY,GAAG,WAAW,CAAC,CAUhD;AAeD,MAAM,CAAC,OAAO,WAAW,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,UAAU,QA4CvD"}
@@ -1,57 +1,61 @@
1
1
  import { DAY, HOUR } from '@atproto/common';
2
- import { InvalidRequestError } from '@atproto/xrpc-server';
2
+ import { ForbiddenError, } from '@atproto/xrpc-server';
3
+ import { ACCESS_FULL } from '../../../../auth-scope.js';
3
4
  import { com } from '../../../../lexicons/index.js';
5
+ // Exposed as a utility to ensure auth in updateEmail and requestEmailUpdate
6
+ // stay consistent.
7
+ export function requestEmailUpdateAuth(ctx) {
8
+ return ctx.authVerifier.authorization({
9
+ checkTakedown: true,
10
+ scopes: ACCESS_FULL,
11
+ authorize: () => {
12
+ throw new ForbiddenError('Use the account manager interface to update email address associated with an account');
13
+ },
14
+ });
15
+ }
16
+ const rateLimit = [
17
+ {
18
+ durationMs: DAY,
19
+ points: 15,
20
+ calcKey: ({ auth }) => auth.credentials.did,
21
+ },
22
+ {
23
+ durationMs: HOUR,
24
+ points: 5,
25
+ calcKey: ({ auth }) => auth.credentials.did,
26
+ },
27
+ ];
4
28
  export default function (server, ctx) {
5
29
  const { entrywayClient } = ctx;
6
- server.add(com.atproto.server.requestEmailUpdate, {
7
- rateLimit: [
8
- {
9
- durationMs: DAY,
10
- points: 15,
11
- calcKey: ({ auth }) => auth.credentials.did,
12
- },
13
- {
14
- durationMs: HOUR,
15
- points: 5,
16
- calcKey: ({ auth }) => auth.credentials.did,
17
- },
18
- ],
19
- auth: ctx.authVerifier.authorization({
20
- checkTakedown: true,
21
- authorize: (permissions) => {
22
- permissions.assertAccount({ attr: 'email', action: 'manage' });
23
- },
24
- }),
25
- handler: async ({ auth, req }) => {
26
- const did = auth.credentials.did;
27
- const account = await ctx.accountManager.getAccount(did, {
28
- includeDeactivated: true,
29
- includeTakenDown: true,
30
- });
31
- if (!account) {
32
- throw new InvalidRequestError('account not found');
33
- }
34
- if (entrywayClient) {
30
+ const auth = requestEmailUpdateAuth(ctx);
31
+ if (entrywayClient) {
32
+ server.add(com.atproto.server.requestEmailUpdate, {
33
+ rateLimit,
34
+ auth,
35
+ handler: async ({ auth, req }) => {
35
36
  const { headers } = await ctx.entrywayAuthHeaders(req, auth.credentials.did, com.atproto.server.requestEmailUpdate.$lxm);
36
37
  return entrywayClient.xrpc(com.atproto.server.requestEmailUpdate, {
37
38
  headers,
38
39
  });
39
- }
40
- if (!account.email) {
41
- throw new InvalidRequestError('account does not have an email address');
42
- }
43
- const tokenRequired = !!account.emailConfirmedAt;
44
- if (tokenRequired) {
45
- const token = await ctx.accountManager.createEmailToken(did, 'update_email');
46
- await ctx.mailer.sendUpdateEmail({ token }, { to: account.email });
47
- }
48
- return {
49
- encoding: 'application/json',
50
- body: {
51
- tokenRequired,
52
- },
53
- };
54
- },
55
- });
40
+ },
41
+ });
42
+ }
43
+ else {
44
+ server.add(com.atproto.server.requestEmailUpdate, {
45
+ rateLimit,
46
+ auth,
47
+ handler: async ({ auth }) => {
48
+ const did = auth.credentials.did;
49
+ // @TODO get the locale somehow (either by adding a field in the request
50
+ // body, or by using the `Accept-Language` header).
51
+ const locale = undefined;
52
+ const { tokenRequired } = await ctx.accountManager.requestEmailUpdate(did, { locale });
53
+ return {
54
+ encoding: 'application/json',
55
+ body: { tokenRequired },
56
+ };
57
+ },
58
+ });
59
+ }
56
60
  }
57
61
  //# sourceMappingURL=requestEmailUpdate.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"requestEmailUpdate.js","sourceRoot":"","sources":["../../../../../src/api/com/atproto/server/requestEmailUpdate.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAA;AAC3C,OAAO,EAAE,mBAAmB,EAAU,MAAM,sBAAsB,CAAA;AAElE,OAAO,EAAE,GAAG,EAAE,MAAM,+BAA+B,CAAA;AAEnD,MAAM,CAAC,OAAO,WAAW,MAAc,EAAE,GAAe;IACtD,MAAM,EAAE,cAAc,EAAE,GAAG,GAAG,CAAA;IAE9B,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,kBAAkB,EAAE;QAChD,SAAS,EAAE;YACT;gBACE,UAAU,EAAE,GAAG;gBACf,MAAM,EAAE,EAAE;gBACV,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,IAAI,CAAC,WAAW,CAAC,GAAG;aAC5C;YACD;gBACE,UAAU,EAAE,IAAI;gBAChB,MAAM,EAAE,CAAC;gBACT,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,IAAI,CAAC,WAAW,CAAC,GAAG;aAC5C;SACF;QACD,IAAI,EAAE,GAAG,CAAC,YAAY,CAAC,aAAa,CAAC;YACnC,aAAa,EAAE,IAAI;YACnB,SAAS,EAAE,CAAC,WAAW,EAAE,EAAE;gBACzB,WAAW,CAAC,aAAa,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,CAAA;YAChE,CAAC;SACF,CAAC;QACF,OAAO,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,GAAG,EAAE,EAAE,EAAE;YAC/B,MAAM,GAAG,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,CAAA;YAChC,MAAM,OAAO,GAAG,MAAM,GAAG,CAAC,cAAc,CAAC,UAAU,CAAC,GAAG,EAAE;gBACvD,kBAAkB,EAAE,IAAI;gBACxB,gBAAgB,EAAE,IAAI;aACvB,CAAC,CAAA;YACF,IAAI,CAAC,OAAO,EAAE,CAAC;gBACb,MAAM,IAAI,mBAAmB,CAAC,mBAAmB,CAAC,CAAA;YACpD,CAAC;YAED,IAAI,cAAc,EAAE,CAAC;gBACnB,MAAM,EAAE,OAAO,EAAE,GAAG,MAAM,GAAG,CAAC,mBAAmB,CAC/C,GAAG,EACH,IAAI,CAAC,WAAW,CAAC,GAAG,EACpB,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,kBAAkB,CAAC,IAAI,CAC3C,CAAA;gBACD,OAAO,cAAc,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,kBAAkB,EAAE;oBAChE,OAAO;iBACR,CAAC,CAAA;YACJ,CAAC;YAED,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;gBACnB,MAAM,IAAI,mBAAmB,CAAC,wCAAwC,CAAC,CAAA;YACzE,CAAC;YAED,MAAM,aAAa,GAAG,CAAC,CAAC,OAAO,CAAC,gBAAgB,CAAA;YAChD,IAAI,aAAa,EAAE,CAAC;gBAClB,MAAM,KAAK,GAAG,MAAM,GAAG,CAAC,cAAc,CAAC,gBAAgB,CACrD,GAAG,EACH,cAAc,CACf,CAAA;gBACD,MAAM,GAAG,CAAC,MAAM,CAAC,eAAe,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,EAAE,OAAO,CAAC,KAAK,EAAE,CAAC,CAAA;YACpE,CAAC;YAED,OAAO;gBACL,QAAQ,EAAE,kBAA2B;gBACrC,IAAI,EAAE;oBACJ,aAAa;iBACd;aACF,CAAA;QACH,CAAC;KACF,CAAC,CAAA;AACJ,CAAC","sourcesContent":["import { DAY, HOUR } from '@atproto/common'\nimport { InvalidRequestError, Server } from '@atproto/xrpc-server'\nimport { AppContext } from '../../../../context.js'\nimport { com } from '../../../../lexicons/index.js'\n\nexport default function (server: Server, ctx: AppContext) {\n const { entrywayClient } = ctx\n\n server.add(com.atproto.server.requestEmailUpdate, {\n rateLimit: [\n {\n durationMs: DAY,\n points: 15,\n calcKey: ({ auth }) => auth.credentials.did,\n },\n {\n durationMs: HOUR,\n points: 5,\n calcKey: ({ auth }) => auth.credentials.did,\n },\n ],\n auth: ctx.authVerifier.authorization({\n checkTakedown: true,\n authorize: (permissions) => {\n permissions.assertAccount({ attr: 'email', action: 'manage' })\n },\n }),\n handler: async ({ auth, req }) => {\n const did = auth.credentials.did\n const account = await ctx.accountManager.getAccount(did, {\n includeDeactivated: true,\n includeTakenDown: true,\n })\n if (!account) {\n throw new InvalidRequestError('account not found')\n }\n\n if (entrywayClient) {\n const { headers } = await ctx.entrywayAuthHeaders(\n req,\n auth.credentials.did,\n com.atproto.server.requestEmailUpdate.$lxm,\n )\n return entrywayClient.xrpc(com.atproto.server.requestEmailUpdate, {\n headers,\n })\n }\n\n if (!account.email) {\n throw new InvalidRequestError('account does not have an email address')\n }\n\n const tokenRequired = !!account.emailConfirmedAt\n if (tokenRequired) {\n const token = await ctx.accountManager.createEmailToken(\n did,\n 'update_email',\n )\n await ctx.mailer.sendUpdateEmail({ token }, { to: account.email })\n }\n\n return {\n encoding: 'application/json' as const,\n body: {\n tokenRequired,\n },\n }\n },\n })\n}\n"]}
1
+ {"version":3,"file":"requestEmailUpdate.js","sourceRoot":"","sources":["../../../../../src/api/com/atproto/server/requestEmailUpdate.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAA;AAC3C,OAAO,EACL,cAAc,GAIf,MAAM,sBAAsB,CAAA;AAE7B,OAAO,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAA;AAEvD,OAAO,EAAE,GAAG,EAAE,MAAM,+BAA+B,CAAA;AAEnD,4EAA4E;AAC5E,mBAAmB;AACnB,MAAM,UAAU,sBAAsB,CACpC,GAAe;IAEf,OAAO,GAAG,CAAC,YAAY,CAAC,aAAa,CAAC;QACpC,aAAa,EAAE,IAAI;QACnB,MAAM,EAAE,WAAW;QACnB,SAAS,EAAE,GAAG,EAAE;YACd,MAAM,IAAI,cAAc,CACtB,sFAAsF,CACvF,CAAA;QACH,CAAC;KACF,CAAC,CAAA;AACJ,CAAC;AAED,MAAM,SAAS,GAAgD;IAC7D;QACE,UAAU,EAAE,GAAG;QACf,MAAM,EAAE,EAAE;QACV,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,IAAI,CAAC,WAAW,CAAC,GAAG;KAC5C;IACD;QACE,UAAU,EAAE,IAAI;QAChB,MAAM,EAAE,CAAC;QACT,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,IAAI,CAAC,WAAW,CAAC,GAAG;KAC5C;CACF,CAAA;AAED,MAAM,CAAC,OAAO,WAAW,MAAc,EAAE,GAAe;IACtD,MAAM,EAAE,cAAc,EAAE,GAAG,GAAG,CAAA;IAE9B,MAAM,IAAI,GAAG,sBAAsB,CAAC,GAAG,CAAC,CAAA;IAExC,IAAI,cAAc,EAAE,CAAC;QACnB,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,kBAAkB,EAAE;YAChD,SAAS;YACT,IAAI;YACJ,OAAO,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,GAAG,EAAE,EAAE,EAAE;gBAC/B,MAAM,EAAE,OAAO,EAAE,GAAG,MAAM,GAAG,CAAC,mBAAmB,CAC/C,GAAG,EACH,IAAI,CAAC,WAAW,CAAC,GAAG,EACpB,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,kBAAkB,CAAC,IAAI,CAC3C,CAAA;gBAED,OAAO,cAAc,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,kBAAkB,EAAE;oBAChE,OAAO;iBACR,CAAC,CAAA;YACJ,CAAC;SACF,CAAC,CAAA;IACJ,CAAC;SAAM,CAAC;QACN,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,kBAAkB,EAAE;YAChD,SAAS;YACT,IAAI;YACJ,OAAO,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE;gBAC1B,MAAM,GAAG,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,CAAA;gBAEhC,wEAAwE;gBACxE,mDAAmD;gBACnD,MAAM,MAAM,GAAG,SAAS,CAAA;gBAExB,MAAM,EAAE,aAAa,EAAE,GAAG,MAAM,GAAG,CAAC,cAAc,CAAC,kBAAkB,CACnE,GAAG,EACH,EAAE,MAAM,EAAE,CACX,CAAA;gBAED,OAAO;oBACL,QAAQ,EAAE,kBAA2B;oBACrC,IAAI,EAAE,EAAE,aAAa,EAAE;iBACxB,CAAA;YACH,CAAC;SACF,CAAC,CAAA;IACJ,CAAC;AACH,CAAC","sourcesContent":["import { DAY, HOUR } from '@atproto/common'\nimport {\n ForbiddenError,\n MethodAuthVerifier,\n MethodRateLimit,\n Server,\n} from '@atproto/xrpc-server'\nimport { AccessOutput, OAuthOutput } from '../../../../auth-output.js'\nimport { ACCESS_FULL } from '../../../../auth-scope.js'\nimport { AppContext } from '../../../../context.js'\nimport { com } from '../../../../lexicons/index.js'\n\n// Exposed as a utility to ensure auth in updateEmail and requestEmailUpdate\n// stay consistent.\nexport function requestEmailUpdateAuth(\n ctx: AppContext,\n): MethodAuthVerifier<AccessOutput | OAuthOutput> {\n return ctx.authVerifier.authorization({\n checkTakedown: true,\n scopes: ACCESS_FULL,\n authorize: () => {\n throw new ForbiddenError(\n 'Use the account manager interface to update email address associated with an account',\n )\n },\n })\n}\n\nconst rateLimit: MethodRateLimit<AccessOutput | OAuthOutput> = [\n {\n durationMs: DAY,\n points: 15,\n calcKey: ({ auth }) => auth.credentials.did,\n },\n {\n durationMs: HOUR,\n points: 5,\n calcKey: ({ auth }) => auth.credentials.did,\n },\n]\n\nexport default function (server: Server, ctx: AppContext) {\n const { entrywayClient } = ctx\n\n const auth = requestEmailUpdateAuth(ctx)\n\n if (entrywayClient) {\n server.add(com.atproto.server.requestEmailUpdate, {\n rateLimit,\n auth,\n handler: async ({ auth, req }) => {\n const { headers } = await ctx.entrywayAuthHeaders(\n req,\n auth.credentials.did,\n com.atproto.server.requestEmailUpdate.$lxm,\n )\n\n return entrywayClient.xrpc(com.atproto.server.requestEmailUpdate, {\n headers,\n })\n },\n })\n } else {\n server.add(com.atproto.server.requestEmailUpdate, {\n rateLimit,\n auth,\n handler: async ({ auth }) => {\n const did = auth.credentials.did\n\n // @TODO get the locale somehow (either by adding a field in the request\n // body, or by using the `Accept-Language` header).\n const locale = undefined\n\n const { tokenRequired } = await ctx.accountManager.requestEmailUpdate(\n did,\n { locale },\n )\n\n return {\n encoding: 'application/json' as const,\n body: { tokenRequired },\n }\n },\n })\n }\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"updateEmail.d.ts","sourceRoot":"","sources":["../../../../../src/api/com/atproto/server/updateEmail.ts"],"names":[],"mappings":"AAEA,OAAO,EAGL,MAAM,EACP,MAAM,sBAAsB,CAAA;AAG7B,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAA;AAGnD,MAAM,CAAC,OAAO,WAAW,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,UAAU,QAqEvD"}
1
+ {"version":3,"file":"updateEmail.d.ts","sourceRoot":"","sources":["../../../../../src/api/com/atproto/server/updateEmail.ts"],"names":[],"mappings":"AAAA,OAAO,EAAuB,MAAM,EAAE,MAAM,sBAAsB,CAAA;AAElE,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAA;AAInD,MAAM,CAAC,OAAO,WAAW,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,UAAU,QA6CvD"}
@@ -1,57 +1,43 @@
1
- import { isEmailValid } from '@hapi/address';
2
- import { isDisposableEmail } from 'disposable-email-domains-js';
3
- import { ForbiddenError, InvalidRequestError, } from '@atproto/xrpc-server';
1
+ import { InvalidRequestError } from '@atproto/xrpc-server';
4
2
  import { UserAlreadyExistsError } from '../../../../account-manager/helpers/account.js';
5
- import { ACCESS_FULL } from '../../../../auth-scope.js';
6
3
  import { com } from '../../../../lexicons/index.js';
4
+ import { requestEmailUpdateAuth } from './requestEmailUpdate.js';
7
5
  export default function (server, ctx) {
8
- server.add(com.atproto.server.updateEmail, {
9
- auth: ctx.authVerifier.authorization({
10
- checkTakedown: true,
11
- scopes: ACCESS_FULL,
12
- authorize: () => {
13
- throw new ForbiddenError('OAuth credentials are not supported for this endpoint');
14
- },
15
- }),
16
- handler: async ({ auth, input: { body }, req }) => {
17
- const did = auth.credentials.did;
18
- const { token, email } = body;
19
- if (!isEmailValid(email) || isDisposableEmail(email)) {
20
- throw new InvalidRequestError('This email address is not supported, please use a different email.');
21
- }
22
- const account = await ctx.accountManager.getAccount(did, {
23
- includeDeactivated: true,
24
- });
25
- if (!account) {
26
- throw new InvalidRequestError('account not found');
27
- }
28
- if (ctx.entrywayClient) {
6
+ const { entrywayClient } = ctx;
7
+ // @NOTE Ensure that both endpoints use the same authentication logic
8
+ const auth = requestEmailUpdateAuth(ctx);
9
+ if (entrywayClient) {
10
+ server.add(com.atproto.server.updateEmail, {
11
+ auth,
12
+ handler: async ({ auth, input: { body }, req }) => {
29
13
  const { headers } = await ctx.entrywayAuthHeaders(req, auth.credentials.did, com.atproto.server.updateEmail.$lxm);
30
- await ctx.entrywayClient.xrpc(com.atproto.server.updateEmail, {
14
+ await entrywayClient.xrpc(com.atproto.server.updateEmail, {
31
15
  headers,
32
16
  body,
33
17
  });
34
- return;
35
- }
36
- // require valid token if account email is confirmed
37
- if (account.emailConfirmedAt) {
38
- if (!token) {
39
- throw new InvalidRequestError('confirmation token required', 'TokenRequired');
40
- }
41
- await ctx.accountManager.assertValidEmailToken(did, 'update_email', token);
42
- }
43
- try {
44
- await ctx.accountManager.updateEmail({ did, email });
45
- }
46
- catch (err) {
47
- if (err instanceof UserAlreadyExistsError) {
48
- throw new InvalidRequestError('This email address is already in use, please use a different email.');
18
+ },
19
+ });
20
+ }
21
+ else {
22
+ server.add(com.atproto.server.updateEmail, {
23
+ auth,
24
+ handler: async ({ auth, input: { body } }) => {
25
+ const did = auth.credentials.did;
26
+ const { token, email } = body;
27
+ // @TODO get the locale somehow (either by adding a field in the request
28
+ // body, or by using the `Accept-Language` header).
29
+ const locale = undefined;
30
+ try {
31
+ await ctx.accountManager.updateEmail(did, email, token, { locale });
49
32
  }
50
- else {
51
- throw err;
33
+ catch (cause) {
34
+ if (cause instanceof UserAlreadyExistsError) {
35
+ throw new InvalidRequestError(cause.message, undefined, { cause });
36
+ }
37
+ throw cause;
52
38
  }
53
- }
54
- },
55
- });
39
+ },
40
+ });
41
+ }
56
42
  }
57
43
  //# sourceMappingURL=updateEmail.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"updateEmail.js","sourceRoot":"","sources":["../../../../../src/api/com/atproto/server/updateEmail.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;AAC5C,OAAO,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAA;AAC/D,OAAO,EACL,cAAc,EACd,mBAAmB,GAEpB,MAAM,sBAAsB,CAAA;AAC7B,OAAO,EAAE,sBAAsB,EAAE,MAAM,gDAAgD,CAAA;AACvF,OAAO,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAA;AAEvD,OAAO,EAAE,GAAG,EAAE,MAAM,+BAA+B,CAAA;AAEnD,MAAM,CAAC,OAAO,WAAW,MAAc,EAAE,GAAe;IACtD,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,WAAW,EAAE;QACzC,IAAI,EAAE,GAAG,CAAC,YAAY,CAAC,aAAa,CAAC;YACnC,aAAa,EAAE,IAAI;YACnB,MAAM,EAAE,WAAW;YACnB,SAAS,EAAE,GAAG,EAAE;gBACd,MAAM,IAAI,cAAc,CACtB,uDAAuD,CACxD,CAAA;YACH,CAAC;SACF,CAAC;QACF,OAAO,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,EAAE,GAAG,EAAE,EAAE,EAAE;YAChD,MAAM,GAAG,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,CAAA;YAChC,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,IAAI,CAAA;YAC7B,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC,IAAI,iBAAiB,CAAC,KAAK,CAAC,EAAE,CAAC;gBACrD,MAAM,IAAI,mBAAmB,CAC3B,oEAAoE,CACrE,CAAA;YACH,CAAC;YACD,MAAM,OAAO,GAAG,MAAM,GAAG,CAAC,cAAc,CAAC,UAAU,CAAC,GAAG,EAAE;gBACvD,kBAAkB,EAAE,IAAI;aACzB,CAAC,CAAA;YACF,IAAI,CAAC,OAAO,EAAE,CAAC;gBACb,MAAM,IAAI,mBAAmB,CAAC,mBAAmB,CAAC,CAAA;YACpD,CAAC;YAED,IAAI,GAAG,CAAC,cAAc,EAAE,CAAC;gBACvB,MAAM,EAAE,OAAO,EAAE,GAAG,MAAM,GAAG,CAAC,mBAAmB,CAC/C,GAAG,EACH,IAAI,CAAC,WAAW,CAAC,GAAG,EACpB,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,WAAW,CAAC,IAAI,CACpC,CAAA;gBAED,MAAM,GAAG,CAAC,cAAc,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,WAAW,EAAE;oBAC5D,OAAO;oBACP,IAAI;iBACL,CAAC,CAAA;gBAEF,OAAM;YACR,CAAC;YAED,oDAAoD;YACpD,IAAI,OAAO,CAAC,gBAAgB,EAAE,CAAC;gBAC7B,IAAI,CAAC,KAAK,EAAE,CAAC;oBACX,MAAM,IAAI,mBAAmB,CAC3B,6BAA6B,EAC7B,eAAe,CAChB,CAAA;gBACH,CAAC;gBACD,MAAM,GAAG,CAAC,cAAc,CAAC,qBAAqB,CAC5C,GAAG,EACH,cAAc,EACd,KAAK,CACN,CAAA;YACH,CAAC;YAED,IAAI,CAAC;gBACH,MAAM,GAAG,CAAC,cAAc,CAAC,WAAW,CAAC,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC,CAAA;YACtD,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,IAAI,GAAG,YAAY,sBAAsB,EAAE,CAAC;oBAC1C,MAAM,IAAI,mBAAmB,CAC3B,qEAAqE,CACtE,CAAA;gBACH,CAAC;qBAAM,CAAC;oBACN,MAAM,GAAG,CAAA;gBACX,CAAC;YACH,CAAC;QACH,CAAC;KACF,CAAC,CAAA;AACJ,CAAC","sourcesContent":["import { isEmailValid } from '@hapi/address'\nimport { isDisposableEmail } from 'disposable-email-domains-js'\nimport {\n ForbiddenError,\n InvalidRequestError,\n Server,\n} from '@atproto/xrpc-server'\nimport { UserAlreadyExistsError } from '../../../../account-manager/helpers/account.js'\nimport { ACCESS_FULL } from '../../../../auth-scope.js'\nimport { AppContext } from '../../../../context.js'\nimport { com } from '../../../../lexicons/index.js'\n\nexport default function (server: Server, ctx: AppContext) {\n server.add(com.atproto.server.updateEmail, {\n auth: ctx.authVerifier.authorization({\n checkTakedown: true,\n scopes: ACCESS_FULL,\n authorize: () => {\n throw new ForbiddenError(\n 'OAuth credentials are not supported for this endpoint',\n )\n },\n }),\n handler: async ({ auth, input: { body }, req }) => {\n const did = auth.credentials.did\n const { token, email } = body\n if (!isEmailValid(email) || isDisposableEmail(email)) {\n throw new InvalidRequestError(\n 'This email address is not supported, please use a different email.',\n )\n }\n const account = await ctx.accountManager.getAccount(did, {\n includeDeactivated: true,\n })\n if (!account) {\n throw new InvalidRequestError('account not found')\n }\n\n if (ctx.entrywayClient) {\n const { headers } = await ctx.entrywayAuthHeaders(\n req,\n auth.credentials.did,\n com.atproto.server.updateEmail.$lxm,\n )\n\n await ctx.entrywayClient.xrpc(com.atproto.server.updateEmail, {\n headers,\n body,\n })\n\n return\n }\n\n // require valid token if account email is confirmed\n if (account.emailConfirmedAt) {\n if (!token) {\n throw new InvalidRequestError(\n 'confirmation token required',\n 'TokenRequired',\n )\n }\n await ctx.accountManager.assertValidEmailToken(\n did,\n 'update_email',\n token,\n )\n }\n\n try {\n await ctx.accountManager.updateEmail({ did, email })\n } catch (err) {\n if (err instanceof UserAlreadyExistsError) {\n throw new InvalidRequestError(\n 'This email address is already in use, please use a different email.',\n )\n } else {\n throw err\n }\n }\n },\n })\n}\n"]}
1
+ {"version":3,"file":"updateEmail.js","sourceRoot":"","sources":["../../../../../src/api/com/atproto/server/updateEmail.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAU,MAAM,sBAAsB,CAAA;AAClE,OAAO,EAAE,sBAAsB,EAAE,MAAM,gDAAgD,CAAA;AAEvF,OAAO,EAAE,GAAG,EAAE,MAAM,+BAA+B,CAAA;AACnD,OAAO,EAAE,sBAAsB,EAAE,MAAM,yBAAyB,CAAA;AAEhE,MAAM,CAAC,OAAO,WAAW,MAAc,EAAE,GAAe;IACtD,MAAM,EAAE,cAAc,EAAE,GAAG,GAAG,CAAA;IAE9B,qEAAqE;IACrE,MAAM,IAAI,GAAG,sBAAsB,CAAC,GAAG,CAAC,CAAA;IAExC,IAAI,cAAc,EAAE,CAAC;QACnB,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,WAAW,EAAE;YACzC,IAAI;YACJ,OAAO,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,EAAE,GAAG,EAAE,EAAE,EAAE;gBAChD,MAAM,EAAE,OAAO,EAAE,GAAG,MAAM,GAAG,CAAC,mBAAmB,CAC/C,GAAG,EACH,IAAI,CAAC,WAAW,CAAC,GAAG,EACpB,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,WAAW,CAAC,IAAI,CACpC,CAAA;gBAED,MAAM,cAAc,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,WAAW,EAAE;oBACxD,OAAO;oBACP,IAAI;iBACL,CAAC,CAAA;YACJ,CAAC;SACF,CAAC,CAAA;IACJ,CAAC;SAAM,CAAC;QACN,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,WAAW,EAAE;YACzC,IAAI;YACJ,OAAO,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,EAAE;gBAC3C,MAAM,GAAG,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,CAAA;gBAChC,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,IAAI,CAAA;gBAE7B,wEAAwE;gBACxE,mDAAmD;gBACnD,MAAM,MAAM,GAAG,SAAS,CAAA;gBAExB,IAAI,CAAC;oBACH,MAAM,GAAG,CAAC,cAAc,CAAC,WAAW,CAAC,GAAG,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,CAAC,CAAA;gBACrE,CAAC;gBAAC,OAAO,KAAK,EAAE,CAAC;oBACf,IAAI,KAAK,YAAY,sBAAsB,EAAE,CAAC;wBAC5C,MAAM,IAAI,mBAAmB,CAAC,KAAK,CAAC,OAAO,EAAE,SAAS,EAAE,EAAE,KAAK,EAAE,CAAC,CAAA;oBACpE,CAAC;oBAED,MAAM,KAAK,CAAA;gBACb,CAAC;YACH,CAAC;SACF,CAAC,CAAA;IACJ,CAAC;AACH,CAAC","sourcesContent":["import { InvalidRequestError, Server } from '@atproto/xrpc-server'\nimport { UserAlreadyExistsError } from '../../../../account-manager/helpers/account.js'\nimport { AppContext } from '../../../../context.js'\nimport { com } from '../../../../lexicons/index.js'\nimport { requestEmailUpdateAuth } from './requestEmailUpdate.js'\n\nexport default function (server: Server, ctx: AppContext) {\n const { entrywayClient } = ctx\n\n // @NOTE Ensure that both endpoints use the same authentication logic\n const auth = requestEmailUpdateAuth(ctx)\n\n if (entrywayClient) {\n server.add(com.atproto.server.updateEmail, {\n auth,\n handler: async ({ auth, input: { body }, req }) => {\n const { headers } = await ctx.entrywayAuthHeaders(\n req,\n auth.credentials.did,\n com.atproto.server.updateEmail.$lxm,\n )\n\n await entrywayClient.xrpc(com.atproto.server.updateEmail, {\n headers,\n body,\n })\n },\n })\n } else {\n server.add(com.atproto.server.updateEmail, {\n auth,\n handler: async ({ auth, input: { body } }) => {\n const did = auth.credentials.did\n const { token, email } = body\n\n // @TODO get the locale somehow (either by adding a field in the request\n // body, or by using the `Accept-Language` header).\n const locale = undefined\n\n try {\n await ctx.accountManager.updateEmail(did, email, token, { locale })\n } catch (cause) {\n if (cause instanceof UserAlreadyExistsError) {\n throw new InvalidRequestError(cause.message, undefined, { cause })\n }\n\n throw cause\n }\n },\n })\n }\n}\n"]}
@@ -1,5 +1,6 @@
1
- import { BrandingInput, HcaptchaConfig } from '@atproto/oauth-provider';
1
+ import { BrandingInput as BrandingConfig, HcaptchaConfig } from '@atproto/oauth-provider';
2
2
  import { ServerEnvironment } from './env.js';
3
+ export type { BrandingConfig };
3
4
  export declare const envToCfg: (env: ServerEnvironment) => ServerConfig;
4
5
  export type ServerConfig = {
5
6
  service: ServiceConfig;
@@ -20,6 +21,7 @@ export type ServerConfig = {
20
21
  crawlers: string[];
21
22
  fetch: FetchConfig;
22
23
  proxy: ProxyConfig;
24
+ branding: BrandingConfig;
23
25
  oauth: OAuthConfig;
24
26
  lexicon: LexiconResolverConfig;
25
27
  };
@@ -105,7 +107,7 @@ export type OAuthConfig = {
105
107
  issuer: string;
106
108
  provider?: {
107
109
  hcaptcha?: HcaptchaConfig;
108
- branding: BrandingInput;
110
+ branding: BrandingConfig;
109
111
  trustedClients?: string[];
110
112
  };
111
113
  };
@@ -122,6 +124,7 @@ export type InvitesConfig = {
122
124
  export type EmailConfig = {
123
125
  smtpUrl: string;
124
126
  fromAddress: string;
127
+ disableConfirmationLink: boolean;
125
128
  };
126
129
  export type SubscriptionConfig = {
127
130
  maxBuffer: number;
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/config/config.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/config/config.ts"],"names":[],"mappings":"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"}
@@ -132,6 +132,7 @@ export const envToCfg = (env) => {
132
132
  emailCfg = {
133
133
  smtpUrl: env.emailSmtpUrl,
134
134
  fromAddress: env.emailFromAddress,
135
+ disableConfirmationLink: env.emailDisableConfirmationLink ?? false,
135
136
  };
136
137
  }
137
138
  let moderationEmailCfg;
@@ -145,6 +146,7 @@ export const envToCfg = (env) => {
145
146
  moderationEmailCfg = {
146
147
  smtpUrl: env.moderationEmailSmtpUrl,
147
148
  fromAddress: env.moderationEmailAddress,
149
+ disableConfirmationLink: false,
148
150
  };
149
151
  }
150
152
  const subscriptionCfg = {
@@ -209,6 +211,52 @@ export const envToCfg = (env) => {
209
211
  : 0,
210
212
  preferCompressed: env.proxyPreferCompressed ?? false,
211
213
  };
214
+ const brandingCfg = {
215
+ name: env.serviceName ?? `${hostname} PDS`,
216
+ logo: env.logoUrl,
217
+ colors: {
218
+ light: env.lightColor,
219
+ dark: env.darkColor,
220
+ contrastSaturation: env.contrastSaturation,
221
+ primary: env.primaryColor,
222
+ primaryContrast: env.primaryColorContrast,
223
+ primaryHue: env.primaryColorHue,
224
+ error: env.errorColor,
225
+ errorContrast: env.errorColorContrast,
226
+ errorHue: env.errorColorHue,
227
+ warning: env.warningColor,
228
+ warningContrast: env.warningColorContrast,
229
+ warningHue: env.warningColorHue,
230
+ info: env.infoColor,
231
+ infoContrast: env.infoColorContrast,
232
+ infoHue: env.infoColorHue,
233
+ success: env.successColor,
234
+ successContrast: env.successColorContrast,
235
+ successHue: env.successColorHue,
236
+ },
237
+ links: [
238
+ {
239
+ title: { en: 'Home', fr: 'Accueil' },
240
+ href: env.homeUrl,
241
+ rel: 'canonical', // Prevents login page from being indexed
242
+ },
243
+ {
244
+ title: { en: 'Terms of Service' },
245
+ href: env.termsOfServiceUrl,
246
+ rel: 'terms-of-service',
247
+ },
248
+ {
249
+ title: { en: 'Privacy Policy' },
250
+ href: env.privacyPolicyUrl,
251
+ rel: 'privacy-policy',
252
+ },
253
+ {
254
+ title: { en: 'Support' },
255
+ href: env.supportUrl,
256
+ rel: 'help',
257
+ },
258
+ ].filter((f) => f.href != null && f.href !== ''),
259
+ };
212
260
  const oauthCfg = entrywayCfg
213
261
  ? {
214
262
  issuer: entrywayCfg.url,
@@ -226,52 +274,7 @@ export const envToCfg = (env) => {
226
274
  tokenSalt: env.hcaptchaTokenSalt,
227
275
  }
228
276
  : undefined,
229
- branding: {
230
- name: env.serviceName ?? `${hostname} PDS`,
231
- logo: env.logoUrl,
232
- colors: {
233
- light: env.lightColor,
234
- dark: env.darkColor,
235
- contrastSaturation: env.contrastSaturation,
236
- primary: env.primaryColor,
237
- primaryContrast: env.primaryColorContrast,
238
- primaryHue: env.primaryColorHue,
239
- error: env.errorColor,
240
- errorContrast: env.errorColorContrast,
241
- errorHue: env.errorColorHue,
242
- warning: env.warningColor,
243
- warningContrast: env.warningColorContrast,
244
- warningHue: env.warningColorHue,
245
- info: env.infoColor,
246
- infoContrast: env.infoColorContrast,
247
- infoHue: env.infoColorHue,
248
- success: env.successColor,
249
- successContrast: env.successColorContrast,
250
- successHue: env.successColorHue,
251
- },
252
- links: [
253
- {
254
- title: { en: 'Home', fr: 'Accueil' },
255
- href: env.homeUrl,
256
- rel: 'canonical', // Prevents login page from being indexed
257
- },
258
- {
259
- title: { en: 'Terms of Service' },
260
- href: env.termsOfServiceUrl,
261
- rel: 'terms-of-service',
262
- },
263
- {
264
- title: { en: 'Privacy Policy' },
265
- href: env.privacyPolicyUrl,
266
- rel: 'privacy-policy',
267
- },
268
- {
269
- title: { en: 'Support' },
270
- href: env.supportUrl,
271
- rel: 'help',
272
- },
273
- ].filter((f) => f.href != null && f.href !== ''),
274
- },
277
+ branding: brandingCfg,
275
278
  trustedClients: env.trustedOAuthClients,
276
279
  },
277
280
  };
@@ -300,6 +303,7 @@ export const envToCfg = (env) => {
300
303
  fetch: fetchCfg,
301
304
  lexicon: lexiconCfg,
302
305
  proxy: proxyCfg,
306
+ branding: brandingCfg,
303
307
  oauth: oauthCfg,
304
308
  };
305
309
  };