638f5a8312
* Fix avatar path resolution in dev-env * changeset * extract dev-env assets to dedicated folder * add comment * fix fmt
222 lines
6.2 KiB
TypeScript
222 lines
6.2 KiB
TypeScript
import { AtpAgent, AtUri } from '@atproto/api'
|
|
import {
|
|
mockNetworkUtilities,
|
|
SeedClient,
|
|
TestNetworkNoAppView,
|
|
TestPds,
|
|
} from '@atproto/dev-env'
|
|
import { readCar } from '@atproto/repo'
|
|
import assert from 'assert'
|
|
import { ids } from '../src/lexicon/lexicons'
|
|
|
|
describe('account migration', () => {
|
|
let network: TestNetworkNoAppView
|
|
let newPds: TestPds
|
|
|
|
let sc: SeedClient
|
|
let oldAgent: AtpAgent
|
|
let newAgent: AtpAgent
|
|
|
|
let alice: string
|
|
|
|
beforeAll(async () => {
|
|
network = await TestNetworkNoAppView.create({
|
|
dbPostgresSchema: 'account_migration',
|
|
})
|
|
newPds = await TestPds.create({
|
|
didPlcUrl: network.plc.url,
|
|
})
|
|
mockNetworkUtilities(newPds)
|
|
|
|
sc = network.getSeedClient()
|
|
oldAgent = network.pds.getClient()
|
|
newAgent = newPds.getClient()
|
|
|
|
await sc.createAccount('alice', {
|
|
email: 'alice@test.com',
|
|
handle: 'alice.test',
|
|
password: 'alice-pass',
|
|
})
|
|
alice = sc.dids.alice
|
|
|
|
for (let i = 0; i < 100; i++) {
|
|
await sc.post(alice, 'test post')
|
|
}
|
|
const img1 = await sc.uploadFile(
|
|
alice,
|
|
'../dev-env/assets/at.png',
|
|
'image/png',
|
|
)
|
|
const img2 = await sc.uploadFile(
|
|
alice,
|
|
'../dev-env/assets/key-alt.jpg',
|
|
'image/jpeg',
|
|
)
|
|
const img3 = await sc.uploadFile(
|
|
alice,
|
|
'../dev-env/assets/key-landscape-small.jpg',
|
|
'image/jpeg',
|
|
)
|
|
|
|
await sc.post(alice, 'test', undefined, [img1])
|
|
await sc.post(alice, 'test', undefined, [img1, img2])
|
|
await sc.post(alice, 'test', undefined, [img3])
|
|
|
|
await network.processAll()
|
|
|
|
await oldAgent.login({
|
|
identifier: sc.accounts[alice].handle,
|
|
password: sc.accounts[alice].password,
|
|
})
|
|
})
|
|
|
|
afterAll(async () => {
|
|
await newPds.close()
|
|
await network.close()
|
|
})
|
|
|
|
it('migrates an account', async () => {
|
|
const describeRes = await newAgent.api.com.atproto.server.describeServer()
|
|
const newServerDid = describeRes.data.did
|
|
|
|
const serviceJwtRes = await oldAgent.com.atproto.server.getServiceAuth({
|
|
aud: newServerDid,
|
|
lxm: ids.ComAtprotoServerCreateAccount,
|
|
})
|
|
const serviceJwt = serviceJwtRes.data.token
|
|
|
|
await newAgent.api.com.atproto.server.createAccount(
|
|
{
|
|
handle: 'new-alice.test',
|
|
email: 'alice@test.com',
|
|
password: 'alice-pass',
|
|
did: alice,
|
|
},
|
|
{
|
|
headers: { authorization: `Bearer ${serviceJwt}` },
|
|
encoding: 'application/json',
|
|
},
|
|
)
|
|
await newAgent.login({
|
|
identifier: 'new-alice.test',
|
|
password: 'alice-pass',
|
|
})
|
|
|
|
const statusRes1 = await newAgent.com.atproto.server.checkAccountStatus()
|
|
expect(statusRes1.data).toMatchObject({
|
|
activated: false,
|
|
validDid: false,
|
|
repoBlocks: 2, // commit & empty data root
|
|
indexedRecords: 0,
|
|
privateStateValues: 0,
|
|
expectedBlobs: 0,
|
|
importedBlobs: 0,
|
|
})
|
|
|
|
const repoRes = await oldAgent.com.atproto.sync.getRepo({ did: alice })
|
|
const carBlocks = await readCar(repoRes.data)
|
|
|
|
await newAgent.com.atproto.repo.importRepo(repoRes.data, {
|
|
encoding: 'application/vnd.ipld.car',
|
|
})
|
|
|
|
const statusRes2 = await newAgent.com.atproto.server.checkAccountStatus()
|
|
expect(statusRes2.data).toMatchObject({
|
|
activated: false,
|
|
validDid: false,
|
|
indexedRecords: 103,
|
|
privateStateValues: 0,
|
|
expectedBlobs: 3,
|
|
importedBlobs: 0,
|
|
})
|
|
expect(statusRes2.data.repoBlocks).toBe(carBlocks.blocks.size)
|
|
|
|
const missingBlobs = await newAgent.com.atproto.repo.listMissingBlobs()
|
|
expect(missingBlobs.data.blobs.length).toBe(3)
|
|
|
|
let blobCursor: string | undefined = undefined
|
|
do {
|
|
const listedBlobs = await oldAgent.com.atproto.sync.listBlobs({
|
|
did: alice,
|
|
cursor: blobCursor,
|
|
})
|
|
for (const cid of listedBlobs.data.cids) {
|
|
const blobRes = await oldAgent.com.atproto.sync.getBlob({
|
|
did: alice,
|
|
cid,
|
|
})
|
|
await newAgent.com.atproto.repo.uploadBlob(blobRes.data, {
|
|
encoding: blobRes.headers['content-type'],
|
|
})
|
|
}
|
|
blobCursor = listedBlobs.data.cursor
|
|
} while (blobCursor)
|
|
|
|
const statusRes3 = await newAgent.com.atproto.server.checkAccountStatus()
|
|
expect(statusRes3.data.expectedBlobs).toBe(3)
|
|
expect(statusRes3.data.importedBlobs).toBe(3)
|
|
|
|
const prefs = await oldAgent.api.app.bsky.actor.getPreferences()
|
|
await newAgent.api.app.bsky.actor.putPreferences(prefs.data)
|
|
|
|
const getDidCredentials =
|
|
await newAgent.com.atproto.identity.getRecommendedDidCredentials()
|
|
|
|
await oldAgent.com.atproto.identity.requestPlcOperationSignature()
|
|
const res = await network.pds.ctx.accountManager.db.db
|
|
.selectFrom('email_token')
|
|
.selectAll()
|
|
.where('did', '=', alice)
|
|
.where('purpose', '=', 'plc_operation')
|
|
.executeTakeFirst()
|
|
const token = res?.token
|
|
assert(token)
|
|
|
|
const plcOp = await oldAgent.com.atproto.identity.signPlcOperation({
|
|
token,
|
|
...getDidCredentials.data,
|
|
})
|
|
|
|
await newAgent.com.atproto.identity.submitPlcOperation({
|
|
operation: plcOp.data.operation,
|
|
})
|
|
|
|
await newAgent.com.atproto.server.activateAccount()
|
|
|
|
const statusRes4 = await newAgent.com.atproto.server.checkAccountStatus()
|
|
expect(statusRes4.data).toMatchObject({
|
|
activated: true,
|
|
validDid: true,
|
|
indexedRecords: 103,
|
|
privateStateValues: 0,
|
|
expectedBlobs: 3,
|
|
importedBlobs: 3,
|
|
})
|
|
|
|
await oldAgent.com.atproto.server.deactivateAccount({})
|
|
|
|
const statusResOldPds =
|
|
await oldAgent.com.atproto.server.checkAccountStatus()
|
|
expect(statusResOldPds.data).toMatchObject({
|
|
activated: false,
|
|
validDid: false,
|
|
})
|
|
|
|
const postRes = await newAgent.api.app.bsky.feed.post.create(
|
|
{ repo: alice },
|
|
{
|
|
text: 'new pds!',
|
|
createdAt: new Date().toISOString(),
|
|
},
|
|
)
|
|
const postUri = new AtUri(postRes.uri)
|
|
const fetchedPost = await newAgent.api.app.bsky.feed.post.get({
|
|
repo: postUri.hostname,
|
|
rkey: postUri.rkey,
|
|
})
|
|
expect(fetchedPost.value.text).toEqual('new pds!')
|
|
const statusRes5 = await newAgent.com.atproto.server.checkAccountStatus()
|
|
expect(statusRes5.data.indexedRecords).toBe(104)
|
|
})
|
|
})
|