@atproto/bsky 0.0.28 → 0.0.29
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 +7 -0
- package/LICENSE.txt +1 -1
- package/dist/auto-moderator/index.d.ts +1 -14
- package/dist/context.d.ts +0 -3
- package/dist/db/index.js +34593 -3478
- package/dist/db/index.js.map +3 -3
- package/dist/db/pagination.d.ts +1 -0
- package/dist/index.d.ts +0 -4
- package/dist/index.js +1531 -1723
- package/dist/index.js.map +3 -3
- package/dist/indexer/config.d.ts +0 -8
- package/dist/lexicon/index.d.ts +0 -2
- package/dist/lexicon/lexicons.d.ts +38 -47
- package/dist/lexicon/types/com/atproto/admin/defs.d.ts +2 -2
- package/dist/lexicon/types/com/atproto/admin/queryModerationEvents.d.ts +7 -0
- package/package.json +7 -6
- package/src/api/app/bsky/actor/getSuggestions.ts +1 -1
- package/src/api/app/bsky/actor/searchActors.ts +1 -0
- package/src/api/app/bsky/feed/getActorFeeds.ts +6 -0
- package/src/api/app/bsky/feed/getActorLikes.ts +4 -0
- package/src/api/app/bsky/feed/getAuthorFeed.ts +4 -0
- package/src/api/app/bsky/feed/getFeed.ts +8 -5
- package/src/api/app/bsky/feed/getLikes.ts +4 -0
- package/src/api/app/bsky/feed/getListFeed.ts +4 -0
- package/src/api/app/bsky/feed/getRepostedBy.ts +4 -0
- package/src/api/app/bsky/feed/getSuggestedFeeds.ts +1 -1
- package/src/api/app/bsky/feed/getTimeline.ts +4 -0
- package/src/api/app/bsky/feed/searchPosts.ts +1 -0
- package/src/api/app/bsky/graph/getBlocks.ts +7 -0
- package/src/api/app/bsky/graph/getFollowers.ts +4 -0
- package/src/api/app/bsky/graph/getFollows.ts +4 -0
- package/src/api/app/bsky/graph/getList.ts +4 -0
- package/src/api/app/bsky/graph/getListBlocks.ts +4 -0
- package/src/api/app/bsky/graph/getListMutes.ts +7 -0
- package/src/api/app/bsky/graph/getLists.ts +7 -0
- package/src/api/app/bsky/graph/getMutes.ts +7 -0
- package/src/api/app/bsky/notification/listNotifications.ts +3 -0
- package/src/api/app/bsky/unspecced/getPopularFeedGenerators.ts +7 -1
- package/src/api/index.ts +0 -6
- package/src/auto-moderator/index.ts +9 -176
- package/src/context.ts +0 -6
- package/src/db/pagination.ts +3 -0
- package/src/index.ts +1 -6
- package/src/indexer/config.ts +0 -29
- package/src/lexicon/index.ts +0 -12
- package/src/lexicon/lexicons.ts +43 -50
- package/src/lexicon/types/com/atproto/admin/defs.ts +2 -0
- package/src/lexicon/types/com/atproto/admin/queryModerationEvents.ts +13 -0
- package/src/logger.ts +32 -0
- package/tests/auto-moderator/labeler.test.ts +2 -0
- package/tests/feed-generation.test.ts +0 -6
- package/tests/views/notifications.test.ts +9 -0
- package/tests/views/timeline.test.ts +8 -0
- package/dist/api/app/bsky/feed/describeFeedGenerator.d.ts +0 -3
- package/dist/api/app/bsky/feed/getFeedSkeleton.d.ts +0 -3
- package/dist/api/app/bsky/unspecced/getTimelineSkeleton.d.ts +0 -3
- package/dist/auto-moderator/abyss.d.ts +0 -48
- package/dist/auto-moderator/fuzzy-matcher.d.ts +0 -14
- package/dist/feed-gen/bsky-team.d.ts +0 -3
- package/dist/feed-gen/hot-classic.d.ts +0 -3
- package/dist/feed-gen/index.d.ts +0 -2
- package/dist/feed-gen/mutuals.d.ts +0 -3
- package/dist/feed-gen/types.d.ts +0 -15
- package/dist/lexicon/types/app/bsky/unspecced/getTimelineSkeleton.d.ts +0 -35
- package/src/api/app/bsky/feed/describeFeedGenerator.ts +0 -21
- package/src/api/app/bsky/feed/getFeedSkeleton.ts +0 -30
- package/src/api/app/bsky/unspecced/getTimelineSkeleton.ts +0 -26
- package/src/auto-moderator/abyss.ts +0 -114
- package/src/auto-moderator/fuzzy-matcher.ts +0 -126
- package/src/feed-gen/bsky-team.ts +0 -42
- package/src/feed-gen/hot-classic.ts +0 -55
- package/src/feed-gen/index.ts +0 -17
- package/src/feed-gen/mutuals.ts +0 -57
- package/src/feed-gen/types.ts +0 -32
- package/src/lexicon/types/app/bsky/unspecced/getTimelineSkeleton.ts +0 -49
- package/tests/algos/hot-classic.test.ts +0 -87
- package/tests/auto-moderator/fuzzy-matcher.test.ts +0 -163
- package/tests/auto-moderator/takedowns.test.ts +0 -202
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* GENERATED CODE - DO NOT MODIFY
|
|
3
|
-
*/
|
|
4
|
-
import express from 'express'
|
|
5
|
-
import { ValidationResult, BlobRef } from '@atproto/lexicon'
|
|
6
|
-
import { lexicons } from '../../../../lexicons'
|
|
7
|
-
import { isObj, hasProp } from '../../../../util'
|
|
8
|
-
import { CID } from 'multiformats/cid'
|
|
9
|
-
import { HandlerAuth } from '@atproto/xrpc-server'
|
|
10
|
-
import * as AppBskyFeedDefs from '../feed/defs'
|
|
11
|
-
|
|
12
|
-
export interface QueryParams {
|
|
13
|
-
limit: number
|
|
14
|
-
cursor?: string
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export type InputSchema = undefined
|
|
18
|
-
|
|
19
|
-
export interface OutputSchema {
|
|
20
|
-
cursor?: string
|
|
21
|
-
feed: AppBskyFeedDefs.SkeletonFeedPost[]
|
|
22
|
-
[k: string]: unknown
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
export type HandlerInput = undefined
|
|
26
|
-
|
|
27
|
-
export interface HandlerSuccess {
|
|
28
|
-
encoding: 'application/json'
|
|
29
|
-
body: OutputSchema
|
|
30
|
-
headers?: { [key: string]: string }
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
export interface HandlerError {
|
|
34
|
-
status: number
|
|
35
|
-
message?: string
|
|
36
|
-
error?: 'UnknownFeed'
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
export type HandlerOutput = HandlerError | HandlerSuccess
|
|
40
|
-
export type HandlerReqCtx<HA extends HandlerAuth = never> = {
|
|
41
|
-
auth: HA
|
|
42
|
-
params: QueryParams
|
|
43
|
-
input: HandlerInput
|
|
44
|
-
req: express.Request
|
|
45
|
-
res: express.Response
|
|
46
|
-
}
|
|
47
|
-
export type Handler<HA extends HandlerAuth = never> = (
|
|
48
|
-
ctx: HandlerReqCtx<HA>,
|
|
49
|
-
) => Promise<HandlerOutput> | HandlerOutput
|
|
@@ -1,87 +0,0 @@
|
|
|
1
|
-
import AtpAgent, { AtUri } from '@atproto/api'
|
|
2
|
-
import { TestNetwork, SeedClient, basicSeed } from '@atproto/dev-env'
|
|
3
|
-
import { makeAlgos } from '../../src'
|
|
4
|
-
|
|
5
|
-
describe('algo hot-classic', () => {
|
|
6
|
-
let network: TestNetwork
|
|
7
|
-
let agent: AtpAgent
|
|
8
|
-
let sc: SeedClient
|
|
9
|
-
|
|
10
|
-
// account dids, for convenience
|
|
11
|
-
let alice: string
|
|
12
|
-
let bob: string
|
|
13
|
-
|
|
14
|
-
const feedPublisherDid = 'did:example:feed-publisher'
|
|
15
|
-
const feedUri = AtUri.make(
|
|
16
|
-
feedPublisherDid,
|
|
17
|
-
'app.bsky.feed.generator',
|
|
18
|
-
'hot-classic',
|
|
19
|
-
).toString()
|
|
20
|
-
|
|
21
|
-
beforeAll(async () => {
|
|
22
|
-
network = await TestNetwork.create({
|
|
23
|
-
dbPostgresSchema: 'bsky_algo_hot_classic',
|
|
24
|
-
bsky: { algos: makeAlgos(feedPublisherDid) },
|
|
25
|
-
})
|
|
26
|
-
agent = new AtpAgent({ service: network.bsky.url })
|
|
27
|
-
sc = network.getSeedClient()
|
|
28
|
-
await basicSeed(sc)
|
|
29
|
-
|
|
30
|
-
alice = sc.dids.alice
|
|
31
|
-
bob = sc.dids.bob
|
|
32
|
-
await network.processAll()
|
|
33
|
-
})
|
|
34
|
-
|
|
35
|
-
afterAll(async () => {
|
|
36
|
-
await network.close()
|
|
37
|
-
})
|
|
38
|
-
|
|
39
|
-
it('returns well liked posts', async () => {
|
|
40
|
-
const img = await sc.uploadFile(
|
|
41
|
-
alice,
|
|
42
|
-
'../dev-env/src/seed/img/key-landscape-small.jpg',
|
|
43
|
-
'image/jpeg',
|
|
44
|
-
)
|
|
45
|
-
const one = await sc.post(alice, 'first post', undefined, [img])
|
|
46
|
-
const two = await sc.post(bob, 'bobby boi')
|
|
47
|
-
const three = await sc.reply(bob, one.ref, one.ref, 'reply')
|
|
48
|
-
|
|
49
|
-
for (let i = 0; i < 12; i++) {
|
|
50
|
-
const name = `user${i}`
|
|
51
|
-
await sc.createAccount(name, {
|
|
52
|
-
handle: `user${i}.test`,
|
|
53
|
-
email: `user${i}@test.com`,
|
|
54
|
-
password: 'password',
|
|
55
|
-
})
|
|
56
|
-
await sc.like(sc.dids[name], one.ref)
|
|
57
|
-
await sc.like(sc.dids[name], two.ref)
|
|
58
|
-
await sc.like(sc.dids[name], three.ref)
|
|
59
|
-
}
|
|
60
|
-
await network.processAll()
|
|
61
|
-
|
|
62
|
-
const res = await agent.api.app.bsky.feed.getFeed(
|
|
63
|
-
{ feed: feedUri },
|
|
64
|
-
{ headers: await network.serviceHeaders(alice) },
|
|
65
|
-
)
|
|
66
|
-
const feedUris = res.data.feed.map((i) => i.post.uri).sort()
|
|
67
|
-
const expected = [one.ref.uriStr, two.ref.uriStr].sort()
|
|
68
|
-
expect(feedUris).toEqual(expected)
|
|
69
|
-
})
|
|
70
|
-
|
|
71
|
-
it('paginates', async () => {
|
|
72
|
-
const res = await agent.api.app.bsky.feed.getFeed(
|
|
73
|
-
{ feed: feedUri },
|
|
74
|
-
{ headers: await network.serviceHeaders(alice) },
|
|
75
|
-
)
|
|
76
|
-
const first = await agent.api.app.bsky.feed.getFeed(
|
|
77
|
-
{ feed: feedUri, limit: 1 },
|
|
78
|
-
{ headers: await network.serviceHeaders(alice) },
|
|
79
|
-
)
|
|
80
|
-
const second = await agent.api.app.bsky.feed.getFeed(
|
|
81
|
-
{ feed: feedUri, cursor: first.data.cursor },
|
|
82
|
-
{ headers: await network.serviceHeaders(alice) },
|
|
83
|
-
)
|
|
84
|
-
|
|
85
|
-
expect([...first.data.feed, ...second.data.feed]).toEqual(res.data.feed)
|
|
86
|
-
})
|
|
87
|
-
})
|
|
@@ -1,163 +0,0 @@
|
|
|
1
|
-
import { TestNetwork, SeedClient, basicSeed } from '@atproto/dev-env'
|
|
2
|
-
import { FuzzyMatcher, encode } from '../../src/auto-moderator/fuzzy-matcher'
|
|
3
|
-
import { AtpAgent } from '@atproto/api'
|
|
4
|
-
import { ImageInvalidator } from '../../src/image/invalidator'
|
|
5
|
-
|
|
6
|
-
describe('fuzzy matcher', () => {
|
|
7
|
-
let network: TestNetwork
|
|
8
|
-
let agent: AtpAgent
|
|
9
|
-
let sc: SeedClient
|
|
10
|
-
let fuzzyMatcher: FuzzyMatcher
|
|
11
|
-
|
|
12
|
-
let alice: string
|
|
13
|
-
|
|
14
|
-
beforeAll(async () => {
|
|
15
|
-
network = await TestNetwork.create({
|
|
16
|
-
dbPostgresSchema: 'fuzzy_matcher',
|
|
17
|
-
bsky: {
|
|
18
|
-
imgInvalidator: new NoopInvalidator(),
|
|
19
|
-
indexer: {
|
|
20
|
-
fuzzyMatchB64: encode(['evil']),
|
|
21
|
-
},
|
|
22
|
-
},
|
|
23
|
-
})
|
|
24
|
-
fuzzyMatcher = new FuzzyMatcher(['evil', 'mean', 'bad'], ['baddie'])
|
|
25
|
-
agent = network.pds.getClient()
|
|
26
|
-
sc = network.getSeedClient()
|
|
27
|
-
await basicSeed(sc)
|
|
28
|
-
await network.processAll()
|
|
29
|
-
alice = sc.dids.alice
|
|
30
|
-
})
|
|
31
|
-
|
|
32
|
-
afterAll(async () => {
|
|
33
|
-
await network.close()
|
|
34
|
-
})
|
|
35
|
-
|
|
36
|
-
const getAllReports = () => {
|
|
37
|
-
return network.ozone.ctx.db.db
|
|
38
|
-
.selectFrom('moderation_event')
|
|
39
|
-
.where('action', '=', 'com.atproto.admin.defs#modEventReport')
|
|
40
|
-
.selectAll()
|
|
41
|
-
.orderBy('id', 'asc')
|
|
42
|
-
.execute()
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
it('identifies fuzzy matches', () => {
|
|
46
|
-
expect(fuzzyMatcher.getMatches('evil.john.test')).toMatchObject(['evil'])
|
|
47
|
-
expect(fuzzyMatcher.getMatches('john.evil.test')).toMatchObject(['evil'])
|
|
48
|
-
expect(fuzzyMatcher.getMatches('john.test.evil')).toMatchObject(['evil'])
|
|
49
|
-
expect(fuzzyMatcher.getMatches('ev1l.test.john')).toMatchObject(['evil'])
|
|
50
|
-
expect(fuzzyMatcher.getMatches('ev-1l.test.john')).toMatchObject(['evil'])
|
|
51
|
-
expect(fuzzyMatcher.getMatches('ev-11.test.john')).toMatchObject(['evil'])
|
|
52
|
-
expect(fuzzyMatcher.getMatches('ev.-1.l-test.john')).toMatchObject(['evil'])
|
|
53
|
-
})
|
|
54
|
-
|
|
55
|
-
it('identifies fuzzy false positivies', () => {
|
|
56
|
-
expect(fuzzyMatcher.getMatches('john.test')).toHaveLength(0)
|
|
57
|
-
expect(fuzzyMatcher.getMatches('good.john.test')).toHaveLength(0)
|
|
58
|
-
expect(fuzzyMatcher.getMatches('john.baddie.test')).toHaveLength(0)
|
|
59
|
-
})
|
|
60
|
-
|
|
61
|
-
it('doesnt label any of the content in the seed', async () => {
|
|
62
|
-
const reports = await getAllReports()
|
|
63
|
-
expect(reports.length).toBe(0)
|
|
64
|
-
})
|
|
65
|
-
|
|
66
|
-
it('flags a handle with an unacceptable word', async () => {
|
|
67
|
-
await sc.updateHandle(alice, 'evil.test')
|
|
68
|
-
await network.processAll()
|
|
69
|
-
const reports = await getAllReports()
|
|
70
|
-
expect(reports.length).toBe(1)
|
|
71
|
-
expect(reports.at(-1)?.subjectDid).toEqual(alice)
|
|
72
|
-
})
|
|
73
|
-
|
|
74
|
-
it('flags a profile with an unacceptable displayName', async () => {
|
|
75
|
-
const res = await agent.api.com.atproto.repo.putRecord(
|
|
76
|
-
{
|
|
77
|
-
repo: alice,
|
|
78
|
-
collection: 'app.bsky.actor.profile',
|
|
79
|
-
rkey: 'self',
|
|
80
|
-
record: {
|
|
81
|
-
displayName: 'evil alice',
|
|
82
|
-
},
|
|
83
|
-
},
|
|
84
|
-
{ headers: sc.getHeaders(alice), encoding: 'application/json' },
|
|
85
|
-
)
|
|
86
|
-
await network.processAll()
|
|
87
|
-
|
|
88
|
-
const reports = await getAllReports()
|
|
89
|
-
expect(reports.length).toBe(2)
|
|
90
|
-
expect(reports.at(-1)?.subjectUri).toEqual(res.data.uri)
|
|
91
|
-
expect(reports.at(-1)?.subjectCid).toEqual(res.data.cid)
|
|
92
|
-
})
|
|
93
|
-
|
|
94
|
-
it('flags a list with an unacceptable name', async () => {
|
|
95
|
-
const res = await agent.api.com.atproto.repo.createRecord(
|
|
96
|
-
{
|
|
97
|
-
repo: alice,
|
|
98
|
-
collection: 'app.bsky.graph.list',
|
|
99
|
-
rkey: 'list',
|
|
100
|
-
record: {
|
|
101
|
-
name: 'myevillist',
|
|
102
|
-
purpose: 'app.bsky.graph.defs#modList',
|
|
103
|
-
createdAt: new Date().toISOString(),
|
|
104
|
-
},
|
|
105
|
-
},
|
|
106
|
-
{ headers: sc.getHeaders(alice), encoding: 'application/json' },
|
|
107
|
-
)
|
|
108
|
-
await network.processAll()
|
|
109
|
-
|
|
110
|
-
const reports = await getAllReports()
|
|
111
|
-
expect(reports.length).toBe(3)
|
|
112
|
-
expect(reports.at(-1)?.subjectUri).toEqual(res.data.uri)
|
|
113
|
-
expect(reports.at(-1)?.subjectCid).toEqual(res.data.cid)
|
|
114
|
-
})
|
|
115
|
-
|
|
116
|
-
it('flags a feed generator with an unacceptable displayName', async () => {
|
|
117
|
-
const res = await agent.api.com.atproto.repo.createRecord(
|
|
118
|
-
{
|
|
119
|
-
repo: alice,
|
|
120
|
-
collection: 'app.bsky.feed.generator',
|
|
121
|
-
rkey: 'generator',
|
|
122
|
-
record: {
|
|
123
|
-
did: alice,
|
|
124
|
-
displayName: 'myevilfeed',
|
|
125
|
-
createdAt: new Date().toISOString(),
|
|
126
|
-
},
|
|
127
|
-
},
|
|
128
|
-
{ headers: sc.getHeaders(alice), encoding: 'application/json' },
|
|
129
|
-
)
|
|
130
|
-
await network.processAll()
|
|
131
|
-
|
|
132
|
-
const reports = await getAllReports()
|
|
133
|
-
expect(reports.length).toBe(4)
|
|
134
|
-
expect(reports.at(-1)?.subjectUri).toEqual(res.data.uri)
|
|
135
|
-
expect(reports.at(-1)?.subjectCid).toEqual(res.data.cid)
|
|
136
|
-
})
|
|
137
|
-
|
|
138
|
-
it('flags a record with an unacceptable rkey', async () => {
|
|
139
|
-
const res = await agent.api.com.atproto.repo.createRecord(
|
|
140
|
-
{
|
|
141
|
-
repo: alice,
|
|
142
|
-
collection: 'app.bsky.feed.generator',
|
|
143
|
-
rkey: 'evilrkey',
|
|
144
|
-
record: {
|
|
145
|
-
did: alice,
|
|
146
|
-
displayName: 'totally fine feed',
|
|
147
|
-
createdAt: new Date().toISOString(),
|
|
148
|
-
},
|
|
149
|
-
},
|
|
150
|
-
{ headers: sc.getHeaders(alice), encoding: 'application/json' },
|
|
151
|
-
)
|
|
152
|
-
await network.processAll()
|
|
153
|
-
|
|
154
|
-
const reports = await getAllReports()
|
|
155
|
-
expect(reports.length).toBe(5)
|
|
156
|
-
expect(reports.at(-1)?.subjectUri).toEqual(res.data.uri)
|
|
157
|
-
expect(reports.at(-1)?.subjectCid).toEqual(res.data.cid)
|
|
158
|
-
})
|
|
159
|
-
})
|
|
160
|
-
|
|
161
|
-
class NoopInvalidator implements ImageInvalidator {
|
|
162
|
-
async invalidate() {}
|
|
163
|
-
}
|
|
@@ -1,202 +0,0 @@
|
|
|
1
|
-
import fs from 'fs/promises'
|
|
2
|
-
import { TestNetwork, SeedClient, ImageRef, usersSeed } from '@atproto/dev-env'
|
|
3
|
-
import { AtpAgent } from '@atproto/api'
|
|
4
|
-
import { AutoModerator } from '../../src/auto-moderator'
|
|
5
|
-
import { sha256RawToCid } from '@atproto/common'
|
|
6
|
-
import { CID } from 'multiformats/cid'
|
|
7
|
-
import { AtUri } from '@atproto/syntax'
|
|
8
|
-
import { ImageFlagger } from '../../src/auto-moderator/abyss'
|
|
9
|
-
import { ImageInvalidator } from '../../src/image/invalidator'
|
|
10
|
-
import { sha256 } from '@atproto/crypto'
|
|
11
|
-
import { ids } from '../../src/lexicon/lexicons'
|
|
12
|
-
import { TestOzone } from '@atproto/dev-env/src/ozone'
|
|
13
|
-
import { PrimaryDatabase } from '../../src'
|
|
14
|
-
|
|
15
|
-
// outside of test suite so that TestLabeler can access them
|
|
16
|
-
let badCid1: CID | undefined = undefined
|
|
17
|
-
let badCid2: CID | undefined = undefined
|
|
18
|
-
|
|
19
|
-
describe('takedowner', () => {
|
|
20
|
-
let network: TestNetwork
|
|
21
|
-
let ozone: TestOzone
|
|
22
|
-
let bskyDb: PrimaryDatabase
|
|
23
|
-
let autoMod: AutoModerator
|
|
24
|
-
let testInvalidator: TestInvalidator
|
|
25
|
-
let pdsAgent: AtpAgent
|
|
26
|
-
let sc: SeedClient
|
|
27
|
-
let alice: string
|
|
28
|
-
let badBlob1: ImageRef
|
|
29
|
-
let badBlob2: ImageRef
|
|
30
|
-
let goodBlob: ImageRef
|
|
31
|
-
|
|
32
|
-
beforeAll(async () => {
|
|
33
|
-
testInvalidator = new TestInvalidator()
|
|
34
|
-
network = await TestNetwork.create({
|
|
35
|
-
dbPostgresSchema: 'bsky_automod_takedown',
|
|
36
|
-
bsky: {
|
|
37
|
-
imgInvalidator: testInvalidator,
|
|
38
|
-
},
|
|
39
|
-
})
|
|
40
|
-
ozone = network.ozone
|
|
41
|
-
bskyDb = network.bsky.ctx.db.getPrimary()
|
|
42
|
-
autoMod = network.bsky.indexer.ctx.autoMod
|
|
43
|
-
autoMod.imageFlagger = new TestFlagger()
|
|
44
|
-
pdsAgent = new AtpAgent({ service: network.pds.url })
|
|
45
|
-
sc = network.getSeedClient()
|
|
46
|
-
await usersSeed(sc)
|
|
47
|
-
await network.processAll()
|
|
48
|
-
alice = sc.dids.alice
|
|
49
|
-
const fileBytes1 = await fs.readFile(
|
|
50
|
-
'../dev-env/src/seed/img/key-portrait-small.jpg',
|
|
51
|
-
)
|
|
52
|
-
const fileBytes2 = await fs.readFile(
|
|
53
|
-
'../dev-env/src/seed/img/key-portrait-large.jpg',
|
|
54
|
-
)
|
|
55
|
-
badCid1 = sha256RawToCid(await sha256(fileBytes1))
|
|
56
|
-
badCid2 = sha256RawToCid(await sha256(fileBytes2))
|
|
57
|
-
goodBlob = await sc.uploadFile(
|
|
58
|
-
alice,
|
|
59
|
-
'../dev-env/src/seed/img/key-landscape-small.jpg',
|
|
60
|
-
'image/jpeg',
|
|
61
|
-
)
|
|
62
|
-
badBlob1 = await sc.uploadFile(
|
|
63
|
-
alice,
|
|
64
|
-
'../dev-env/src/seed/img/key-portrait-small.jpg',
|
|
65
|
-
'image/jpeg',
|
|
66
|
-
)
|
|
67
|
-
badBlob2 = await sc.uploadFile(
|
|
68
|
-
alice,
|
|
69
|
-
'../dev-env/src/seed/img/key-portrait-large.jpg',
|
|
70
|
-
'image/jpeg',
|
|
71
|
-
)
|
|
72
|
-
})
|
|
73
|
-
|
|
74
|
-
afterAll(async () => {
|
|
75
|
-
await network.close()
|
|
76
|
-
})
|
|
77
|
-
|
|
78
|
-
it('takes down flagged content in posts', async () => {
|
|
79
|
-
const post = await sc.post(alice, 'blah', undefined, [goodBlob, badBlob1])
|
|
80
|
-
await network.processAll()
|
|
81
|
-
const [modStatus, takedownEvent] = await Promise.all([
|
|
82
|
-
ozone.ctx.db.db
|
|
83
|
-
.selectFrom('moderation_subject_status')
|
|
84
|
-
.where('did', '=', alice)
|
|
85
|
-
.where(
|
|
86
|
-
'recordPath',
|
|
87
|
-
'=',
|
|
88
|
-
`${post.ref.uri.collection}/${post.ref.uri.rkey}`,
|
|
89
|
-
)
|
|
90
|
-
.select(['takendown', 'id'])
|
|
91
|
-
.executeTakeFirst(),
|
|
92
|
-
ozone.ctx.db.db
|
|
93
|
-
.selectFrom('moderation_event')
|
|
94
|
-
.where('subjectDid', '=', alice)
|
|
95
|
-
.where('action', '=', 'com.atproto.admin.defs#modEventTakedown')
|
|
96
|
-
.selectAll()
|
|
97
|
-
.executeTakeFirst(),
|
|
98
|
-
])
|
|
99
|
-
if (!modStatus || !takedownEvent) {
|
|
100
|
-
throw new Error('expected mod action')
|
|
101
|
-
}
|
|
102
|
-
expect(modStatus.takendown).toEqual(true)
|
|
103
|
-
const record = await bskyDb.db
|
|
104
|
-
.selectFrom('record')
|
|
105
|
-
.where('uri', '=', post.ref.uriStr)
|
|
106
|
-
.select('takedownRef')
|
|
107
|
-
.executeTakeFirst()
|
|
108
|
-
expect(record?.takedownRef).toEqual(`BSKY-TAKEDOWN-${takedownEvent.id}`)
|
|
109
|
-
|
|
110
|
-
const recordPds = await network.pds.ctx.actorStore.read(
|
|
111
|
-
post.ref.uri.hostname,
|
|
112
|
-
(store) =>
|
|
113
|
-
store.db.db
|
|
114
|
-
.selectFrom('record')
|
|
115
|
-
.where('uri', '=', post.ref.uriStr)
|
|
116
|
-
.select('takedownRef')
|
|
117
|
-
.executeTakeFirst(),
|
|
118
|
-
)
|
|
119
|
-
expect(recordPds?.takedownRef).toEqual(`BSKY-TAKEDOWN-${takedownEvent.id}`)
|
|
120
|
-
|
|
121
|
-
expect(testInvalidator.invalidated.length).toBe(1)
|
|
122
|
-
expect(testInvalidator.invalidated[0].subject).toBe(
|
|
123
|
-
badBlob1.image.ref.toString(),
|
|
124
|
-
)
|
|
125
|
-
})
|
|
126
|
-
|
|
127
|
-
it('takes down flagged content in profiles', async () => {
|
|
128
|
-
const res = await pdsAgent.api.com.atproto.repo.putRecord(
|
|
129
|
-
{
|
|
130
|
-
repo: alice,
|
|
131
|
-
collection: ids.AppBskyActorProfile,
|
|
132
|
-
rkey: 'self',
|
|
133
|
-
record: {
|
|
134
|
-
avatar: badBlob2.image,
|
|
135
|
-
},
|
|
136
|
-
},
|
|
137
|
-
{ headers: sc.getHeaders(alice), encoding: 'application/json' },
|
|
138
|
-
)
|
|
139
|
-
await network.processAll()
|
|
140
|
-
const [modStatus, takedownEvent] = await Promise.all([
|
|
141
|
-
ozone.ctx.db.db
|
|
142
|
-
.selectFrom('moderation_subject_status')
|
|
143
|
-
.where('did', '=', alice)
|
|
144
|
-
.where('recordPath', '=', `${ids.AppBskyActorProfile}/self`)
|
|
145
|
-
.select(['takendown', 'id'])
|
|
146
|
-
.executeTakeFirst(),
|
|
147
|
-
ozone.ctx.db.db
|
|
148
|
-
.selectFrom('moderation_event')
|
|
149
|
-
.where('subjectDid', '=', alice)
|
|
150
|
-
.where(
|
|
151
|
-
'subjectUri',
|
|
152
|
-
'=',
|
|
153
|
-
AtUri.make(alice, ids.AppBskyActorProfile, 'self').toString(),
|
|
154
|
-
)
|
|
155
|
-
.where('action', '=', 'com.atproto.admin.defs#modEventTakedown')
|
|
156
|
-
.selectAll()
|
|
157
|
-
.executeTakeFirst(),
|
|
158
|
-
])
|
|
159
|
-
if (!modStatus || !takedownEvent) {
|
|
160
|
-
throw new Error('expected mod action')
|
|
161
|
-
}
|
|
162
|
-
expect(modStatus.takendown).toEqual(true)
|
|
163
|
-
const recordBsky = await bskyDb.db
|
|
164
|
-
.selectFrom('record')
|
|
165
|
-
.where('uri', '=', res.data.uri)
|
|
166
|
-
.select('takedownRef')
|
|
167
|
-
.executeTakeFirst()
|
|
168
|
-
expect(recordBsky?.takedownRef).toEqual(`BSKY-TAKEDOWN-${takedownEvent.id}`)
|
|
169
|
-
|
|
170
|
-
const recordPds = await network.pds.ctx.actorStore.read(alice, (store) =>
|
|
171
|
-
store.db.db
|
|
172
|
-
.selectFrom('record')
|
|
173
|
-
.where('uri', '=', res.data.uri)
|
|
174
|
-
.select('takedownRef')
|
|
175
|
-
.executeTakeFirst(),
|
|
176
|
-
)
|
|
177
|
-
expect(recordPds?.takedownRef).toEqual(`BSKY-TAKEDOWN-${takedownEvent.id}`)
|
|
178
|
-
|
|
179
|
-
expect(testInvalidator.invalidated.length).toBe(2)
|
|
180
|
-
expect(testInvalidator.invalidated[1].subject).toBe(
|
|
181
|
-
badBlob2.image.ref.toString(),
|
|
182
|
-
)
|
|
183
|
-
})
|
|
184
|
-
})
|
|
185
|
-
|
|
186
|
-
class TestInvalidator implements ImageInvalidator {
|
|
187
|
-
public invalidated: { subject: string; paths: string[] }[] = []
|
|
188
|
-
async invalidate(subject: string, paths: string[]) {
|
|
189
|
-
this.invalidated.push({ subject, paths })
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
class TestFlagger implements ImageFlagger {
|
|
194
|
-
async scanImage(_did: string, cid: CID, _uri: AtUri): Promise<string[]> {
|
|
195
|
-
if (cid.equals(badCid1)) {
|
|
196
|
-
return ['kill-it']
|
|
197
|
-
} else if (cid.equals(badCid2)) {
|
|
198
|
-
return ['with-fire']
|
|
199
|
-
}
|
|
200
|
-
return []
|
|
201
|
-
}
|
|
202
|
-
}
|