From e72b3d0137cfb2f8ee650e9ad7b6755c97480f70 Mon Sep 17 00:00:00 2001 From: volodymyr-basiuk <31999965+volodymyr-basiuk@users.noreply.github.com> Date: Mon, 23 Dec 2024 12:29:00 +0200 Subject: [PATCH] specify protocol version in getSupportedProfiles (#295) * specify protocol version in getSupportedProfiles --- src/iden3comm/handlers/auth.ts | 45 ++++++++++-------------- src/iden3comm/packers/jws.ts | 27 +++++++++----- src/iden3comm/packers/plain.ts | 12 +++++-- src/iden3comm/packers/zkp.ts | 36 ++++++++++--------- tests/handlers/discover-protocol.test.ts | 26 ++++++++------ tests/iden3comm/jws.test.ts | 6 ++++ tests/iden3comm/packageManager.test.ts | 12 +++++++ tests/iden3comm/zkp.test.ts | 10 +++++- 8 files changed, 106 insertions(+), 68 deletions(-) diff --git a/src/iden3comm/handlers/auth.ts b/src/iden3comm/handlers/auth.ts index 9ae9bfe6..beb470e2 100644 --- a/src/iden3comm/handlers/auth.ts +++ b/src/iden3comm/handlers/auth.ts @@ -1,4 +1,4 @@ -import { MediaType, ProtocolVersion } from '../constants'; +import { MediaType } from '../constants'; import { IProofService } from '../../proof/proof-service'; import { PROTOCOL_MESSAGE_TYPE } from '../constants'; @@ -489,35 +489,26 @@ export class AuthHandler profile?: string[] | undefined ): MediaType { let mediaType: MediaType; - if (profile?.length) { - const supportedMediaTypes: MediaType[] = []; - for (const acceptProfile of profile) { - // 1. check protocol version - const { protocolVersion, env } = parseAcceptProfile(acceptProfile); - const responseTypeVersion = Number(responseType.split('/').at(-2)); - if ( - protocolVersion !== ProtocolVersion.V1 || - (protocolVersion === ProtocolVersion.V1 && - (responseTypeVersion < 1 || responseTypeVersion >= 2)) - ) { - continue; - } - // 2. check packer support - if (this._packerMgr.isProfileSupported(env, acceptProfile)) { - supportedMediaTypes.push(env); - } + if (!profile?.length) { + return ctx.mediaType || MediaType.ZKPMessage; + } + const supportedMediaTypes: MediaType[] = []; + for (const acceptProfile of profile) { + const { env } = parseAcceptProfile(acceptProfile); + if (this._packerMgr.isProfileSupported(env, acceptProfile)) { + supportedMediaTypes.push(env); } + } - if (!supportedMediaTypes.length) { - throw new Error('no packer with profile which meets `accept` header requirements'); - } + if (!supportedMediaTypes.length) { + throw new Error('no packer with profile which meets `accept` header requirements'); + } - mediaType = supportedMediaTypes[0]; - if (ctx.mediaType && supportedMediaTypes.includes(ctx.mediaType)) { - mediaType = ctx.mediaType; - } - } else { - mediaType = ctx.mediaType || MediaType.ZKPMessage; + mediaType = supportedMediaTypes.includes(MediaType.ZKPMessage) + ? MediaType.ZKPMessage + : supportedMediaTypes[0]; + if (ctx.mediaType && supportedMediaTypes.includes(ctx.mediaType)) { + mediaType = ctx.mediaType; } return mediaType; } diff --git a/src/iden3comm/packers/jws.ts b/src/iden3comm/packers/jws.ts index e382aaad..6667e3bf 100644 --- a/src/iden3comm/packers/jws.ts +++ b/src/iden3comm/packers/jws.ts @@ -1,5 +1,10 @@ import { BasicMessage, IPacker, JWSPackerParams } from '../types'; -import { AcceptJwsAlgorithms, MediaType, SUPPORTED_PUBLIC_KEY_TYPES } from '../constants'; +import { + AcceptJwsAlgorithms, + MediaType, + ProtocolVersion, + SUPPORTED_PUBLIC_KEY_TYPES +} from '../constants'; import { extractPublicKeyBytes, resolveVerificationMethods } from '../utils/did'; import { keyPath, KMS } from '../../kms/'; @@ -23,6 +28,9 @@ import { parseAcceptProfile } from '../utils'; * @implements implements IPacker interface */ export class JWSPacker implements IPacker { + private readonly supportedAlgorithms = [AcceptJwsAlgorithms.ES256K, AcceptJwsAlgorithms.ES256KR]; + private readonly supportedProtocolVersions = [ProtocolVersion.V1]; + /** * Creates an instance of JWSPacker. * @@ -105,12 +113,18 @@ export class JWSPacker implements IPacker { /** {@inheritDoc IPacker.getSupportedProfiles} */ getSupportedProfiles(): string[] { - return [`env=${this.mediaType()}&alg=${this.getSupportedAlgorithms().join(',')}`]; + return this.supportedProtocolVersions.map( + (v) => `${v};env=${this.mediaType()};alg=${this.supportedAlgorithms.join(',')}` + ); } /** {@inheritDoc IPacker.isProfileSupported} */ isProfileSupported(profile: string) { - const { env, circuits, alg } = parseAcceptProfile(profile); + const { protocolVersion, env, circuits, alg } = parseAcceptProfile(profile); + + if (!this.supportedProtocolVersions.includes(protocolVersion)) { + return false; + } if (env !== this.mediaType()) { return false; } @@ -119,16 +133,11 @@ export class JWSPacker implements IPacker { throw new Error(`Circuits are not supported for ${env} media type`); } - const supportedAlgArr = this.getSupportedAlgorithms(); const algSupported = - !alg?.length || alg.some((a) => supportedAlgArr.includes(a as AcceptJwsAlgorithms)); + !alg?.length || alg.some((a) => this.supportedAlgorithms.includes(a as AcceptJwsAlgorithms)); return algSupported; } - private getSupportedAlgorithms(): AcceptJwsAlgorithms[] { - return [AcceptJwsAlgorithms.ES256K, AcceptJwsAlgorithms.ES256KR]; - } - private async resolveDidDoc(from: string) { let didDocument: DIDDocument; try { diff --git a/src/iden3comm/packers/plain.ts b/src/iden3comm/packers/plain.ts index b5eaeb7d..b3383b65 100644 --- a/src/iden3comm/packers/plain.ts +++ b/src/iden3comm/packers/plain.ts @@ -1,5 +1,5 @@ import { BasicMessage, IPacker } from '../types'; -import { MediaType } from '../constants'; +import { MediaType, ProtocolVersion } from '../constants'; import { byteDecoder, byteEncoder } from '../../utils'; import { parseAcceptProfile } from '../utils'; @@ -11,6 +11,8 @@ import { parseAcceptProfile } from '../utils'; * @implements implements IPacker interface */ export class PlainPacker implements IPacker { + private readonly supportedProtocolVersions = [ProtocolVersion.V1]; + /** * Packs a basic message using the specified parameters. * @@ -57,12 +59,16 @@ export class PlainPacker implements IPacker { /** {@inheritDoc IPacker.getSupportedProfiles} */ getSupportedProfiles(): string[] { - return [`env=${this.mediaType()}`]; + return this.supportedProtocolVersions.map((v) => `${v};env=${this.mediaType()}`); } /** {@inheritDoc IPacker.isProfileSupported} */ isProfileSupported(profile: string) { - const { env, circuits, alg } = parseAcceptProfile(profile); + const { protocolVersion, env, circuits, alg } = parseAcceptProfile(profile); + + if (!this.supportedProtocolVersions.includes(protocolVersion)) { + return false; + } if (env !== this.mediaType()) { return false; } diff --git a/src/iden3comm/packers/zkp.ts b/src/iden3comm/packers/zkp.ts index 94d7e9ba..43f9a7fa 100644 --- a/src/iden3comm/packers/zkp.ts +++ b/src/iden3comm/packers/zkp.ts @@ -20,7 +20,7 @@ import { ErrStateVerificationFailed, ErrUnknownCircuitID } from '../errors'; -import { AcceptAuthCircuits, AcceptJwzAlgorithms, MediaType } from '../constants'; +import { AcceptAuthCircuits, AcceptJwzAlgorithms, MediaType, ProtocolVersion } from '../constants'; import { byteDecoder, byteEncoder } from '../../utils'; import { DEFAULT_AUTH_VERIFY_DELAY } from '../constants'; import { parseAcceptProfile } from '../utils'; @@ -86,6 +86,10 @@ export class VerificationHandlerFunc { * @implements implements IPacker interface */ export class ZKPPacker implements IPacker { + private readonly supportedProtocolVersions = [ProtocolVersion.V1]; + private readonly supportedAlgorithms = [AcceptJwzAlgorithms.Groth16]; + private readonly supportedCircuitIds = [AcceptAuthCircuits.AuthV2]; + /** * Creates an instance of ZKPPacker. * @param {Map} provingParamsMap - string is derived by JSON.parse(ProvingMethodAlg) @@ -178,37 +182,35 @@ export class ZKPPacker implements IPacker { /** {@inheritDoc IPacker.getSupportedProfiles} */ getSupportedProfiles(): string[] { - return [ - `env=${this.mediaType()}&alg=${this.getSupportedAlgorithms().join( - ',' - )}&circuitIds=${this.getSupportedCircuitIds().join(',')}` - ]; + return this.supportedProtocolVersions.map( + (v) => + `${v};env=${this.mediaType()};alg=${this.supportedAlgorithms.join( + ',' + )};circuitIds=${this.supportedCircuitIds.join(',')}` + ); } /** {@inheritDoc IPacker.isProfileSupported} */ isProfileSupported(profile: string) { - const { env, circuits, alg } = parseAcceptProfile(profile); + const { protocolVersion, env, circuits, alg } = parseAcceptProfile(profile); + + if (!this.supportedProtocolVersions.includes(protocolVersion)) { + return false; + } + if (env !== this.mediaType()) { return false; } - const supportedCircuitIds = this.getSupportedCircuitIds(); + const supportedCircuitIds = this.supportedCircuitIds; const circuitIdSupported = !circuits?.length || circuits.some((c) => supportedCircuitIds.includes(c)); - const supportedAlgArr = this.getSupportedAlgorithms(); + const supportedAlgArr = this.supportedAlgorithms; const algSupported = !alg?.length || alg.some((a) => supportedAlgArr.includes(a as AcceptJwzAlgorithms)); return algSupported && circuitIdSupported; } - - private getSupportedAlgorithms(): AcceptJwzAlgorithms[] { - return [AcceptJwzAlgorithms.Groth16]; - } - - private getSupportedCircuitIds(): AcceptAuthCircuits[] { - return [AcceptAuthCircuits.AuthV2]; - } } const verifySender = async (token: Token, msg: BasicMessage): Promise => { diff --git a/tests/handlers/discover-protocol.test.ts b/tests/handlers/discover-protocol.test.ts index e5c117f0..12a7ac5e 100644 --- a/tests/handlers/discover-protocol.test.ts +++ b/tests/handlers/discover-protocol.test.ts @@ -49,7 +49,7 @@ describe('discovery-protocol', () => { expect(disclosures[0][DiscoverFeatureQueryType.FeatureType]).to.be.eq( DiscoveryProtocolFeatureType.Accept ); - expect(disclosures[0].id).to.be.eq('env=application/iden3comm-plain-json'); + expect(disclosures[0].id).to.be.eq('iden3comm/v1;env=application/iden3comm-plain-json'); }); it('jws and plain message accept disclosures', async () => { @@ -72,8 +72,10 @@ describe('discovery-protocol', () => { DiscoveryProtocolFeatureType.Accept ); const disclosureIds = disclosures.map((d) => d.id); - expect(disclosureIds).to.include('env=application/iden3comm-plain-json'); - expect(disclosureIds).to.include('env=application/iden3comm-signed-json&alg=ES256K,ES256K-R'); + expect(disclosureIds).to.include('iden3comm/v1;env=application/iden3comm-plain-json'); + expect(disclosureIds).to.include( + 'iden3comm/v1;env=application/iden3comm-signed-json;alg=ES256K,ES256K-R' + ); }); it('zkp and plain message accept disclosures', async () => { @@ -95,9 +97,9 @@ describe('discovery-protocol', () => { DiscoveryProtocolFeatureType.Accept ); const disclosureIds = disclosures.map((d) => d.id); - expect(disclosureIds).to.include('env=application/iden3comm-plain-json'); + expect(disclosureIds).to.include('iden3comm/v1;env=application/iden3comm-plain-json'); expect(disclosureIds).to.include( - 'env=application/iden3-zkp-json&alg=groth16&circuitIds=authV2' + 'iden3comm/v1;env=application/iden3-zkp-json;alg=groth16;circuitIds=authV2' ); }); @@ -123,11 +125,13 @@ describe('discovery-protocol', () => { DiscoveryProtocolFeatureType.Accept ); const disclosureIds = disclosures.map((d) => d.id); - expect(disclosureIds).to.include('env=application/iden3comm-plain-json'); + expect(disclosureIds).to.include('iden3comm/v1;env=application/iden3comm-plain-json'); + expect(disclosureIds).to.include( + 'iden3comm/v1;env=application/iden3-zkp-json;alg=groth16;circuitIds=authV2' + ); expect(disclosureIds).to.include( - 'env=application/iden3-zkp-json&alg=groth16&circuitIds=authV2' + 'iden3comm/v1;env=application/iden3comm-signed-json;alg=ES256K,ES256K-R' ); - expect(disclosureIds).to.include('env=application/iden3comm-signed-json&alg=ES256K,ES256K-R'); }); it('zkp, jws and plain message accept disclosures with exact match', async () => { @@ -140,7 +144,7 @@ describe('discovery-protocol', () => { const acceptQueryMessageWithMatch = createDiscoveryFeatureQueryMessage([ { [DiscoverFeatureQueryType.FeatureType]: DiscoveryProtocolFeatureType.Accept, - match: 'env=application/iden3-zkp-json&alg=groth16&circuitIds=authV2' + match: 'iden3comm/v1;env=application/iden3-zkp-json;alg=groth16;circuitIds=authV2' } ]); @@ -153,7 +157,7 @@ describe('discovery-protocol', () => { DiscoveryProtocolFeatureType.Accept ); expect(disclosures[0].id).to.include( - 'env=application/iden3-zkp-json&alg=groth16&circuitIds=authV2' + 'iden3comm/v1;env=application/iden3-zkp-json;alg=groth16;circuitIds=authV2' ); }); @@ -306,7 +310,7 @@ describe('discovery-protocol', () => { DiscoveryProtocolFeatureType.Protocol ); const disclosureIds = disclosures.map((d) => d.id); - expect(disclosureIds).to.include('env=application/iden3comm-plain-json'); + expect(disclosureIds).to.include('iden3comm/v1;env=application/iden3comm-plain-json'); expect(disclosureIds).to.include(PROTOCOL_MESSAGE_TYPE.AUTHORIZATION_REQUEST_MESSAGE_TYPE); expect(disclosureIds).to.include(PROTOCOL_MESSAGE_TYPE.AUTHORIZATION_REQUEST_MESSAGE_TYPE); }); diff --git a/tests/iden3comm/jws.test.ts b/tests/iden3comm/jws.test.ts index 003a83ef..da3f9fdd 100644 --- a/tests/iden3comm/jws.test.ts +++ b/tests/iden3comm/jws.test.ts @@ -17,6 +17,7 @@ import { DIDResolutionResult } from 'did-resolver'; import { ES256KSigner } from 'did-jwt'; import { DID, getChainId, Id } from '@iden3/js-iden3-core'; import { Hex } from '@iden3/js-crypto'; +import { MediaType } from '../../src/iden3comm/constants'; const didExample = { '@context': [ @@ -217,4 +218,9 @@ describe('jws packer tests', () => { const data = await packer.unpack(tokenBytes); expect(data).to.not.be.undefined; }); + + it('test getSupportedProfiles', () => { + const [accept] = packer.getSupportedProfiles(); + expect(accept).to.be.eq(`iden3comm/v1;env=${MediaType.SignedMessage};alg=ES256K,ES256K-R`); + }); }); diff --git a/tests/iden3comm/packageManager.test.ts b/tests/iden3comm/packageManager.test.ts index 83037ef3..9aa06f92 100644 --- a/tests/iden3comm/packageManager.test.ts +++ b/tests/iden3comm/packageManager.test.ts @@ -1,6 +1,7 @@ import { DataPrepareHandlerFunc, PackageManager, + PlainPacker, VerificationHandlerFunc, ZKPPacker } from '../../src/iden3comm/index'; @@ -70,6 +71,17 @@ describe('tests packageManager with ZKP Packer', () => { expect(senderDID.string()).to.deep.equal(unpackedMessage.from); expect(byteDecoder.decode(msgBytes)).to.deep.equal(JSON.stringify(unpackedMessage)); }); + + it('test getSupportedProfiles', () => { + const pm = new PackageManager(); + pm.registerPackers([new ZKPPacker(new Map(), new Map()), new PlainPacker()]); + const supportedProfiles = pm.getSupportedProfiles(); + expect(supportedProfiles.length).to.be.eq(2); + expect(supportedProfiles).to.include( + `iden3comm/v1;env=${MediaType.ZKPMessage};alg=groth16;circuitIds=authV2` + ); + expect(supportedProfiles).to.include(`iden3comm/v1;env=${MediaType.PlainMessage}`); + }); }); const createFetchCredentialMessage = (typ: MediaType, from: DID, to: DID) => { diff --git a/tests/iden3comm/zkp.test.ts b/tests/iden3comm/zkp.test.ts index 8aad0d85..06f88f12 100644 --- a/tests/iden3comm/zkp.test.ts +++ b/tests/iden3comm/zkp.test.ts @@ -2,7 +2,7 @@ import { DID } from '@iden3/js-iden3-core'; import { Token, ProvingMethodAlg } from '@iden3/js-jwz'; import { ZKPPackerParams } from '../../src/iden3comm/types'; import { AuthV2PubSignals } from '../../src/circuits'; -import { PROTOCOL_MESSAGE_TYPE } from '../../src/iden3comm/constants'; +import { MediaType, PROTOCOL_MESSAGE_TYPE } from '../../src/iden3comm/constants'; import { byteDecoder, byteEncoder } from '../../src'; import { expect } from 'chai'; import { initZKPPacker } from './mock/proving'; @@ -41,4 +41,12 @@ describe('zkp packer tests', () => { expect(PROTOCOL_MESSAGE_TYPE.AUTHORIZATION_RESPONSE_MESSAGE_TYPE).to.deep.equal(iden3msg.type); }); + + it('test getSupportedProfiles', async () => { + const p = await initZKPPacker(); + const [accept] = p.getSupportedProfiles(); + expect(accept).to.be.eq( + `iden3comm/v1;env=${MediaType.ZKPMessage};alg=groth16;circuitIds=authV2` + ); + }); });