Skip to content

Commit

Permalink
Merge branch 'main' into fix/basic-message-assert-connection
Browse files Browse the repository at this point in the history
  • Loading branch information
TimoGlastra authored Mar 3, 2022
2 parents fdfaa4c + 15a5e6b commit 90b66ef
Show file tree
Hide file tree
Showing 10 changed files with 172 additions and 22 deletions.
1 change: 0 additions & 1 deletion demo/src/Faber.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@ export class Faber extends BaseAgent {

public async acceptConnection(invitation_url: string) {
const connectionRecord = await this.receiveConnectionRequest(invitation_url)

this.connectionRecordAliceId = await this.waitForConnection(connectionRecord)
}

Expand Down
13 changes: 7 additions & 6 deletions packages/core/src/modules/proofs/services/ProofService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { EventEmitter } from '../../../agent/EventEmitter'
import { InjectionSymbols } from '../../../constants'
import { Attachment, AttachmentData } from '../../../decorators/attachment/Attachment'
import { AriesFrameworkError } from '../../../error'
import { checkProofRequestForDuplicates } from '../../../utils'
import { JsonEncoder } from '../../../utils/JsonEncoder'
import { JsonTransformer } from '../../../utils/JsonTransformer'
import { uuid } from '../../../utils/uuid'
Expand Down Expand Up @@ -257,8 +258,8 @@ export class ProofService {
comment?: string
}
): Promise<ProofProtocolMsgReturnType<RequestPresentationMessage>> {
// Assert attribute and predicate group names do not match
this.assertAttributePredicateGroupNamesDoNotMatch(proofRequest)
// Assert attribute and predicate (group) names do not match
checkProofRequestForDuplicates(proofRequest)

// Assert
proofRecord.assertState(ProofState.ProposalReceived)
Expand Down Expand Up @@ -305,8 +306,8 @@ export class ProofService {
): Promise<ProofProtocolMsgReturnType<RequestPresentationMessage>> {
this.logger.debug(`Creating proof request`)

// Assert attribute and predicate group names do not match
this.assertAttributePredicateGroupNamesDoNotMatch(proofRequest)
// Assert attribute and predicate (group) names do not match
checkProofRequestForDuplicates(proofRequest)

// Assert
connectionRecord?.assertReady()
Expand Down Expand Up @@ -369,8 +370,8 @@ export class ProofService {
}
await validateOrReject(proofRequest)

// Assert attribute and predicate group names do not match
this.assertAttributePredicateGroupNamesDoNotMatch(proofRequest)
// Assert attribute and predicate (group) names do not match
checkProofRequestForDuplicates(proofRequest)

this.logger.debug('received proof request', proofRequest)

Expand Down
10 changes: 10 additions & 0 deletions packages/core/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,19 @@ import type { IndyPoolConfig } from './modules/ledger/IndyPool'
import type { AutoAcceptProof } from './modules/proofs'
import type { MediatorPickupStrategy } from './modules/routing'

export const enum KeyDerivationMethod {
/** default value in indy-sdk. Will be used when no value is provided */
Argon2IMod = 'ARGON2I_MOD',
/** less secure, but faster */
Argon2IInt = 'ARGON2I_INT',
/** raw wallet master key */
Raw = 'RAW',
}

export interface WalletConfig {
id: string
key: string
keyDerivationMethod?: KeyDerivationMethod
}

export type EncryptedMessage = {
Expand Down
90 changes: 90 additions & 0 deletions packages/core/src/utils/__tests__/indyProofRequest.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import { checkProofRequestForDuplicates } from '..'

import {
AriesFrameworkError,
AttributeFilter,
PredicateType,
ProofAttributeInfo,
ProofPredicateInfo,
ProofRequest,
} from '@aries-framework/core'

export const INDY_CREDENTIAL_OFFER_ATTACHMENT_ID = 'libindy-cred-offer-0'

describe('Present Proof', () => {
let credDefId: string

beforeAll(() => {
credDefId = '9vPXgSpQJPkJEALbLXueBp:3:CL:57753:tag1'
})

test('attribute names match, same cred def filter', () => {
const attributes = {
name: new ProofAttributeInfo({
name: 'age',
restrictions: [
new AttributeFilter({
credentialDefinitionId: credDefId,
}),
],
}),
age: new ProofAttributeInfo({
name: 'age',
restrictions: [
new AttributeFilter({
credentialDefinitionId: credDefId,
}),
],
}),
}

const nonce = 'testtesttest12345'

const proofRequest = new ProofRequest({
name: 'proof-request',
version: '1.0',
nonce,
requestedAttributes: attributes,
})

expect(() => checkProofRequestForDuplicates(proofRequest)).toThrowError(AriesFrameworkError)
})

test('attribute names match with predicates name, same cred def filter', () => {
const attributes = {
name: new ProofAttributeInfo({
name: 'age',
restrictions: [
new AttributeFilter({
credentialDefinitionId: credDefId,
}),
],
}),
}

const predicates = {
age: new ProofPredicateInfo({
name: 'age',
predicateType: PredicateType.GreaterThanOrEqualTo,
predicateValue: 50,
restrictions: [
new AttributeFilter({
credentialDefinitionId: credDefId,
}),
],
}),
}

const nonce = 'testtesttest12345'

const proofRequest = new ProofRequest({
name: 'proof-request',
version: '1.0',
nonce,
requestedAttributes: attributes,
requestedPredicates: predicates,
})

expect(() => checkProofRequestForDuplicates(proofRequest)).toThrowError(AriesFrameworkError)
})
})
11 changes: 11 additions & 0 deletions packages/core/src/utils/assertNoDuplicates.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { AriesFrameworkError } from '../error/AriesFrameworkError'

export function assertNoDuplicatesInArray(arr: string[]) {
const arrayLength = arr.length
const uniqueArrayLength = new Set(arr).size

if (arrayLength === uniqueArrayLength) return

const duplicates = arr.filter((item, index) => arr.indexOf(item) != index)
throw new AriesFrameworkError(`The proof request contains duplicate items: ${duplicates.toString()}`)
}
1 change: 1 addition & 0 deletions packages/core/src/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ export * from './MultiBaseEncoder'
export * from './buffer'
export * from './MultiHashEncoder'
export * from './JWE'
export * from './indyProofRequest'
22 changes: 22 additions & 0 deletions packages/core/src/utils/indyProofRequest.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import type { ProofRequest } from '../modules/proofs/models/ProofRequest'

import { assertNoDuplicatesInArray } from './assertNoDuplicates'

export function attributeNamesToArray(proofRequest: ProofRequest) {
// Attributes can contain either a `name` string value or an `names` string array. We reduce it to a single array
// containing all attribute names from the requested attributes.
return Array.from(proofRequest.requestedAttributes.values()).reduce<string[]>(
(names, a) => [...names, ...(a.name ? [a.name] : a.names ? a.names : [])],
[]
)
}

export function predicateNamesToArray(proofRequest: ProofRequest) {
return Array.from(proofRequest.requestedPredicates.values()).map((a) => a.name)
}

export function checkProofRequestForDuplicates(proofRequest: ProofRequest) {
const attributes = attributeNamesToArray(proofRequest)
const predicates = predicateNamesToArray(proofRequest)
assertNoDuplicatesInArray(attributes.concat(predicates))
}
27 changes: 15 additions & 12 deletions packages/core/src/wallet/IndyWallet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,12 +93,12 @@ export class IndyWallet implements Wallet {
this.logger.debug(`Creating wallet '${walletConfig.id}' using SQLite storage`)

try {
await this.indy.createWallet({ id: walletConfig.id }, { key: walletConfig.key })
await this.indy.createWallet(
{ id: walletConfig.id },
{ key: walletConfig.key, key_derivation_method: walletConfig.keyDerivationMethod }
)

this.walletConfig = {
id: walletConfig.id,
key: walletConfig.key,
}
this.walletConfig = walletConfig

// We usually want to create master secret only once, therefore, we can to do so when creating a wallet.
await this.open(walletConfig)
Expand Down Expand Up @@ -141,11 +141,11 @@ export class IndyWallet implements Wallet {
}

try {
this.walletHandle = await this.indy.openWallet({ id: walletConfig.id }, { key: walletConfig.key })
this.walletConfig = {
id: walletConfig.id,
key: walletConfig.key,
}
this.walletHandle = await this.indy.openWallet(
{ id: walletConfig.id },
{ key: walletConfig.key, key_derivation_method: walletConfig.keyDerivationMethod }
)
this.walletConfig = walletConfig
} catch (error) {
if (isIndyError(error, 'WalletNotFoundError')) {
const errorMessage = `Wallet '${walletConfig.id}' not found`
Expand Down Expand Up @@ -192,7 +192,10 @@ export class IndyWallet implements Wallet {
}

try {
await this.indy.deleteWallet({ id: this.walletConfig.id }, { key: this.walletConfig.key })
await this.indy.deleteWallet(
{ id: this.walletConfig.id },
{ key: this.walletConfig.key, key_derivation_method: this.walletConfig.keyDerivationMethod }
)
} catch (error) {
if (isIndyError(error, 'WalletNotFoundError')) {
const errorMessage = `Error deleting wallet: wallet '${this.walletConfig.id}' not found`
Expand All @@ -219,7 +222,7 @@ export class IndyWallet implements Wallet {
*/
public async close(): Promise<void> {
if (!this.walletHandle) {
throw new WalletError('Wallet is in inavlid state, you are trying to close wallet that has no `walletHandle`.')
throw new WalletError('Wallet is in invalid state, you are trying to close wallet that has no `walletHandle`.')
}

try {
Expand Down
5 changes: 2 additions & 3 deletions packages/core/tests/proofs.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ describe('Present Proof', () => {
testLogger.test('Initializing the agents')
;({ faberAgent, aliceAgent, credDefId, faberConnection, aliceConnection, presentationPreview } =
await setupProofsTest('Faber agent', 'Alice agent'))
testLogger.test('Issuing second credential')
})

afterAll(async () => {
Expand Down Expand Up @@ -365,8 +366,6 @@ describe('Present Proof', () => {
requestedAttributes: attributes,
requestedPredicates: predicates,
})
).rejects.toThrowError(
`The proof request contains an attribute group name that matches a predicate group name: age`
)
).rejects.toThrowError(`The proof request contains duplicate items: age`)
})
})
14 changes: 14 additions & 0 deletions packages/core/tests/wallet.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { Subject } from 'rxjs'
import { SubjectInboundTransport } from '../../../tests/transport/SubjectInboundTransport'
import { SubjectOutboundTransport } from '../../../tests/transport/SubjectOutboundTransport'
import { Agent } from '../src/agent/Agent'
import { KeyDerivationMethod } from '../src/types'

import { getBaseConfig } from './helpers'

Expand Down Expand Up @@ -101,4 +102,17 @@ describe('=== wallet', () => {

await expect(aliceAgent.wallet.open(walletConfig)).resolves.toBeUndefined()
})

test('create wallet with custom key derivation method', async () => {
const walletConfig = {
id: 'mywallet',
key: 'mysecretwalletkey',
keyDerivationMethod: KeyDerivationMethod.Argon2IInt,
}

await aliceAgent.wallet.create(walletConfig)
await aliceAgent.wallet.open(walletConfig)

expect(aliceAgent.wallet.isInitialized).toBe(true)
})
})

0 comments on commit 90b66ef

Please sign in to comment.