Skip to content

Commit

Permalink
working on tests
Browse files Browse the repository at this point in the history
Signed-off-by: blu3beri <[email protected]>
  • Loading branch information
blu3beri committed Mar 13, 2023
1 parent f8e423c commit fac9efb
Show file tree
Hide file tree
Showing 4 changed files with 190 additions and 108 deletions.
16 changes: 11 additions & 5 deletions packages/indy-sdk-to-askar-migration/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
"main": "build/index",
"types": "build/index",
"version": "0.3.3",
"files": ["build"],
"files": [
"build"
],
"license": "Apache-2.0",
"publishConfig": {
"access": "public"
Expand All @@ -22,12 +24,16 @@
"test": "jest"
},
"dependencies": {
"@aries-framework/anoncreds": "0.4.0-alpha.22",
"@aries-framework/core": "0.3.3",
"@hyperledger/aries-askar-shared": "0.1.0-dev.3"
"@aries-framework/anoncreds": "0.4.0-alpha.71",
"@aries-framework/askar": "0.4.0-alpha.71",
"@aries-framework/core": "0.4.0-alpha.71",
"@aries-framework/indy-sdk": "0.4.0-alpha.71",
"@aries-framework/node": "0.4.0-alpha.71",
"@hyperledger/aries-askar-shared": "file:/Users/beri/Developer/work/hyperledger/aries-askar/wrappers/javascript/aries-askar-shared"
},
"devDependencies": {
"@hyperledger/aries-askar-nodejs": "0.1.0-dev.3",
"@hyperledger/aries-askar-nodejs": "file:/Users/beri/Developer/work/hyperledger/aries-askar/wrappers/javascript/aries-askar-nodejs",
"indy-sdk": "1.16.0-dev-1655",
"rimraf": "^4.0.7",
"typescript": "~4.9.4"
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,36 +1,69 @@
/* eslint-disable no-console */
import type { AnonCredsCredentialValue } from '@aries-framework/anoncreds'
import type { Agent, FileSystem } from '@aries-framework/core'
import type { EntryObject } from '@hyperledger/aries-askar-shared'

import { AnonCredsCredentialRecord, AnonCredsLinkSecretRecord } from '@aries-framework/anoncreds'
import { JsonTransformer, TypedArrayEncoder } from '@aries-framework/core'
import { InjectionSymbols, KeyDerivationMethod, JsonTransformer, TypedArrayEncoder } from '@aries-framework/core'
import { Key, KeyAlgs, Store, StoreKeyMethod } from '@hyperledger/aries-askar-shared'

import { IndySdkToAskarMigrationError } from './errors/IndySdkToAskarMigrationError'
import { transformFromRecordTagValues } from './utils'

export class IndySdkToAskarMigrationUpdater {
private store: Store
private walletName: string
private defaultLinkSecretId: string
private agent: Agent

private constructor(store: Store, walletName: string) {
private constructor(store: Store, walletName: string, agent: Agent, defaultLinkSecretId?: string) {
this.store = store
this.walletName = walletName
this.agent = agent
this.defaultLinkSecretId = defaultLinkSecretId ?? walletName
}

public static async init(uri: string, walletName: string, masterPassword: string) {
const store = await Store.open({ uri, passKey: masterPassword, keyMethod: StoreKeyMethod.Raw })
return new IndySdkToAskarMigrationUpdater(store, walletName)
public static async initialize({ uri, agent }: { uri: string; agent: Agent }) {
const {
config: { walletConfig },
} = agent
if (!walletConfig) throw new IndySdkToAskarMigrationError('Wallet config is required for updating the wallet')

const keyMethod =
walletConfig.keyDerivationMethod == KeyDerivationMethod.Raw ? StoreKeyMethod.Raw : StoreKeyMethod.Kdf
const store = await Store.open({ uri, passKey: walletConfig.key, keyMethod })
return new IndySdkToAskarMigrationUpdater(store, walletConfig.id, agent)
}

private async backupDatabase() {
const fs = this.agent.dependencyManager.resolve<FileSystem>(InjectionSymbols.FileSystem)
}

private async revertDatabase() {
const fs = this.agent.dependencyManager.resolve<FileSystem>(InjectionSymbols.FileSystem)
}

private async cleanBackup() {
const fs = this.agent.dependencyManager.resolve<FileSystem>(InjectionSymbols.FileSystem)
}

public async update() {
await this.updateKeys()
await this.updateMasterSecret()
await this.updateCredentials()
try {
await this.updateKeys()
await this.updateMasterSecret()
await this.updateCredentials()
} catch (e) {
this.agent.config.logger?.error('Migration failed. Reverting state.')

await this.revertDatabase()
} finally {
await this.cleanBackup()
}
}

private async updateKeys() {
const category = 'Indy::Key'

console.log(`Updating ${category}`)
this.agent.config.logger?.trace(`[indy-sdk-to-askar-migration]: Updating category: ${category}`)

let updateCount = 0
const session = this.store.transaction()
Expand All @@ -56,16 +89,19 @@ export class IndySdkToAskarMigrationUpdater {
await txn.commit()
}

console.log(`Updated ${updateCount} instances inside ${category}`)
this.agent.config.logger?.trace(
`[indy-sdk-to-askar-migration]: Updated ${updateCount} instances inside ${category}`
)
}

private async updateMasterSecret() {
const category = 'Indy::MasterSecret'

console.log(`Updating ${category}`)
this.agent.config.logger?.trace(`[indy-sdk-to-askar-migration]: Updating category: ${category}`)

let updateCount = 0
const session = this.store.transaction()

for (;;) {
const txn = await session.open()
const masterSecrets = await txn.fetchAll({ category, limit: 50 })
Expand All @@ -74,12 +110,14 @@ export class IndySdkToAskarMigrationUpdater {
break
}

let id = ''
if (!masterSecrets.some((ms: EntryObject) => ms.name === this.defaultLinkSecretId)) {
throw new IndySdkToAskarMigrationError('defaultLinkSecretId can not be established')
}

for (const row of masterSecrets) {
const isDefault = masterSecrets.length === 0 ?? row.name === this.walletName
await txn.remove({ category, name: row.name })

const isDefault = row.name === this.walletName

const {
value: { ms },
} = JSON.parse(row.value as string) as { value: { ms: string } }
Expand All @@ -90,20 +128,21 @@ export class IndySdkToAskarMigrationUpdater {

const tags = transformFromRecordTagValues(record.getTags())

id = record.id
await txn.insert({ category: record.type, name: record.id, value, tags })
updateCount++
}
await txn.commit()
}

console.log(`Updated ${updateCount} instances inside ${category}`)
this.agent.config.logger?.trace(
`[indy-sdk-to-askar-migration]: Updated ${updateCount} instances inside ${category}`
)
}

private async updateCredentials() {
const category = 'Indy::Credential'

console.log(`Updating ${category}`)
this.agent.config.logger?.trace(`[indy-sdk-to-askar-migration]: Updating category: ${category}`)

let updateCount = 0
const session = this.store.transaction()
Expand Down Expand Up @@ -136,11 +175,11 @@ export class IndySdkToAskarMigrationUpdater {
schemaName,
schemaIssuerId,
schemaVersion,
credentialId: 'TODO',
linkSecretId: 'TODO',
credentialId: row.name,
linkSecretId: this.defaultLinkSecretId,
})

const tags = { ...this.credentialTags(data), ...transformFromRecordTagValues(record.getTags()) }
const tags = transformFromRecordTagValues(record.getTags())
const value = JsonTransformer.serialize(record)

await txn.insert({ category: record.type, name: record.id, value, tags })
Expand All @@ -149,37 +188,8 @@ export class IndySdkToAskarMigrationUpdater {
await txn.commit()
}

console.log(`Updated ${updateCount} instances inside ${category}`)
}

private credentialTags(credentialData: Record<string, unknown>) {
const schemaId = credentialData.schema_id as string
const credentialDefinitionId = credentialData.cred_def_id as string

const { did, schemaName, schemaVersion } =
/^(?<did>\w+):2:(?<schemaName>[^:]+):(?<schemaVersion>[^:]+)$/.exec(schemaId)?.groups ?? {}
if (!did || !schemaName || !schemaVersion) throw new Error(`Error parsing credential schema id: ${schemaId}`)

const { issuerId } =
/^(?<issuerId>\w+):3:CL:(?<schemaIdOrSeqNo>[^:]+):(?<tag>[^:]+)$/.exec(credentialDefinitionId)?.groups ?? {}
if (!issuerId) throw new Error(`Error parsing credential definition id: ${credentialDefinitionId}`)

const tags = {
schema_id: schemaId,
schema_issuer_did: did,
schema_name: schemaName,
schema_version: schemaVersion,
issuer_did: issuerId,
cred_def_id: credentialDefinitionId,
rev_reg_id: (credentialData.rev_reg_id as string) ?? 'None',
} as Record<string, string>

for (const [k, attrValue] of Object.entries(credentialData.values as Record<string, { raw: string }>)) {
const attrName = k.replace(' ', '')
const id = `attr::${attrName}::value`
tags[id] = attrValue.raw
}

return tags
this.agent.config.logger?.trace(
`[indy-sdk-to-askar-migration]: Updated ${updateCount} instances inside ${category}`
)
}
}
98 changes: 72 additions & 26 deletions packages/indy-sdk-to-askar-migration/tests/migrate.test.ts
Original file line number Diff line number Diff line change
@@ -1,39 +1,85 @@
import { ariesAskar } from '@hyperledger/aries-askar-nodejs'
/* eslint-disable @typescript-eslint/no-non-null-assertion */
import type { InitConfig, WalletConfig } from '@aries-framework/core'

import { AskarModule } from '@aries-framework/askar'
import { utils, ConsoleLogger, LogLevel, KeyDerivationMethod, Agent } from '@aries-framework/core'
import { IndySdkModule } from '@aries-framework/indy-sdk'
import { agentDependencies } from '@aries-framework/node'
import { ariesAskar, Migration } from '@hyperledger/aries-askar-nodejs'
import { registerAriesAskar } from '@hyperledger/aries-askar-shared'
import fs from 'fs'
import indy from 'indy-sdk'
import { homedir } from 'os'
import path from 'path'

import { IndySdkToAskarMigrationUpdater } from '../src'

describe('Migrate', () => {
const config: InitConfig = {
label: 'test-agent',
walletConfig: {
id: `walletwallet.0-${utils.uuid()}`,
key: 'GfwU1DC7gEZNs3w41tjBiZYj7BNToDoFEqKY6wZXqs1A',
keyDerivationMethod: KeyDerivationMethod.Raw,
},
// logger: new ConsoleLogger(LogLevel.trace),
}

const oldAgent = new Agent({
config,
modules: { indySdk: new IndySdkModule({ indySdk: indy }) },
dependencies: agentDependencies,
})

const newAgent = new Agent({
config,
modules: { askar: new AskarModule() },
dependencies: agentDependencies,
})

const oldDbPath = `${homedir()}/.indy_client/wallet/${oldAgent.config.walletConfig?.id}/sqlite.db`
const newDbPath = `${homedir()}/.afj/data/wallet/${newAgent.config.walletConfig?.id}/sqlite.db`

beforeAll(() => {
registerAriesAskar({ askar: ariesAskar })
})

// beforeEach(async () => {
// await new Promise((resolve) =>
// fs.copyFile(
// '/Users/beri/.indy_client/wallet/walletwallet.0/sqlite.db',
// '/Users/beri/.indy_client/wallet/walletwallet.0/sqlite.bak.db',
// resolve
// )
// )
// })

// TODO: update with an aca-py issued revokable credential
// community agent MIGHT have revocrevoc
// TODO: should take uninitialized agent
test('indy-sdk sqlite to aries-askar sqlite', async () => {
// try {
const walletName = 'walletwallet.0'
const walletKey = 'GfwU1DC7gEZNs3w41tjBiZYj7BNToDoFEqKY6wZXqs1A'
const dbPath = `/Users/beri/Developer/work/hyperledger/aries-askar/tests/indy_wallet_sqlite_upgraded.db`
const specUri = `sqlite://${dbPath}`
const updater = await IndySdkToAskarMigrationUpdater.init(specUri, walletName, walletKey)
const genericRecord = { foo: 'bar' }

await oldAgent.initialize()

const record = await oldAgent.genericRecords.save({ content: genericRecord })

const walletConfig: WalletConfig = {
key: oldAgent.config.walletConfig!.key,
id: oldAgent.config.walletConfig!.id,
keyDerivationMethod: oldAgent.config.walletConfig!.keyDerivationMethod,
}

await oldAgent.shutdown()

await Migration.migrate({
walletName: walletConfig.id,
walletKey: walletConfig.key,
kdfLevel: walletConfig.keyDerivationMethod?.toString() ?? 'ARGON2I_MOD',
specUri: oldDbPath,
})

const updater = await IndySdkToAskarMigrationUpdater.initialize({ uri: `sqlite://${oldDbPath}`, agent: oldAgent })
await updater.update()
// } finally {
// await new Promise((resolve) =>
// fs.rename(
// '/Users/beri/.indy_client/wallet/walletwallet.0/sqlite.bak.db',
// '/Users/beri/.indy_client/wallet/walletwallet.0/sqlite.db',
// resolve
// )
// )
// }

fs.mkdirSync(path.dirname(newDbPath), { recursive: true })

await newAgent.initialize()
// await newAgent.wallet.import(oldAgent.config.walletConfig!, {
// path: oldDbPath,
// key: oldAgent.config.walletConfig!.key,
// })

await expect(newAgent.genericRecords.findById(record.id)).resolves.toMatchObject(genericRecord)
})
})
Loading

0 comments on commit fac9efb

Please sign in to comment.