@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
@@ -6,8 +6,8 @@ import {
6
6
  ModeratorClient,
7
7
  } from '@atproto/dev-env'
8
8
  import {
9
- ComAtprotoAdminDefs,
10
- ComAtprotoAdminQueryModerationStatuses,
9
+ ToolsOzoneModerationDefs,
10
+ ToolsOzoneModerationQueryStatuses,
11
11
  } from '@atproto/api'
12
12
  import { forSnapshot } from './_util'
13
13
  import {
@@ -17,7 +17,7 @@ import {
17
17
  import {
18
18
  REVIEWOPEN,
19
19
  REVIEWNONE,
20
- } from '../src/lexicon/types/com/atproto/admin/defs'
20
+ } from '../src/lexicon/types/tools/ozone/moderation/defs'
21
21
 
22
22
  describe('moderation-statuses', () => {
23
23
  let network: TestNetwork
@@ -79,19 +79,19 @@ describe('moderation-statuses', () => {
79
79
 
80
80
  describe('query statuses', () => {
81
81
  it('returns statuses for subjects that received moderation events', async () => {
82
- const response = await modClient.queryModerationStatuses({})
82
+ const response = await modClient.queryStatuses({})
83
83
 
84
84
  expect(forSnapshot(response.subjectStatuses)).toMatchSnapshot()
85
85
  })
86
86
 
87
87
  it('returns statuses filtered by subject language', async () => {
88
- const klingonQueue = await modClient.queryModerationStatuses({
88
+ const klingonQueue = await modClient.queryStatuses({
89
89
  tags: ['lang:i'],
90
90
  })
91
91
 
92
92
  expect(forSnapshot(klingonQueue.subjectStatuses)).toMatchSnapshot()
93
93
 
94
- const nonKlingonQueue = await modClient.queryModerationStatuses({
94
+ const nonKlingonQueue = await modClient.queryStatuses({
95
95
  excludeTags: ['lang:i'],
96
96
  })
97
97
 
@@ -104,13 +104,13 @@ describe('moderation-statuses', () => {
104
104
  it('returns paginated statuses', async () => {
105
105
  // We know there will be exactly 4 statuses in db
106
106
  const getPaginatedStatuses = async (
107
- params: ComAtprotoAdminQueryModerationStatuses.QueryParams,
107
+ params: ToolsOzoneModerationQueryStatuses.QueryParams,
108
108
  ) => {
109
109
  let cursor: string | undefined = ''
110
- const statuses: ComAtprotoAdminDefs.SubjectStatusView[] = []
110
+ const statuses: ToolsOzoneModerationDefs.SubjectStatusView[] = []
111
111
  let count = 0
112
112
  do {
113
- const results = await modClient.queryModerationStatuses({
113
+ const results = await modClient.queryStatuses({
114
114
  limit: 1,
115
115
  cursor,
116
116
  ...params,
@@ -128,10 +128,10 @@ describe('moderation-statuses', () => {
128
128
  expect(list[0].id).toEqual(7)
129
129
  expect(list[list.length - 1].id).toEqual(1)
130
130
 
131
- await modClient.emitModerationEvent({
131
+ await modClient.emitEvent({
132
132
  subject: list[1].subject,
133
133
  event: {
134
- $type: 'com.atproto.admin.defs#modEventAcknowledge',
134
+ $type: 'tools.ozone.moderation.defs#modEventAcknowledge',
135
135
  comment: 'X',
136
136
  },
137
137
  })
@@ -160,7 +160,7 @@ describe('moderation-statuses', () => {
160
160
  cid: sc.posts[sc.dids.alice][0].ref.cidStr,
161
161
  }
162
162
  const getBobsAccountStatus = async () => {
163
- const data = await modClient.queryModerationStatuses({
163
+ const data = await modClient.queryStatuses({
164
164
  subject: bobsAccount.did,
165
165
  })
166
166
 
@@ -170,20 +170,20 @@ describe('moderation-statuses', () => {
170
170
  const bobsAccountStatusBeforeTag = await getBobsAccountStatus()
171
171
 
172
172
  await Promise.all([
173
- modClient.emitModerationEvent({
173
+ modClient.emitEvent({
174
174
  subject: bobsAccount,
175
175
  event: {
176
- $type: 'com.atproto.admin.defs#modEventTag',
176
+ $type: 'tools.ozone.moderation.defs#modEventTag',
177
177
  add: ['newTag'],
178
178
  remove: [],
179
179
  comment: 'X',
180
180
  },
181
181
  createdBy: sc.dids.alice,
182
182
  }),
183
- modClient.emitModerationEvent({
183
+ modClient.emitEvent({
184
184
  subject: bobsAccount,
185
185
  event: {
186
- $type: 'com.atproto.admin.defs#modEventComment',
186
+ $type: 'tools.ozone.moderation.defs#modEventComment',
187
187
  comment: 'X',
188
188
  },
189
189
  createdBy: sc.dids.alice,
@@ -197,7 +197,7 @@ describe('moderation-statuses', () => {
197
197
 
198
198
  // Since alice's post didn't have a reviewState it is set to reviewNone on first non-impactful event
199
199
  const getAlicesPostStatus = async () => {
200
- const data = await modClient.queryModerationStatuses({
200
+ const data = await modClient.queryStatuses({
201
201
  subject: alicesPost.uri,
202
202
  })
203
203
 
@@ -207,10 +207,10 @@ describe('moderation-statuses', () => {
207
207
  const alicesPostStatusBeforeTag = await getAlicesPostStatus()
208
208
  expect(alicesPostStatusBeforeTag).toBeUndefined()
209
209
 
210
- await modClient.emitModerationEvent({
210
+ await modClient.emitEvent({
211
211
  subject: alicesPost,
212
212
  event: {
213
- $type: 'com.atproto.admin.defs#modEventComment',
213
+ $type: 'tools.ozone.moderation.defs#modEventComment',
214
214
  comment: 'X',
215
215
  },
216
216
  createdBy: sc.dids.alice,
@@ -218,10 +218,10 @@ describe('moderation-statuses', () => {
218
218
  const alicesPostStatusAfterTag = await getAlicesPostStatus()
219
219
  expect(alicesPostStatusAfterTag.reviewState).toEqual(REVIEWNONE)
220
220
 
221
- await modClient.emitModerationEvent({
221
+ await modClient.emitEvent({
222
222
  subject: alicesPost,
223
223
  event: {
224
- $type: 'com.atproto.admin.defs#modEventReport',
224
+ $type: 'tools.ozone.moderation.defs#modEventReport',
225
225
  reportType: REASONMISLEADING,
226
226
  comment: 'X',
227
227
  },
@@ -236,9 +236,9 @@ describe('moderation-statuses', () => {
236
236
  it('are tracked on takendown subject', async () => {
237
237
  const post = sc.posts[sc.dids.carol][0]
238
238
  assert(post.images.length > 1)
239
- await modClient.emitModerationEvent({
239
+ await modClient.emitEvent({
240
240
  event: {
241
- $type: 'com.atproto.admin.defs#modEventTakedown',
241
+ $type: 'tools.ozone.moderation.defs#modEventTakedown',
242
242
  },
243
243
  subject: {
244
244
  $type: 'com.atproto.repo.strongRef',
@@ -248,7 +248,7 @@ describe('moderation-statuses', () => {
248
248
  subjectBlobCids: [post.images[0].image.ref.toString()],
249
249
  createdBy: sc.dids.alice,
250
250
  })
251
- const result = await modClient.queryModerationStatuses({
251
+ const result = await modClient.queryStatuses({
252
252
  subject: post.ref.uriStr,
253
253
  })
254
254
  expect(result.subjectStatuses.length).toBe(1)
@@ -260,9 +260,9 @@ describe('moderation-statuses', () => {
260
260
 
261
261
  it('are tracked on reverse-takendown subject based on previous status', async () => {
262
262
  const post = sc.posts[sc.dids.carol][0]
263
- await modClient.emitModerationEvent({
263
+ await modClient.emitEvent({
264
264
  event: {
265
- $type: 'com.atproto.admin.defs#modEventReverseTakedown',
265
+ $type: 'tools.ozone.moderation.defs#modEventReverseTakedown',
266
266
  },
267
267
  subject: {
268
268
  $type: 'com.atproto.repo.strongRef',
@@ -270,7 +270,7 @@ describe('moderation-statuses', () => {
270
270
  cid: post.ref.cidStr,
271
271
  },
272
272
  })
273
- const result = await modClient.queryModerationStatuses({
273
+ const result = await modClient.queryStatuses({
274
274
  subject: post.ref.uriStr,
275
275
  })
276
276
  expect(result.subjectStatuses.length).toBe(1)
@@ -6,7 +6,7 @@ import {
6
6
  basicSeed,
7
7
  ModeratorClient,
8
8
  } from '@atproto/dev-env'
9
- import AtpAgent, { ComAtprotoAdminEmitModerationEvent } from '@atproto/api'
9
+ import AtpAgent, { ToolsOzoneModerationEmitEvent } from '@atproto/api'
10
10
  import { AtUri } from '@atproto/syntax'
11
11
  import { forSnapshot } from './_util'
12
12
  import {
@@ -18,7 +18,7 @@ import {
18
18
  ModEventLabel,
19
19
  REVIEWCLOSED,
20
20
  REVIEWESCALATED,
21
- } from '../src/lexicon/types/com/atproto/admin/defs'
21
+ } from '../src/lexicon/types/tools/ozone/moderation/defs'
22
22
  import { EventReverser } from '../src'
23
23
  import { TestOzone } from '@atproto/dev-env/src/ozone'
24
24
  import { ImageInvalidator } from '../src/image-invalidator'
@@ -176,10 +176,9 @@ describe('moderation', () => {
176
176
  subject: repoSubject(sc.dids.bob),
177
177
  })
178
178
 
179
- const moderationStatusOnBobsAccount =
180
- await modClient.queryModerationStatuses({
181
- subject: sc.dids.bob,
182
- })
179
+ const moderationStatusOnBobsAccount = await modClient.queryStatuses({
180
+ subject: sc.dids.bob,
181
+ })
183
182
 
184
183
  // Validate that subject status is set to review closed and takendown flag is on
185
184
  expect(moderationStatusOnBobsAccount.subjectStatuses[0]).toMatchObject({
@@ -204,10 +203,10 @@ describe('moderation', () => {
204
203
  uri: alicesPostRef.uri.toString(),
205
204
  cid: alicesPostRef.cid.toString(),
206
205
  }
207
- await modClient.emitModerationEvent(
206
+ await modClient.emitEvent(
208
207
  {
209
208
  event: {
210
- $type: 'com.atproto.admin.defs#modEventEscalate',
209
+ $type: 'tools.ozone.moderation.defs#modEventEscalate',
211
210
  comment: 'Y',
212
211
  },
213
212
  subject: alicesPostSubject,
@@ -216,7 +215,7 @@ describe('moderation', () => {
216
215
  'triage',
217
216
  )
218
217
 
219
- const alicesPostStatus = await modClient.queryModerationStatuses({
218
+ const alicesPostStatus = await modClient.queryStatuses({
220
219
  subject: alicesPostRef.uri.toString(),
221
220
  })
222
221
 
@@ -234,10 +233,10 @@ describe('moderation', () => {
234
233
  uri: alicesPostRef.uri.toString(),
235
234
  cid: alicesPostRef.cid.toString(),
236
235
  }
237
- await modClient.emitModerationEvent(
236
+ await modClient.emitEvent(
238
237
  {
239
238
  event: {
240
- $type: 'com.atproto.admin.defs#modEventComment',
239
+ $type: 'tools.ozone.moderation.defs#modEventComment',
241
240
  sticky: true,
242
241
  comment: 'This is a persistent note',
243
242
  },
@@ -247,7 +246,7 @@ describe('moderation', () => {
247
246
  'triage',
248
247
  )
249
248
 
250
- const alicesPostStatus = await modClient.queryModerationStatuses({
249
+ const alicesPostStatus = await modClient.queryStatuses({
251
250
  subject: alicesPostRef.uri.toString(),
252
251
  })
253
252
 
@@ -259,8 +258,8 @@ describe('moderation', () => {
259
258
  it('reverses status when revert event is triggered.', async () => {
260
259
  const alicesPostRef = sc.posts[sc.dids.alice][0].ref
261
260
  const emitModEvent = async (
262
- event: ComAtprotoAdminEmitModerationEvent.InputSchema['event'],
263
- overwrites: Partial<ComAtprotoAdminEmitModerationEvent.InputSchema> = {},
261
+ event: ToolsOzoneModerationEmitEvent.InputSchema['event'],
262
+ overwrites: Partial<ToolsOzoneModerationEmitEvent.InputSchema> = {},
264
263
  ) => {
265
264
  const baseAction = {
266
265
  subject: {
@@ -270,7 +269,7 @@ describe('moderation', () => {
270
269
  },
271
270
  createdBy: 'did:example:admin',
272
271
  }
273
- return modClient.emitModerationEvent({
272
+ return modClient.emitEvent({
274
273
  event,
275
274
  ...baseAction,
276
275
  ...overwrites,
@@ -278,20 +277,19 @@ describe('moderation', () => {
278
277
  }
279
278
  // Validate that subject status is marked as escalated
280
279
  await emitModEvent({
281
- $type: 'com.atproto.admin.defs#modEventReport',
280
+ $type: 'tools.ozone.moderation.defs#modEventReport',
282
281
  reportType: REASONSPAM,
283
282
  })
284
283
  await emitModEvent({
285
- $type: 'com.atproto.admin.defs#modEventReport',
284
+ $type: 'tools.ozone.moderation.defs#modEventReport',
286
285
  reportType: REASONMISLEADING,
287
286
  })
288
287
  await emitModEvent({
289
- $type: 'com.atproto.admin.defs#modEventEscalate',
288
+ $type: 'tools.ozone.moderation.defs#modEventEscalate',
289
+ })
290
+ const alicesPostStatusAfterEscalation = await modClient.queryStatuses({
291
+ subject: alicesPostRef.uriStr,
290
292
  })
291
- const alicesPostStatusAfterEscalation =
292
- await modClient.queryModerationStatuses({
293
- subject: alicesPostRef.uriStr,
294
- })
295
293
  expect(
296
294
  alicesPostStatusAfterEscalation.subjectStatuses[0].reviewState,
297
295
  ).toEqual(REVIEWESCALATED)
@@ -299,30 +297,28 @@ describe('moderation', () => {
299
297
  // Validate that subject status is marked as takendown
300
298
 
301
299
  await emitModEvent({
302
- $type: 'com.atproto.admin.defs#modEventLabel',
300
+ $type: 'tools.ozone.moderation.defs#modEventLabel',
303
301
  createLabelVals: ['nsfw'],
304
302
  negateLabelVals: [],
305
303
  })
306
304
  await emitModEvent({
307
- $type: 'com.atproto.admin.defs#modEventTakedown',
305
+ $type: 'tools.ozone.moderation.defs#modEventTakedown',
308
306
  })
309
307
 
310
- const alicesPostStatusAfterTakedown =
311
- await modClient.queryModerationStatuses({
312
- subject: alicesPostRef.uriStr,
313
- })
308
+ const alicesPostStatusAfterTakedown = await modClient.queryStatuses({
309
+ subject: alicesPostRef.uriStr,
310
+ })
314
311
  expect(alicesPostStatusAfterTakedown.subjectStatuses[0]).toMatchObject({
315
312
  reviewState: REVIEWCLOSED,
316
313
  takendown: true,
317
314
  })
318
315
 
319
316
  await emitModEvent({
320
- $type: 'com.atproto.admin.defs#modEventReverseTakedown',
317
+ $type: 'tools.ozone.moderation.defs#modEventReverseTakedown',
318
+ })
319
+ const alicesPostStatusAfterRevert = await modClient.queryStatuses({
320
+ subject: alicesPostRef.uriStr,
321
321
  })
322
- const alicesPostStatusAfterRevert =
323
- await modClient.queryModerationStatuses({
324
- subject: alicesPostRef.uriStr,
325
- })
326
322
  // Validate that after reverting, the status of the subject is reverted to the last status changing event
327
323
  expect(alicesPostStatusAfterRevert.subjectStatuses[0]).toMatchObject({
328
324
  reviewState: REVIEWCLOSED,
@@ -482,10 +478,10 @@ describe('moderation', () => {
482
478
  })
483
479
 
484
480
  it('does not allow triage moderators to label.', async () => {
485
- const attemptLabel = modClient.emitModerationEvent(
481
+ const attemptLabel = modClient.emitEvent(
486
482
  {
487
483
  event: {
488
- $type: 'com.atproto.admin.defs#modEventLabel',
484
+ $type: 'tools.ozone.moderation.defs#modEventLabel',
489
485
  negateLabelVals: ['a'],
490
486
  createLabelVals: ['b', 'c'],
491
487
  },
@@ -624,10 +620,10 @@ describe('moderation', () => {
624
620
  })
625
621
 
626
622
  it('allows full moderators to takedown.', async () => {
627
- await modClient.emitModerationEvent(
623
+ await modClient.emitEvent(
628
624
  {
629
625
  event: {
630
- $type: 'com.atproto.admin.defs#modEventTakedown',
626
+ $type: 'tools.ozone.moderation.defs#modEventTakedown',
631
627
  },
632
628
  createdBy: 'did:example:moderator',
633
629
  subject: {
@@ -647,10 +643,10 @@ describe('moderation', () => {
647
643
  })
648
644
 
649
645
  it('does not allow non-full moderators to takedown.', async () => {
650
- const attemptTakedownTriage = modClient.emitModerationEvent(
646
+ const attemptTakedownTriage = modClient.emitEvent(
651
647
  {
652
648
  event: {
653
- $type: 'com.atproto.admin.defs#modEventTakedown',
649
+ $type: 'tools.ozone.moderation.defs#modEventTakedown',
654
650
  },
655
651
  createdBy: 'did:example:moderator',
656
652
  subject: {
@@ -679,7 +675,7 @@ describe('moderation', () => {
679
675
  })
680
676
  await ozone.processAll()
681
677
 
682
- const statusesAfterTakedown = await modClient.queryModerationStatuses(
678
+ const statusesAfterTakedown = await modClient.queryStatuses(
683
679
  { subject: sc.dids.bob },
684
680
  'moderator',
685
681
  )
@@ -697,11 +693,8 @@ describe('moderation', () => {
697
693
  await ozone.processAll()
698
694
 
699
695
  const [eventList, statuses] = await Promise.all([
700
- modClient.queryModerationEvents({ subject: sc.dids.bob }, 'moderator'),
701
- modClient.queryModerationStatuses(
702
- { subject: sc.dids.bob },
703
- 'moderator',
704
- ),
696
+ modClient.queryEvents({ subject: sc.dids.bob }, 'moderator'),
697
+ modClient.queryStatuses({ subject: sc.dids.bob }, 'moderator'),
705
698
  ])
706
699
 
707
700
  expect(statuses.subjectStatuses[0]).toMatchObject({
@@ -713,7 +706,7 @@ describe('moderation', () => {
713
706
  expect(eventList.events[0]).toMatchObject({
714
707
  createdBy: action.createdBy,
715
708
  event: {
716
- $type: 'com.atproto.admin.defs#modEventReverseTakedown',
709
+ $type: 'tools.ozone.moderation.defs#modEventReverseTakedown',
717
710
  comment:
718
711
  '[SCHEDULED_REVERSAL] Reverting action as originally scheduled',
719
712
  },
@@ -737,16 +730,16 @@ describe('moderation', () => {
737
730
  })
738
731
 
739
732
  async function emitLabelEvent(
740
- opts: Partial<ComAtprotoAdminEmitModerationEvent.InputSchema> & {
741
- subject: ComAtprotoAdminEmitModerationEvent.InputSchema['subject']
733
+ opts: Partial<ToolsOzoneModerationEmitEvent.InputSchema> & {
734
+ subject: ToolsOzoneModerationEmitEvent.InputSchema['subject']
742
735
  createLabelVals: ModEventLabel['createLabelVals']
743
736
  negateLabelVals: ModEventLabel['negateLabelVals']
744
737
  },
745
738
  ) {
746
739
  const { createLabelVals, negateLabelVals } = opts
747
- const result = await modClient.emitModerationEvent({
740
+ const result = await modClient.emitEvent({
748
741
  event: {
749
- $type: 'com.atproto.admin.defs#modEventLabel',
742
+ $type: 'tools.ozone.moderation.defs#modEventLabel',
750
743
  createLabelVals,
751
744
  negateLabelVals,
752
745
  },
@@ -758,13 +751,13 @@ describe('moderation', () => {
758
751
  }
759
752
 
760
753
  async function reverse(
761
- opts: Partial<ComAtprotoAdminEmitModerationEvent.InputSchema> & {
762
- subject: ComAtprotoAdminEmitModerationEvent.InputSchema['subject']
754
+ opts: Partial<ToolsOzoneModerationEmitEvent.InputSchema> & {
755
+ subject: ToolsOzoneModerationEmitEvent.InputSchema['subject']
763
756
  },
764
757
  ) {
765
- await modClient.emitModerationEvent({
758
+ await modClient.emitEvent({
766
759
  event: {
767
- $type: 'com.atproto.admin.defs#modEventReverseTakedown',
760
+ $type: 'tools.ozone.moderation.defs#modEventReverseTakedown',
768
761
  },
769
762
  createdBy: 'did:example:admin',
770
763
  reason: 'Y',
@@ -773,7 +766,7 @@ describe('moderation', () => {
773
766
  }
774
767
 
775
768
  async function getRecordLabels(uri: string) {
776
- const result = await agent.api.com.atproto.admin.getRecord(
769
+ const result = await agent.api.tools.ozone.moderation.getRecord(
777
770
  { uri },
778
771
  { headers: await network.ozone.modHeaders() },
779
772
  )
@@ -782,7 +775,7 @@ describe('moderation', () => {
782
775
  }
783
776
 
784
777
  async function getRepoLabels(did: string) {
785
- const result = await agent.api.com.atproto.admin.getRepo(
778
+ const result = await agent.api.tools.ozone.moderation.getRepo(
786
779
  { did },
787
780
  { headers: await network.ozone.modHeaders() },
788
781
  )
@@ -818,7 +811,7 @@ describe('moderation', () => {
818
811
  })
819
812
 
820
813
  it('sets blobCids in moderation status', async () => {
821
- const { subjectStatuses } = await modClient.queryModerationStatuses({
814
+ const { subjectStatuses } = await modClient.queryStatuses({
822
815
  subject: post.ref.uriStr,
823
816
  })
824
817
 
@@ -1,12 +1,16 @@
1
1
  import AtpAgent from '@atproto/api'
2
- import { TestNetwork } from '@atproto/dev-env'
2
+ import { EXAMPLE_LABELER, TestNetwork } from '@atproto/dev-env'
3
3
  import { DisconnectError, Subscription } from '@atproto/xrpc-server'
4
4
  import { ids, lexicons } from '../src/lexicon/lexicons'
5
5
  import { Label } from '../src/lexicon/types/com/atproto/label/defs'
6
+ import { Secp256k1Keypair, verifySignature } from '@atproto/crypto'
7
+ import { cborEncode } from '@atproto/common'
8
+ import { ModerationService } from '../src/mod-service'
6
9
  import {
7
10
  OutputSchema as LabelMessage,
8
11
  isLabels,
9
12
  } from '../src/lexicon/types/com/atproto/label/subscribeLabels'
13
+ import { getSigningKeyId } from '../src/util'
10
14
 
11
15
  describe('ozone query labels', () => {
12
16
  let network: TestNetwork
@@ -21,44 +25,44 @@ describe('ozone query labels', () => {
21
25
 
22
26
  agent = network.ozone.getClient()
23
27
 
24
- labels = [
28
+ const toCreate = [
25
29
  {
26
- src: 'did:example:labeler',
30
+ src: EXAMPLE_LABELER,
27
31
  uri: 'did:example:blah',
28
32
  val: 'spam',
29
33
  neg: false,
30
34
  cts: new Date().toISOString(),
31
35
  },
32
36
  {
33
- src: 'did:example:labeler',
37
+ src: EXAMPLE_LABELER,
34
38
  uri: 'did:example:blah',
35
39
  val: 'impersonation',
36
40
  neg: false,
37
41
  cts: new Date().toISOString(),
38
42
  },
39
43
  {
40
- src: 'did:example:labeler',
44
+ src: EXAMPLE_LABELER,
41
45
  uri: 'at://did:example:blah/app.bsky.feed.post/1234abcde',
42
46
  val: 'spam',
43
47
  neg: false,
44
48
  cts: new Date().toISOString(),
45
49
  },
46
50
  {
47
- src: 'did:example:labeler',
51
+ src: EXAMPLE_LABELER,
48
52
  uri: 'at://did:example:blah/app.bsky.feed.post/1234abcfg',
49
53
  val: 'spam',
50
54
  neg: false,
51
55
  cts: new Date().toISOString(),
52
56
  },
53
57
  {
54
- src: 'did:example:labeler',
58
+ src: EXAMPLE_LABELER,
55
59
  uri: 'at://did:example:blah/app.bsky.actor.profile/self',
56
60
  val: 'spam',
57
61
  neg: false,
58
62
  cts: new Date().toISOString(),
59
63
  },
60
64
  {
61
- src: 'did:example:labeler',
65
+ src: EXAMPLE_LABELER,
62
66
  uri: 'did:example:thing',
63
67
  val: 'spam',
64
68
  neg: false,
@@ -67,7 +71,7 @@ describe('ozone query labels', () => {
67
71
  ]
68
72
 
69
73
  const modService = network.ozone.ctx.modService(network.ozone.ctx.db)
70
- await modService.createLabels(labels)
74
+ labels = await modService.createLabels(toCreate)
71
75
  })
72
76
 
73
77
  afterAll(async () => {
@@ -128,6 +132,72 @@ describe('ozone query labels', () => {
128
132
  )
129
133
  })
130
134
 
135
+ it('returns validly signed labels', async () => {
136
+ const res = await agent.api.com.atproto.label.queryLabels({
137
+ uriPatterns: ['*'],
138
+ })
139
+ const signingKey = network.ozone.ctx.signingKey.did()
140
+ for (const label of res.data.labels) {
141
+ const { sig, ...rest } = label
142
+ if (!sig) {
143
+ throw new Error('Missing signature')
144
+ }
145
+ const encodedLabel = cborEncode(rest)
146
+ const isValid = await verifySignature(signingKey, encodedLabel, sig)
147
+ expect(isValid).toBe(true)
148
+ }
149
+ })
150
+
151
+ it('resigns labels if the signingKey changes', async () => {
152
+ // mock changing the signing key for the service
153
+ const ctx = network.ozone.ctx
154
+ const origModServiceFn = ctx.modService
155
+
156
+ const modSrvc = ctx.modService(ctx.db)
157
+ const newSigningKey = await Secp256k1Keypair.create()
158
+ const newSigningKeyId = await getSigningKeyId(ctx.db, newSigningKey.did())
159
+ ctx.devOverride({
160
+ modService: ModerationService.creator(
161
+ newSigningKey,
162
+ newSigningKeyId,
163
+ ctx.cfg,
164
+ modSrvc.backgroundQueue,
165
+ ctx.idResolver,
166
+ modSrvc.eventPusher,
167
+ modSrvc.appviewAgent,
168
+ ctx.serviceAuthHeaders,
169
+ ),
170
+ })
171
+
172
+ const res = await agent.api.com.atproto.label.queryLabels({
173
+ uriPatterns: ['*'],
174
+ })
175
+ for (const label of res.data.labels) {
176
+ const { sig, ...rest } = label
177
+ if (!sig) {
178
+ throw new Error('Missing signature')
179
+ }
180
+ const encodedLabel = cborEncode(rest)
181
+ const isValid = await verifySignature(
182
+ newSigningKey.did(),
183
+ encodedLabel,
184
+ sig,
185
+ )
186
+ expect(isValid).toBe(true)
187
+ }
188
+
189
+ await network.ozone.processAll()
190
+
191
+ const fromDb = await ctx.db.db.selectFrom('label').selectAll().execute()
192
+ expect(fromDb.every((row) => row.signingKeyId === newSigningKeyId)).toBe(
193
+ true,
194
+ )
195
+
196
+ ctx.devOverride({
197
+ modService: origModServiceFn,
198
+ })
199
+ })
200
+
131
201
  describe('subscribeLabels', () => {
132
202
  it('streams all labels from initial cursor.', async () => {
133
203
  const ac = new AbortController()
@@ -154,7 +224,13 @@ describe('ozone query labels', () => {
154
224
  for await (const message of sub) {
155
225
  resetDoneTimer()
156
226
  if (isLabels(message)) {
157
- streamedLabels.push(...message.labels)
227
+ for (const label of message.labels) {
228
+ // sigs are currently parsed as a Buffer which is a Uint8Array under the hood, but fails our equality test so we cast to Uint8Array
229
+ streamedLabels.push({
230
+ ...label,
231
+ sig: label.sig ? new Uint8Array(label.sig) : undefined,
232
+ })
233
+ }
158
234
  }
159
235
  }
160
236
  expect(streamedLabels).toEqual(labels)