atproto/packages/pds/tests/account-deactivation.test.ts
Daniel Holmgren 255d5ea1f0
Account deactivation ()
* subscribe repos lex: new #account event type

* lex: getAccountStatus endpoint

* lex: add account status errors to sync methods

* tweak type of token union

* fix getAccountStatus parameter name

* codegen

* Account -> Repo

* re-codegen

* update errors in sync methods

* add getRepoStatus route

* add account events to sequencer

* emit account evts

* fix test + small bugfixin

* handle evt on bsky side

* codegen

* loggable message

* schema tweaks

* build errors & tidy

* tidy account deactivation tests

* more subscribe repos tests

* identity evt tests + tidy

* return optional did doc on identity evts

* update identity evt

* update impl for identity evt handles

* add description to handle field

* status on listRepos & notate deprecated firehose events

* return status on listRepos

* pr feedback

* tests

* protos

* add status to session schemas

* codegen

* revamp auth-verifier

* thread through agent

* fix tests

* fix account deletion test

* fix more tests

* fix type error in repo.test

* bsky index account evts

* apply in appview

* add to admin route

* add deactivatedAt to ozone views

* pds tests

* appview tests

* ozone test

* fix bsky test

* fix agent test

* fix indexing test

* tweak session schemas

* update session routes & clean up status handling in pds & agent

* changeset

* patch pds test

* rm active from knownValues

---------

Co-authored-by: bryan newbold <bnewbold@robocracy.org>
2024-05-31 16:39:21 -05:00

204 lines
5.4 KiB
TypeScript

import AtpAgent from '@atproto/api'
import {
ImageRef,
SeedClient,
TestNetworkNoAppView,
basicSeed,
} from '@atproto/dev-env'
describe('account deactivation', () => {
let network: TestNetworkNoAppView
let sc: SeedClient
let agent: AtpAgent
let alice: string
let aliceAvatar: ImageRef
beforeAll(async () => {
network = await TestNetworkNoAppView.create({
dbPostgresSchema: 'account_deactivation',
})
sc = network.getSeedClient()
agent = network.pds.getClient()
await basicSeed(sc)
alice = sc.dids.alice
aliceAvatar = await sc.uploadFile(
alice,
'../dev-env/src/seed/img/key-portrait-small.jpg',
'image/jpeg',
)
await sc.updateProfile(alice, {
avatar: aliceAvatar.image,
})
await network.processAll()
})
afterAll(async () => {
await network.close()
})
it('deactivates account', async () => {
await agent.com.atproto.server.deactivateAccount(
{},
{ encoding: 'application/json', headers: sc.getHeaders(alice) },
)
})
it('returns deactivated status', async () => {
const res = await agent.com.atproto.sync.getRepoStatus({ did: alice })
expect(res.data).toEqual({
did: alice,
active: false,
status: 'deactivated',
})
const adminRes = await agent.com.atproto.admin.getAccountInfo(
{
did: alice,
},
{ headers: network.pds.adminAuthHeaders() },
)
expect(typeof adminRes.data.deactivatedAt).toBeDefined()
})
it('no longer serves repo data', async () => {
await expect(
agent.com.atproto.sync.getRepo({ did: alice }),
).rejects.toThrow(/Repo has been deactivated/)
await expect(
agent.com.atproto.sync.getLatestCommit({ did: alice }),
).rejects.toThrow(/Repo has been deactivated/)
await expect(
agent.com.atproto.sync.listBlobs({ did: alice }),
).rejects.toThrow(/Repo has been deactivated/)
const recordUri = sc.posts[alice][0].ref.uri
await expect(
agent.com.atproto.sync.getRecord({
did: alice,
collection: recordUri.collection,
rkey: recordUri.rkey,
}),
).rejects.toThrow(/Repo has been deactivated/)
await expect(
agent.com.atproto.repo.getRecord({
repo: alice,
collection: recordUri.collection,
rkey: recordUri.rkey,
}),
).rejects.toThrow()
await expect(
agent.com.atproto.repo.describeRepo({
repo: alice,
}),
).rejects.toThrow(/Repo has been deactivated/)
await expect(
agent.com.atproto.sync.getBlob({
did: alice,
cid: aliceAvatar.image.ref.toString(),
}),
).rejects.toThrow(/Repo has been deactivated/)
const listedRepos = await agent.com.atproto.sync.listRepos()
const listedAlice = listedRepos.data.repos.find((r) => r.did === alice)
expect(listedAlice?.active).toBe(false)
expect(listedAlice?.status).toBe('deactivated')
})
it('no longer resolves handle', async () => {
await expect(
agent.com.atproto.identity.resolveHandle({
handle: sc.accounts[alice].handle,
}),
).rejects.toThrow()
})
it('still allows login and returns status', async () => {
const res = await agent.com.atproto.server.createSession({
identifier: alice,
password: sc.accounts[alice].password,
})
expect(res.data.status).toEqual('deactivated')
})
it('returns status on getSession', async () => {
const res = await agent.com.atproto.server.getSession(undefined, {
headers: sc.getHeaders(alice),
})
expect(res.data.status).toEqual('deactivated')
})
it('does not allow writes', async () => {
const createAttempt = agent.com.atproto.repo.createRecord(
{
repo: alice,
collection: 'app.bsky.feed.post',
record: {
text: 'blah',
createdAt: new Date().toISOString(),
},
},
{
encoding: 'application/json',
headers: sc.getHeaders(alice),
},
)
const uri = sc.posts[alice][0].ref.uri
await expect(createAttempt).rejects.toThrow('Account is deactivated')
const putAttempt = agent.com.atproto.repo.putRecord(
{
repo: alice,
collection: uri.collection,
rkey: uri.rkey,
record: {
text: 'blah',
createdAt: new Date().toISOString(),
},
},
{
encoding: 'application/json',
headers: sc.getHeaders(alice),
},
)
await expect(putAttempt).rejects.toThrow('Account is deactivated')
const deleteAttempt = agent.com.atproto.repo.deleteRecord(
{
repo: alice,
collection: uri.collection,
rkey: uri.rkey,
},
{
encoding: 'application/json',
headers: sc.getHeaders(alice),
},
)
await expect(deleteAttempt).rejects.toThrow('Account is deactivated')
})
it('reactivates', async () => {
await agent.com.atproto.server.activateAccount(undefined, {
headers: sc.getHeaders(alice),
})
await agent.com.atproto.sync.getRepo({ did: alice })
const statusRes = await agent.com.atproto.sync.getRepoStatus({ did: alice })
expect(statusRes.data.active).toBe(true)
expect(statusRes.data.status).toBeUndefined()
const adminRes = await agent.com.atproto.admin.getAccountInfo(
{
did: alice,
},
{ headers: network.pds.adminAuthHeaders() },
)
expect(adminRes.data.deactivatedAt).toBeUndefined()
})
})