From 936acba076595556d3fbc8835502b8abb0746a76 Mon Sep 17 00:00:00 2001 From: GopherDID <74898029+vmidyllic@users.noreply.github.com> Date: Mon, 9 Sep 2024 16:45:38 +0300 Subject: [PATCH] ability to replace auth bjj with another status (#264) * add logic for removal of the credential with another status * add possibility to disable publishing of the genesis state --- package-lock.json | 4 +- package.json | 2 +- src/identity/identity-wallet.ts | 68 ++++++++++++++++++--------------- tests/identity/id.test.ts | 56 ++++++++++++++++++++++++++- 4 files changed, 95 insertions(+), 35 deletions(-) diff --git a/package-lock.json b/package-lock.json index 76533a19..a24fccbe 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@0xpolygonid/js-sdk", - "version": "1.18.3", + "version": "1.18.4", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@0xpolygonid/js-sdk", - "version": "1.18.3", + "version": "1.18.4", "license": "MIT or Apache-2.0", "dependencies": { "@noble/curves": "^1.4.0", diff --git a/package.json b/package.json index a389ceb1..c55a9976 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@0xpolygonid/js-sdk", - "version": "1.18.3", + "version": "1.18.4", "description": "SDK to work with Polygon ID", "main": "dist/node/cjs/index.js", "module": "dist/node/esm/index.js", diff --git a/src/identity/identity-wallet.ts b/src/identity/identity-wallet.ts index cd05362f..980cbb57 100644 --- a/src/identity/identity-wallet.ts +++ b/src/identity/identity-wallet.ts @@ -76,13 +76,19 @@ export type IdentityCreationOptions = { /** * Options for creating Auth BJJ credential * seed - seed to generate BJJ key pair - * revocationOpts - + * revocationOpts + * nonce - explicit revocation nonce to use + * onChain - onchain status related option + * txCallback - defines how the TransactionReceipt is handled + * publishMode - specifies the work of transaction polling type: sync / async / callback + * genesisPublishingDisabled - genesis is publishing by default. Set `true` to prevent genesis publishing */ export type AuthBJJCredentialCreationOptions = { revocationOpts: { id: string; type: CredentialStatusType; nonce?: number; + genesisPublishingDisabled?: boolean; onChain?: { txCallback?: (tx: TransactionReceipt) => Promise; publishMode?: PublishMode; @@ -661,13 +667,24 @@ export class IdentityWallet implements IIdentityWallet { allowedIssuers: [did.string()] }); - if (credentials.length) { + // if credential exists with the same credential status type we return this credential + if ( + credentials.length === 1 && + credentials[0].credentialStatus.type === opts.revocationOpts.type + ) { return { did, credential: credentials[0] }; } + // otherwise something is already wrong with storage as it has more than 1 credential in it or credential status type of existing credential is different from what user provides - We should remove everything and create new credential. + // in this way credential status of auth credential can be upgraded + for (let i = 0; i < credentials.length; i++) { + await this._credentialWallet.remove(credentials[i].id); + } + + // otherwise we create a new credential const credential = await this.createAuthBJJCredential( did, pubKey, @@ -695,10 +712,13 @@ export class IdentityWallet implements IIdentityWallet { credential.proof = [mtpProof]; - await this.publishRevocationInfoByCredentialStatusType(did, opts.revocationOpts.type, { - rhsUrl: opts.revocationOpts.id, - onChain: opts.revocationOpts.onChain - }); + // only if user specified that genesis state publishing is not needed we won't do this. + if (!opts.revocationOpts.genesisPublishingDisabled) { + await this.publishRevocationInfoByCredentialStatusType(did, opts.revocationOpts.type, { + rhsUrl: opts.revocationOpts.id, + onChain: opts.revocationOpts.onChain + }); + } await this._credentialWallet.save(credential); @@ -1248,30 +1268,18 @@ export class IdentityWallet implements IIdentityWallet { } let nodes: ProofNode[] = []; - if (opts?.treeModel) { - nodes = await getNodesRepresentation( - opts.revokedNonces, - { - revocationTree: opts.treeModel.revocationTree, - claimsTree: opts.treeModel.claimsTree, - state: opts.treeModel.state, - rootsTree: opts.treeModel.rootsTree - }, - opts.treeModel.state - ); - } else { - const treeState = await this.getDIDTreeModel(issuerDID); - nodes = await getNodesRepresentation( - opts?.revokedNonces, - { - revocationTree: treeState.revocationTree, - claimsTree: treeState.claimsTree, - state: treeState.state, - rootsTree: treeState.rootsTree - }, - treeState.state - ); - } + + const tree = opts?.treeModel ?? (await this.getDIDTreeModel(issuerDID)); + nodes = await getNodesRepresentation( + opts?.revokedNonces ?? [], + { + revocationTree: tree.revocationTree, + claimsTree: tree.claimsTree, + state: tree.state, + rootsTree: tree.rootsTree + }, + tree.state + ); if (!nodes.length) { return; diff --git a/tests/identity/id.test.ts b/tests/identity/id.test.ts index de79646a..2644c8eb 100644 --- a/tests/identity/id.test.ts +++ b/tests/identity/id.test.ts @@ -15,7 +15,8 @@ import { NativeProver, Iden3SparseMerkleTreeProof, BJJSignatureProof2021, - TreeState + TreeState, + IdentityCreationOptions } from '../../src'; import { MOCK_STATE_STORAGE, @@ -26,7 +27,8 @@ import { registerKeyProvidersInMemoryKMS, WALLET_KEY, createEthereumBasedIdentity, - SEED_ISSUER + SEED_ISSUER, + RHS_CONTRACT_ADDRESS } from '../helpers'; import { expect } from 'chai'; import { Wallet } from 'ethers'; @@ -397,4 +399,54 @@ describe('identity', () => { expect(credential).to.be.deep.eq(restoredCredential); expect(did.string()).to.be.eq(restoredDid.string()); }); + + it('replace auth bjj credential', async () => { + const idRequest: IdentityCreationOptions = { + method: DidMethod.Iden3, + blockchain: Blockchain.Polygon, + networkId: NetworkId.Amoy, + seed: SEED_ISSUER, + revocationOpts: { + type: CredentialStatusType.Iden3ReverseSparseMerkleTreeProof, + id: RHS_URL + } + }; + const { did, credential } = await idWallet.createIdentity(idRequest); + expect(did.string()).to.equal(expectedDID); + + let credentials = await credWallet.findByQuery({ + credentialSubject: { + x: { + $eq: credential.credentialSubject['x'] + }, + y: { + $eq: credential.credentialSubject['y'] + } + } + }); + expect(credentials.length).to.be.equal(1); + + idRequest.revocationOpts.type = CredentialStatusType.Iden3OnchainSparseMerkleTreeProof2023; + idRequest.revocationOpts.id = RHS_CONTRACT_ADDRESS; + idRequest.revocationOpts.genesisPublishingDisabled = true; + + const { did: did2, credential: credential2 } = await idWallet.createIdentity(idRequest); + expect(did2.string()).to.equal(expectedDID); + expect(credential2.credentialStatus.type).to.be.equal( + CredentialStatusType.Iden3OnchainSparseMerkleTreeProof2023 + ); + expect(credential2.credentialStatus.id).to.contain('state'); + + credentials = await credWallet.findByQuery({ + credentialSubject: { + x: { + $eq: credential2.credentialSubject['x'] + }, + y: { + $eq: credential2.credentialSubject['y'] + } + } + }); + expect(credentials.length).to.be.equal(1); + }); });