atproto/packages/bsky/tests/views/labels-takedown.test.ts
devin ivy 167270bd7a
Appview: fix takendown blocklist application on actor.getProfile (#3108)
appview: fix takendown blocklist application on actor.getProfile
2024-11-26 17:23:03 -05:00

217 lines
6.2 KiB
TypeScript

import { AtpAgent } from '@atproto/api'
import { TestNetwork, SeedClient, basicSeed, RecordRef } from '@atproto/dev-env'
import { ids } from '../../src/lexicon/lexicons'
describe('bsky takedown labels', () => {
let network: TestNetwork
let agent: AtpAgent
let pdsAgent: AtpAgent
let sc: SeedClient
let takendownSubjects: string[]
let aliceListRef: RecordRef
let carolListRef: RecordRef
let aliceGenRef: RecordRef
let bobGenRef: RecordRef
let carolGenRef: RecordRef
beforeAll(async () => {
network = await TestNetwork.create({
dbPostgresSchema: 'bsky_views_takedown_labels',
})
agent = network.bsky.getClient()
pdsAgent = network.pds.getClient()
sc = network.getSeedClient()
await basicSeed(sc)
aliceListRef = await sc.createList(sc.dids.alice, 'alice list', 'mod')
// carol blocks dan via alice's (takendown) list
await sc.addToList(sc.dids.alice, sc.dids.dan, aliceListRef)
await pdsAgent.app.bsky.graph.listblock.create(
{ repo: sc.dids.carol },
{
subject: aliceListRef.uriStr,
createdAt: new Date().toISOString(),
},
sc.getHeaders(sc.dids.carol),
)
carolListRef = await sc.createList(sc.dids.carol, 'carol list', 'mod')
aliceGenRef = await sc.createFeedGen(
sc.dids.alice,
'did:web:example.com',
'alice generator',
)
bobGenRef = await sc.createFeedGen(
sc.dids.bob,
'did:web:example.com',
'bob generator',
)
carolGenRef = await sc.createFeedGen(
sc.dids.carol,
'did:web:example.com',
'carol generator',
)
// labelers
await sc.createAccount('labeler1', {
email: 'lab1@test.com',
handle: 'lab1.test',
password: 'lab1',
})
await sc.agent.api.com.atproto.repo.createRecord(
{
repo: sc.dids.labeler1,
collection: ids.AppBskyLabelerService,
rkey: 'self',
record: {
policies: { labelValues: ['spam'] },
createdAt: new Date().toISOString(),
},
},
{
headers: sc.getHeaders(sc.dids.labeler1),
encoding: 'application/json',
},
)
await sc.createAccount('labeler2', {
email: 'lab2@test.com',
handle: 'lab2.test',
password: 'lab2',
})
await sc.agent.api.com.atproto.repo.createRecord(
{
repo: sc.dids.labeler2,
collection: ids.AppBskyLabelerService,
rkey: 'self',
record: {
policies: { labelValues: ['spam'] },
createdAt: new Date().toISOString(),
},
},
{
headers: sc.getHeaders(sc.dids.labeler2),
encoding: 'application/json',
},
)
await network.processAll()
takendownSubjects = [
sc.posts[sc.dids.alice][0].ref.uriStr,
sc.dids.carol,
aliceListRef.uriStr,
aliceGenRef.uriStr,
sc.dids.labeler1,
]
const src = network.ozone.ctx.cfg.service.did
const cts = new Date().toISOString()
const labels = takendownSubjects.map((uri) => ({
src,
uri,
cid: '',
val: '!takedown',
neg: false,
cts,
}))
AtpAgent.configure({ appLabelers: [src] })
await network.bsky.db.db.insertInto('label').values(labels).execute()
})
afterAll(async () => {
await network.close()
})
it('takesdown profiles', async () => {
const attempt = agent.api.app.bsky.actor.getProfile({
actor: sc.dids.carol,
})
await expect(attempt).rejects.toThrow('Account has been suspended')
const res = await agent.api.app.bsky.actor.getProfiles({
actors: [sc.dids.alice, sc.dids.bob, sc.dids.carol],
})
expect(res.data.profiles.length).toBe(2)
expect(res.data.profiles.some((p) => p.did === sc.dids.carol)).toBe(false)
})
it('takesdown posts', async () => {
const uris = [
sc.posts[sc.dids.alice][0].ref.uriStr,
sc.posts[sc.dids.alice][1].ref.uriStr,
sc.posts[sc.dids.bob][0].ref.uriStr,
sc.posts[sc.dids.carol][0].ref.uriStr,
sc.posts[sc.dids.dan][1].ref.uriStr,
sc.replies[sc.dids.alice][0].ref.uriStr,
]
const res = await agent.api.app.bsky.feed.getPosts({ uris })
expect(res.data.posts.length).toBe(4)
expect(res.data.posts.some((p) => p.author.did === sc.dids.carol)).toBe(
false,
)
expect(
res.data.posts.some(
(p) => p.uri === sc.posts[sc.dids.alice][0].ref.uriStr,
),
).toBe(false)
})
it('takesdown lists', async () => {
// record takedown
const attempt1 = agent.api.app.bsky.graph.getList({
list: aliceListRef.uriStr,
})
await expect(attempt1).rejects.toThrow('List not found')
// actor takedown
const attempt2 = agent.api.app.bsky.graph.getList({
list: carolListRef.uriStr,
})
await expect(attempt2).rejects.toThrow('List not found')
})
it('halts application of mod lists', async () => {
const { data: profile } = await agent.app.bsky.actor.getProfile(
{
actor: sc.dids.dan, // blocked via alice's takendown list
},
{
headers: await network.serviceHeaders(
sc.dids.carol,
ids.AppBskyActorGetProfile,
),
},
)
expect(profile.did).toBe(sc.dids.dan)
expect(profile.viewer).not.toBeUndefined()
expect(profile.viewer?.blockedBy).toBe(false)
expect(profile.viewer?.blocking).toBeUndefined()
expect(profile.viewer?.blockingByList).toBeUndefined()
})
it('takesdown feed generators', async () => {
const res = await agent.api.app.bsky.feed.getFeedGenerators({
feeds: [aliceGenRef.uriStr, bobGenRef.uriStr, carolGenRef.uriStr],
})
expect(res.data.feeds.length).toBe(1)
expect(res.data.feeds.at(0)?.uri).toEqual(bobGenRef.uriStr)
})
it('takesdown labelers', async () => {
const res = await agent.api.app.bsky.labeler.getServices({
dids: [sc.dids.labeler1, sc.dids.labeler2],
})
expect(res.data.views.length).toBe(1)
expect(res.data.views[0].creator?.['did']).toBe(sc.dids.labeler2)
})
it('only applies if the relevant labeler is configured', async () => {
AtpAgent.configure({ appLabelers: ['did:web:example.com'] })
const res = await agent.api.app.bsky.actor.getProfile({
actor: sc.dids.carol,
})
expect(res.data.did).toEqual(sc.dids.carol)
})
})