Skip to content

Commit

Permalink
feat: indy revocation (prover & verifier) (#592)
Browse files Browse the repository at this point in the history
* Added recepientRevocation for createProof

Signed-off-by: Patrick Kenyon <treek.kenyon@gmail.com>

* Initial revocation functions for getRequestedCredentialsForProofRequest

Signed-off-by: Patrick Kenyon <treek.kenyon@gmail.com>

* Added option to check for revocation status in getRequestedCredentials

Signed-off-by: Patrick Kenyon <treek.kenyon@gmail.com>

* sorted transports

Signed-off-by: Adam Burdett <burdettadam@gmail.com>

* broken message sender tests

Signed-off-by: Adam Burdett <burdettadam@gmail.com>

* structure fix

Signed-off-by: Adam Burdett <burdettadam@gmail.com>

* lint import ordering

Signed-off-by: Adam Burdett <burdettadam@gmail.com>

* if(0) does not work.

Signed-off-by: Adam Burdett <burdettadam@gmail.com>

* utf-8 decode ws event.data

Signed-off-by: Adam Burdett <burdettadam@gmail.com>

* indy wallet friendly bits

Signed-off-by: Adam Burdett <burdettadam@gmail.com>

* correct protocal type

Signed-off-by: Adam Burdett <burdettadam@gmail.com>

* check invite during init

Signed-off-by: Adam Burdett <burdettadam@gmail.com>

* id check

Signed-off-by: Adam Burdett <burdettadam@gmail.com>

* keep sockets with mediators open

Signed-off-by: Adam Burdett <burdettadam@gmail.com>

* recursive backoff

Signed-off-by: Adam Burdett <burdettadam@gmail.com>

* timeout

Signed-off-by: Adam Burdett <burdettadam@gmail.com>

* timeout time

Signed-off-by: Adam Burdett <burdettadam@gmail.com>

* logger

Signed-off-by: Adam Burdett <burdettadam@gmail.com>

* propper recursive backoff

Signed-off-by: Adam Burdett <burdettadam@gmail.com>

* multiple socket timeout support

Signed-off-by: Adam Burdett <burdettadam@gmail.com>

* Code cleanup

Signed-off-by: Patrick Kenyon <treek.kenyon@gmail.com>

* Fix tests and types

Signed-off-by: Patrick Kenyon <treek.kenyon@gmail.com>

* Formatting and type fixes

Signed-off-by: Patrick Kenyon <treek.kenyon@gmail.com>

* revocation fixes

Signed-off-by: Patrick Kenyon <treek.kenyon@gmail.com>

* ran prettier

Signed-off-by: Patrick Kenyon <treek.kenyon@gmail.com>

* chore: add ts ignore until types are updated

Signed-off-by: James Ebert <jamesebert.k@gmail.com>

* feat: updated tails download to utilize axios and added inline docs

Signed-off-by: James Ebert <jamesebert.k@gmail.com>

* chore: fixed formatting

Signed-off-by: James Ebert <jamesebert.k@gmail.com>

* chore: removed husky

Signed-off-by: James Ebert <jamesebert.k@gmail.com>

* fix: add back husky pre-push

Signed-off-by: James Ebert <jamesebert.k@gmail.com>

* chore: formatting

Signed-off-by: James Ebert <jamesebert.k@gmail.com>

* fix: fixed error imports

Signed-off-by: James Ebert <jamesebert.k@gmail.com>

* chore: resolve dependency loop issues

Signed-off-by: James Ebert <jamesebert.k@gmail.com>

* chore: formatting

Signed-off-by: James Ebert <jamesebert.k@gmail.com>

* feature: revocation ledger methods & proof get requested credentials revoked status

Signed-off-by: James Ebert <jamesebert.k@gmail.com>

* feature: added revocation state creation

Signed-off-by: James Ebert <jamesebert.k@gmail.com>

* fix: small tweaks and fixes for revocation

Signed-off-by: James Ebert <jamesebert.k@gmail.com>

* feature: takes into account referent revocation intervals

Signed-off-by: James Ebert <jamesebert.k@gmail.com>

* chore: cleanup & prettier

Signed-off-by: James Ebert <jamesebert.k@gmail.com>

* fix: fixed createrevocationstate types & initial rev reg def caching

Signed-off-by: James Ebert <jamesebert.k@gmail.com>

* chore: formatting

Signed-off-by: James Ebert <jamesebert.k@gmail.com>

* fix: fixed proofservice test mock

Signed-off-by: James Ebert <jamesebert.k@gmail.com>

* chore: minor cleanup

Signed-off-by: James Ebert <jamesebert.k@gmail.com>

* chore: rename indyutilitiesservice

Signed-off-by: James Ebert <jamesebert.k@gmail.com>

* chore: troubleshooting revocation, added ledger methods for verifying proof of non revocation

Signed-off-by: James Ebert <jamesebert.k@gmail.com>

* chore: cleanup & credential storage w/revocation

Signed-off-by: James Ebert <jamesebert.k@gmail.com>

* feat: add download to file method to file system

Signed-off-by: Timo Glastra <timo@animo.id>

* refactor: use rnfs for react native

Signed-off-by: Timo Glastra <timo@animo.id>

* chore: cleanup & log adjustments

Signed-off-by: James Ebert <jamesebert.k@gmail.com>

* chore: formatting

Signed-off-by: James Ebert <jamesebert.k@gmail.com>

* feat: verify proofs containing proof of non_revocation

Signed-off-by: James Ebert <jamesebert.k@gmail.com>

* chore: formatting

Signed-off-by: James Ebert <jamesebert.k@gmail.com>

* chore: update indy-sdk-react-native & indy-sdk types

Signed-off-by: James Ebert <jamesebert.k@gmail.com>

* chore: adjusts names to be consistent & removing abbreviations

Signed-off-by: James Ebert <jamesebert.k@gmail.com>

* chore: updated indy-sdk types to fix proof identifier types

Signed-off-by: James Ebert <jamesebert.k@gmail.com>

* fix: indyverifierservice prototype pollution

Signed-off-by: James Ebert <jamesebert.k@gmail.com>

Co-authored-by: Patrick Kenyon <treek.kenyon@gmail.com>
Co-authored-by: Adam Burdett <burdettadam@gmail.com>
Co-authored-by: Timo Glastra <timo@animo.id>
  • Loading branch information
4 people committed Feb 9, 2022
1 parent 0d478a7 commit fb19ff5
Show file tree
Hide file tree
Showing 22 changed files with 797 additions and 118 deletions.
2 changes: 1 addition & 1 deletion packages/core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
"@multiformats/base-x": "^4.0.1",
"@stablelib/ed25519": "^1.0.2",
"@stablelib/sha256": "^1.0.1",
"@types/indy-sdk": "^1.16.8",
"@types/indy-sdk": "^1.16.12",
"@types/node-fetch": "^2.5.10",
"@types/ws": "^7.4.4",
"abort-controller": "^3.0.0",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -648,11 +648,21 @@ export class CredentialService {

const credentialDefinition = await this.ledgerService.getCredentialDefinition(indyCredential.cred_def_id)

//Fetch Revocation Registry Definition if the issued credential has an associated revocation registry id
let revocationRegistryDefinition
if (indyCredential.rev_reg_id) {
const revocationRegistryDefinitionData = await this.ledgerService.getRevocationRegistryDefinition(
indyCredential.rev_reg_id
)
revocationRegistryDefinition = revocationRegistryDefinitionData.revocationRegistryDefinition
}

const credentialId = await this.indyHolderService.storeCredential({
credentialId: uuid(),
credentialRequestMetadata,
credential: indyCredential,
credentialDefinition,
revocationRegistryDefinition,
})
credentialRecord.credentialId = credentialId
credentialRecord.credentialMessage = issueCredentialMessage
Expand Down
85 changes: 69 additions & 16 deletions packages/core/src/modules/indy/services/IndyHolderService.ts
Original file line number Diff line number Diff line change
@@ -1,41 +1,78 @@
import type { Logger } from '../../../logger'
import type { RequestedCredentials } from '../../proofs'
import type * as Indy from 'indy-sdk'

import { Lifecycle, scoped } from 'tsyringe'

import { AgentConfig } from '../../../agent/AgentConfig'
import { IndySdkError } from '../../../error'
import { IndySdkError } from '../../../error/IndySdkError'
import { isIndyError } from '../../../utils/indyError'
import { IndyWallet } from '../../../wallet/IndyWallet'

import { IndyRevocationService } from './IndyRevocationService'

@scoped(Lifecycle.ContainerScoped)
export class IndyHolderService {
private indy: typeof Indy
private logger: Logger
private wallet: IndyWallet
private indyRevocationService: IndyRevocationService

public constructor(agentConfig: AgentConfig, wallet: IndyWallet) {
public constructor(agentConfig: AgentConfig, indyRevocationService: IndyRevocationService, wallet: IndyWallet) {
this.indy = agentConfig.agentDependencies.indy
this.wallet = wallet
this.indyRevocationService = indyRevocationService
this.logger = agentConfig.logger
}

/**
* Creates an Indy Proof in response to a proof request. Will create revocation state if the proof request requests proof of non-revocation
*
* @param proofRequest a Indy proof request
* @param requestedCredentials the requested credentials to use for the proof creation
* @param schemas schemas to use in proof creation
* @param credentialDefinitions credential definitions to use in proof creation
* @throws {Error} if there is an error during proof generation or revocation state generation
* @returns a promise of Indy Proof
*
* @todo support attribute non_revoked fields
*/
public async createProof({
proofRequest,
requestedCredentials,
schemas,
credentialDefinitions,
revocationStates = {},
}: CreateProofOptions) {
}: CreateProofOptions): Promise<Indy.IndyProof> {
try {
return await this.indy.proverCreateProof(
this.logger.debug('Creating Indy Proof')
const revocationStates: Indy.RevStates = await this.indyRevocationService.createRevocationState(
proofRequest,
requestedCredentials
)

const indyProof: Indy.IndyProof = await this.indy.proverCreateProof(
this.wallet.handle,
proofRequest,
requestedCredentials,
requestedCredentials.toJSON(),
this.wallet.masterSecretId,
schemas,
credentialDefinitions,
revocationStates
)

this.logger.trace('Created Indy Proof', {
indyProof,
})

return indyProof
} catch (error) {
throw new IndySdkError(error)
this.logger.error(`Error creating Indy Proof`, {
error,
proofRequest,
requestedCredentials,
})

throw isIndyError(error) ? new IndySdkError(error) : error
}
}

Expand All @@ -49,7 +86,7 @@ export class IndyHolderService {
credential,
credentialDefinition,
credentialId,
revocationRegistryDefinitions,
revocationRegistryDefinition,
}: StoreCredentialOptions): Promise<Indy.CredentialId> {
try {
return await this.indy.proverStoreCredential(
Expand All @@ -58,10 +95,14 @@ export class IndyHolderService {
credentialRequestMetadata,
credential,
credentialDefinition,
revocationRegistryDefinitions ?? null
revocationRegistryDefinition ?? null
)
} catch (error) {
throw new IndySdkError(error)
this.logger.error(`Error storing Indy Credential '${credentialId}'`, {
error,
})

throw isIndyError(error) ? new IndySdkError(error) : error
}
}

Expand All @@ -78,7 +119,11 @@ export class IndyHolderService {
try {
return await this.indy.proverGetCredential(this.wallet.handle, credentialId)
} catch (error) {
throw new IndySdkError(error)
this.logger.error(`Error getting Indy Credential '${credentialId}'`, {
error,
})

throw isIndyError(error) ? new IndySdkError(error) : error
}
}

Expand All @@ -101,7 +146,12 @@ export class IndyHolderService {
this.wallet.masterSecretId
)
} catch (error) {
throw new IndySdkError(error)
this.logger.error(`Error creating Indy Credential Request`, {
error,
credentialOffer,
})

throw isIndyError(error) ? new IndySdkError(error) : error
}
}

Expand Down Expand Up @@ -177,7 +227,11 @@ export class IndyHolderService {

return credentials
} catch (error) {
throw new IndySdkError(error)
this.logger.error(`Error Fetching Indy Credentials For Referent`, {
error,
})

throw isIndyError(error) ? new IndySdkError(error) : error
}
}
}
Expand All @@ -201,13 +255,12 @@ export interface StoreCredentialOptions {
credential: Indy.Cred
credentialDefinition: Indy.CredDef
credentialId?: Indy.CredentialId
revocationRegistryDefinitions?: Indy.RevRegsDefs
revocationRegistryDefinition?: Indy.RevocRegDef
}

export interface CreateProofOptions {
proofRequest: Indy.IndyProofRequest
requestedCredentials: Indy.IndyRequestedCredentials
requestedCredentials: RequestedCredentials
schemas: Indy.Schemas
credentialDefinitions: Indy.CredentialDefs
revocationStates?: Indy.RevStates
}
53 changes: 10 additions & 43 deletions packages/core/src/modules/indy/services/IndyIssuerService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import type {
CredReq,
CredRevocId,
CredValues,
BlobReaderHandle,
} from 'indy-sdk'

import { Lifecycle, scoped } from 'tsyringe'
Expand All @@ -18,18 +17,21 @@ import { AgentConfig } from '../../../agent/AgentConfig'
import { AriesFrameworkError } from '../../../error/AriesFrameworkError'
import { IndySdkError } from '../../../error/IndySdkError'
import { isIndyError } from '../../../utils/indyError'
import { getDirFromFilePath } from '../../../utils/path'
import { IndyWallet } from '../../../wallet/IndyWallet'

import { IndyUtilitiesService } from './IndyUtilitiesService'

@scoped(Lifecycle.ContainerScoped)
export class IndyIssuerService {
private indy: typeof Indy
private wallet: IndyWallet
private indyUtilitiesService: IndyUtilitiesService
private fileSystem: FileSystem

public constructor(agentConfig: AgentConfig, wallet: IndyWallet) {
public constructor(agentConfig: AgentConfig, wallet: IndyWallet, indyUtilitiesService: IndyUtilitiesService) {
this.indy = agentConfig.agentDependencies.indy
this.wallet = wallet
this.indyUtilitiesService = indyUtilitiesService
this.fileSystem = agentConfig.fileSystem
}

Expand All @@ -44,7 +46,7 @@ export class IndyIssuerService {

return schema
} catch (error) {
throw new IndySdkError(error)
throw isIndyError(error) ? new IndySdkError(error) : error
}
}

Expand Down Expand Up @@ -74,7 +76,7 @@ export class IndyIssuerService {

return credentialDefinition
} catch (error) {
throw new IndySdkError(error)
throw isIndyError(error) ? new IndySdkError(error) : error
}
}

Expand All @@ -88,7 +90,7 @@ export class IndyIssuerService {
try {
return await this.indy.issuerCreateCredentialOffer(this.wallet.handle, credentialDefinitionId)
} catch (error) {
throw new IndySdkError(error)
throw isIndyError(error) ? new IndySdkError(error) : error
}
}

Expand All @@ -106,7 +108,7 @@ export class IndyIssuerService {
}: CreateCredentialOptions): Promise<[Cred, CredRevocId]> {
try {
// Indy SDK requires tailsReaderHandle. Use null if no tailsFilePath is present
const tailsReaderHandle = tailsFilePath ? await this.createTailsReader(tailsFilePath) : 0
const tailsReaderHandle = tailsFilePath ? await this.indyUtilitiesService.createTailsReader(tailsFilePath) : 0

if (revocationRegistryId || tailsFilePath) {
throw new AriesFrameworkError('Revocation not supported yet')
Expand All @@ -123,42 +125,7 @@ export class IndyIssuerService {

return [credential, credentialRevocationId]
} catch (error) {
if (isIndyError(error)) {
throw new IndySdkError(error)
}

throw error
}
}

/**
* Get a handler for the blob storage tails file reader.
*
* @param tailsFilePath The path of the tails file
* @returns The blob storage reader handle
*/
private async createTailsReader(tailsFilePath: string): Promise<BlobReaderHandle> {
try {
const tailsFileExists = await this.fileSystem.exists(tailsFilePath)

// Extract directory from path (should also work with windows paths)
const dirname = getDirFromFilePath(tailsFilePath)

if (!tailsFileExists) {
throw new AriesFrameworkError(`Tails file does not exist at path ${tailsFilePath}`)
}

const tailsReaderConfig = {
base_dir: dirname,
}

return await this.indy.openBlobStorageReader('default', tailsReaderConfig)
} catch (error) {
if (isIndyError(error)) {
throw new IndySdkError(error)
}

throw error
throw isIndyError(error) ? new IndySdkError(error) : error
}
}
}
Expand Down
Loading

0 comments on commit fb19ff5

Please sign in to comment.