Skip to content

Commit

Permalink
Add specced takedown labels (#2309)
Browse files Browse the repository at this point in the history
* add specced takedown labels

* fix up tests

* fix test

* only reverse takedown labels
  • Loading branch information
dholms authored Mar 13, 2024
1 parent a0625ba commit 16ac2ef
Show file tree
Hide file tree
Showing 7 changed files with 53 additions and 208 deletions.
14 changes: 1 addition & 13 deletions packages/ozone/src/api/label/fetchLabels.ts
Original file line number Diff line number Diff line change
@@ -1,30 +1,18 @@
import { Server } from '../../lexicon'
import AppContext from '../../context'
import {
UNSPECCED_TAKEDOWN_BLOBS_LABEL,
UNSPECCED_TAKEDOWN_LABEL,
} from '../../mod-service/types'

export default function (server: Server, ctx: AppContext) {
server.com.atproto.temp.fetchLabels({
auth: ctx.authVerifier.standardOptionalOrAdminToken,
handler: async ({ auth, params }) => {
handler: async ({ params }) => {
const { limit } = params
const since =
params.since !== undefined ? new Date(params.since).toISOString() : ''
const includeUnspeccedTakedowns =
auth.credentials.type === 'none' ? false : auth.credentials.isAdmin
const labelRes = await ctx.db.db
.selectFrom('label')
.selectAll()
.orderBy('label.cts', 'asc')
.where('cts', '>', since)
.if(!includeUnspeccedTakedowns, (q) =>
q.where('label.val', 'not in', [
UNSPECCED_TAKEDOWN_LABEL,
UNSPECCED_TAKEDOWN_BLOBS_LABEL,
]),
)
.limit(limit)
.execute()

Expand Down
91 changes: 23 additions & 68 deletions packages/ozone/src/mod-service/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,6 @@ import {
ModerationEventRow,
ModerationSubjectStatusRow,
ReversibleModerationEvent,
UNSPECCED_TAKEDOWN_BLOBS_LABEL,
UNSPECCED_TAKEDOWN_LABEL,
} from './types'
import { ModerationEvent } from '../db/schema/moderation_event'
import { StatusKeyset, TimeIdKeyset, paginate } from '../db/pagination'
Expand Down Expand Up @@ -480,8 +478,10 @@ export class ModerationService {
)
.returning('id')
.execute()

const takedownLabel = isSuspend ? SUSPEND_LABEL : TAKEDOWN_LABEL
await this.formatAndCreateLabels(subject.did, null, {
create: [UNSPECCED_TAKEDOWN_LABEL],
create: [takedownLabel],
})

this.db.onCommit(() => {
Expand All @@ -506,8 +506,18 @@ export class ModerationService {
})
.returning('id')
.execute()

const existingTakedownLabels = await this.db.db
.selectFrom('label')
.where('label.uri', '=', subject.did)
.where('label.val', 'in', [TAKEDOWN_LABEL, SUSPEND_LABEL])
.where('neg', '=', false)
.selectAll()
.execute()

const takedownVals = existingTakedownLabels.map((row) => row.val)
await this.formatAndCreateLabels(subject.did, null, {
negate: [UNSPECCED_TAKEDOWN_LABEL],
negate: takedownVals,
})

this.db.onCommit(() => {
Expand All @@ -521,44 +531,12 @@ export class ModerationService {

async takedownRecord(subject: RecordSubject, takedownId: number) {
this.db.assertTransaction()
const takedownRef = `BSKY-TAKEDOWN-${takedownId}`
const values = this.eventPusher.takedowns.map((eventType) => ({
eventType,
subjectDid: subject.did,
subjectUri: subject.uri,
subjectCid: subject.cid,
takedownRef,
}))
const blobCids = subject.blobCids
const labels: string[] = [UNSPECCED_TAKEDOWN_LABEL]
if (blobCids && blobCids.length > 0) {
labels.push(UNSPECCED_TAKEDOWN_BLOBS_LABEL)
}
const recordEvts = await this.db.db
.insertInto('record_push_event')
.values(values)
.onConflict((oc) =>
oc.columns(['subjectUri', 'eventType']).doUpdateSet({
takedownRef,
confirmedAt: null,
attempts: 0,
lastAttempted: null,
}),
)
.returning('id')
.execute()
await this.formatAndCreateLabels(subject.uri, subject.cid, {
create: labels,
})

this.db.onCommit(() => {
this.backgroundQueue.add(async () => {
await Promise.all(
recordEvts.map((evt) => this.eventPusher.attemptRecordEvent(evt.id)),
)
})
create: [TAKEDOWN_LABEL],
})

const takedownRef = `BSKY-TAKEDOWN-${takedownId}`
const blobCids = subject.blobCids
if (blobCids && blobCids.length > 0) {
const blobValues: Insertable<BlobPushEvent>[] = []
for (const eventType of this.eventPusher.takedowns) {
Expand Down Expand Up @@ -613,37 +591,11 @@ export class ModerationService {

async reverseTakedownRecord(subject: RecordSubject) {
this.db.assertTransaction()
const labels: string[] = [UNSPECCED_TAKEDOWN_LABEL]
const blobCids = subject.blobCids
if (blobCids && blobCids.length > 0) {
labels.push(UNSPECCED_TAKEDOWN_BLOBS_LABEL)
}
const recordEvts = await this.db.db
.updateTable('record_push_event')
.where('eventType', 'in', TAKEDOWNS)
.where('subjectDid', '=', subject.did)
.where('subjectUri', '=', subject.uri)
.set({
takedownRef: null,
confirmedAt: null,
attempts: 0,
lastAttempted: null,
})
.returning('id')
.execute()
await this.formatAndCreateLabels(subject.uri, subject.cid, {
negate: labels,
}),
this.db.onCommit(() => {
this.backgroundQueue.add(async () => {
await Promise.all(
recordEvts.map((evt) =>
this.eventPusher.attemptRecordEvent(evt.id),
),
)
})
})
negate: [TAKEDOWN_LABEL],
})

const blobCids = subject.blobCids
if (blobCids && blobCids.length > 0) {
const blobEvts = await this.db.db
.updateTable('blob_push_event')
Expand Down Expand Up @@ -963,6 +915,9 @@ const isSafeUrl = (url: URL) => {

const TAKEDOWNS = ['pds_takedown' as const, 'appview_takedown' as const]

export const TAKEDOWN_LABEL = '!takedown'
export const SUSPEND_LABEL = '!suspend'

export type TakedownSubjects = {
did: string
subjects: (RepoRef | RepoBlobRef | StrongRef)[]
Expand Down
4 changes: 0 additions & 4 deletions packages/ozone/src/mod-service/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,3 @@ export type ModEventType =
| ToolsOzoneModerationDefs.ModEventMute
| ToolsOzoneModerationDefs.ModEventReverseTakedown
| ToolsOzoneModerationDefs.ModEventTag

export const UNSPECCED_TAKEDOWN_LABEL = '!unspecced-takedown'

export const UNSPECCED_TAKEDOWN_BLOBS_LABEL = '!unspecced-takedown-blobs'
4 changes: 2 additions & 2 deletions packages/ozone/tests/__snapshots__/get-record.test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ Object {
},
"src": "user(2)",
"uri": "record(0)",
"val": "!unspecced-takedown",
"val": "!takedown",
"ver": 1,
},
Object {
Expand Down Expand Up @@ -117,7 +117,7 @@ Object {
},
"src": "user(2)",
"uri": "record(0)",
"val": "!unspecced-takedown",
"val": "!takedown",
"ver": 1,
},
Object {
Expand Down
2 changes: 1 addition & 1 deletion packages/ozone/tests/__snapshots__/get-repo.test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ Object {
},
"src": "user(2)",
"uri": "user(0)",
"val": "!unspecced-takedown",
"val": "!takedown",
"ver": 1,
},
],
Expand Down
107 changes: 4 additions & 103 deletions packages/ozone/tests/moderation.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import {
TestNetwork,
TestOzone,
ImageRef,
RecordRef,
SeedClient,
Expand All @@ -20,12 +21,8 @@ import {
REVIEWESCALATED,
} from '../src/lexicon/types/tools/ozone/moderation/defs'
import { EventReverser } from '../src'
import { TestOzone } from '@atproto/dev-env/src/ozone'
import { ImageInvalidator } from '../src/image-invalidator'
import {
UNSPECCED_TAKEDOWN_BLOBS_LABEL,
UNSPECCED_TAKEDOWN_LABEL,
} from '../src/mod-service/types'
import { TAKEDOWN_LABEL } from '../src/mod-service'

describe('moderation', () => {
let network: TestNetwork
Expand Down Expand Up @@ -542,10 +539,7 @@ describe('moderation', () => {
)
expect(bskyRes1.data.takedown?.applied).toBe(true)

const takedownLabel1 = await getLabel(
sc.dids.bob,
UNSPECCED_TAKEDOWN_LABEL,
)
const takedownLabel1 = await getLabel(sc.dids.bob, TAKEDOWN_LABEL)
expect(takedownLabel1).toBeDefined()

// cleanup
Expand All @@ -570,52 +564,7 @@ describe('moderation', () => {
)
expect(bskyRes2.data.takedown?.applied).toBe(false)

const takedownLabel2 = await getLabel(
sc.dids.bob,
UNSPECCED_TAKEDOWN_LABEL,
)
expect(takedownLabel2).toBeUndefined()
})

it('fans out record takedowns', async () => {
const post = sc.posts[sc.dids.bob][0].ref
const uri = post.uriStr
await modClient.performTakedown({
subject: recordSubject(post),
})
await ozone.processAll()

const pdsRes1 = await pdsAgent.api.com.atproto.admin.getSubjectStatus(
{ uri },
{ headers: network.pds.adminAuthHeaders() },
)
expect(pdsRes1.data.takedown?.applied).toBe(true)

const bskyRes1 = await bskyAgent.api.com.atproto.admin.getSubjectStatus(
{ uri },
{ headers: network.bsky.adminAuthHeaders() },
)
expect(bskyRes1.data.takedown?.applied).toBe(true)

const takedownLabel1 = await getLabel(uri, UNSPECCED_TAKEDOWN_LABEL)
expect(takedownLabel1).toBeDefined()

// cleanup
await modClient.performReverseTakedown({ subject: recordSubject(post) })
await ozone.processAll()

const pdsRes2 = await pdsAgent.api.com.atproto.admin.getSubjectStatus(
{ uri },
{ headers: network.pds.adminAuthHeaders() },
)
expect(pdsRes2.data.takedown?.applied).toBe(false)
const bskyRes2 = await bskyAgent.api.com.atproto.admin.getSubjectStatus(
{ uri },
{ headers: network.bsky.adminAuthHeaders() },
)
expect(bskyRes2.data.takedown?.applied).toBe(false)

const takedownLabel2 = await getLabel(uri, UNSPECCED_TAKEDOWN_LABEL)
const takedownLabel2 = await getLabel(sc.dids.bob, TAKEDOWN_LABEL)
expect(takedownLabel2).toBeUndefined()
})

Expand Down Expand Up @@ -713,22 +662,6 @@ describe('moderation', () => {
})
})

it('serves label when authed', async () => {
const { data: unauthed } = await agent.api.com.atproto.temp.fetchLabels(
{},
)
expect(unauthed.labels.map((l) => l.val)).not.toContain(
UNSPECCED_TAKEDOWN_LABEL,
)
const { data: authed } = await agent.api.com.atproto.temp.fetchLabels(
{},
{ headers: network.bsky.adminAuthHeaders() },
)
expect(authed.labels.map((l) => l.val)).toContain(
UNSPECCED_TAKEDOWN_LABEL,
)
})

async function emitLabelEvent(
opts: Partial<ToolsOzoneModerationEmitEvent.InputSchema> & {
subject: ToolsOzoneModerationEmitEvent.InputSchema['subject']
Expand Down Expand Up @@ -860,14 +793,6 @@ describe('moderation', () => {
expect(res.data.takedown?.applied).toBe(true)
})

it('creates a takedown blobs label', async () => {
const label = await getLabel(
post.ref.uriStr,
UNSPECCED_TAKEDOWN_BLOBS_LABEL,
)
expect(label).toBeDefined()
})

it('restores blob when action is reversed.', async () => {
await modClient.performReverseTakedown({
subject: recordSubject(post.ref),
Expand Down Expand Up @@ -898,30 +823,6 @@ describe('moderation', () => {
)
expect(res.data.takedown?.applied).toBe(false)
})

it('serves label when authed', async () => {
const { data: unauthed } = await agent.api.com.atproto.temp.fetchLabels(
{},
)
expect(unauthed.labels.map((l) => l.val)).not.toContain(
UNSPECCED_TAKEDOWN_BLOBS_LABEL,
)
const { data: authed } = await agent.api.com.atproto.temp.fetchLabels(
{},
{ headers: network.bsky.adminAuthHeaders() },
)
expect(authed.labels.map((l) => l.val)).toContain(
UNSPECCED_TAKEDOWN_BLOBS_LABEL,
)
})

it('negates takedown blobs label on reversal', async () => {
const label = await getLabel(
post.ref.uriStr,
UNSPECCED_TAKEDOWN_BLOBS_LABEL,
)
expect(label).toBeUndefined()
})
})
})

Expand Down
Loading

0 comments on commit 16ac2ef

Please sign in to comment.