@atproto/ozone 0.2.8 → 0.2.11
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 +33 -0
- package/package.json +25 -21
- package/bin/migration-create.ts +0 -38
- package/jest.config.cjs +0 -22
- package/src/api/chat/getActorMetadata.ts +0 -23
- package/src/api/chat/getConvo.ts +0 -23
- package/src/api/chat/getConvoMembers.ts +0 -23
- package/src/api/chat/getConvos.ts +0 -23
- package/src/api/chat/getMessageContext.ts +0 -42
- package/src/api/chat/index.ts +0 -16
- package/src/api/communication/createTemplate.ts +0 -51
- package/src/api/communication/deleteTemplate.ts +0 -23
- package/src/api/communication/listTemplates.ts +0 -31
- package/src/api/communication/updateTemplate.ts +0 -51
- package/src/api/health.ts +0 -27
- package/src/api/index.ts +0 -146
- package/src/api/label/fetchLabels.ts +0 -32
- package/src/api/label/queryLabels.ts +0 -57
- package/src/api/label/subscribeLabels.ts +0 -25
- package/src/api/moderation/cancelScheduledActions.ts +0 -72
- package/src/api/moderation/emitEvent.ts +0 -475
- package/src/api/moderation/getAccountTimeline.ts +0 -160
- package/src/api/moderation/getEvent.ts +0 -19
- package/src/api/moderation/getRecord.ts +0 -40
- package/src/api/moderation/getRecords.ts +0 -50
- package/src/api/moderation/getRepo.ts +0 -34
- package/src/api/moderation/getReporterStats.ts +0 -18
- package/src/api/moderation/getRepos.ts +0 -41
- package/src/api/moderation/getSubjects.ts +0 -101
- package/src/api/moderation/listScheduledActions.ts +0 -45
- package/src/api/moderation/queryEvents.ts +0 -72
- package/src/api/moderation/queryStatuses.ts +0 -23
- package/src/api/moderation/scheduleAction.ts +0 -129
- package/src/api/moderation/searchRepos.ts +0 -46
- package/src/api/moderation/util.ts +0 -96
- package/src/api/proxied.ts +0 -327
- package/src/api/queue/assignModerator.ts +0 -31
- package/src/api/queue/createQueue.ts +0 -62
- package/src/api/queue/deleteQueue.ts +0 -56
- package/src/api/queue/getAssignments.ts +0 -19
- package/src/api/queue/listQueues.ts +0 -39
- package/src/api/queue/routeReports.ts +0 -44
- package/src/api/queue/unassignModerator.ts +0 -26
- package/src/api/queue/updateQueue.ts +0 -54
- package/src/api/report/assignModerator.ts +0 -36
- package/src/api/report/createActivity.ts +0 -57
- package/src/api/report/createReport.ts +0 -93
- package/src/api/report/getAssignments.ts +0 -20
- package/src/api/report/getHistoricalStats.ts +0 -41
- package/src/api/report/getLatestReport.ts +0 -44
- package/src/api/report/getLiveStats.ts +0 -26
- package/src/api/report/getReport.ts +0 -55
- package/src/api/report/listActivities.ts +0 -37
- package/src/api/report/queryActivities.ts +0 -64
- package/src/api/report/queryReports.ts +0 -44
- package/src/api/report/reassignQueue.ts +0 -68
- package/src/api/report/refreshStats.ts +0 -27
- package/src/api/report/unassignModerator.ts +0 -21
- package/src/api/safelink/addRule.ts +0 -48
- package/src/api/safelink/queryEvents.ts +0 -32
- package/src/api/safelink/queryRules.ts +0 -58
- package/src/api/safelink/removeRule.ts +0 -42
- package/src/api/safelink/updateRule.ts +0 -48
- package/src/api/server/getConfig.ts +0 -35
- package/src/api/set/addValues.ts +0 -28
- package/src/api/set/deleteSet.ts +0 -34
- package/src/api/set/deleteValues.ts +0 -31
- package/src/api/set/getValues.ts +0 -42
- package/src/api/set/querySets.ts +0 -36
- package/src/api/set/upsertSet.ts +0 -38
- package/src/api/setting/listOptions.ts +0 -44
- package/src/api/setting/removeOptions.ts +0 -64
- package/src/api/setting/upsertOption.ts +0 -156
- package/src/api/team/addMember.ts +0 -51
- package/src/api/team/deleteMember.ts +0 -29
- package/src/api/team/listMembers.ts +0 -20
- package/src/api/team/updateMember.ts +0 -47
- package/src/api/util.ts +0 -265
- package/src/api/verification/grantVerifications.ts +0 -90
- package/src/api/verification/listVerifications.ts +0 -44
- package/src/api/verification/revokeVerifications.ts +0 -43
- package/src/api/well-known.ts +0 -46
- package/src/assignment/index.ts +0 -728
- package/src/auth-verifier.ts +0 -227
- package/src/background.ts +0 -183
- package/src/communication-service/template.ts +0 -110
- package/src/communication-service/util.ts +0 -8
- package/src/config/config.ts +0 -211
- package/src/config/env.ts +0 -95
- package/src/config/index.ts +0 -3
- package/src/config/secrets.ts +0 -17
- package/src/context.ts +0 -399
- package/src/daemon/blob-diverter.ts +0 -186
- package/src/daemon/context.ts +0 -247
- package/src/daemon/event-pusher.ts +0 -363
- package/src/daemon/event-reverser.ts +0 -128
- package/src/daemon/index.ts +0 -33
- package/src/daemon/job-cursor.ts +0 -33
- package/src/daemon/materialized-view-refresher.ts +0 -33
- package/src/daemon/queue-router.ts +0 -101
- package/src/daemon/scheduled-action-processor.ts +0 -304
- package/src/daemon/stats-computer.ts +0 -101
- package/src/daemon/strike-expiry-processor.ts +0 -95
- package/src/daemon/team-profile-synchronizer.ts +0 -15
- package/src/daemon/verification-listener.ts +0 -169
- package/src/db/index.ts +0 -203
- package/src/db/migrations/20231219T205730722Z-init.ts +0 -170
- package/src/db/migrations/20240116T085607200Z-communication-template.ts +0 -23
- package/src/db/migrations/20240201T051104136Z-mod-event-blobs.ts +0 -15
- package/src/db/migrations/20240208T213404429Z-add-tags-column-to-moderation-subject.ts +0 -31
- package/src/db/migrations/20240228T003647759Z-add-label-sigs.ts +0 -25
- package/src/db/migrations/20240408T192432676Z-mute-reporting.ts +0 -15
- package/src/db/migrations/20240506T225055595Z-message-subject.ts +0 -21
- package/src/db/migrations/20240521T211332580Z-member.ts +0 -17
- package/src/db/migrations/20240814T003647759Z-event-created-at-index.ts +0 -13
- package/src/db/migrations/20240903T205730722Z-add-template-lang.ts +0 -12
- package/src/db/migrations/20240904T205730722Z-add-subject-did-index.ts +0 -13
- package/src/db/migrations/20241001T205730722Z-subject-status-review-state-index.ts +0 -15
- package/src/db/migrations/20241008T205730722Z-sets.ts +0 -53
- package/src/db/migrations/20241018T205730722Z-setting.ts +0 -27
- package/src/db/migrations/20241026T205730722Z-add-hosting-status-to-subject-status.ts +0 -57
- package/src/db/migrations/20241220T144630860Z-stats-materialized-views.ts +0 -215
- package/src/db/migrations/20250204T003647759Z-add-subject-priority-score.ts +0 -22
- package/src/db/migrations/20250211T003647759Z-add-reporter-stats-index.ts +0 -38
- package/src/db/migrations/20250211T132135150Z-moderation-event-message-partial-idx.ts +0 -26
- package/src/db/migrations/20250221T132135150Z-member-details.ts +0 -14
- package/src/db/migrations/20250404T201720309Z-subject-status-sort-idxs.ts +0 -18
- package/src/db/migrations/20250415T201720309Z-verification.ts +0 -34
- package/src/db/migrations/20250417T201720309Z-firehose-cursor.ts +0 -16
- package/src/db/migrations/20250609T110704000Z-safelink.ts +0 -53
- package/src/db/migrations/20250618T180246000Z-add-mod-tool-to-moderation-event.ts +0 -18
- package/src/db/migrations/20250701T000000000Z-add-age-assurance-state.ts +0 -25
- package/src/db/migrations/20250715T000000000Z-add-mod-event-external-id.ts +0 -15
- package/src/db/migrations/20250718T150931000Z-update-appeal-reason-stats.ts +0 -310
- package/src/db/migrations/20250813T000000000Z-mod-tool-batch-id-index.ts +0 -14
- package/src/db/migrations/20250923T000000000Z-scheduled-actions.ts +0 -56
- package/src/db/migrations/20251008T120000000Z-add-strike-system.ts +0 -87
- package/src/db/migrations/20260210T154806448Z-mod-event-created-by-indexes.ts +0 -22
- package/src/db/migrations/20260219T164523000Z-create-report-table.ts +0 -155
- package/src/db/migrations/20260219T165302248Z-moderator-assignment.ts +0 -42
- package/src/db/migrations/20260225T000000000Z-add-report-queue-table.ts +0 -41
- package/src/db/migrations/20260313T000000000Z-add-report-activity-table.ts +0 -48
- package/src/db/migrations/20260318T152058935Z-add-report-stat.ts +0 -35
- package/src/db/migrations/20260428T000000000Z-add-expiring-tag-table.ts +0 -32
- package/src/db/migrations/20260513T202941104Z-add-subject-convo-id.ts +0 -114
- package/src/db/migrations/20260602T120000000Z-add-report-activity-created-index.ts +0 -17
- package/src/db/migrations/index.ts +0 -44
- package/src/db/migrations/provider.ts +0 -26
- package/src/db/pagination.ts +0 -335
- package/src/db/schema/account_events_stats.ts +0 -16
- package/src/db/schema/account_record_events_stats.ts +0 -15
- package/src/db/schema/account_record_status_stats.ts +0 -15
- package/src/db/schema/account_strike.ts +0 -13
- package/src/db/schema/blob_push_event.ts +0 -21
- package/src/db/schema/communication_template.ts +0 -19
- package/src/db/schema/expiring_tag.ts +0 -18
- package/src/db/schema/firehose_cursor.ts +0 -13
- package/src/db/schema/index.ts +0 -60
- package/src/db/schema/job_cursor.ts +0 -13
- package/src/db/schema/label.ts +0 -22
- package/src/db/schema/member.ts +0 -22
- package/src/db/schema/moderation_event.ts +0 -61
- package/src/db/schema/moderation_subject_status.ts +0 -52
- package/src/db/schema/moderator_assignment.ts +0 -16
- package/src/db/schema/ozone_set.ts +0 -24
- package/src/db/schema/record_events_stats.ts +0 -15
- package/src/db/schema/record_push_event.ts +0 -21
- package/src/db/schema/repo_push_event.ts +0 -19
- package/src/db/schema/report.ts +0 -28
- package/src/db/schema/report_activity.ts +0 -22
- package/src/db/schema/report_queue.ts +0 -21
- package/src/db/schema/report_stat.ts +0 -27
- package/src/db/schema/safelink.ts +0 -39
- package/src/db/schema/scheduled-action.ts +0 -25
- package/src/db/schema/setting.ts +0 -24
- package/src/db/schema/signing_key.ts +0 -10
- package/src/db/schema/verification.ts +0 -21
- package/src/db/types.ts +0 -24
- package/src/error.ts +0 -12
- package/src/image-invalidator.ts +0 -7
- package/src/index.ts +0 -154
- package/src/jetstream/service.ts +0 -107
- package/src/logger.ts +0 -29
- package/src/mod-service/expiring-tags.ts +0 -104
- package/src/mod-service/index.ts +0 -1842
- package/src/mod-service/profile.ts +0 -139
- package/src/mod-service/report.ts +0 -429
- package/src/mod-service/status.ts +0 -549
- package/src/mod-service/strike.ts +0 -96
- package/src/mod-service/subject.ts +0 -311
- package/src/mod-service/types.ts +0 -96
- package/src/mod-service/util.ts +0 -99
- package/src/mod-service/views.ts +0 -912
- package/src/queue/service.ts +0 -603
- package/src/report/activity.ts +0 -281
- package/src/report/handle-report-update.ts +0 -209
- package/src/report/reassign.ts +0 -109
- package/src/report/stats.ts +0 -852
- package/src/report/views.ts +0 -239
- package/src/safelink/service.ts +0 -304
- package/src/scheduled-action/service.ts +0 -281
- package/src/scheduled-action/types.ts +0 -17
- package/src/sequencer/index.ts +0 -2
- package/src/sequencer/outbox.ts +0 -123
- package/src/sequencer/sequencer.ts +0 -147
- package/src/set/service.ts +0 -230
- package/src/setting/constants.ts +0 -3
- package/src/setting/service.ts +0 -148
- package/src/setting/types.ts +0 -3
- package/src/setting/validators.ts +0 -333
- package/src/tag-service/content-tagger.ts +0 -30
- package/src/tag-service/embed-tagger.ts +0 -70
- package/src/tag-service/index.ts +0 -70
- package/src/tag-service/language-data.ts +0 -561
- package/src/tag-service/language-tagger.ts +0 -101
- package/src/tag-service/util.ts +0 -13
- package/src/team/index.ts +0 -296
- package/src/util.ts +0 -230
- package/src/verification/issuer.ts +0 -146
- package/src/verification/service.ts +0 -208
- package/src/verification/util.ts +0 -53
- package/test.env +0 -2
- package/tests/3p-labeler.test.ts +0 -288
- package/tests/__snapshots__/account-strikes.test.ts.snap +0 -159
- package/tests/__snapshots__/age-assurance.test.ts.snap +0 -66
- package/tests/__snapshots__/blob-divert.test.ts.snap +0 -219
- package/tests/__snapshots__/get-account-timeline.test.ts.snap +0 -36
- package/tests/__snapshots__/get-record.test.ts.snap +0 -271
- package/tests/__snapshots__/get-records.test.ts.snap +0 -175
- package/tests/__snapshots__/get-repo.test.ts.snap +0 -91
- package/tests/__snapshots__/get-repos.test.ts.snap +0 -127
- package/tests/__snapshots__/get-starter-pack.test.ts.snap +0 -535
- package/tests/__snapshots__/get-subjects.test.ts.snap +0 -529
- package/tests/__snapshots__/moderation-events.test.ts.snap +0 -347
- package/tests/__snapshots__/moderation-statuses.test.ts.snap +0 -276
- package/tests/__snapshots__/moderation.test.ts.snap +0 -85
- package/tests/__snapshots__/report-reason.test.ts.snap +0 -14
- package/tests/__snapshots__/safelink.test.ts.snap +0 -179
- package/tests/__snapshots__/scheduled-action.test.ts.snap +0 -61
- package/tests/__snapshots__/sets.test.ts.snap +0 -46
- package/tests/__snapshots__/settings.test.ts.snap +0 -52
- package/tests/__snapshots__/team.test.ts.snap +0 -374
- package/tests/__snapshots__/verification-listener.test.ts.snap +0 -152
- package/tests/__snapshots__/verification.test.ts.snap +0 -302
- package/tests/_util.ts +0 -242
- package/tests/account-strikes.test.ts +0 -184
- package/tests/ack-all-subjects-of-account.test.ts +0 -177
- package/tests/age-assurance.test.ts +0 -372
- package/tests/blob-divert.test.ts +0 -106
- package/tests/communication-templates.test.ts +0 -149
- package/tests/content-tagger.test.ts +0 -170
- package/tests/db.test.ts +0 -184
- package/tests/expiring-label.test.ts +0 -72
- package/tests/expiring-tags.test.ts +0 -232
- package/tests/get-account-timeline.test.ts +0 -85
- package/tests/get-config.test.ts +0 -55
- package/tests/get-lists.test.ts +0 -111
- package/tests/get-profiles.test.ts +0 -70
- package/tests/get-record.test.ts +0 -130
- package/tests/get-records.test.ts +0 -91
- package/tests/get-repo.test.ts +0 -171
- package/tests/get-report.test.ts +0 -136
- package/tests/get-reporter-stats.test.ts +0 -132
- package/tests/get-repos.test.ts +0 -91
- package/tests/get-starter-pack.test.ts +0 -115
- package/tests/get-subjects.test.ts +0 -81
- package/tests/mod-tool.test.ts +0 -268
- package/tests/moderation-appeals.test.ts +0 -260
- package/tests/moderation-events.test.ts +0 -756
- package/tests/moderation-status-tags.test.ts +0 -140
- package/tests/moderation-statuses.test.ts +0 -495
- package/tests/moderation.test.ts +0 -992
- package/tests/protected-tags.test.ts +0 -218
- package/tests/query-labels.test.ts +0 -238
- package/tests/query-reports.test.ts +0 -608
- package/tests/queue-assignment.test.ts +0 -428
- package/tests/queue-router.test.ts +0 -306
- package/tests/queues.test.ts +0 -690
- package/tests/record-and-account-events.test.ts +0 -197
- package/tests/repo-search.test.ts +0 -136
- package/tests/report-action.test.ts +0 -308
- package/tests/report-activity.test.ts +0 -711
- package/tests/report-assignment.test.ts +0 -517
- package/tests/report-muting.test.ts +0 -100
- package/tests/report-reason.test.ts +0 -154
- package/tests/report-reassign-queue.test.ts +0 -340
- package/tests/report-routing.test.ts +0 -245
- package/tests/report-stats.test.ts +0 -545
- package/tests/revoke-account-credentials.test.ts +0 -54
- package/tests/safelink.test.ts +0 -534
- package/tests/scheduled-action-processor.test.ts +0 -488
- package/tests/scheduled-action.test.ts +0 -334
- package/tests/sequencer.test.ts +0 -227
- package/tests/server.test.ts +0 -62
- package/tests/sets.test.ts +0 -246
- package/tests/settings.test.ts +0 -308
- package/tests/strike-expiry-processor.test.ts +0 -299
- package/tests/subject-priority-score.test.ts +0 -96
- package/tests/takedown.test.ts +0 -105
- package/tests/team.test.ts +0 -216
- package/tests/verification-listener.test.ts +0 -129
- package/tests/verification.test.ts +0 -186
- package/tsconfig.build.json +0 -9
- package/tsconfig.build.tsbuildinfo +0 -1
- package/tsconfig.json +0 -7
- package/tsconfig.tests.json +0 -8
|
@@ -1,333 +0,0 @@
|
|
|
1
|
-
import { Selectable } from 'kysely'
|
|
2
|
-
import { InvalidRequestError } from '@atproto/xrpc-server'
|
|
3
|
-
import { Setting } from '../db/schema/setting.js'
|
|
4
|
-
import {
|
|
5
|
-
PolicyListSettingKey,
|
|
6
|
-
ProtectedTagSettingKey,
|
|
7
|
-
SeverityLevelSettingKey,
|
|
8
|
-
} from './constants.js'
|
|
9
|
-
|
|
10
|
-
export const settingValidators = new Map<
|
|
11
|
-
string,
|
|
12
|
-
(setting: Partial<Selectable<Setting>>) => Promise<void>
|
|
13
|
-
>([
|
|
14
|
-
[
|
|
15
|
-
ProtectedTagSettingKey,
|
|
16
|
-
/*
|
|
17
|
-
* Example configuration:
|
|
18
|
-
* {
|
|
19
|
-
* "sensitive-tag": {
|
|
20
|
-
* "roles": ["tools.ozone.team.defs#roleAdmin", "tools.ozone.team.defs#roleModerator"],
|
|
21
|
-
* "moderators": ["did:plc:example1", "did:plc:example2"]
|
|
22
|
-
* },
|
|
23
|
-
* "high-risk-tag": {
|
|
24
|
-
* "roles": ["tools.ozone.team.defs#roleAdmin"]
|
|
25
|
-
* },
|
|
26
|
-
* "admin-only-tag": {
|
|
27
|
-
* "moderators": ["did:plc:admin1"]
|
|
28
|
-
* }
|
|
29
|
-
* }
|
|
30
|
-
*/
|
|
31
|
-
async (setting: Partial<Selectable<Setting>>) => {
|
|
32
|
-
if (setting.managerRole !== 'tools.ozone.team.defs#roleAdmin') {
|
|
33
|
-
throw new InvalidRequestError(
|
|
34
|
-
'Only admins should be able to configure protected tags',
|
|
35
|
-
)
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
if (typeof setting.value !== 'object') {
|
|
39
|
-
throw new InvalidRequestError('Invalid value')
|
|
40
|
-
}
|
|
41
|
-
for (const [key, val] of Object.entries(setting.value)) {
|
|
42
|
-
if (!val || typeof val !== 'object') {
|
|
43
|
-
throw new InvalidRequestError(`Invalid configuration for tag ${key}`)
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
if (!val['roles'] && !val['moderators']) {
|
|
47
|
-
throw new InvalidRequestError(
|
|
48
|
-
`Must define who a list of moderators or a role who can action subjects with ${key} tag`,
|
|
49
|
-
)
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
if (val['roles']) {
|
|
53
|
-
if (!Array.isArray(val['roles'])) {
|
|
54
|
-
throw new InvalidRequestError(
|
|
55
|
-
`Roles must be an array of moderator roles for tag ${key}`,
|
|
56
|
-
)
|
|
57
|
-
}
|
|
58
|
-
if (!val['roles']?.length) {
|
|
59
|
-
throw new InvalidRequestError(
|
|
60
|
-
`Must define at least one role for tag ${key}`,
|
|
61
|
-
)
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
if (val['moderators']) {
|
|
66
|
-
if (!Array.isArray(val['moderators'])) {
|
|
67
|
-
throw new InvalidRequestError(
|
|
68
|
-
`Moderators must be an array of moderator DIDs for tag ${key}`,
|
|
69
|
-
)
|
|
70
|
-
}
|
|
71
|
-
if (!val['moderators']?.length) {
|
|
72
|
-
throw new InvalidRequestError(
|
|
73
|
-
`Must define at least one moderator DID for tag ${key}`,
|
|
74
|
-
)
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
},
|
|
79
|
-
],
|
|
80
|
-
[
|
|
81
|
-
PolicyListSettingKey,
|
|
82
|
-
/*
|
|
83
|
-
* Example configuration:
|
|
84
|
-
* {
|
|
85
|
-
* "harassment": {
|
|
86
|
-
* "name": "Anti-Harassment",
|
|
87
|
-
* "description": "Content that harasses, intimidates, or bullies users",
|
|
88
|
-
* "severityLevels": {
|
|
89
|
-
* "sev-1": {
|
|
90
|
-
* "description": "Minor harassment",
|
|
91
|
-
* "isDefault": true
|
|
92
|
-
* },
|
|
93
|
-
* "sev-2": {
|
|
94
|
-
* "description": "Moderate harassment",
|
|
95
|
-
* "isDefault": false
|
|
96
|
-
* },
|
|
97
|
-
* "sev-4": {
|
|
98
|
-
* "description": "Severe harassment",
|
|
99
|
-
* "isDefault": false
|
|
100
|
-
* }
|
|
101
|
-
* }
|
|
102
|
-
* },
|
|
103
|
-
* "death-threats": {
|
|
104
|
-
* "name": "Death Threats",
|
|
105
|
-
* "description": "Threats of violence or death against individuals",
|
|
106
|
-
* "severityLevels": {
|
|
107
|
-
* "death-threat": {
|
|
108
|
-
* "description": "Death threat violation",
|
|
109
|
-
* "isDefault": true
|
|
110
|
-
* }
|
|
111
|
-
* }
|
|
112
|
-
* },
|
|
113
|
-
* "spam": {
|
|
114
|
-
* "name": "Spam",
|
|
115
|
-
* "description": "Unsolicited or repetitive content",
|
|
116
|
-
* "severityLevels": {
|
|
117
|
-
* "sev-0": {
|
|
118
|
-
* "description": "Minor spam",
|
|
119
|
-
* "isDefault": false
|
|
120
|
-
* },
|
|
121
|
-
* "sev-1": {
|
|
122
|
-
* "description": "Moderate spam",
|
|
123
|
-
* "isDefault": true
|
|
124
|
-
* },
|
|
125
|
-
* "sev-2": {
|
|
126
|
-
* "description": "Severe spam",
|
|
127
|
-
* "isDefault": false
|
|
128
|
-
* }
|
|
129
|
-
* }
|
|
130
|
-
* },
|
|
131
|
-
* "minimal-policy": {
|
|
132
|
-
* "name": "Basic Policy",
|
|
133
|
-
* "description": "Simple policy without severity levels"
|
|
134
|
-
* }
|
|
135
|
-
* }
|
|
136
|
-
*/
|
|
137
|
-
async (setting: Partial<Selectable<Setting>>) => {
|
|
138
|
-
if (setting.managerRole !== 'tools.ozone.team.defs#roleAdmin') {
|
|
139
|
-
throw new InvalidRequestError(
|
|
140
|
-
'Only admins should be able to manage policy list',
|
|
141
|
-
)
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
if (typeof setting.value !== 'object') {
|
|
145
|
-
throw new InvalidRequestError('Invalid value')
|
|
146
|
-
}
|
|
147
|
-
for (const [key, val] of Object.entries(setting.value)) {
|
|
148
|
-
if (!val || typeof val !== 'object') {
|
|
149
|
-
throw new InvalidRequestError(
|
|
150
|
-
`Invalid configuration for policy ${key}`,
|
|
151
|
-
)
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
if (!val['name'] || !val['description']) {
|
|
155
|
-
throw new InvalidRequestError(
|
|
156
|
-
`Must define a name and description for policy ${key}`,
|
|
157
|
-
)
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
if (val['severityLevels'] !== undefined) {
|
|
161
|
-
if (typeof val['severityLevels'] !== 'object') {
|
|
162
|
-
throw new InvalidRequestError(
|
|
163
|
-
`Severity levels must be an object for policy ${key}`,
|
|
164
|
-
)
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
let hasDefault = false
|
|
168
|
-
for (const [severityKey, severityVal] of Object.entries(
|
|
169
|
-
val['severityLevels'],
|
|
170
|
-
)) {
|
|
171
|
-
if (!severityVal || typeof severityVal !== 'object') {
|
|
172
|
-
throw new InvalidRequestError(
|
|
173
|
-
`Invalid configuration for severity level ${severityKey} in policy ${key}`,
|
|
174
|
-
)
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
if (
|
|
178
|
-
severityVal['description'] !== undefined &&
|
|
179
|
-
typeof severityVal['description'] !== 'string'
|
|
180
|
-
) {
|
|
181
|
-
throw new InvalidRequestError(
|
|
182
|
-
`Description must be a string for severity level ${severityKey} in policy ${key}`,
|
|
183
|
-
)
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
if (severityVal['isDefault'] !== undefined) {
|
|
187
|
-
if (typeof severityVal['isDefault'] !== 'boolean') {
|
|
188
|
-
throw new InvalidRequestError(
|
|
189
|
-
`isDefault must be a boolean for severity level ${severityKey} in policy ${key}`,
|
|
190
|
-
)
|
|
191
|
-
}
|
|
192
|
-
if (severityVal['isDefault']) {
|
|
193
|
-
if (hasDefault) {
|
|
194
|
-
throw new InvalidRequestError(
|
|
195
|
-
`Only one severity level can be the default for policy ${key}`,
|
|
196
|
-
)
|
|
197
|
-
}
|
|
198
|
-
hasDefault = true
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
if (severityVal['targetServices'] !== undefined) {
|
|
203
|
-
if (!Array.isArray(severityVal['targetServices'])) {
|
|
204
|
-
throw new InvalidRequestError(
|
|
205
|
-
`targetServices must be an array for severity level ${severityKey} in policy ${key}`,
|
|
206
|
-
)
|
|
207
|
-
}
|
|
208
|
-
for (const service of severityVal['targetServices']) {
|
|
209
|
-
if (typeof service !== 'string') {
|
|
210
|
-
throw new InvalidRequestError(
|
|
211
|
-
`Each target service must be a string for severity level ${severityKey} in policy ${key}`,
|
|
212
|
-
)
|
|
213
|
-
}
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
},
|
|
220
|
-
],
|
|
221
|
-
[
|
|
222
|
-
SeverityLevelSettingKey,
|
|
223
|
-
/*
|
|
224
|
-
* Example configuration:
|
|
225
|
-
* {
|
|
226
|
-
* "sev-0": {
|
|
227
|
-
* "strikeCount": 0
|
|
228
|
-
* },
|
|
229
|
-
* "sev-1": {
|
|
230
|
-
* "strikeCount": 1,
|
|
231
|
-
* "strikeOnOccurrence": 2
|
|
232
|
-
* },
|
|
233
|
-
* "sev-2": {
|
|
234
|
-
* "strikeCount": 2
|
|
235
|
-
* },
|
|
236
|
-
* "sev-4": {
|
|
237
|
-
* "strikeCount": 4,
|
|
238
|
-
* "expiresInDays": 365
|
|
239
|
-
* },
|
|
240
|
-
* "sev-5": {
|
|
241
|
-
* "needsTakedown": true
|
|
242
|
-
* },
|
|
243
|
-
* "death-threat": {
|
|
244
|
-
* "strikeCount": 4,
|
|
245
|
-
* "firstOccurrenceStrikeCount": 4,
|
|
246
|
-
* },
|
|
247
|
-
* "custom-severity": {
|
|
248
|
-
* "strikeCount": 3,
|
|
249
|
-
* "strikeOnOccurrence": 1,
|
|
250
|
-
* },
|
|
251
|
-
* "escalating-severity": {
|
|
252
|
-
* "firstOccurrenceStrikeCount": 2,
|
|
253
|
-
* "repeatOccurrenceStrikeCount": 5
|
|
254
|
-
* }
|
|
255
|
-
* }
|
|
256
|
-
*/
|
|
257
|
-
async (setting: Partial<Selectable<Setting>>) => {
|
|
258
|
-
if (setting.managerRole !== 'tools.ozone.team.defs#roleAdmin') {
|
|
259
|
-
throw new InvalidRequestError(
|
|
260
|
-
'Only admins should be able to manage severity levels',
|
|
261
|
-
)
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
if (typeof setting.value !== 'object') {
|
|
265
|
-
throw new InvalidRequestError('Invalid value')
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
for (const [key, val] of Object.entries(setting.value)) {
|
|
269
|
-
if (!val || typeof val !== 'object') {
|
|
270
|
-
throw new InvalidRequestError(
|
|
271
|
-
`Invalid configuration for severity level ${key}`,
|
|
272
|
-
)
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
if (val['strikeCount'] !== undefined) {
|
|
276
|
-
if (
|
|
277
|
-
typeof val['strikeCount'] !== 'number' ||
|
|
278
|
-
!Number.isInteger(val['strikeCount']) ||
|
|
279
|
-
val['strikeCount'] < 0
|
|
280
|
-
) {
|
|
281
|
-
throw new InvalidRequestError(
|
|
282
|
-
`Strike count must be a non-negative integer for severity level ${key}`,
|
|
283
|
-
)
|
|
284
|
-
}
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
if (val['strikeOnOccurrence'] !== undefined) {
|
|
288
|
-
if (
|
|
289
|
-
typeof val['strikeOnOccurrence'] !== 'number' ||
|
|
290
|
-
!Number.isInteger(val['strikeOnOccurrence']) ||
|
|
291
|
-
val['strikeOnOccurrence'] < 1
|
|
292
|
-
) {
|
|
293
|
-
throw new InvalidRequestError(
|
|
294
|
-
`Strike on occurrence must be a positive integer for severity level ${key}`,
|
|
295
|
-
)
|
|
296
|
-
}
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
if (val['needsTakedown'] !== undefined) {
|
|
300
|
-
if (typeof val['needsTakedown'] !== 'boolean') {
|
|
301
|
-
throw new InvalidRequestError(
|
|
302
|
-
`Needs takedown must be a boolean for severity level ${key}`,
|
|
303
|
-
)
|
|
304
|
-
}
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
if (val['expiresInDays'] !== undefined) {
|
|
308
|
-
if (
|
|
309
|
-
typeof val['expiresInDays'] !== 'number' ||
|
|
310
|
-
!Number.isInteger(val['expiresInDays']) ||
|
|
311
|
-
val['expiresInDays'] < 0
|
|
312
|
-
) {
|
|
313
|
-
throw new InvalidRequestError(
|
|
314
|
-
`Expires in days must be a non-negative integer for severity level ${key}`,
|
|
315
|
-
)
|
|
316
|
-
}
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
if (val['firstOccurrenceStrikeCount'] !== undefined) {
|
|
320
|
-
if (
|
|
321
|
-
typeof val['firstOccurrenceStrikeCount'] !== 'number' ||
|
|
322
|
-
!Number.isInteger(val['firstOccurrenceStrikeCount']) ||
|
|
323
|
-
val['firstOccurrenceStrikeCount'] < 0
|
|
324
|
-
) {
|
|
325
|
-
throw new InvalidRequestError(
|
|
326
|
-
`First occurrence strike count must be a non-negative integer for severity level ${key}`,
|
|
327
|
-
)
|
|
328
|
-
}
|
|
329
|
-
}
|
|
330
|
-
}
|
|
331
|
-
},
|
|
332
|
-
],
|
|
333
|
-
])
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
import { ModerationService } from '../mod-service/index.js'
|
|
2
|
-
import { ModSubject } from '../mod-service/subject.js'
|
|
3
|
-
import { ModerationSubjectStatusRow } from '../mod-service/types.js'
|
|
4
|
-
|
|
5
|
-
export abstract class ContentTagger {
|
|
6
|
-
constructor(
|
|
7
|
-
protected subject: ModSubject,
|
|
8
|
-
protected subjectStatus: ModerationSubjectStatusRow | null,
|
|
9
|
-
protected moderationService: ModerationService,
|
|
10
|
-
) {}
|
|
11
|
-
|
|
12
|
-
protected abstract tagPrefix: string
|
|
13
|
-
|
|
14
|
-
protected abstract isApplicable(): boolean
|
|
15
|
-
protected abstract buildTags(): Promise<string[]>
|
|
16
|
-
|
|
17
|
-
async getTags(): Promise<string[]> {
|
|
18
|
-
if (!this.isApplicable()) {
|
|
19
|
-
return []
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
return this.buildTags()
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
protected tagAlreadyExists(): boolean {
|
|
26
|
-
return Boolean(
|
|
27
|
-
this.subjectStatus?.tags?.some((tag) => tag.startsWith(this.tagPrefix)),
|
|
28
|
-
)
|
|
29
|
-
}
|
|
30
|
-
}
|
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
AppBskyEmbedExternal,
|
|
3
|
-
AppBskyEmbedImages,
|
|
4
|
-
AppBskyEmbedRecordWithMedia,
|
|
5
|
-
AppBskyEmbedVideo,
|
|
6
|
-
AppBskyFeedPost,
|
|
7
|
-
} from '@atproto/api'
|
|
8
|
-
import { ids } from '../lexicon/lexicons.js'
|
|
9
|
-
import { langLogger as log } from '../logger.js'
|
|
10
|
-
import { ContentTagger } from './content-tagger.js'
|
|
11
|
-
|
|
12
|
-
export class EmbedTagger extends ContentTagger {
|
|
13
|
-
tagPrefix = 'embed:'
|
|
14
|
-
|
|
15
|
-
isApplicable(): boolean {
|
|
16
|
-
return (
|
|
17
|
-
!!this.subjectStatus &&
|
|
18
|
-
!this.tagAlreadyExists() &&
|
|
19
|
-
this.subject.isRecord() &&
|
|
20
|
-
this.subject.parsedUri.collection === ids.AppBskyFeedPost
|
|
21
|
-
)
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
async buildTags(): Promise<string[]> {
|
|
25
|
-
try {
|
|
26
|
-
const recordValue = await this.getRecordValue()
|
|
27
|
-
if (!recordValue) {
|
|
28
|
-
return []
|
|
29
|
-
}
|
|
30
|
-
const tags: string[] = []
|
|
31
|
-
const result = AppBskyFeedPost.validateRecord(recordValue)
|
|
32
|
-
|
|
33
|
-
if (result.success) {
|
|
34
|
-
const embedContent = AppBskyEmbedRecordWithMedia.isMain(
|
|
35
|
-
result.value.embed,
|
|
36
|
-
)
|
|
37
|
-
? result.value.embed.media
|
|
38
|
-
: result.value.embed
|
|
39
|
-
|
|
40
|
-
if (AppBskyEmbedImages.isMain(embedContent)) {
|
|
41
|
-
tags.push(`${this.tagPrefix}image`)
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
if (AppBskyEmbedVideo.isMain(embedContent)) {
|
|
45
|
-
tags.push(`${this.tagPrefix}video`)
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
if (AppBskyEmbedExternal.isMain(embedContent)) {
|
|
49
|
-
tags.push(`${this.tagPrefix}external`)
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
return tags
|
|
53
|
-
} catch (err) {
|
|
54
|
-
log.error({ subject: this.subject, err }, 'Error getting record langs')
|
|
55
|
-
return []
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
async getRecordValue(): Promise<Record<string, unknown> | undefined> {
|
|
60
|
-
if (!this.subject.isRecord()) {
|
|
61
|
-
return undefined
|
|
62
|
-
}
|
|
63
|
-
const recordByUri = await this.moderationService.views.fetchRecords([
|
|
64
|
-
this.subject,
|
|
65
|
-
])
|
|
66
|
-
|
|
67
|
-
const record = recordByUri.get(this.subject.uri)
|
|
68
|
-
return record?.value
|
|
69
|
-
}
|
|
70
|
-
}
|
package/src/tag-service/index.ts
DELETED
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
import { langLogger as log } from '../logger.js'
|
|
2
|
-
import { ModerationService } from '../mod-service/index.js'
|
|
3
|
-
import { ModSubject } from '../mod-service/subject.js'
|
|
4
|
-
import { ModerationSubjectStatusRow } from '../mod-service/types.js'
|
|
5
|
-
import { ContentTagger } from './content-tagger.js'
|
|
6
|
-
import { EmbedTagger } from './embed-tagger.js'
|
|
7
|
-
import { LanguageTagger } from './language-tagger.js'
|
|
8
|
-
|
|
9
|
-
export class TagService {
|
|
10
|
-
private taggers: ContentTagger[]
|
|
11
|
-
|
|
12
|
-
constructor(
|
|
13
|
-
private subject: ModSubject,
|
|
14
|
-
protected subjectStatus: ModerationSubjectStatusRow | null,
|
|
15
|
-
private taggerDid: string,
|
|
16
|
-
private moderationService: ModerationService,
|
|
17
|
-
) {
|
|
18
|
-
this.taggers = [
|
|
19
|
-
new LanguageTagger(subject, subjectStatus, moderationService),
|
|
20
|
-
new EmbedTagger(subject, subjectStatus, moderationService),
|
|
21
|
-
// Add more taggers as needed
|
|
22
|
-
]
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
// Allow the caller to seed the initial tags
|
|
26
|
-
async evaluateForSubject(initialTags?: Iterable<string>) {
|
|
27
|
-
try {
|
|
28
|
-
const tags = new Set(initialTags)
|
|
29
|
-
|
|
30
|
-
await Promise.all(
|
|
31
|
-
this.taggers.map(async (tagger) => {
|
|
32
|
-
try {
|
|
33
|
-
const newTags = await tagger.getTags()
|
|
34
|
-
for (const newTag of newTags) {
|
|
35
|
-
tags.add(newTag)
|
|
36
|
-
}
|
|
37
|
-
} catch (e) {
|
|
38
|
-
// Don't let one tagger error stop the rest from running
|
|
39
|
-
log.error(
|
|
40
|
-
{ subject: this.subject, err: e },
|
|
41
|
-
'Error applying tagger',
|
|
42
|
-
)
|
|
43
|
-
}
|
|
44
|
-
}),
|
|
45
|
-
)
|
|
46
|
-
|
|
47
|
-
// Ensure that before inserting new tags, we discard any tag that may
|
|
48
|
-
// have been evaluated to be added but is already present in the subject
|
|
49
|
-
if (this.subjectStatus?.tags?.length) {
|
|
50
|
-
for (const tag of this.subjectStatus.tags) {
|
|
51
|
-
tags.delete(tag)
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
if (tags.size) {
|
|
56
|
-
await this.moderationService.logEvent({
|
|
57
|
-
event: {
|
|
58
|
-
$type: 'tools.ozone.moderation.defs#modEventTag',
|
|
59
|
-
add: [...tags],
|
|
60
|
-
remove: [],
|
|
61
|
-
},
|
|
62
|
-
subject: this.subject,
|
|
63
|
-
createdBy: this.taggerDid,
|
|
64
|
-
})
|
|
65
|
-
}
|
|
66
|
-
} catch (err) {
|
|
67
|
-
log.error({ subject: this.subject, err }, 'Error tagging subject')
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
}
|