@atproto/bsky 0.0.172 → 0.0.173

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.
@@ -23,6 +23,7 @@ export interface HandlerSuccess {
23
23
  export interface HandlerError {
24
24
  status: number;
25
25
  message?: string;
26
+ error?: 'InvalidEmail' | 'DidTooLong';
26
27
  }
27
28
  export type HandlerOutput = HandlerError | HandlerSuccess;
28
29
  //# sourceMappingURL=initAgeAssurance.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"initAgeAssurance.d.ts","sourceRoot":"","sources":["../../../../../../src/lexicon/types/app/bsky/unspecced/initAgeAssurance.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,KAAK,oBAAoB,MAAM,WAAW,CAAA;AAMtD,MAAM,MAAM,WAAW,GAAG,EAAE,CAAA;AAE5B,MAAM,WAAW,WAAW;IAC1B,kEAAkE;IAClE,KAAK,EAAE,MAAM,CAAA;IACb,oFAAoF;IACpF,QAAQ,EAAE,MAAM,CAAA;IAChB,yDAAyD;IACzD,WAAW,EAAE,MAAM,CAAA;CACpB;AAED,MAAM,MAAM,YAAY,GAAG,oBAAoB,CAAC,iBAAiB,CAAA;AAEjE,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,kBAAkB,CAAA;IAC5B,IAAI,EAAE,WAAW,CAAA;CAClB;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,kBAAkB,CAAA;IAC5B,IAAI,EAAE,YAAY,CAAA;IAClB,OAAO,CAAC,EAAE;QAAE,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAA;KAAE,CAAA;CACpC;AAED,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,MAAM,CAAA;IACd,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB;AAED,MAAM,MAAM,aAAa,GAAG,YAAY,GAAG,cAAc,CAAA"}
1
+ {"version":3,"file":"initAgeAssurance.d.ts","sourceRoot":"","sources":["../../../../../../src/lexicon/types/app/bsky/unspecced/initAgeAssurance.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,KAAK,oBAAoB,MAAM,WAAW,CAAA;AAMtD,MAAM,MAAM,WAAW,GAAG,EAAE,CAAA;AAE5B,MAAM,WAAW,WAAW;IAC1B,kEAAkE;IAClE,KAAK,EAAE,MAAM,CAAA;IACb,oFAAoF;IACpF,QAAQ,EAAE,MAAM,CAAA;IAChB,yDAAyD;IACzD,WAAW,EAAE,MAAM,CAAA;CACpB;AAED,MAAM,MAAM,YAAY,GAAG,oBAAoB,CAAC,iBAAiB,CAAA;AAEjE,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,kBAAkB,CAAA;IAC5B,IAAI,EAAE,WAAW,CAAA;CAClB;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,kBAAkB,CAAA;IAC5B,IAAI,EAAE,YAAY,CAAA;IAClB,OAAO,CAAC,EAAE;QAAE,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAA;KAAE,CAAA;CACpC;AAED,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,MAAM,CAAA;IACd,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,KAAK,CAAC,EAAE,cAAc,GAAG,YAAY,CAAA;CACtC;AAED,MAAM,MAAM,aAAa,GAAG,YAAY,GAAG,cAAc,CAAA"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atproto/bsky",
3
- "version": "0.0.172",
3
+ "version": "0.0.173",
4
4
  "license": "MIT",
5
5
  "description": "Reference implementation of app.bsky App View (Bluesky API)",
6
6
  "keywords": [
@@ -52,8 +52,8 @@
52
52
  "zod": "3.23.8",
53
53
  "@atproto-labs/fetch-node": "0.1.9",
54
54
  "@atproto-labs/xrpc-utils": "0.0.17",
55
- "@atproto/api": "^0.15.26",
56
55
  "@atproto/common": "^0.4.11",
56
+ "@atproto/api": "^0.15.26",
57
57
  "@atproto/crypto": "^0.4.4",
58
58
  "@atproto/did": "^0.1.5",
59
59
  "@atproto/identity": "^0.4.8",
@@ -8,7 +8,10 @@ import {
8
8
  } from '@atproto/xrpc-server'
9
9
  import { AppContext } from '../../../../context'
10
10
  import { GateID } from '../../../../feature-gates'
11
+ import { KwsExternalPayloadError } from '../../../../kws'
11
12
  import { Server } from '../../../../lexicon'
13
+ import { InputSchema } from '../../../../lexicon/types/app/bsky/unspecced/initAgeAssurance'
14
+ import { httpLogger as log } from '../../../../logger'
12
15
  import { KwsExternalPayload } from '../../../kws/types'
13
16
  import { createStashEvent, getClientUa } from '../../../kws/util'
14
17
 
@@ -30,12 +33,7 @@ export default function (server: Server, ctx: AppContext) {
30
33
  throw new ForbiddenError()
31
34
  }
32
35
 
33
- const { email, language, countryCode } = input.body
34
- if (!isEmailValid(email) || isDisposableEmail(email)) {
35
- throw new InvalidRequestError(
36
- 'This email address is not supported, please use a different email.',
37
- )
38
- }
36
+ const { countryCode, email, language } = validateInput(input.body)
39
37
 
40
38
  const attemptId = crypto.randomUUID()
41
39
  // Assumes `app.set('trust proxy', ...)` configured with `true` or specific values.
@@ -43,12 +41,26 @@ export default function (server: Server, ctx: AppContext) {
43
41
  const initUa = getClientUa(req)
44
42
  const externalPayload: KwsExternalPayload = { actorDid, attemptId }
45
43
 
46
- await ctx.kwsClient.sendEmail({
47
- countryCode: countryCode.toUpperCase(),
48
- email,
49
- externalPayload,
50
- language,
51
- })
44
+ try {
45
+ await ctx.kwsClient.sendEmail({
46
+ countryCode: countryCode.toUpperCase(),
47
+ email,
48
+ externalPayload,
49
+ language,
50
+ })
51
+ } catch (err) {
52
+ if (err instanceof KwsExternalPayloadError) {
53
+ log.error(
54
+ { externalPayload },
55
+ 'Age Assurance flow failed because external payload got too long, which is caused by the DID being too long',
56
+ )
57
+ throw new InvalidRequestError(
58
+ 'Age Assurance flow failed because DID is too long',
59
+ 'DidTooLong',
60
+ )
61
+ }
62
+ throw err
63
+ }
52
64
 
53
65
  const event = await createStashEvent(ctx, {
54
66
  actorDid,
@@ -69,3 +81,44 @@ export default function (server: Server, ctx: AppContext) {
69
81
  },
70
82
  })
71
83
  }
84
+
85
+ // Supported languages for KWS Adult Verification.
86
+ // This list comes from KWS's AV Developer Guide PDF doc.
87
+ const kwsAvSupportedLanguages = [
88
+ 'en',
89
+ 'ar',
90
+ 'zh-Hans',
91
+ 'nl',
92
+ 'tl',
93
+ 'fr',
94
+ 'de',
95
+ 'id',
96
+ 'it',
97
+ 'ja',
98
+ 'ko',
99
+ 'pl',
100
+ 'pt-BR',
101
+ 'pt',
102
+ 'ru',
103
+ 'es',
104
+ 'th',
105
+ 'tr',
106
+ 'vi',
107
+ ]
108
+
109
+ const validateInput = (input: InputSchema): InputSchema => {
110
+ const { countryCode, email, language } = input
111
+
112
+ if (!isEmailValid(email) || isDisposableEmail(email)) {
113
+ throw new InvalidRequestError(
114
+ 'This email address is not supported, please use a different email.',
115
+ 'InvalidEmail',
116
+ )
117
+ }
118
+
119
+ return {
120
+ countryCode,
121
+ email,
122
+ language: kwsAvSupportedLanguages.includes(language) ? language : 'en',
123
+ }
124
+ }
package/src/kws.ts CHANGED
@@ -14,6 +14,9 @@ const authResponseSchema = z.object({
14
14
  access_token: z.string(),
15
15
  })
16
16
 
17
+ const EXTERNAL_PAYLOAD_CHAR_LIMIT = 200
18
+ export class KwsExternalPayloadError extends Error {}
19
+
17
20
  export class KwsClient {
18
21
  constructor(public cfg: KwsConfig) {}
19
22
 
@@ -76,6 +79,11 @@ export class KwsClient {
76
79
  externalPayload: KwsExternalPayload
77
80
  language: string
78
81
  }) {
82
+ const serializedExternalPayload = serializeExternalPayload(externalPayload)
83
+ if (serializedExternalPayload.length > EXTERNAL_PAYLOAD_CHAR_LIMIT) {
84
+ throw new KwsExternalPayloadError()
85
+ }
86
+
79
87
  const res = await this.fetchWithAuth(
80
88
  `${this.cfg.apiOrigin}/v1/verifications/send-email`,
81
89
  {
@@ -86,7 +94,7 @@ export class KwsClient {
86
94
  },
87
95
  body: JSON.stringify({
88
96
  email,
89
- externalPayload: serializeExternalPayload(externalPayload),
97
+ externalPayload: serializedExternalPayload,
90
98
  language,
91
99
  location: countryCode,
92
100
  userContext: 'adult',
@@ -11589,6 +11589,14 @@ export const schemaDict = {
11589
11589
  ref: 'lex:app.bsky.unspecced.defs#ageAssuranceState',
11590
11590
  },
11591
11591
  },
11592
+ errors: [
11593
+ {
11594
+ name: 'InvalidEmail',
11595
+ },
11596
+ {
11597
+ name: 'DidTooLong',
11598
+ },
11599
+ ],
11592
11600
  },
11593
11601
  },
11594
11602
  },
@@ -42,6 +42,7 @@ export interface HandlerSuccess {
42
42
  export interface HandlerError {
43
43
  status: number
44
44
  message?: string
45
+ error?: 'InvalidEmail' | 'DidTooLong'
45
46
  }
46
47
 
47
48
  export type HandlerOutput = HandlerError | HandlerSuccess