@atproto/ozone 0.0.17-next.0 → 0.0.17-next.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 (146) hide show
  1. package/dist/api/util.d.ts +10 -0
  2. package/dist/auth-verifier.d.ts +2 -2
  3. package/dist/communication-service/template.d.ts +2 -2
  4. package/dist/config/config.d.ts +5 -0
  5. package/dist/config/env.d.ts +2 -0
  6. package/dist/context.d.ts +6 -0
  7. package/dist/daemon/blob-diverter.d.ts +26 -0
  8. package/dist/daemon/event-pusher.d.ts +4 -0
  9. package/dist/daemon/index.d.ts +1 -0
  10. package/dist/db/index.js +21 -1
  11. package/dist/db/index.js.map +3 -3
  12. package/dist/db/migrations/20240228T003647759Z-add-label-sigs.d.ts +3 -0
  13. package/dist/db/migrations/index.d.ts +1 -0
  14. package/dist/db/schema/index.d.ts +2 -1
  15. package/dist/db/schema/label.d.ts +4 -0
  16. package/dist/db/schema/moderation_event.d.ts +1 -1
  17. package/dist/db/schema/moderation_subject_status.d.ts +1 -1
  18. package/dist/db/schema/signing_key.d.ts +9 -0
  19. package/dist/index.js +10949 -10628
  20. package/dist/index.js.map +3 -3
  21. package/dist/lexicon/index.d.ts +48 -28
  22. package/dist/lexicon/lexicons.d.ts +4641 -4650
  23. package/dist/lexicon/types/app/bsky/actor/defs.d.ts +7 -7
  24. package/dist/lexicon/types/app/bsky/feed/defs.d.ts +1 -0
  25. package/dist/lexicon/types/app/bsky/graph/defs.d.ts +3 -0
  26. package/dist/lexicon/types/com/atproto/admin/defs.d.ts +0 -305
  27. package/dist/lexicon/types/com/atproto/label/defs.d.ts +5 -0
  28. package/dist/lexicon/types/{com/atproto/admin/createCommunicationTemplate.d.ts → tools/ozone/communication/createTemplate.d.ts} +2 -2
  29. package/dist/lexicon/types/tools/ozone/communication/defs.d.ts +14 -0
  30. package/dist/lexicon/types/{com/atproto/admin/listCommunicationTemplates.d.ts → tools/ozone/communication/listTemplates.d.ts} +2 -2
  31. package/dist/lexicon/types/{com/atproto/admin/updateCommunicationTemplate.d.ts → tools/ozone/communication/updateTemplate.d.ts} +2 -2
  32. package/dist/lexicon/types/tools/ozone/moderation/defs.d.ts +269 -0
  33. package/dist/lexicon/types/{com/atproto/admin/emitModerationEvent.d.ts → tools/ozone/moderation/emitEvent.d.ts} +5 -4
  34. package/dist/lexicon/types/{com/atproto/admin/getModerationEvent.d.ts → tools/ozone/moderation/getEvent.d.ts} +2 -2
  35. package/dist/lexicon/types/{com/atproto/admin → tools/ozone/moderation}/getRecord.d.ts +2 -2
  36. package/dist/lexicon/types/{com/atproto/admin → tools/ozone/moderation}/getRepo.d.ts +2 -2
  37. package/dist/lexicon/types/{com/atproto/admin/queryModerationEvents.d.ts → tools/ozone/moderation/queryEvents.d.ts} +2 -2
  38. package/dist/lexicon/types/{com/atproto/admin/queryModerationStatuses.d.ts → tools/ozone/moderation/queryStatuses.d.ts} +2 -2
  39. package/dist/lexicon/types/{com/atproto/admin → tools/ozone/moderation}/searchRepos.d.ts +2 -2
  40. package/dist/mod-service/index.d.ts +16 -15
  41. package/dist/mod-service/subject.d.ts +1 -1
  42. package/dist/mod-service/types.d.ts +2 -2
  43. package/dist/mod-service/util.d.ts +6 -0
  44. package/dist/mod-service/views.d.ts +9 -3
  45. package/dist/sequencer/sequencer.d.ts +6 -4
  46. package/dist/util.d.ts +2 -0
  47. package/package.json +7 -7
  48. package/src/api/{admin/createCommunicationTemplate.ts → communication/createTemplate.ts} +1 -1
  49. package/src/api/{admin/deleteCommunicationTemplate.ts → communication/deleteTemplate.ts} +1 -1
  50. package/src/api/{admin/listCommunicationTemplates.ts → communication/listTemplates.ts} +1 -1
  51. package/src/api/{admin/updateCommunicationTemplate.ts → communication/updateTemplate.ts} +1 -1
  52. package/src/api/index.ts +21 -21
  53. package/src/api/{temp → label}/fetchLabels.ts +4 -2
  54. package/src/api/label/queryLabels.ts +4 -2
  55. package/src/api/moderation/emitEvent.ts +218 -0
  56. package/src/api/{admin/getModerationEvent.ts → moderation/getEvent.ts} +1 -1
  57. package/src/api/{admin → moderation}/getRecord.ts +2 -2
  58. package/src/api/{admin → moderation}/getRepo.ts +2 -2
  59. package/src/api/{admin/queryModerationEvents.ts → moderation/queryEvents.ts} +2 -2
  60. package/src/api/{admin/queryModerationStatuses.ts → moderation/queryStatuses.ts} +2 -2
  61. package/src/api/{admin → moderation}/searchRepos.ts +1 -1
  62. package/src/api/{moderation → report}/createReport.ts +1 -1
  63. package/src/api/util.ts +119 -0
  64. package/src/auth-verifier.ts +2 -2
  65. package/src/communication-service/template.ts +2 -2
  66. package/src/config/config.ts +14 -0
  67. package/src/config/env.ts +4 -0
  68. package/src/context.ts +35 -9
  69. package/src/daemon/blob-diverter.ts +150 -0
  70. package/src/daemon/context.ts +9 -5
  71. package/src/daemon/event-pusher.ts +49 -14
  72. package/src/daemon/index.ts +1 -0
  73. package/src/db/migrations/20240228T003647759Z-add-label-sigs.ts +25 -0
  74. package/src/db/migrations/index.ts +1 -0
  75. package/src/db/schema/index.ts +2 -0
  76. package/src/db/schema/label.ts +3 -0
  77. package/src/db/schema/moderation_event.ts +11 -11
  78. package/src/db/schema/moderation_subject_status.ts +1 -1
  79. package/src/db/schema/signing_key.ts +10 -0
  80. package/src/lexicon/index.ts +178 -138
  81. package/src/lexicon/lexicons.ts +6078 -6106
  82. package/src/lexicon/types/app/bsky/actor/defs.ts +11 -11
  83. package/src/lexicon/types/app/bsky/feed/defs.ts +1 -0
  84. package/src/lexicon/types/app/bsky/graph/defs.ts +3 -0
  85. package/src/lexicon/types/com/atproto/admin/defs.ts +0 -697
  86. package/src/lexicon/types/com/atproto/label/defs.ts +10 -0
  87. package/src/lexicon/types/{com/atproto/admin/createCommunicationTemplate.ts → tools/ozone/communication/createTemplate.ts} +2 -2
  88. package/src/lexicon/types/tools/ozone/communication/defs.ts +35 -0
  89. package/src/lexicon/types/{com/atproto/admin/listCommunicationTemplates.ts → tools/ozone/communication/listTemplates.ts} +2 -2
  90. package/src/lexicon/types/{com/atproto/admin/updateCommunicationTemplate.ts → tools/ozone/communication/updateTemplate.ts} +2 -2
  91. package/src/lexicon/types/tools/ozone/moderation/defs.ts +641 -0
  92. package/src/lexicon/types/{com/atproto/admin/emitModerationEvent.ts → tools/ozone/moderation/emitEvent.ts} +15 -14
  93. package/src/lexicon/types/{com/atproto/admin/getModerationEvent.ts → tools/ozone/moderation/getEvent.ts} +2 -2
  94. package/src/lexicon/types/{com/atproto/admin → tools/ozone/moderation}/getRecord.ts +2 -2
  95. package/src/lexicon/types/{com/atproto/admin → tools/ozone/moderation}/getRepo.ts +2 -2
  96. package/src/lexicon/types/{com/atproto/admin/queryModerationEvents.ts → tools/ozone/moderation/queryEvents.ts} +3 -3
  97. package/src/lexicon/types/{com/atproto/admin/queryModerationStatuses.ts → tools/ozone/moderation/queryStatuses.ts} +2 -2
  98. package/src/lexicon/types/{com/atproto/admin → tools/ozone/moderation}/searchRepos.ts +2 -2
  99. package/src/mod-service/index.ts +42 -47
  100. package/src/mod-service/lang.ts +1 -1
  101. package/src/mod-service/status.ts +19 -16
  102. package/src/mod-service/subject.ts +1 -1
  103. package/src/mod-service/types.ts +10 -10
  104. package/src/mod-service/util.ts +49 -5
  105. package/src/mod-service/views.ts +45 -18
  106. package/src/sequencer/sequencer.ts +12 -11
  107. package/src/util.ts +21 -0
  108. package/tests/__snapshots__/blob-divert.test.ts.snap +22 -0
  109. package/tests/__snapshots__/get-record.test.ts.snap +10 -2
  110. package/tests/__snapshots__/get-repo.test.ts.snap +5 -1
  111. package/tests/__snapshots__/moderation-events.test.ts.snap +8 -8
  112. package/tests/__snapshots__/moderation-statuses.test.ts.snap +6 -6
  113. package/tests/_util.ts +5 -0
  114. package/tests/blob-divert.test.ts +87 -0
  115. package/tests/communication-templates.test.ts +30 -34
  116. package/tests/db.test.ts +6 -6
  117. package/tests/get-record.test.ts +6 -6
  118. package/tests/get-repo.test.ts +11 -11
  119. package/tests/moderation-appeals.test.ts +28 -28
  120. package/tests/moderation-events.test.ts +44 -44
  121. package/tests/moderation-status-tags.test.ts +8 -10
  122. package/tests/moderation-statuses.test.ts +27 -27
  123. package/tests/moderation.test.ts +50 -57
  124. package/tests/query-labels.test.ts +86 -10
  125. package/tests/repo-search.test.ts +8 -8
  126. package/tests/sequencer.test.ts +6 -3
  127. package/dist/api/admin/util.d.ts +0 -5
  128. package/dist/api/moderation/util.d.ts +0 -4
  129. package/src/api/admin/emitModerationEvent.ts +0 -174
  130. package/src/api/admin/util.ts +0 -54
  131. package/src/api/moderation/util.ts +0 -67
  132. /package/dist/api/{admin/createCommunicationTemplate.d.ts → communication/createTemplate.d.ts} +0 -0
  133. /package/dist/api/{admin/deleteCommunicationTemplate.d.ts → communication/deleteTemplate.d.ts} +0 -0
  134. /package/dist/api/{admin/emitModerationEvent.d.ts → communication/listTemplates.d.ts} +0 -0
  135. /package/dist/api/{admin/getModerationEvent.d.ts → communication/updateTemplate.d.ts} +0 -0
  136. /package/dist/api/{temp → label}/fetchLabels.d.ts +0 -0
  137. /package/dist/api/{admin/getRecord.d.ts → moderation/emitEvent.d.ts} +0 -0
  138. /package/dist/api/{admin/getRepo.d.ts → moderation/getEvent.d.ts} +0 -0
  139. /package/dist/api/{admin/listCommunicationTemplates.d.ts → moderation/getRecord.d.ts} +0 -0
  140. /package/dist/api/{admin/queryModerationEvents.d.ts → moderation/getRepo.d.ts} +0 -0
  141. /package/dist/api/{admin/queryModerationStatuses.d.ts → moderation/queryEvents.d.ts} +0 -0
  142. /package/dist/api/{admin/searchRepos.d.ts → moderation/queryStatuses.d.ts} +0 -0
  143. /package/dist/api/{admin/updateCommunicationTemplate.d.ts → moderation/searchRepos.d.ts} +0 -0
  144. /package/dist/api/{moderation → report}/createReport.d.ts +0 -0
  145. /package/dist/lexicon/types/{com/atproto/admin/deleteCommunicationTemplate.d.ts → tools/ozone/communication/deleteTemplate.d.ts} +0 -0
  146. /package/src/lexicon/types/{com/atproto/admin/deleteCommunicationTemplate.ts → tools/ozone/communication/deleteTemplate.ts} +0 -0
@@ -7,7 +7,7 @@ import { lexicons } from '../../../../lexicons'
7
7
  import { isObj, hasProp } from '../../../../util'
8
8
  import { CID } from 'multiformats/cid'
9
9
  import { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server'
10
- import * as ComAtprotoAdminDefs from './defs'
10
+ import * as ToolsOzoneModerationDefs from './defs'
11
11
 
12
12
  export interface QueryParams {
13
13
  uri: string
@@ -15,7 +15,7 @@ export interface QueryParams {
15
15
  }
16
16
 
17
17
  export type InputSchema = undefined
18
- export type OutputSchema = ComAtprotoAdminDefs.RecordViewDetail
18
+ export type OutputSchema = ToolsOzoneModerationDefs.RecordViewDetail
19
19
  export type HandlerInput = undefined
20
20
 
21
21
  export interface HandlerSuccess {
@@ -7,14 +7,14 @@ import { lexicons } from '../../../../lexicons'
7
7
  import { isObj, hasProp } from '../../../../util'
8
8
  import { CID } from 'multiformats/cid'
9
9
  import { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server'
10
- import * as ComAtprotoAdminDefs from './defs'
10
+ import * as ToolsOzoneModerationDefs from './defs'
11
11
 
12
12
  export interface QueryParams {
13
13
  did: string
14
14
  }
15
15
 
16
16
  export type InputSchema = undefined
17
- export type OutputSchema = ComAtprotoAdminDefs.RepoViewDetail
17
+ export type OutputSchema = ToolsOzoneModerationDefs.RepoViewDetail
18
18
  export type HandlerInput = undefined
19
19
 
20
20
  export interface HandlerSuccess {
@@ -7,10 +7,10 @@ import { lexicons } from '../../../../lexicons'
7
7
  import { isObj, hasProp } from '../../../../util'
8
8
  import { CID } from 'multiformats/cid'
9
9
  import { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server'
10
- import * as ComAtprotoAdminDefs from './defs'
10
+ import * as ToolsOzoneModerationDefs from './defs'
11
11
 
12
12
  export interface QueryParams {
13
- /** The types of events (fully qualified string in the format of com.atproto.admin#modEvent<name>) to filter by. If not specified, all events are returned. */
13
+ /** The types of events (fully qualified string in the format of tools.ozone.moderation.defs#modEvent<name>) to filter by. If not specified, all events are returned. */
14
14
  types?: string[]
15
15
  createdBy?: string
16
16
  /** Sort direction for the events. Defaults to descending order of created at timestamp. */
@@ -43,7 +43,7 @@ export type InputSchema = undefined
43
43
 
44
44
  export interface OutputSchema {
45
45
  cursor?: string
46
- events: ComAtprotoAdminDefs.ModEventView[]
46
+ events: ToolsOzoneModerationDefs.ModEventView[]
47
47
  [k: string]: unknown
48
48
  }
49
49
 
@@ -7,7 +7,7 @@ import { lexicons } from '../../../../lexicons'
7
7
  import { isObj, hasProp } from '../../../../util'
8
8
  import { CID } from 'multiformats/cid'
9
9
  import { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server'
10
- import * as ComAtprotoAdminDefs from './defs'
10
+ import * as ToolsOzoneModerationDefs from './defs'
11
11
 
12
12
  export interface QueryParams {
13
13
  subject?: string
@@ -44,7 +44,7 @@ export type InputSchema = undefined
44
44
 
45
45
  export interface OutputSchema {
46
46
  cursor?: string
47
- subjectStatuses: ComAtprotoAdminDefs.SubjectStatusView[]
47
+ subjectStatuses: ToolsOzoneModerationDefs.SubjectStatusView[]
48
48
  [k: string]: unknown
49
49
  }
50
50
 
@@ -7,7 +7,7 @@ import { lexicons } from '../../../../lexicons'
7
7
  import { isObj, hasProp } from '../../../../util'
8
8
  import { CID } from 'multiformats/cid'
9
9
  import { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server'
10
- import * as ComAtprotoAdminDefs from './defs'
10
+ import * as ToolsOzoneModerationDefs from './defs'
11
11
 
12
12
  export interface QueryParams {
13
13
  /** DEPRECATED: use 'q' instead */
@@ -21,7 +21,7 @@ export type InputSchema = undefined
21
21
 
22
22
  export interface OutputSchema {
23
23
  cursor?: string
24
- repos: ComAtprotoAdminDefs.RepoView[]
24
+ repos: ToolsOzoneModerationDefs.RepoView[]
25
25
  [k: string]: unknown
26
26
  }
27
27
 
@@ -4,6 +4,7 @@ import { CID } from 'multiformats/cid'
4
4
  import { AtUri, INVALID_HANDLE } from '@atproto/syntax'
5
5
  import { InvalidRequestError } from '@atproto/xrpc-server'
6
6
  import { addHoursToDate } from '@atproto/common'
7
+ import { Keypair } from '@atproto/crypto'
7
8
  import { IdResolver } from '@atproto/identity'
8
9
  import AtpAgent from '@atproto/api'
9
10
  import { Database } from '../db'
@@ -17,9 +18,8 @@ import {
17
18
  isModEventTakedown,
18
19
  isModEventEmail,
19
20
  isModEventTag,
20
- RepoRef,
21
- RepoBlobRef,
22
- } from '../lexicon/types/com/atproto/admin/defs'
21
+ } from '../lexicon/types/tools/ozone/moderation/defs'
22
+ import { RepoRef, RepoBlobRef } from '../lexicon/types/com/atproto/admin/defs'
23
23
  import {
24
24
  adjustModerationSubjectStatus,
25
25
  getStatusIdentifierFromSubject,
@@ -46,6 +46,7 @@ import { LabelChannel } from '../db/schema/label'
46
46
  import { BlobPushEvent } from '../db/schema/blob_push_event'
47
47
  import { BackgroundQueue } from '../background'
48
48
  import { EventPusher } from '../daemon'
49
+ import { formatLabel, formatLabelRow, signLabel } from './util'
49
50
  import { ImageInvalidator } from '../image-invalidator'
50
51
  import { httpLogger as log } from '../logger'
51
52
  import { OzoneConfig } from '../config'
@@ -55,45 +56,49 @@ export type ModerationServiceCreator = (db: Database) => ModerationService
55
56
  export class ModerationService {
56
57
  constructor(
57
58
  public db: Database,
59
+ public signingKey: Keypair,
60
+ public signingKeyId: number,
58
61
  public cfg: OzoneConfig,
59
62
  public backgroundQueue: BackgroundQueue,
60
63
  public idResolver: IdResolver,
61
64
  public eventPusher: EventPusher,
62
65
  public appviewAgent: AtpAgent,
63
66
  private createAuthHeaders: (aud: string) => Promise<AuthHeaders>,
64
- public serverDid: string,
65
67
  public imgInvalidator?: ImageInvalidator,
66
- public cdnPaths?: string[],
67
68
  ) {}
68
69
 
69
70
  static creator(
71
+ signingKey: Keypair,
72
+ signingKeyId: number,
70
73
  cfg: OzoneConfig,
71
74
  backgroundQueue: BackgroundQueue,
72
75
  idResolver: IdResolver,
73
76
  eventPusher: EventPusher,
74
77
  appviewAgent: AtpAgent,
75
78
  createAuthHeaders: (aud: string) => Promise<AuthHeaders>,
76
- serverDid: string,
77
79
  imgInvalidator?: ImageInvalidator,
78
- cdnPaths?: string[],
79
80
  ) {
80
81
  return (db: Database) =>
81
82
  new ModerationService(
82
83
  db,
84
+ signingKey,
85
+ signingKeyId,
83
86
  cfg,
84
87
  backgroundQueue,
85
88
  idResolver,
86
89
  eventPusher,
87
90
  appviewAgent,
88
91
  createAuthHeaders,
89
- serverDid,
90
92
  imgInvalidator,
91
- cdnPaths,
92
93
  )
93
94
  }
94
95
 
95
- views = new ModerationViews(this.db, this.appviewAgent, () =>
96
- this.createAuthHeaders(this.cfg.appview.did),
96
+ views = new ModerationViews(
97
+ this.db,
98
+ this.signingKey,
99
+ this.signingKeyId,
100
+ this.appviewAgent,
101
+ () => this.createAuthHeaders(this.cfg.appview.did),
97
102
  )
98
103
 
99
104
  async getEvent(id: number): Promise<ModerationEventRow | undefined> {
@@ -247,7 +252,7 @@ export class ModerationService {
247
252
  async getReport(id: number): Promise<ModerationEventRow | undefined> {
248
253
  return await this.db.db
249
254
  .selectFrom('moderation_event')
250
- .where('action', '=', 'com.atproto.admin.defs#modEventReport')
255
+ .where('action', '=', 'tools.ozone.moderation.defs#modEventReport')
251
256
  .selectAll()
252
257
  .where('id', '=', id)
253
258
  .executeTakeFirst()
@@ -370,12 +375,12 @@ export class ModerationService {
370
375
  // Means the subject was suspended and needs to be unsuspended
371
376
  if (subject.reverseSuspend) {
372
377
  builder = builder
373
- .where('action', '=', 'com.atproto.admin.defs#modEventTakedown')
378
+ .where('action', '=', 'tools.ozone.moderation.defs#modEventTakedown')
374
379
  .where('durationInHours', 'is not', null)
375
380
  }
376
381
  if (subject.reverseMute) {
377
382
  builder = builder
378
- .where('action', '=', 'com.atproto.admin.defs#modEventMute')
383
+ .where('action', '=', 'tools.ozone.moderation.defs#modEventMute')
379
384
  .where('durationInHours', 'is not', null)
380
385
  }
381
386
 
@@ -422,13 +427,13 @@ export class ModerationService {
422
427
  subject,
423
428
  }: ReversibleModerationEvent): Promise<ModerationEventRow> {
424
429
  const isRevertingTakedown =
425
- action === 'com.atproto.admin.defs#modEventTakedown'
430
+ action === 'tools.ozone.moderation.defs#modEventTakedown'
426
431
  this.db.assertTransaction()
427
432
  const { event } = await this.logEvent({
428
433
  event: {
429
434
  $type: isRevertingTakedown
430
- ? 'com.atproto.admin.defs#modEventReverseTakedown'
431
- : 'com.atproto.admin.defs#modEventUnmute',
435
+ ? 'tools.ozone.moderation.defs#modEventReverseTakedown'
436
+ : 'tools.ozone.moderation.defs#modEventUnmute',
432
437
  comment: comment ?? undefined,
433
438
  },
434
439
  createdAt,
@@ -560,27 +565,17 @@ export class ModerationService {
560
565
  for (const cid of blobCids) {
561
566
  blobValues.push({
562
567
  eventType,
568
+ takedownRef,
563
569
  subjectDid: subject.did,
570
+ subjectUri: subject.uri || null,
564
571
  subjectBlobCid: cid.toString(),
565
- takedownRef,
566
572
  })
567
573
  }
568
574
  }
569
- const blobEvts = await this.db.db
570
- .insertInto('blob_push_event')
571
- .values(blobValues)
572
- .onConflict((oc) =>
573
- oc
574
- .columns(['subjectDid', 'subjectBlobCid', 'eventType'])
575
- .doUpdateSet({
576
- takedownRef,
577
- confirmedAt: null,
578
- attempts: 0,
579
- lastAttempted: null,
580
- }),
581
- )
582
- .returning(['id', 'subjectDid', 'subjectBlobCid', 'eventType'])
583
- .execute()
575
+ const blobEvts = await this.eventPusher.logBlobPushEvent(
576
+ blobValues,
577
+ takedownRef,
578
+ )
584
579
 
585
580
  this.db.onCommit(() => {
586
581
  this.backgroundQueue.add(async () => {
@@ -597,7 +592,7 @@ export class ModerationService {
597
592
  if (this.imgInvalidator) {
598
593
  await Promise.allSettled(
599
594
  (subject.blobCids ?? []).map((cid) => {
600
- const paths = (this.cdnPaths ?? []).map((path) =>
595
+ const paths = (this.cfg.cdn.paths ?? []).map((path) =>
601
596
  path.replace('%s', subject.did).replace('%s', cid),
602
597
  )
603
598
  return this.imgInvalidator
@@ -698,7 +693,7 @@ export class ModerationService {
698
693
 
699
694
  const result = await this.logEvent({
700
695
  event: {
701
- $type: 'com.atproto.admin.defs#modEventReport',
696
+ $type: 'tools.ozone.moderation.defs#modEventReport',
702
697
  reportType: reasonType,
703
698
  comment: reason,
704
699
  },
@@ -876,7 +871,7 @@ export class ModerationService {
876
871
  ): Promise<Label[]> {
877
872
  const { create = [], negate = [] } = labels
878
873
  const toCreate = create.map((val) => ({
879
- src: this.serverDid,
874
+ src: this.cfg.service.did,
880
875
  uri,
881
876
  cid: cid ?? undefined,
882
877
  val,
@@ -884,7 +879,7 @@ export class ModerationService {
884
879
  cts: new Date().toISOString(),
885
880
  }))
886
881
  const toNegate = negate.map((val) => ({
887
- src: this.serverDid,
882
+ src: this.cfg.service.did,
888
883
  uri,
889
884
  cid: cid ?? undefined,
890
885
  val,
@@ -892,21 +887,19 @@ export class ModerationService {
892
887
  cts: new Date().toISOString(),
893
888
  }))
894
889
  const formatted = [...toCreate, ...toNegate]
895
- await this.createLabels(formatted)
896
- return formatted
890
+ return this.createLabels(formatted)
897
891
  }
898
892
 
899
- async createLabels(labels: Label[]) {
900
- if (labels.length < 1) return
901
- const dbVals = labels.map((l) => ({
902
- ...l,
903
- cid: l.cid ?? '',
904
- neg: !!l.neg,
905
- }))
893
+ async createLabels(labels: Label[]): Promise<Label[]> {
894
+ if (labels.length < 1) return []
895
+ const signedLabels = await Promise.all(
896
+ labels.map((l) => signLabel(l, this.signingKey)),
897
+ )
898
+ const dbVals = signedLabels.map((l) => formatLabelRow(l, this.signingKeyId))
906
899
  const { ref } = this.db.db.dynamic
907
900
  await sql`notify ${ref(LabelChannel)}`.execute(this.db.db)
908
901
  const excluded = (col: string) => ref(`excluded.${col}`)
909
- await this.db.db
902
+ const res = await this.db.db
910
903
  .insertInto('label')
911
904
  .values(dbVals)
912
905
  .onConflict((oc) =>
@@ -916,7 +909,9 @@ export class ModerationService {
916
909
  cts: sql`${excluded('cts')}`,
917
910
  }),
918
911
  )
912
+ .returningAll()
919
913
  .execute()
914
+ return res.map((row) => formatLabel(row))
920
915
  }
921
916
 
922
917
  async sendEmail(opts: {
@@ -25,7 +25,7 @@ export class ModerationLangService {
25
25
  })
26
26
  await this.moderationService.logEvent({
27
27
  event: {
28
- $type: 'com.atproto.admin.defs#modEventTag',
28
+ $type: 'tools.ozone.moderation.defs#modEventTag',
29
29
  add: recordLangs
30
30
  ? recordLangs.map((lang) => `lang:${lang}`)
31
31
  : ['lang:und'],
@@ -8,7 +8,7 @@ import {
8
8
  REVIEWCLOSED,
9
9
  REVIEWESCALATED,
10
10
  REVIEWNONE,
11
- } from '../lexicon/types/com/atproto/admin/defs'
11
+ } from '../lexicon/types/tools/ozone/moderation/defs'
12
12
  import { ModerationEventRow, ModerationSubjectStatusRow } from './types'
13
13
  import { HOUR } from '@atproto/common'
14
14
  import { REASONAPPEAL } from '../lexicon/types/com/atproto/moderation/defs'
@@ -32,24 +32,24 @@ const getSubjectStatusForModerationEvent = ({
32
32
  : REVIEWNONE
33
33
 
34
34
  switch (action) {
35
- case 'com.atproto.admin.defs#modEventAcknowledge':
35
+ case 'tools.ozone.moderation.defs#modEventAcknowledge':
36
36
  return {
37
37
  lastReviewedBy: createdBy,
38
38
  reviewState: REVIEWCLOSED,
39
39
  lastReviewedAt: createdAt,
40
40
  }
41
- case 'com.atproto.admin.defs#modEventReport':
41
+ case 'tools.ozone.moderation.defs#modEventReport':
42
42
  return {
43
43
  reviewState: REVIEWOPEN,
44
44
  lastReportedAt: createdAt,
45
45
  }
46
- case 'com.atproto.admin.defs#modEventEscalate':
46
+ case 'tools.ozone.moderation.defs#modEventEscalate':
47
47
  return {
48
48
  lastReviewedBy: createdBy,
49
49
  reviewState: REVIEWESCALATED,
50
50
  lastReviewedAt: createdAt,
51
51
  }
52
- case 'com.atproto.admin.defs#modEventReverseTakedown':
52
+ case 'tools.ozone.moderation.defs#modEventReverseTakedown':
53
53
  return {
54
54
  lastReviewedBy: createdBy,
55
55
  reviewState: REVIEWCLOSED,
@@ -57,7 +57,7 @@ const getSubjectStatusForModerationEvent = ({
57
57
  suspendUntil: null,
58
58
  lastReviewedAt: createdAt,
59
59
  }
60
- case 'com.atproto.admin.defs#modEventUnmute':
60
+ case 'tools.ozone.moderation.defs#modEventUnmute':
61
61
  return {
62
62
  lastReviewedBy: createdBy,
63
63
  muteUntil: null,
@@ -66,7 +66,7 @@ const getSubjectStatusForModerationEvent = ({
66
66
  reviewState: defaultReviewState,
67
67
  lastReviewedAt: createdAt,
68
68
  }
69
- case 'com.atproto.admin.defs#modEventTakedown':
69
+ case 'tools.ozone.moderation.defs#modEventTakedown':
70
70
  return {
71
71
  takendown: true,
72
72
  lastReviewedBy: createdBy,
@@ -76,7 +76,7 @@ const getSubjectStatusForModerationEvent = ({
76
76
  ? new Date(Date.now() + durationInHours * HOUR).toISOString()
77
77
  : null,
78
78
  }
79
- case 'com.atproto.admin.defs#modEventMute':
79
+ case 'tools.ozone.moderation.defs#modEventMute':
80
80
  return {
81
81
  lastReviewedBy: createdBy,
82
82
  lastReviewedAt: createdAt,
@@ -88,15 +88,15 @@ const getSubjectStatusForModerationEvent = ({
88
88
  // but if it does happen, default to unnecessary
89
89
  reviewState: defaultReviewState,
90
90
  }
91
- case 'com.atproto.admin.defs#modEventComment':
91
+ case 'tools.ozone.moderation.defs#modEventComment':
92
92
  return {
93
93
  lastReviewedBy: createdBy,
94
94
  lastReviewedAt: createdAt,
95
95
  reviewState: defaultReviewState,
96
96
  }
97
- case 'com.atproto.admin.defs#modEventTag':
97
+ case 'tools.ozone.moderation.defs#modEventTag':
98
98
  return { tags: [], reviewState: defaultReviewState }
99
- case 'com.atproto.admin.defs#modEventResolveAppeal':
99
+ case 'tools.ozone.moderation.defs#modEventResolveAppeal':
100
100
  return {
101
101
  appealed: false,
102
102
  }
@@ -141,7 +141,7 @@ export const adjustModerationSubjectStatus = async (
141
141
  .executeTakeFirst()
142
142
 
143
143
  const isAppealEvent =
144
- action === 'com.atproto.admin.defs#modEventReport' &&
144
+ action === 'tools.ozone.moderation.defs#modEventReport' &&
145
145
  meta?.reportType === REASONAPPEAL
146
146
 
147
147
  const subjectStatus = getSubjectStatusForModerationEvent({
@@ -183,7 +183,7 @@ export const adjustModerationSubjectStatus = async (
183
183
  }
184
184
 
185
185
  if (
186
- action === 'com.atproto.admin.defs#modEventReverseTakedown' &&
186
+ action === 'tools.ozone.moderation.defs#modEventReverseTakedown' &&
187
187
  !subjectStatus.takendown
188
188
  ) {
189
189
  newStatus.takendown = false
@@ -201,19 +201,22 @@ export const adjustModerationSubjectStatus = async (
201
201
  }
202
202
 
203
203
  if (
204
- action === 'com.atproto.admin.defs#modEventResolveAppeal' &&
204
+ action === 'tools.ozone.moderation.defs#modEventResolveAppeal' &&
205
205
  subjectStatus.appealed
206
206
  ) {
207
207
  newStatus.appealed = false
208
208
  subjectStatus.appealed = false
209
209
  }
210
210
 
211
- if (action === 'com.atproto.admin.defs#modEventComment' && meta?.sticky) {
211
+ if (
212
+ action === 'tools.ozone.moderation.defs#modEventComment' &&
213
+ meta?.sticky
214
+ ) {
212
215
  newStatus.comment = comment
213
216
  subjectStatus.comment = comment
214
217
  }
215
218
 
216
- if (action === 'com.atproto.admin.defs#modEventTag') {
219
+ if (action === 'tools.ozone.moderation.defs#modEventTag') {
217
220
  let tags = currentStatus?.tags || []
218
221
  if (addedTags?.length) {
219
222
  tags = tags.concat(addedTags)
@@ -1,6 +1,6 @@
1
1
  import { AtUri } from '@atproto/syntax'
2
2
  import { InputSchema as ReportInput } from '../lexicon/types/com/atproto/moderation/createReport'
3
- import { InputSchema as ActionInput } from '../lexicon/types/com/atproto/admin/emitModerationEvent'
3
+ import { InputSchema as ActionInput } from '../lexicon/types/tools/ozone/moderation/emitEvent'
4
4
  import { InvalidRequestError } from '@atproto/xrpc-server'
5
5
  import { ModerationEventRow, ModerationSubjectStatusRow } from './types'
6
6
  import { RepoRef } from '../lexicon/types/com/atproto/admin/defs'
@@ -1,7 +1,7 @@
1
1
  import { Selectable } from 'kysely'
2
2
  import { ModerationEvent } from '../db/schema/moderation_event'
3
3
  import { ModerationSubjectStatus } from '../db/schema/moderation_subject_status'
4
- import { ComAtprotoAdminDefs } from '@atproto/api'
4
+ import { ToolsOzoneModerationDefs } from '@atproto/api'
5
5
  import { ModSubject } from './subject'
6
6
 
7
7
  export type ModerationEventRow = Selectable<ModerationEvent>
@@ -22,15 +22,15 @@ export type ModerationSubjectStatusRowWithHandle =
22
22
  ModerationSubjectStatusRow & { handle: string | null }
23
23
 
24
24
  export type ModEventType =
25
- | ComAtprotoAdminDefs.ModEventTakedown
26
- | ComAtprotoAdminDefs.ModEventAcknowledge
27
- | ComAtprotoAdminDefs.ModEventEscalate
28
- | ComAtprotoAdminDefs.ModEventComment
29
- | ComAtprotoAdminDefs.ModEventLabel
30
- | ComAtprotoAdminDefs.ModEventReport
31
- | ComAtprotoAdminDefs.ModEventMute
32
- | ComAtprotoAdminDefs.ModEventReverseTakedown
33
- | ComAtprotoAdminDefs.ModEventTag
25
+ | ToolsOzoneModerationDefs.ModEventTakedown
26
+ | ToolsOzoneModerationDefs.ModEventAcknowledge
27
+ | ToolsOzoneModerationDefs.ModEventEscalate
28
+ | ToolsOzoneModerationDefs.ModEventComment
29
+ | ToolsOzoneModerationDefs.ModEventLabel
30
+ | ToolsOzoneModerationDefs.ModEventReport
31
+ | ToolsOzoneModerationDefs.ModEventMute
32
+ | ToolsOzoneModerationDefs.ModEventReverseTakedown
33
+ | ToolsOzoneModerationDefs.ModEventTag
34
34
 
35
35
  export const UNSPECCED_TAKEDOWN_LABEL = '!unspecced-takedown'
36
36
 
@@ -1,17 +1,61 @@
1
+ import { cborEncode, noUndefinedVals } from '@atproto/common'
2
+ import { Keypair } from '@atproto/crypto'
1
3
  import { LabelRow } from '../db/schema/label'
2
4
  import { Label } from '../lexicon/types/com/atproto/label/defs'
3
5
 
6
+ export type SignedLabel = Label & { sig: Uint8Array }
7
+
4
8
  export const formatLabel = (row: LabelRow): Label => {
5
- const label: Label = {
9
+ return noUndefinedVals({
10
+ ver: 1,
6
11
  src: row.src,
7
12
  uri: row.uri,
13
+ cid: row.cid === '' ? undefined : row.cid,
8
14
  val: row.val,
9
15
  neg: row.neg,
10
16
  cts: row.cts,
17
+ exp: row.exp ?? undefined,
18
+ sig: row.sig ? new Uint8Array(row.sig) : undefined,
19
+ }) as Label
20
+ }
21
+
22
+ export const formatLabelRow = (
23
+ label: Label,
24
+ signingKeyId?: number,
25
+ ): Omit<LabelRow, 'id'> => {
26
+ return {
27
+ src: label.src,
28
+ uri: label.uri,
29
+ cid: label.cid ?? '',
30
+ val: label.val,
31
+ neg: !!label.neg,
32
+ cts: label.cts,
33
+ exp: label.exp ?? null,
34
+ sig: label.sig ? Buffer.from(label.sig) : null,
35
+ signingKeyId: signingKeyId ?? null,
11
36
  }
12
- if (row.cid !== '') {
13
- // @NOTE avoiding undefined values on label, which dag-cbor chokes on when serializing.
14
- label.cid = row.cid
37
+ }
38
+
39
+ export const signLabel = async (
40
+ label: Label,
41
+ signingKey: Keypair,
42
+ ): Promise<SignedLabel> => {
43
+ const { ver, src, uri, cid, val, neg, cts, exp } = label
44
+ const reformatted = noUndefinedVals({
45
+ ver: ver ?? 1,
46
+ src,
47
+ uri,
48
+ cid,
49
+ val,
50
+ neg,
51
+ cts,
52
+ exp,
53
+ }) as Label
54
+
55
+ const bytes = cborEncode(reformatted)
56
+ const sig = await signingKey.sign(bytes)
57
+ return {
58
+ ...reformatted,
59
+ sig,
15
60
  }
16
- return label
17
61
  }