@atproto/ozone 0.1.107 → 0.1.108
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.
- package/CHANGELOG.md +10 -0
- package/dist/api/index.d.ts.map +1 -1
- package/dist/api/index.js +6 -0
- package/dist/api/index.js.map +1 -1
- package/dist/api/server/getConfig.d.ts.map +1 -1
- package/dist/api/server/getConfig.js +1 -0
- package/dist/api/server/getConfig.js.map +1 -1
- package/dist/api/setting/removeOptions.d.ts.map +1 -1
- package/dist/api/setting/removeOptions.js +1 -0
- package/dist/api/setting/removeOptions.js.map +1 -1
- package/dist/api/setting/upsertOption.js +7 -0
- package/dist/api/setting/upsertOption.js.map +1 -1
- package/dist/api/util.d.ts +1 -1
- package/dist/api/util.d.ts.map +1 -1
- package/dist/api/util.js +6 -1
- package/dist/api/util.js.map +1 -1
- package/dist/api/verification/grantVerifications.d.ts +4 -0
- package/dist/api/verification/grantVerifications.d.ts.map +1 -0
- package/dist/api/verification/grantVerifications.js +52 -0
- package/dist/api/verification/grantVerifications.js.map +1 -0
- package/dist/api/verification/listVerifications.d.ts +4 -0
- package/dist/api/verification/listVerifications.d.ts.map +1 -0
- package/dist/api/verification/listVerifications.js +32 -0
- package/dist/api/verification/listVerifications.js.map +1 -0
- package/dist/api/verification/revokeVerifications.d.ts +4 -0
- package/dist/api/verification/revokeVerifications.d.ts.map +1 -0
- package/dist/api/verification/revokeVerifications.js +36 -0
- package/dist/api/verification/revokeVerifications.js.map +1 -0
- package/dist/auth-verifier.d.ts +4 -1
- package/dist/auth-verifier.d.ts.map +1 -1
- package/dist/auth-verifier.js +4 -3
- package/dist/auth-verifier.js.map +1 -1
- package/dist/background.d.ts +3 -1
- package/dist/background.d.ts.map +1 -1
- package/dist/background.js +3 -2
- package/dist/background.js.map +1 -1
- package/dist/config/config.d.ts +9 -0
- package/dist/config/config.d.ts.map +1 -1
- package/dist/config/config.js +10 -0
- package/dist/config/config.js.map +1 -1
- package/dist/config/env.d.ts +5 -0
- package/dist/config/env.d.ts.map +1 -1
- package/dist/config/env.js +5 -0
- package/dist/config/env.js.map +1 -1
- package/dist/context.d.ts +6 -0
- package/dist/context.d.ts.map +1 -1
- package/dist/context.js +12 -0
- package/dist/context.js.map +1 -1
- package/dist/daemon/context.d.ts +3 -0
- package/dist/daemon/context.d.ts.map +1 -1
- package/dist/daemon/context.js +11 -0
- package/dist/daemon/context.js.map +1 -1
- package/dist/daemon/verification-listener.d.ts +29 -0
- package/dist/daemon/verification-listener.d.ts.map +1 -0
- package/dist/daemon/verification-listener.js +171 -0
- package/dist/daemon/verification-listener.js.map +1 -0
- package/dist/db/migrations/20250415T201720309Z-verification.d.ts +4 -0
- package/dist/db/migrations/20250415T201720309Z-verification.d.ts.map +1 -0
- package/dist/db/migrations/20250415T201720309Z-verification.js +35 -0
- package/dist/db/migrations/20250415T201720309Z-verification.js.map +1 -0
- package/dist/db/migrations/20250417T201720309Z-firehose-cursor.d.ts +4 -0
- package/dist/db/migrations/20250417T201720309Z-firehose-cursor.d.ts.map +1 -0
- package/dist/db/migrations/20250417T201720309Z-firehose-cursor.js +17 -0
- package/dist/db/migrations/20250417T201720309Z-firehose-cursor.js.map +1 -0
- package/dist/db/migrations/index.d.ts +2 -0
- package/dist/db/migrations/index.d.ts.map +1 -1
- package/dist/db/migrations/index.js +3 -1
- package/dist/db/migrations/index.js.map +1 -1
- package/dist/db/pagination.d.ts +15 -0
- package/dist/db/pagination.d.ts.map +1 -1
- package/dist/db/pagination.js +23 -1
- package/dist/db/pagination.js.map +1 -1
- package/dist/db/schema/firehose_cursor.d.ts +11 -0
- package/dist/db/schema/firehose_cursor.d.ts.map +1 -0
- package/dist/db/schema/firehose_cursor.js +5 -0
- package/dist/db/schema/firehose_cursor.js.map +1 -0
- package/dist/db/schema/index.d.ts +3 -1
- package/dist/db/schema/index.d.ts.map +1 -1
- package/dist/db/schema/member.d.ts +1 -1
- package/dist/db/schema/member.d.ts.map +1 -1
- package/dist/db/schema/verification.d.ts +19 -0
- package/dist/db/schema/verification.d.ts.map +1 -0
- package/dist/db/schema/verification.js +5 -0
- package/dist/db/schema/verification.js.map +1 -0
- package/dist/jetstream/service.d.ts +64 -0
- package/dist/jetstream/service.d.ts.map +1 -0
- package/dist/jetstream/service.js +65 -0
- package/dist/jetstream/service.js.map +1 -0
- package/dist/lexicon/index.d.ts +12 -0
- package/dist/lexicon/index.d.ts.map +1 -1
- package/dist/lexicon/index.js +33 -1
- package/dist/lexicon/index.js.map +1 -1
- package/dist/lexicon/lexicons.d.ts +672 -12
- package/dist/lexicon/lexicons.d.ts.map +1 -1
- package/dist/lexicon/lexicons.js +353 -0
- package/dist/lexicon/lexicons.js.map +1 -1
- package/dist/lexicon/types/tools/ozone/server/getConfig.d.ts +3 -1
- package/dist/lexicon/types/tools/ozone/server/getConfig.d.ts.map +1 -1
- package/dist/lexicon/types/tools/ozone/server/getConfig.js.map +1 -1
- package/dist/lexicon/types/tools/ozone/setting/defs.d.ts +1 -1
- package/dist/lexicon/types/tools/ozone/setting/defs.d.ts.map +1 -1
- package/dist/lexicon/types/tools/ozone/setting/defs.js.map +1 -1
- package/dist/lexicon/types/tools/ozone/setting/upsertOption.d.ts +1 -1
- package/dist/lexicon/types/tools/ozone/setting/upsertOption.d.ts.map +1 -1
- package/dist/lexicon/types/tools/ozone/team/addMember.d.ts +1 -1
- package/dist/lexicon/types/tools/ozone/team/addMember.d.ts.map +1 -1
- package/dist/lexicon/types/tools/ozone/team/defs.d.ts +3 -1
- package/dist/lexicon/types/tools/ozone/team/defs.d.ts.map +1 -1
- package/dist/lexicon/types/tools/ozone/team/defs.js +3 -1
- package/dist/lexicon/types/tools/ozone/team/defs.js.map +1 -1
- package/dist/lexicon/types/tools/ozone/team/updateMember.d.ts +1 -1
- package/dist/lexicon/types/tools/ozone/team/updateMember.d.ts.map +1 -1
- package/dist/lexicon/types/tools/ozone/verification/defs.d.ts +43 -0
- package/dist/lexicon/types/tools/ozone/verification/defs.d.ts.map +1 -0
- package/dist/lexicon/types/tools/ozone/verification/defs.js +16 -0
- package/dist/lexicon/types/tools/ozone/verification/defs.js.map +1 -0
- package/dist/lexicon/types/tools/ozone/verification/grantVerifications.d.ts +66 -0
- package/dist/lexicon/types/tools/ozone/verification/grantVerifications.d.ts.map +1 -0
- package/dist/lexicon/types/tools/ozone/verification/grantVerifications.js +25 -0
- package/dist/lexicon/types/tools/ozone/verification/grantVerifications.js.map +1 -0
- package/dist/lexicon/types/tools/ozone/verification/listVerifications.d.ts +52 -0
- package/dist/lexicon/types/tools/ozone/verification/listVerifications.d.ts.map +1 -0
- package/dist/lexicon/types/tools/ozone/verification/listVerifications.js +7 -0
- package/dist/lexicon/types/tools/ozone/verification/listVerifications.js.map +1 -0
- package/dist/lexicon/types/tools/ozone/verification/revokeVerifications.d.ts +56 -0
- package/dist/lexicon/types/tools/ozone/verification/revokeVerifications.d.ts.map +1 -0
- package/dist/lexicon/types/tools/ozone/verification/revokeVerifications.js +16 -0
- package/dist/lexicon/types/tools/ozone/verification/revokeVerifications.js.map +1 -0
- package/dist/logger.d.ts +1 -0
- package/dist/logger.d.ts.map +1 -1
- package/dist/logger.js +2 -1
- package/dist/logger.js.map +1 -1
- package/dist/mod-service/status.d.ts +6 -0
- package/dist/mod-service/status.d.ts.map +1 -1
- package/dist/team/index.d.ts +1 -0
- package/dist/team/index.d.ts.map +1 -1
- package/dist/team/index.js +3 -0
- package/dist/team/index.js.map +1 -1
- package/dist/verification/issuer.d.ts +37 -0
- package/dist/verification/issuer.d.ts.map +1 -0
- package/dist/verification/issuer.js +119 -0
- package/dist/verification/issuer.js.map +1 -0
- package/dist/verification/service.d.ts +47 -0
- package/dist/verification/service.d.ts.map +1 -0
- package/dist/verification/service.js +141 -0
- package/dist/verification/service.js.map +1 -0
- package/dist/verification/util.d.ts +6 -0
- package/dist/verification/util.d.ts.map +1 -0
- package/dist/verification/util.js +32 -0
- package/dist/verification/util.js.map +1 -0
- package/package.json +5 -4
- package/src/api/index.ts +6 -0
- package/src/api/server/getConfig.ts +1 -0
- package/src/api/setting/removeOptions.ts +1 -0
- package/src/api/setting/upsertOption.ts +7 -0
- package/src/api/util.ts +7 -1
- package/src/api/verification/grantVerifications.ts +74 -0
- package/src/api/verification/listVerifications.ts +44 -0
- package/src/api/verification/revokeVerifications.ts +43 -0
- package/src/auth-verifier.ts +8 -4
- package/src/background.ts +7 -2
- package/src/config/config.ts +21 -0
- package/src/config/env.ts +10 -0
- package/src/context.ts +22 -0
- package/src/daemon/context.ts +19 -0
- package/src/daemon/verification-listener.ts +164 -0
- package/src/db/migrations/20250415T201720309Z-verification.ts +34 -0
- package/src/db/migrations/20250417T201720309Z-firehose-cursor.ts +16 -0
- package/src/db/migrations/index.ts +2 -0
- package/src/db/pagination.ts +31 -0
- package/src/db/schema/firehose_cursor.ts +13 -0
- package/src/db/schema/index.ts +5 -1
- package/src/db/schema/member.ts +1 -0
- package/src/db/schema/verification.ts +21 -0
- package/src/jetstream/service.ts +110 -0
- package/src/lexicon/index.ts +47 -0
- package/src/lexicon/lexicons.ts +372 -0
- package/src/lexicon/types/tools/ozone/server/getConfig.ts +3 -0
- package/src/lexicon/types/tools/ozone/setting/defs.ts +1 -0
- package/src/lexicon/types/tools/ozone/setting/upsertOption.ts +1 -0
- package/src/lexicon/types/tools/ozone/team/addMember.ts +1 -0
- package/src/lexicon/types/tools/ozone/team/defs.ts +3 -0
- package/src/lexicon/types/tools/ozone/team/updateMember.ts +1 -0
- package/src/lexicon/types/tools/ozone/verification/defs.ts +59 -0
- package/src/lexicon/types/tools/ozone/verification/grantVerifications.ts +100 -0
- package/src/lexicon/types/tools/ozone/verification/listVerifications.ts +70 -0
- package/src/lexicon/types/tools/ozone/verification/revokeVerifications.ts +81 -0
- package/src/logger.ts +2 -0
- package/src/team/index.ts +4 -0
- package/src/verification/issuer.ts +135 -0
- package/src/verification/service.ts +208 -0
- package/src/verification/util.ts +50 -0
- package/tests/__snapshots__/verification-listener.test.ts.snap +146 -0
- package/tests/__snapshots__/verification.test.ts.snap +288 -0
- package/tests/verification-listener.test.ts +102 -0
- package/tests/verification.test.ts +136 -0
- package/tsconfig.build.tsbuildinfo +1 -1
- package/tsconfig.tests.tsbuildinfo +1 -1
|
@@ -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,
|
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
|
|
|
@@ -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
|
+
}
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
import { Selectable } from 'kysely'
|
|
2
|
+
import {
|
|
3
|
+
$Typed,
|
|
4
|
+
AppBskyActorDefs,
|
|
5
|
+
AtUri,
|
|
6
|
+
ToolsOzoneModerationDefs,
|
|
7
|
+
ToolsOzoneVerificationDefs,
|
|
8
|
+
} from '@atproto/api'
|
|
9
|
+
import { Database } from '../db'
|
|
10
|
+
import { CreatedAtUriKeyset, paginate } from '../db/pagination'
|
|
11
|
+
import { Verification } from '../db/schema/verification'
|
|
12
|
+
|
|
13
|
+
export type VerificationServiceCreator = (db: Database) => VerificationService
|
|
14
|
+
|
|
15
|
+
export class VerificationService {
|
|
16
|
+
constructor(public db: Database) {}
|
|
17
|
+
|
|
18
|
+
static creator() {
|
|
19
|
+
return (db: Database) => new VerificationService(db)
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
async create(
|
|
23
|
+
verifications: Pick<
|
|
24
|
+
Verification,
|
|
25
|
+
| 'uri'
|
|
26
|
+
| 'issuer'
|
|
27
|
+
| 'subject'
|
|
28
|
+
| 'handle'
|
|
29
|
+
| 'displayName'
|
|
30
|
+
| 'createdAt'
|
|
31
|
+
| 'cid'
|
|
32
|
+
>[],
|
|
33
|
+
) {
|
|
34
|
+
return this.db.transaction(async (tx) => {
|
|
35
|
+
return tx.db
|
|
36
|
+
.insertInto('verification')
|
|
37
|
+
.values(verifications)
|
|
38
|
+
.onConflict((oc) => oc.doNothing())
|
|
39
|
+
.returningAll()
|
|
40
|
+
.execute()
|
|
41
|
+
})
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
async markRevoked({
|
|
45
|
+
uris,
|
|
46
|
+
revokedBy,
|
|
47
|
+
revokedAt,
|
|
48
|
+
revokeReason,
|
|
49
|
+
}: {
|
|
50
|
+
uris: string[]
|
|
51
|
+
revokedBy?: string
|
|
52
|
+
revokedAt?: string
|
|
53
|
+
revokeReason?: string
|
|
54
|
+
}) {
|
|
55
|
+
const now = new Date().toISOString()
|
|
56
|
+
return this.db.transaction(async (tx) => {
|
|
57
|
+
for (const uri of uris) {
|
|
58
|
+
return tx.db
|
|
59
|
+
.updateTable('verification')
|
|
60
|
+
.set({
|
|
61
|
+
revokeReason,
|
|
62
|
+
updatedAt: now,
|
|
63
|
+
revokedAt: revokedAt || now,
|
|
64
|
+
// Allow setting revokedBy to a moderator/verifier DID and if it isn't set, default to the author of the verification record
|
|
65
|
+
revokedBy: revokedBy || new AtUri(uri).host,
|
|
66
|
+
})
|
|
67
|
+
.where('uri', '=', uri)
|
|
68
|
+
.where('revokedAt', 'is', null)
|
|
69
|
+
.execute()
|
|
70
|
+
}
|
|
71
|
+
})
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
async list({
|
|
75
|
+
sortDirection,
|
|
76
|
+
cursor,
|
|
77
|
+
createdAfter,
|
|
78
|
+
createdBefore,
|
|
79
|
+
issuers = [],
|
|
80
|
+
subjects = [],
|
|
81
|
+
isRevoked,
|
|
82
|
+
limit = 100,
|
|
83
|
+
}: {
|
|
84
|
+
sortDirection?: 'asc' | 'desc'
|
|
85
|
+
cursor?: string
|
|
86
|
+
createdAfter?: string
|
|
87
|
+
createdBefore?: string
|
|
88
|
+
issuers?: string[]
|
|
89
|
+
subjects?: string[]
|
|
90
|
+
isRevoked?: boolean
|
|
91
|
+
limit?: number
|
|
92
|
+
}) {
|
|
93
|
+
const { ref } = this.db.db.dynamic
|
|
94
|
+
|
|
95
|
+
let qb = this.db.db.selectFrom('verification').selectAll()
|
|
96
|
+
|
|
97
|
+
if (issuers.length) {
|
|
98
|
+
qb = qb.where('issuer', 'in', issuers)
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
if (isRevoked !== undefined) {
|
|
102
|
+
qb = qb.where('revokedAt', isRevoked ? 'is not' : 'is', null)
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
if (subjects.length) {
|
|
106
|
+
qb = qb.where('subject', 'in', subjects)
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
if (createdAfter) {
|
|
110
|
+
qb = qb.where('createdAt', '>=', createdAfter)
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
if (createdBefore) {
|
|
114
|
+
qb = qb.where('createdAt', '<=', createdBefore)
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
const keyset = new CreatedAtUriKeyset(ref(`createdAt`), ref('uri'))
|
|
118
|
+
const paginatedBuilder = paginate(qb, {
|
|
119
|
+
limit,
|
|
120
|
+
cursor,
|
|
121
|
+
keyset,
|
|
122
|
+
tryIndex: true,
|
|
123
|
+
direction: sortDirection === 'desc' ? 'desc' : 'asc',
|
|
124
|
+
})
|
|
125
|
+
|
|
126
|
+
const result = await paginatedBuilder.execute()
|
|
127
|
+
return { verifications: result, cursor: keyset.packFromResult(result) }
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
view(
|
|
131
|
+
verifications: Selectable<Verification>[],
|
|
132
|
+
repos: Map<
|
|
133
|
+
string,
|
|
134
|
+
| $Typed<ToolsOzoneModerationDefs.RepoViewDetail>
|
|
135
|
+
| $Typed<ToolsOzoneModerationDefs.RepoViewNotFound>
|
|
136
|
+
>,
|
|
137
|
+
profiles: Map<string, AppBskyActorDefs.ProfileViewDetailed>,
|
|
138
|
+
): $Typed<ToolsOzoneVerificationDefs.VerificationView>[] {
|
|
139
|
+
return verifications.map((verification) => {
|
|
140
|
+
const issuerRepo = repos.get(verification.issuer)
|
|
141
|
+
const subjectRepo = repos.get(verification.subject)
|
|
142
|
+
const subjectProfile = profiles.get(verification.subject)
|
|
143
|
+
const issuerProfile = profiles.get(verification.issuer)
|
|
144
|
+
return {
|
|
145
|
+
$type: 'tools.ozone.verification.defs#verificationView',
|
|
146
|
+
uri: verification.uri,
|
|
147
|
+
issuer: verification.issuer,
|
|
148
|
+
subject: verification.subject,
|
|
149
|
+
createdAt: verification.createdAt,
|
|
150
|
+
displayName: verification.displayName,
|
|
151
|
+
handle: verification.handle,
|
|
152
|
+
updatedAt: verification.updatedAt || undefined,
|
|
153
|
+
revokedAt: verification.revokedAt || undefined,
|
|
154
|
+
revokedBy: verification.revokedBy || undefined,
|
|
155
|
+
revokeReason: verification.revokeReason || undefined,
|
|
156
|
+
issuerRepo,
|
|
157
|
+
subjectRepo,
|
|
158
|
+
subjectProfile: subjectProfile
|
|
159
|
+
? {
|
|
160
|
+
$type: 'app.bsky.actor.defs#profileViewDetailed',
|
|
161
|
+
...subjectProfile,
|
|
162
|
+
}
|
|
163
|
+
: undefined,
|
|
164
|
+
issuerProfile: issuerProfile
|
|
165
|
+
? {
|
|
166
|
+
$type: 'app.bsky.actor.defs#profileViewDetailed',
|
|
167
|
+
...issuerProfile,
|
|
168
|
+
}
|
|
169
|
+
: undefined,
|
|
170
|
+
}
|
|
171
|
+
})
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
async getFirehoseCursor() {
|
|
175
|
+
const entry = await this.db.db
|
|
176
|
+
.selectFrom('firehose_cursor')
|
|
177
|
+
.select('cursor')
|
|
178
|
+
.where('service', '=', 'verification')
|
|
179
|
+
.executeTakeFirst()
|
|
180
|
+
|
|
181
|
+
return entry?.cursor || null
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
createFirehoseCursor() {
|
|
185
|
+
return this.db.db
|
|
186
|
+
.insertInto('firehose_cursor')
|
|
187
|
+
.values({
|
|
188
|
+
service: 'verification',
|
|
189
|
+
cursor: null,
|
|
190
|
+
})
|
|
191
|
+
.onConflict((oc) => oc.doNothing())
|
|
192
|
+
.execute()
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
async updateFirehoseCursor(cursor: number) {
|
|
196
|
+
const updated = await this.db.db
|
|
197
|
+
.updateTable('firehose_cursor')
|
|
198
|
+
.set({ cursor })
|
|
199
|
+
.where('service', '=', 'verification')
|
|
200
|
+
.where((qb) =>
|
|
201
|
+
qb.where('cursor', '<', cursor).orWhere('cursor', 'is', null),
|
|
202
|
+
)
|
|
203
|
+
.returningAll()
|
|
204
|
+
.executeTakeFirst()
|
|
205
|
+
|
|
206
|
+
return updated?.cursor
|
|
207
|
+
}
|
|
208
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { $Typed, ToolsOzoneModerationDefs } from '@atproto/api'
|
|
2
|
+
import { addAccountInfoToRepoViewDetail, getPdsAccountInfos } from '../api/util'
|
|
3
|
+
import { AppContext } from '../context'
|
|
4
|
+
import { ModerationService } from '../mod-service'
|
|
5
|
+
import { ParsedLabelers } from '../util'
|
|
6
|
+
|
|
7
|
+
export const getReposForVerifications = async (
|
|
8
|
+
ctx: AppContext,
|
|
9
|
+
labelers: ParsedLabelers,
|
|
10
|
+
modService: ModerationService,
|
|
11
|
+
dids: string[],
|
|
12
|
+
isModerator: boolean,
|
|
13
|
+
) => {
|
|
14
|
+
const [partialRepos, accountInfo] = await Promise.all([
|
|
15
|
+
modService.views.repoDetails(dids, labelers),
|
|
16
|
+
getPdsAccountInfos(ctx, dids),
|
|
17
|
+
])
|
|
18
|
+
|
|
19
|
+
const repos = new Map<
|
|
20
|
+
string,
|
|
21
|
+
| $Typed<ToolsOzoneModerationDefs.RepoViewDetail>
|
|
22
|
+
| $Typed<ToolsOzoneModerationDefs.RepoViewNotFound>
|
|
23
|
+
>(
|
|
24
|
+
dids.map((did) => {
|
|
25
|
+
const partialRepo = partialRepos.get(did)
|
|
26
|
+
if (!partialRepo) {
|
|
27
|
+
return [
|
|
28
|
+
did,
|
|
29
|
+
{
|
|
30
|
+
did,
|
|
31
|
+
$type: 'tools.ozone.moderation.defs#repoViewNotFound',
|
|
32
|
+
},
|
|
33
|
+
]
|
|
34
|
+
}
|
|
35
|
+
return [
|
|
36
|
+
did,
|
|
37
|
+
{
|
|
38
|
+
...addAccountInfoToRepoViewDetail(
|
|
39
|
+
partialRepo,
|
|
40
|
+
accountInfo.get(did) || null,
|
|
41
|
+
isModerator,
|
|
42
|
+
),
|
|
43
|
+
$type: 'tools.ozone.moderation.defs#repoViewDetail',
|
|
44
|
+
},
|
|
45
|
+
]
|
|
46
|
+
}),
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
return repos
|
|
50
|
+
}
|