@atproto/ozone 0.1.107 → 0.1.109

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 (222) hide show
  1. package/CHANGELOG.md +27 -0
  2. package/dist/api/health.js +1 -1
  3. package/dist/api/health.js.map +1 -1
  4. package/dist/api/index.d.ts.map +1 -1
  5. package/dist/api/index.js +6 -0
  6. package/dist/api/index.js.map +1 -1
  7. package/dist/api/server/getConfig.d.ts.map +1 -1
  8. package/dist/api/server/getConfig.js +1 -0
  9. package/dist/api/server/getConfig.js.map +1 -1
  10. package/dist/api/setting/removeOptions.d.ts.map +1 -1
  11. package/dist/api/setting/removeOptions.js +1 -0
  12. package/dist/api/setting/removeOptions.js.map +1 -1
  13. package/dist/api/setting/upsertOption.js +7 -0
  14. package/dist/api/setting/upsertOption.js.map +1 -1
  15. package/dist/api/util.d.ts +1 -1
  16. package/dist/api/util.d.ts.map +1 -1
  17. package/dist/api/util.js +6 -1
  18. package/dist/api/util.js.map +1 -1
  19. package/dist/api/verification/grantVerifications.d.ts +4 -0
  20. package/dist/api/verification/grantVerifications.d.ts.map +1 -0
  21. package/dist/api/verification/grantVerifications.js +60 -0
  22. package/dist/api/verification/grantVerifications.js.map +1 -0
  23. package/dist/api/verification/listVerifications.d.ts +4 -0
  24. package/dist/api/verification/listVerifications.d.ts.map +1 -0
  25. package/dist/api/verification/listVerifications.js +32 -0
  26. package/dist/api/verification/listVerifications.js.map +1 -0
  27. package/dist/api/verification/revokeVerifications.d.ts +4 -0
  28. package/dist/api/verification/revokeVerifications.d.ts.map +1 -0
  29. package/dist/api/verification/revokeVerifications.js +36 -0
  30. package/dist/api/verification/revokeVerifications.js.map +1 -0
  31. package/dist/auth-verifier.d.ts +4 -1
  32. package/dist/auth-verifier.d.ts.map +1 -1
  33. package/dist/auth-verifier.js +4 -3
  34. package/dist/auth-verifier.js.map +1 -1
  35. package/dist/background.d.ts +3 -1
  36. package/dist/background.d.ts.map +1 -1
  37. package/dist/background.js +4 -3
  38. package/dist/background.js.map +1 -1
  39. package/dist/config/config.d.ts +9 -0
  40. package/dist/config/config.d.ts.map +1 -1
  41. package/dist/config/config.js +10 -0
  42. package/dist/config/config.js.map +1 -1
  43. package/dist/config/env.d.ts +5 -0
  44. package/dist/config/env.d.ts.map +1 -1
  45. package/dist/config/env.js +5 -0
  46. package/dist/config/env.js.map +1 -1
  47. package/dist/context.d.ts +6 -0
  48. package/dist/context.d.ts.map +1 -1
  49. package/dist/context.js +12 -0
  50. package/dist/context.js.map +1 -1
  51. package/dist/daemon/context.d.ts +3 -0
  52. package/dist/daemon/context.d.ts.map +1 -1
  53. package/dist/daemon/context.js +11 -0
  54. package/dist/daemon/context.js.map +1 -1
  55. package/dist/daemon/verification-listener.d.ts +29 -0
  56. package/dist/daemon/verification-listener.d.ts.map +1 -0
  57. package/dist/daemon/verification-listener.js +171 -0
  58. package/dist/daemon/verification-listener.js.map +1 -0
  59. package/dist/db/migrations/20250415T201720309Z-verification.d.ts +4 -0
  60. package/dist/db/migrations/20250415T201720309Z-verification.d.ts.map +1 -0
  61. package/dist/db/migrations/20250415T201720309Z-verification.js +35 -0
  62. package/dist/db/migrations/20250415T201720309Z-verification.js.map +1 -0
  63. package/dist/db/migrations/20250417T201720309Z-firehose-cursor.d.ts +4 -0
  64. package/dist/db/migrations/20250417T201720309Z-firehose-cursor.d.ts.map +1 -0
  65. package/dist/db/migrations/20250417T201720309Z-firehose-cursor.js +17 -0
  66. package/dist/db/migrations/20250417T201720309Z-firehose-cursor.js.map +1 -0
  67. package/dist/db/migrations/index.d.ts +2 -0
  68. package/dist/db/migrations/index.d.ts.map +1 -1
  69. package/dist/db/migrations/index.js +3 -1
  70. package/dist/db/migrations/index.js.map +1 -1
  71. package/dist/db/pagination.d.ts +15 -0
  72. package/dist/db/pagination.d.ts.map +1 -1
  73. package/dist/db/pagination.js +23 -1
  74. package/dist/db/pagination.js.map +1 -1
  75. package/dist/db/schema/firehose_cursor.d.ts +11 -0
  76. package/dist/db/schema/firehose_cursor.d.ts.map +1 -0
  77. package/dist/db/schema/firehose_cursor.js +5 -0
  78. package/dist/db/schema/firehose_cursor.js.map +1 -0
  79. package/dist/db/schema/index.d.ts +3 -1
  80. package/dist/db/schema/index.d.ts.map +1 -1
  81. package/dist/db/schema/member.d.ts +1 -1
  82. package/dist/db/schema/member.d.ts.map +1 -1
  83. package/dist/db/schema/verification.d.ts +19 -0
  84. package/dist/db/schema/verification.d.ts.map +1 -0
  85. package/dist/db/schema/verification.js +5 -0
  86. package/dist/db/schema/verification.js.map +1 -0
  87. package/dist/error.js +1 -1
  88. package/dist/error.js.map +1 -1
  89. package/dist/jetstream/service.d.ts +60 -0
  90. package/dist/jetstream/service.d.ts.map +1 -0
  91. package/dist/jetstream/service.js +65 -0
  92. package/dist/jetstream/service.js.map +1 -0
  93. package/dist/lexicon/index.d.ts +15 -0
  94. package/dist/lexicon/index.d.ts.map +1 -1
  95. package/dist/lexicon/index.js +36 -1
  96. package/dist/lexicon/index.js.map +1 -1
  97. package/dist/lexicon/lexicons.d.ts +918 -98
  98. package/dist/lexicon/lexicons.d.ts.map +1 -1
  99. package/dist/lexicon/lexicons.js +434 -0
  100. package/dist/lexicon/lexicons.js.map +1 -1
  101. package/dist/lexicon/types/app/bsky/actor/defs.d.ts +21 -0
  102. package/dist/lexicon/types/app/bsky/actor/defs.d.ts.map +1 -1
  103. package/dist/lexicon/types/app/bsky/actor/defs.js +9 -0
  104. package/dist/lexicon/types/app/bsky/actor/defs.js.map +1 -1
  105. package/dist/lexicon/types/app/bsky/actor/status.d.ts +23 -0
  106. package/dist/lexicon/types/app/bsky/actor/status.d.ts.map +1 -0
  107. package/dist/lexicon/types/app/bsky/actor/status.js +19 -0
  108. package/dist/lexicon/types/app/bsky/actor/status.js.map +1 -0
  109. package/dist/lexicon/types/tools/ozone/server/getConfig.d.ts +3 -1
  110. package/dist/lexicon/types/tools/ozone/server/getConfig.d.ts.map +1 -1
  111. package/dist/lexicon/types/tools/ozone/server/getConfig.js.map +1 -1
  112. package/dist/lexicon/types/tools/ozone/setting/defs.d.ts +1 -1
  113. package/dist/lexicon/types/tools/ozone/setting/defs.d.ts.map +1 -1
  114. package/dist/lexicon/types/tools/ozone/setting/defs.js.map +1 -1
  115. package/dist/lexicon/types/tools/ozone/setting/upsertOption.d.ts +1 -1
  116. package/dist/lexicon/types/tools/ozone/setting/upsertOption.d.ts.map +1 -1
  117. package/dist/lexicon/types/tools/ozone/team/addMember.d.ts +1 -1
  118. package/dist/lexicon/types/tools/ozone/team/addMember.d.ts.map +1 -1
  119. package/dist/lexicon/types/tools/ozone/team/defs.d.ts +3 -1
  120. package/dist/lexicon/types/tools/ozone/team/defs.d.ts.map +1 -1
  121. package/dist/lexicon/types/tools/ozone/team/defs.js +3 -1
  122. package/dist/lexicon/types/tools/ozone/team/defs.js.map +1 -1
  123. package/dist/lexicon/types/tools/ozone/team/updateMember.d.ts +1 -1
  124. package/dist/lexicon/types/tools/ozone/team/updateMember.d.ts.map +1 -1
  125. package/dist/lexicon/types/tools/ozone/verification/defs.d.ts +43 -0
  126. package/dist/lexicon/types/tools/ozone/verification/defs.d.ts.map +1 -0
  127. package/dist/lexicon/types/tools/ozone/verification/defs.js +16 -0
  128. package/dist/lexicon/types/tools/ozone/verification/defs.js.map +1 -0
  129. package/dist/lexicon/types/tools/ozone/verification/grantVerifications.d.ts +66 -0
  130. package/dist/lexicon/types/tools/ozone/verification/grantVerifications.d.ts.map +1 -0
  131. package/dist/lexicon/types/tools/ozone/verification/grantVerifications.js +25 -0
  132. package/dist/lexicon/types/tools/ozone/verification/grantVerifications.js.map +1 -0
  133. package/dist/lexicon/types/tools/ozone/verification/listVerifications.d.ts +52 -0
  134. package/dist/lexicon/types/tools/ozone/verification/listVerifications.d.ts.map +1 -0
  135. package/dist/lexicon/types/tools/ozone/verification/listVerifications.js +7 -0
  136. package/dist/lexicon/types/tools/ozone/verification/listVerifications.js.map +1 -0
  137. package/dist/lexicon/types/tools/ozone/verification/revokeVerifications.d.ts +56 -0
  138. package/dist/lexicon/types/tools/ozone/verification/revokeVerifications.d.ts.map +1 -0
  139. package/dist/lexicon/types/tools/ozone/verification/revokeVerifications.js +16 -0
  140. package/dist/lexicon/types/tools/ozone/verification/revokeVerifications.js.map +1 -0
  141. package/dist/logger.d.ts +1 -0
  142. package/dist/logger.d.ts.map +1 -1
  143. package/dist/logger.js +2 -1
  144. package/dist/logger.js.map +1 -1
  145. package/dist/mod-service/index.js +1 -1
  146. package/dist/mod-service/index.js.map +1 -1
  147. package/dist/mod-service/status.d.ts +6 -0
  148. package/dist/mod-service/status.d.ts.map +1 -1
  149. package/dist/mod-service/views.d.ts.map +1 -1
  150. package/dist/mod-service/views.js +2 -0
  151. package/dist/mod-service/views.js.map +1 -1
  152. package/dist/team/index.d.ts +1 -0
  153. package/dist/team/index.d.ts.map +1 -1
  154. package/dist/team/index.js +5 -2
  155. package/dist/team/index.js.map +1 -1
  156. package/dist/verification/issuer.d.ts +37 -0
  157. package/dist/verification/issuer.d.ts.map +1 -0
  158. package/dist/verification/issuer.js +119 -0
  159. package/dist/verification/issuer.js.map +1 -0
  160. package/dist/verification/service.d.ts +47 -0
  161. package/dist/verification/service.d.ts.map +1 -0
  162. package/dist/verification/service.js +141 -0
  163. package/dist/verification/service.js.map +1 -0
  164. package/dist/verification/util.d.ts +6 -0
  165. package/dist/verification/util.d.ts.map +1 -0
  166. package/dist/verification/util.js +32 -0
  167. package/dist/verification/util.js.map +1 -0
  168. package/package.json +10 -9
  169. package/src/api/health.ts +1 -1
  170. package/src/api/index.ts +6 -0
  171. package/src/api/server/getConfig.ts +1 -0
  172. package/src/api/setting/removeOptions.ts +1 -0
  173. package/src/api/setting/upsertOption.ts +7 -0
  174. package/src/api/util.ts +7 -1
  175. package/src/api/verification/grantVerifications.ts +90 -0
  176. package/src/api/verification/listVerifications.ts +44 -0
  177. package/src/api/verification/revokeVerifications.ts +43 -0
  178. package/src/auth-verifier.ts +8 -4
  179. package/src/background.ts +8 -3
  180. package/src/config/config.ts +21 -0
  181. package/src/config/env.ts +10 -0
  182. package/src/context.ts +22 -0
  183. package/src/daemon/context.ts +19 -0
  184. package/src/daemon/verification-listener.ts +164 -0
  185. package/src/db/migrations/20250415T201720309Z-verification.ts +34 -0
  186. package/src/db/migrations/20250417T201720309Z-firehose-cursor.ts +16 -0
  187. package/src/db/migrations/index.ts +2 -0
  188. package/src/db/pagination.ts +31 -0
  189. package/src/db/schema/firehose_cursor.ts +13 -0
  190. package/src/db/schema/index.ts +5 -1
  191. package/src/db/schema/member.ts +1 -0
  192. package/src/db/schema/verification.ts +21 -0
  193. package/src/error.ts +1 -1
  194. package/src/jetstream/service.ts +104 -0
  195. package/src/lexicon/index.ts +50 -0
  196. package/src/lexicon/lexicons.ts +457 -0
  197. package/src/lexicon/types/app/bsky/actor/defs.ts +26 -0
  198. package/src/lexicon/types/app/bsky/actor/status.ts +40 -0
  199. package/src/lexicon/types/tools/ozone/server/getConfig.ts +3 -0
  200. package/src/lexicon/types/tools/ozone/setting/defs.ts +1 -0
  201. package/src/lexicon/types/tools/ozone/setting/upsertOption.ts +1 -0
  202. package/src/lexicon/types/tools/ozone/team/addMember.ts +1 -0
  203. package/src/lexicon/types/tools/ozone/team/defs.ts +3 -0
  204. package/src/lexicon/types/tools/ozone/team/updateMember.ts +1 -0
  205. package/src/lexicon/types/tools/ozone/verification/defs.ts +59 -0
  206. package/src/lexicon/types/tools/ozone/verification/grantVerifications.ts +100 -0
  207. package/src/lexicon/types/tools/ozone/verification/listVerifications.ts +70 -0
  208. package/src/lexicon/types/tools/ozone/verification/revokeVerifications.ts +81 -0
  209. package/src/logger.ts +2 -0
  210. package/src/mod-service/index.ts +1 -1
  211. package/src/mod-service/views.ts +4 -0
  212. package/src/team/index.ts +6 -5
  213. package/src/verification/issuer.ts +135 -0
  214. package/src/verification/service.ts +208 -0
  215. package/src/verification/util.ts +50 -0
  216. package/tests/__snapshots__/verification-listener.test.ts.snap +146 -0
  217. package/tests/__snapshots__/verification.test.ts.snap +288 -0
  218. package/tests/expiring-label.test.ts +72 -0
  219. package/tests/verification-listener.test.ts +102 -0
  220. package/tests/verification.test.ts +166 -0
  221. package/tsconfig.build.tsbuildinfo +1 -1
  222. package/tsconfig.tests.tsbuildinfo +1 -1
@@ -27,6 +27,7 @@ export interface Member {
27
27
  | 'lex:tools.ozone.team.defs#roleAdmin'
28
28
  | 'lex:tools.ozone.team.defs#roleModerator'
29
29
  | 'lex:tools.ozone.team.defs#roleTriage'
30
+ | 'lex:tools.ozone.team.defs#roleVerifier'
30
31
  | (string & {})
31
32
  }
32
33
 
@@ -46,3 +47,5 @@ export const ROLEADMIN = `${id}#roleAdmin`
46
47
  export const ROLEMODERATOR = `${id}#roleModerator`
47
48
  /** Triage role. Mostly intended for monitoring and escalating issues. */
48
49
  export const ROLETRIAGE = `${id}#roleTriage`
50
+ /** Verifier role. Only allowed to issue verifications. */
51
+ export const ROLEVERIFIER = `${id}#roleVerifier`
@@ -25,6 +25,7 @@ export interface InputSchema {
25
25
  role?:
26
26
  | 'tools.ozone.team.defs#roleAdmin'
27
27
  | 'tools.ozone.team.defs#roleModerator'
28
+ | 'tools.ozone.team.defs#roleVerifier'
28
29
  | 'tools.ozone.team.defs#roleTriage'
29
30
  | (string & {})
30
31
  }
@@ -0,0 +1,59 @@
1
+ /**
2
+ * GENERATED CODE - DO NOT MODIFY
3
+ */
4
+ import { type ValidationResult, BlobRef } from '@atproto/lexicon'
5
+ import { CID } from 'multiformats/cid'
6
+ import { validate as _validate } from '../../../../lexicons'
7
+ import {
8
+ type $Typed,
9
+ is$typed as _is$typed,
10
+ type OmitKey,
11
+ } from '../../../../util'
12
+ import type * as ToolsOzoneModerationDefs from '../moderation/defs.js'
13
+
14
+ const is$typed = _is$typed,
15
+ validate = _validate
16
+ const id = 'tools.ozone.verification.defs'
17
+
18
+ /** Verification data for the associated subject. */
19
+ export interface VerificationView {
20
+ $type?: 'tools.ozone.verification.defs#verificationView'
21
+ /** The user who issued this verification. */
22
+ issuer: string
23
+ /** The AT-URI of the verification record. */
24
+ uri: string
25
+ /** The subject of the verification. */
26
+ subject: string
27
+ /** Handle of the subject the verification applies to at the moment of verifying, which might not be the same at the time of viewing. The verification is only valid if the current handle matches the one at the time of verifying. */
28
+ handle: string
29
+ /** Display name of the subject the verification applies to at the moment of verifying, which might not be the same at the time of viewing. The verification is only valid if the current displayName matches the one at the time of verifying. */
30
+ displayName: string
31
+ /** Timestamp when the verification was created. */
32
+ createdAt: string
33
+ /** Describes the reason for revocation, also indicating that the verification is no longer valid. */
34
+ revokeReason?: string
35
+ /** Timestamp when the verification was revoked. */
36
+ revokedAt?: string
37
+ /** The user who revoked this verification. */
38
+ revokedBy?: string
39
+ subjectProfile?: { $type: string }
40
+ issuerProfile?: { $type: string }
41
+ subjectRepo?:
42
+ | $Typed<ToolsOzoneModerationDefs.RepoViewDetail>
43
+ | $Typed<ToolsOzoneModerationDefs.RepoViewNotFound>
44
+ | { $type: string }
45
+ issuerRepo?:
46
+ | $Typed<ToolsOzoneModerationDefs.RepoViewDetail>
47
+ | $Typed<ToolsOzoneModerationDefs.RepoViewNotFound>
48
+ | { $type: string }
49
+ }
50
+
51
+ const hashVerificationView = 'verificationView'
52
+
53
+ export function isVerificationView<V>(v: V) {
54
+ return is$typed(v, id, hashVerificationView)
55
+ }
56
+
57
+ export function validateVerificationView<V>(v: V) {
58
+ return validate<VerificationView & V>(v, id, hashVerificationView)
59
+ }
@@ -0,0 +1,100 @@
1
+ /**
2
+ * GENERATED CODE - DO NOT MODIFY
3
+ */
4
+ import express from 'express'
5
+ import { type ValidationResult, BlobRef } from '@atproto/lexicon'
6
+ import { CID } from 'multiformats/cid'
7
+ import { validate as _validate } from '../../../../lexicons'
8
+ import {
9
+ type $Typed,
10
+ is$typed as _is$typed,
11
+ type OmitKey,
12
+ } from '../../../../util'
13
+ import { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server'
14
+ import type * as ToolsOzoneVerificationDefs from './defs.js'
15
+
16
+ const is$typed = _is$typed,
17
+ validate = _validate
18
+ const id = 'tools.ozone.verification.grantVerifications'
19
+
20
+ export interface QueryParams {}
21
+
22
+ export interface InputSchema {
23
+ /** Array of verification requests to process */
24
+ verifications: VerificationInput[]
25
+ }
26
+
27
+ export interface OutputSchema {
28
+ verifications: ToolsOzoneVerificationDefs.VerificationView[]
29
+ failedVerifications: GrantError[]
30
+ }
31
+
32
+ export interface HandlerInput {
33
+ encoding: 'application/json'
34
+ body: InputSchema
35
+ }
36
+
37
+ export interface HandlerSuccess {
38
+ encoding: 'application/json'
39
+ body: OutputSchema
40
+ headers?: { [key: string]: string }
41
+ }
42
+
43
+ export interface HandlerError {
44
+ status: number
45
+ message?: string
46
+ }
47
+
48
+ export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough
49
+ export type HandlerReqCtx<HA extends HandlerAuth = never> = {
50
+ auth: HA
51
+ params: QueryParams
52
+ input: HandlerInput
53
+ req: express.Request
54
+ res: express.Response
55
+ resetRouteRateLimits: () => Promise<void>
56
+ }
57
+ export type Handler<HA extends HandlerAuth = never> = (
58
+ ctx: HandlerReqCtx<HA>,
59
+ ) => Promise<HandlerOutput> | HandlerOutput
60
+
61
+ export interface VerificationInput {
62
+ $type?: 'tools.ozone.verification.grantVerifications#verificationInput'
63
+ /** The did of the subject being verified */
64
+ subject: string
65
+ /** Handle of the subject the verification applies to at the moment of verifying. */
66
+ handle: string
67
+ /** Display name of the subject the verification applies to at the moment of verifying. */
68
+ displayName: string
69
+ /** Timestamp for verification record. Defaults to current time when not specified. */
70
+ createdAt?: string
71
+ }
72
+
73
+ const hashVerificationInput = 'verificationInput'
74
+
75
+ export function isVerificationInput<V>(v: V) {
76
+ return is$typed(v, id, hashVerificationInput)
77
+ }
78
+
79
+ export function validateVerificationInput<V>(v: V) {
80
+ return validate<VerificationInput & V>(v, id, hashVerificationInput)
81
+ }
82
+
83
+ /** Error object for failed verifications. */
84
+ export interface GrantError {
85
+ $type?: 'tools.ozone.verification.grantVerifications#grantError'
86
+ /** Error message describing the reason for failure. */
87
+ error: string
88
+ /** The did of the subject being verified */
89
+ subject: string
90
+ }
91
+
92
+ const hashGrantError = 'grantError'
93
+
94
+ export function isGrantError<V>(v: V) {
95
+ return is$typed(v, id, hashGrantError)
96
+ }
97
+
98
+ export function validateGrantError<V>(v: V) {
99
+ return validate<GrantError & V>(v, id, hashGrantError)
100
+ }
@@ -0,0 +1,70 @@
1
+ /**
2
+ * GENERATED CODE - DO NOT MODIFY
3
+ */
4
+ import express from 'express'
5
+ import { type ValidationResult, BlobRef } from '@atproto/lexicon'
6
+ import { CID } from 'multiformats/cid'
7
+ import { validate as _validate } from '../../../../lexicons'
8
+ import {
9
+ type $Typed,
10
+ is$typed as _is$typed,
11
+ type OmitKey,
12
+ } from '../../../../util'
13
+ import { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server'
14
+ import type * as ToolsOzoneVerificationDefs from './defs.js'
15
+
16
+ const is$typed = _is$typed,
17
+ validate = _validate
18
+ const id = 'tools.ozone.verification.listVerifications'
19
+
20
+ export interface QueryParams {
21
+ /** Pagination cursor */
22
+ cursor?: string
23
+ /** Maximum number of results to return */
24
+ limit: number
25
+ /** Filter to verifications created after this timestamp */
26
+ createdAfter?: string
27
+ /** Filter to verifications created before this timestamp */
28
+ createdBefore?: string
29
+ /** Filter to verifications from specific issuers */
30
+ issuers?: string[]
31
+ /** Filter to specific verified DIDs */
32
+ subjects?: string[]
33
+ /** Sort direction for creation date */
34
+ sortDirection: 'asc' | 'desc'
35
+ /** Filter to verifications that are revoked or not. By default, includes both. */
36
+ isRevoked?: boolean
37
+ }
38
+
39
+ export type InputSchema = undefined
40
+
41
+ export interface OutputSchema {
42
+ cursor?: string
43
+ verifications: ToolsOzoneVerificationDefs.VerificationView[]
44
+ }
45
+
46
+ export type HandlerInput = undefined
47
+
48
+ export interface HandlerSuccess {
49
+ encoding: 'application/json'
50
+ body: OutputSchema
51
+ headers?: { [key: string]: string }
52
+ }
53
+
54
+ export interface HandlerError {
55
+ status: number
56
+ message?: string
57
+ }
58
+
59
+ export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough
60
+ export type HandlerReqCtx<HA extends HandlerAuth = never> = {
61
+ auth: HA
62
+ params: QueryParams
63
+ input: HandlerInput
64
+ req: express.Request
65
+ res: express.Response
66
+ resetRouteRateLimits: () => Promise<void>
67
+ }
68
+ export type Handler<HA extends HandlerAuth = never> = (
69
+ ctx: HandlerReqCtx<HA>,
70
+ ) => Promise<HandlerOutput> | HandlerOutput
@@ -0,0 +1,81 @@
1
+ /**
2
+ * GENERATED CODE - DO NOT MODIFY
3
+ */
4
+ import express from 'express'
5
+ import { type ValidationResult, BlobRef } from '@atproto/lexicon'
6
+ import { CID } from 'multiformats/cid'
7
+ import { validate as _validate } from '../../../../lexicons'
8
+ import {
9
+ type $Typed,
10
+ is$typed as _is$typed,
11
+ type OmitKey,
12
+ } from '../../../../util'
13
+ import { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server'
14
+
15
+ const is$typed = _is$typed,
16
+ validate = _validate
17
+ const id = 'tools.ozone.verification.revokeVerifications'
18
+
19
+ export interface QueryParams {}
20
+
21
+ export interface InputSchema {
22
+ /** Array of verification record uris to revoke */
23
+ uris: string[]
24
+ /** Reason for revoking the verification. This is optional and can be omitted if not needed. */
25
+ revokeReason?: string
26
+ }
27
+
28
+ export interface OutputSchema {
29
+ /** List of verification uris successfully revoked */
30
+ revokedVerifications: string[]
31
+ /** List of verification uris that couldn't be revoked, including failure reasons */
32
+ failedRevocations: RevokeError[]
33
+ }
34
+
35
+ export interface HandlerInput {
36
+ encoding: 'application/json'
37
+ body: InputSchema
38
+ }
39
+
40
+ export interface HandlerSuccess {
41
+ encoding: 'application/json'
42
+ body: OutputSchema
43
+ headers?: { [key: string]: string }
44
+ }
45
+
46
+ export interface HandlerError {
47
+ status: number
48
+ message?: string
49
+ }
50
+
51
+ export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough
52
+ export type HandlerReqCtx<HA extends HandlerAuth = never> = {
53
+ auth: HA
54
+ params: QueryParams
55
+ input: HandlerInput
56
+ req: express.Request
57
+ res: express.Response
58
+ resetRouteRateLimits: () => Promise<void>
59
+ }
60
+ export type Handler<HA extends HandlerAuth = never> = (
61
+ ctx: HandlerReqCtx<HA>,
62
+ ) => Promise<HandlerOutput> | HandlerOutput
63
+
64
+ /** Error object for failed revocations */
65
+ export interface RevokeError {
66
+ $type?: 'tools.ozone.verification.revokeVerifications#revokeError'
67
+ /** The AT-URI of the verification record that failed to revoke. */
68
+ uri: string
69
+ /** Description of the error that occurred during revocation. */
70
+ error: string
71
+ }
72
+
73
+ const hashRevokeError = 'revokeError'
74
+
75
+ export function isRevokeError<V>(v: V) {
76
+ return is$typed(v, id, hashRevokeError)
77
+ }
78
+
79
+ export function validateRevokeError<V>(v: V) {
80
+ return validate<RevokeError & V>(v, id, hashRevokeError)
81
+ }
package/src/logger.ts CHANGED
@@ -10,6 +10,8 @@ export const httpLogger: ReturnType<typeof subsystemLogger> =
10
10
  subsystemLogger('ozone')
11
11
  export const langLogger: ReturnType<typeof subsystemLogger> =
12
12
  subsystemLogger('ozone:lang')
13
+ export const verificationLogger: ReturnType<typeof subsystemLogger> =
14
+ subsystemLogger('ozone:verification')
13
15
 
14
16
  export const loggerMiddleware = pinoHttp({
15
17
  logger: httpLogger,
@@ -727,7 +727,7 @@ export class ModerationService {
727
727
  this.eventPusher
728
728
  .attemptBlobEvent(evt.id)
729
729
  .catch((err) =>
730
- log.error({ err, ...evt }, 'failed to push blob event'),
730
+ log.error({ ...evt, err }, 'failed to push blob event'),
731
731
  ),
732
732
  ),
733
733
  )
@@ -544,10 +544,14 @@ export class ModerationViews {
544
544
  subjects: string[],
545
545
  includeNeg?: boolean,
546
546
  ): Promise<Map<string, Label[]>> {
547
+ const now = new Date().toISOString()
547
548
  const labels = new Map<string, Label[]>()
548
549
  const res = await this.db.db
549
550
  .selectFrom('label')
550
551
  .where('label.uri', 'in', subjects)
552
+ .where((qb) =>
553
+ qb.where('label.exp', 'is', null).orWhere('label.exp', '>', now),
554
+ )
551
555
  .if(!includeNeg, (qb) => qb.where('neg', '=', false))
552
556
  .selectAll()
553
557
  .execute()
package/src/team/index.ts CHANGED
@@ -54,6 +54,7 @@ export class TeamService {
54
54
  (r) =>
55
55
  r === 'tools.ozone.team.defs#roleAdmin' ||
56
56
  r === 'tools.ozone.team.defs#roleModerator' ||
57
+ r === 'tools.ozone.team.defs#roleVerifier' ||
57
58
  r === 'tools.ozone.team.defs#roleTriage',
58
59
  )
59
60
 
@@ -197,11 +198,14 @@ export class TeamService {
197
198
  isAdmin || member?.role === 'tools.ozone.team.defs#roleModerator'
198
199
  const isTriage =
199
200
  isModerator || member?.role === 'tools.ozone.team.defs#roleTriage'
201
+ const isVerifier =
202
+ isAdmin || member?.role === 'tools.ozone.team.defs#roleVerifier'
200
203
 
201
204
  return {
202
205
  isModerator,
203
206
  isAdmin,
204
207
  isTriage,
208
+ isVerifier,
205
209
  }
206
210
  }
207
211
 
@@ -225,11 +229,8 @@ export class TeamService {
225
229
  profiles.set(profile.did, profile)
226
230
  })
227
231
  }
228
- } catch (error) {
229
- httpLogger.error(
230
- { error, dids },
231
- 'Failed to get profiles for team members',
232
- )
232
+ } catch (err) {
233
+ httpLogger.error({ err, dids }, 'Failed to get profiles for team members')
233
234
  }
234
235
 
235
236
  return profiles
@@ -0,0 +1,135 @@
1
+ import { Selectable } from 'kysely'
2
+ import { Agent, AtUri, CredentialSession } from '@atproto/api'
3
+ import { VerifierConfig } from '../config'
4
+ import { Verification } from '../db/schema/verification'
5
+
6
+ export type VerificationInput = {
7
+ displayName: string
8
+ handle: string
9
+ subject: string
10
+ createdAt?: string
11
+ }
12
+
13
+ export type VerificationIssuerCreator = (
14
+ verifierConfig: VerifierConfig,
15
+ ) => VerificationIssuer
16
+
17
+ export class VerificationIssuer {
18
+ private session = new CredentialSession(new URL(this.verifierConfig.url))
19
+ private agent = new Agent(this.session)
20
+ constructor(private verifierConfig: VerifierConfig) {}
21
+
22
+ static creator() {
23
+ return (verifierConfig: VerifierConfig) =>
24
+ new VerificationIssuer(verifierConfig)
25
+ }
26
+
27
+ async getAgent() {
28
+ if (!this.session.hasSession) {
29
+ await this.session.login({
30
+ identifier: this.verifierConfig.did,
31
+ password: this.verifierConfig.password,
32
+ })
33
+ }
34
+
35
+ // Trigger a test request to check if the session is still valid, if not, we will login again
36
+ try {
37
+ await this.agent.com.atproto.server.getSession()
38
+ } catch (err) {
39
+ if ((err as any).status === 401) {
40
+ await this.session.login({
41
+ identifier: this.verifierConfig.did,
42
+ password: this.verifierConfig.password,
43
+ })
44
+ }
45
+ }
46
+
47
+ return this.agent
48
+ }
49
+
50
+ async verify(verifications: VerificationInput[]) {
51
+ const grantedVerifications: Selectable<Verification>[] = []
52
+ const failedVerifications: {
53
+ $type: 'tools.ozone.verification.grantVerifications#grantError'
54
+ subject: string
55
+ error: string
56
+ }[] = []
57
+ const now = new Date().toISOString()
58
+ const agent = await this.getAgent()
59
+ await Promise.allSettled(
60
+ verifications.map(async ({ displayName, handle, subject, createdAt }) => {
61
+ try {
62
+ const verificationRecord = {
63
+ createdAt: createdAt || now,
64
+ issuer: this.verifierConfig.did,
65
+ displayName,
66
+ handle,
67
+ subject,
68
+ }
69
+ const {
70
+ data: { uri, cid },
71
+ } = await agent.com.atproto.repo.createRecord({
72
+ repo: this.verifierConfig.did,
73
+ record: verificationRecord,
74
+ collection: 'app.bsky.graph.verification',
75
+ })
76
+ grantedVerifications.push({
77
+ ...verificationRecord,
78
+ uri,
79
+ cid,
80
+ revokedAt: null,
81
+ updatedAt: now,
82
+ revokedBy: null,
83
+ revokeReason: null,
84
+ })
85
+ } catch (err) {
86
+ failedVerifications.push({
87
+ $type: 'tools.ozone.verification.grantVerifications#grantError',
88
+ error: (err as Error).message,
89
+ subject,
90
+ })
91
+ return
92
+ }
93
+ }),
94
+ )
95
+
96
+ return { grantedVerifications, failedVerifications }
97
+ }
98
+
99
+ async revoke({ uris }: { uris: string[] }) {
100
+ const revokedVerifications: string[] = []
101
+ const failedRevocations: Array<{ uri: string; error: string }> = []
102
+
103
+ const agent = await this.getAgent()
104
+
105
+ await Promise.allSettled(
106
+ uris.map(async (uri) => {
107
+ try {
108
+ const atUri = new AtUri(uri)
109
+
110
+ if (atUri.collection !== 'app.bsky.graph.verification') {
111
+ throw new Error(`Only verification records can be revoked`)
112
+ }
113
+
114
+ if (atUri.host !== this.verifierConfig.did) {
115
+ throw new Error(
116
+ `Cannot revoke verification record ${uri} not issued by ${this.verifierConfig.did}`,
117
+ )
118
+ }
119
+
120
+ await agent.com.atproto.repo.deleteRecord({
121
+ collection: atUri.collection,
122
+ repo: this.verifierConfig.did,
123
+ rkey: atUri.rkey,
124
+ })
125
+ revokedVerifications.push(uri)
126
+ } catch (err) {
127
+ failedRevocations.push({ uri, error: (err as Error).message })
128
+ return
129
+ }
130
+ }),
131
+ )
132
+
133
+ return { revokedVerifications, failedRevocations }
134
+ }
135
+ }