Skip to content

Commit

Permalink
feat!: allow to import created dids (and remove legacy `publicDidSeed…
Browse files Browse the repository at this point in the history
…`) (openwallet-foundation#1325)

Signed-off-by: Timo Glastra <timo@animo.id>
  • Loading branch information
TimoGlastra committed Feb 24, 2023
1 parent dc60acb commit 21d4bf7
Show file tree
Hide file tree
Showing 52 changed files with 985 additions and 364 deletions.
22 changes: 0 additions & 22 deletions demo/src/BaseAgent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,6 @@ import {
import { AnonCredsRsModule } from '@aries-framework/anoncreds-rs'
import { AskarModule } from '@aries-framework/askar'
import {
TypedArrayEncoder,
KeyType,
DidsModule,
V2ProofProtocol,
V2CredentialProtocol,
Expand Down Expand Up @@ -53,7 +51,6 @@ export class BaseAgent {
public name: string
public config: InitConfig
public agent: DemoAgent
public anonCredsIssuerId: string
public useLegacyIndySdk: boolean

public constructor({
Expand All @@ -74,15 +71,12 @@ export class BaseAgent {
id: name,
key: name,
},
publicDidSeed: 'afjdemoverysercure00000000000000',
endpoints: [`http://localhost:${this.port}`],
autoAcceptConnections: true,
} satisfies InitConfig

this.config = config

// TODO: do not hardcode this
this.anonCredsIssuerId = '2jEvRuKmfBJTRa7QowDpNN'
this.useLegacyIndySdk = useLegacyIndySdk

this.agent = new Agent({
Expand All @@ -97,22 +91,6 @@ export class BaseAgent {
public async initializeAgent() {
await this.agent.initialize()

// FIXME:
// We need to make sure the key to submit transactions is created. We should update this to use the dids module, and allow
// to add an existing did based on a seed/secretKey, and not register it on the the ledger. However for Indy SDK we currently
// use the deprecated publicDidSeed property (which will register the did in the wallet), and for Askar we manually create the key
// in the wallet.
if (!this.useLegacyIndySdk) {
try {
await this.agent.context.wallet.createKey({
keyType: KeyType.Ed25519,
privateKey: TypedArrayEncoder.fromString('afjdemoverysercure00000000000000'),
})
} catch (error) {
// We assume the key already exists, and that's why askar failed
}
}

console.log(greenText(`\nAgent ${this.name} created!\n`))
}
}
Expand Down
32 changes: 29 additions & 3 deletions demo/src/Faber.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import type { RegisterCredentialDefinitionReturnStateFinished } from '../../pack
import type { ConnectionRecord, ConnectionStateChangedEvent } from '@aries-framework/core'
import type BottomBar from 'inquirer/lib/ui/bottom-bar'

import { utils, ConnectionEventTypes } from '@aries-framework/core'
import { KeyType, TypedArrayEncoder, utils, ConnectionEventTypes } from '@aries-framework/core'
import { ui } from 'inquirer'

import { BaseAgent } from './BaseAgent'
Expand All @@ -11,16 +11,35 @@ import { Color, greenText, Output, purpleText, redText } from './OutputClass'
export class Faber extends BaseAgent {
public outOfBandId?: string
public credentialDefinition?: RegisterCredentialDefinitionReturnStateFinished
public anonCredsIssuerId?: string
public ui: BottomBar

public constructor(port: number, name: string) {
super({ port, name })
super({ port, name, useLegacyIndySdk: true })
this.ui = new ui.BottomBar()
}

public static async build(): Promise<Faber> {
const faber = new Faber(9001, 'faber')
await faber.initializeAgent()

// NOTE: we assume the did is already registered on the ledger, we just store the private key in the wallet
// and store the existing did in the wallet
const privateKey = TypedArrayEncoder.fromString('afjdemoverysercure00000000000000')

const key = await faber.agent.wallet.createKey({
keyType: KeyType.Ed25519,
privateKey,
})

// did is first 16 bytes of public key encoded as base58
const unqualifiedIndyDid = TypedArrayEncoder.toBase58(key.publicKey.slice(0, 16))
await faber.agent.dids.import({
did: `did:sov:${unqualifiedIndyDid}`,
})

faber.anonCredsIssuerId = unqualifiedIndyDid

return faber
}

Expand Down Expand Up @@ -102,6 +121,9 @@ export class Faber extends BaseAgent {
}

private async registerSchema() {
if (!this.anonCredsIssuerId) {
throw new Error(redText('Missing anoncreds issuerId'))
}
const schemaTemplate = {
name: 'Faber College' + utils.uuid(),
version: '1.0.0',
Expand All @@ -120,14 +142,18 @@ export class Faber extends BaseAgent {

if (schemaState.state !== 'finished') {
throw new Error(
`Error registering schema: ${schemaState.state === 'failed' ? schemaState.reason : 'Not Finished'}}`
`Error registering schema: ${schemaState.state === 'failed' ? schemaState.reason : 'Not Finished'}`
)
}
this.ui.updateBottomBar('\nSchema registered!\n')
return schemaState
}

private async registerCredentialDefinition(schemaId: string) {
if (!this.anonCredsIssuerId) {
throw new Error(redText('Missing anoncreds issuerId'))
}

this.ui.updateBottomBar('\nRegistering credential definition...\n')
const { credentialDefinitionState } = await this.agent.modules.anoncreds.registerCredentialDefinition({
credentialDefinition: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -325,7 +325,6 @@ describe('V1 Proofs - Connectionless - Indy', () => {

const { credentialDefinition } = await prepareForAnonCredsIssuance(faberAgent, {
attributeNames: ['name', 'age', 'image_0', 'image_1'],
issuerId: faberAgent.publicDid?.did as string,
})

const [faberConnection, aliceConnection] = await makeConnection(faberAgent, aliceAgent)
Expand Down
15 changes: 9 additions & 6 deletions packages/anoncreds/tests/anoncreds.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Agent, KeyDerivationMethod } from '@aries-framework/core'
import { Agent, KeyDerivationMethod, KeyType, TypedArrayEncoder } from '@aries-framework/core'
import { agentDependencies } from '@aries-framework/node'
import indySdk from 'indy-sdk'
import * as indySdk from 'indy-sdk'

import { IndySdkModule } from '../../indy-sdk/src/IndySdkModule'
import { AnonCredsCredentialDefinitionRepository, AnonCredsModule, AnonCredsSchemaRepository } from '../src'
Expand Down Expand Up @@ -186,10 +186,13 @@ describe('AnonCreds API', () => {
})

test('register a credential definition', async () => {
// NOTE: the indy-sdk MUST have a did created, we can't just create a key
await agent.context.wallet.initPublicDid({ seed: '00000000000000000000000000000My1' })
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const issuerId = agent.context.wallet.publicDid!.did
// Create key
await agent.wallet.createKey({
privateKey: TypedArrayEncoder.fromString('00000000000000000000000000000My1'),
keyType: KeyType.Ed25519,
})

const issuerId = 'VsKV7grR1BUE29mG2Fm2kX'

const credentialDefinitionResult = await agent.modules.anoncreds.registerCredentialDefinition({
credentialDefinition: {
Expand Down
21 changes: 14 additions & 7 deletions packages/anoncreds/tests/legacyAnonCredsSetup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import type {
import type { AutoAcceptProof, ConnectionRecord } from '@aries-framework/core'

import {
TypedArrayEncoder,
CacheModule,
InMemoryLruCache,
Agent,
Expand All @@ -30,11 +31,14 @@ import { randomUUID } from 'crypto'

import { AnonCredsRsModule } from '../../anoncreds-rs/src'
import { AskarModule } from '../../askar/src'
import { sleep } from '../../core/src/utils/sleep'
import { uuid } from '../../core/src/utils/uuid'
import { setupSubjectTransports, setupEventReplaySubjects } from '../../core/tests'
import {
getAgentOptions,
importExistingIndyDidFromPrivateKey,
makeConnection,
publicDidSeed,
genesisTransactions,
taaVersion,
taaAcceptanceMechanism,
Expand Down Expand Up @@ -403,9 +407,6 @@ export async function setupAnonCredsTests<

const { credentialDefinition, schema } = await prepareForAnonCredsIssuance(issuerAgent, {
attributeNames,
// TODO: replace with more dynamic / generic value We should create a did using the dids module
// and use that probably
issuerId: issuerAgent.publicDid?.did as string,
})

let issuerHolderConnection: ConnectionRecord | undefined
Expand Down Expand Up @@ -441,10 +442,10 @@ export async function setupAnonCredsTests<
} as unknown as SetupAnonCredsTestsReturn<VerifierName, CreateConnections>
}

export async function prepareForAnonCredsIssuance(
agent: Agent,
{ attributeNames, issuerId }: { attributeNames: string[]; issuerId: string }
) {
export async function prepareForAnonCredsIssuance(agent: Agent, { attributeNames }: { attributeNames: string[] }) {
// Add existing endorser did to the wallet
const issuerId = await importExistingIndyDidFromPrivateKey(agent, TypedArrayEncoder.fromString(publicDidSeed))

const schema = await registerSchema(agent, {
// TODO: update attrNames to attributeNames
attrNames: attributeNames,
Expand All @@ -453,12 +454,18 @@ export async function prepareForAnonCredsIssuance(
issuerId,
})

// Wait some time pass to let ledger settle the object
await sleep(1000)

const credentialDefinition = await registerCredentialDefinition(agent, {
schemaId: schema.schemaId,
issuerId,
tag: 'default',
})

// Wait some time pass to let ledger settle the object
await sleep(1000)

return {
schema,
credentialDefinition,
Expand Down
12 changes: 6 additions & 6 deletions packages/askar/src/storage/AskarStorageService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {
} from '@aries-framework/core'
import { Scan } from '@hyperledger/aries-askar-shared'

import { askarErrors, isAskarError } from '../utils/askarError'
import { AskarErrorCode, isAskarError } from '../utils/askarError'
import { assertAskarWallet } from '../utils/assertAskarWallet'

import { askarQueryFromSearchQuery, recordToInstance, transformFromRecordTagValues } from './utils'
Expand All @@ -29,7 +29,7 @@ export class AskarStorageService<T extends BaseRecord> implements StorageService
try {
await session.insert({ category: record.type, name: record.id, value, tags })
} catch (error) {
if (isAskarError(error) && error.code === askarErrors.Duplicate) {
if (isAskarError(error, AskarErrorCode.Duplicate)) {
throw new RecordDuplicateError(`Record with id ${record.id} already exists`, { recordType: record.type })
}

Expand All @@ -50,7 +50,7 @@ export class AskarStorageService<T extends BaseRecord> implements StorageService
try {
await session.replace({ category: record.type, name: record.id, value, tags })
} catch (error) {
if (isAskarError(error) && error.code === askarErrors.NotFound) {
if (isAskarError(error, AskarErrorCode.NotFound)) {
throw new RecordNotFoundError(`record with id ${record.id} not found.`, {
recordType: record.type,
cause: error,
Expand All @@ -69,7 +69,7 @@ export class AskarStorageService<T extends BaseRecord> implements StorageService
try {
await session.remove({ category: record.type, name: record.id })
} catch (error) {
if (isAskarError(error) && error.code === askarErrors.NotFound) {
if (isAskarError(error, AskarErrorCode.NotFound)) {
throw new RecordNotFoundError(`record with id ${record.id} not found.`, {
recordType: record.type,
cause: error,
Expand All @@ -91,7 +91,7 @@ export class AskarStorageService<T extends BaseRecord> implements StorageService
try {
await session.remove({ category: recordClass.type, name: id })
} catch (error) {
if (isAskarError(error) && error.code === askarErrors.NotFound) {
if (isAskarError(error, AskarErrorCode.NotFound)) {
throw new RecordNotFoundError(`record with id ${id} not found.`, {
recordType: recordClass.type,
cause: error,
Expand All @@ -117,7 +117,7 @@ export class AskarStorageService<T extends BaseRecord> implements StorageService
} catch (error) {
if (
isAskarError(error) &&
(error.code === askarErrors.NotFound ||
(error.code === AskarErrorCode.NotFound ||
// FIXME: this is current output from askar wrapper but does not describe specifically a not found scenario
error.message === 'Received null pointer. The native library could not find the value.')
) {
Expand Down
5 changes: 3 additions & 2 deletions packages/askar/src/utils/askarError.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { AriesAskarError } from '@hyperledger/aries-askar-shared'

export enum askarErrors {
export enum AskarErrorCode {
Success = 0,
Backend = 1,
Busy = 2,
Expand All @@ -13,4 +13,5 @@ export enum askarErrors {
Custom = 100,
}

export const isAskarError = (error: Error) => error instanceof AriesAskarError
export const isAskarError = (error: Error, askarErrorCode?: AskarErrorCode): error is AriesAskarError =>
error instanceof AriesAskarError && (askarErrorCode === undefined || error.code === askarErrorCode)
Loading

0 comments on commit 21d4bf7

Please sign in to comment.