diff --git a/src/domain/index.ts b/src/domain/index.ts index 07b949791..8711f5afa 100644 --- a/src/domain/index.ts +++ b/src/domain/index.ts @@ -6,3 +6,4 @@ export * from "./buildingBlocks/Castor"; export * from "./buildingBlocks/Mercury"; export * from "./buildingBlocks/Pluto"; export * from "./buildingBlocks/Pollux"; +export * from "./utils/JWT"; diff --git a/src/domain/models/DIDDocument.ts b/src/domain/models/DIDDocument.ts index 266eda176..9ee8b7346 100644 --- a/src/domain/models/DIDDocument.ts +++ b/src/domain/models/DIDDocument.ts @@ -122,6 +122,15 @@ export class DIDDocument { return serviceArray; }, [] as Service[]); } + + get verificationMethods(): VerificationMethod[] { + return this.coreProperties.reduce((serviceArray, coreProperty) => { + if (coreProperty instanceof VerificationMethods) { + return [...serviceArray, ...coreProperty.values]; + } + return serviceArray; + }, [] as VerificationMethod[]); + } } export interface PublicKeyJWK { diff --git a/src/domain/utils/JWT.ts b/src/domain/utils/JWT.ts new file mode 100644 index 000000000..e89d3326f --- /dev/null +++ b/src/domain/utils/JWT.ts @@ -0,0 +1,83 @@ +import { JWTPayload, Signer, createJWT } from "did-jwt"; +import { base64url } from "multiformats/bases/base64"; +import { DID, PrivateKey } from ".."; +import { asJsonObj, isNil } from "../../utils/guards"; + +export namespace JWT { + export interface Header { + typ: string; + alg: string; + [key: string]: any; + } + + export type Payload = JWTPayload; + + export interface DecodedObj { + header: Header; + payload: Payload; + signature: string; + data: string; + } + + + /** + * Creates a signed JWT + * + * @param issuer + * @param privateKey + * @param payload + * @returns + */ + export const sign = async ( + issuer: DID, + privateKey: PrivateKey, + payload: Partial, + header?: Partial
+ ): Promise => { + if (!privateKey.isSignable()) { + throw new Error("Key is not signable"); + } + + const signer: Signer = async (data: any) => { + const signature = privateKey.sign(Buffer.from(data)); + const encoded = base64url.baseEncode(signature); + return encoded; + }; + + const jwt = await createJWT( + payload, + { issuer: issuer.toString(), signer }, + { alg: privateKey.alg, ...asJsonObj(header) } + ); + + return jwt; + }; + + /** + * decode a JWT into its parts + * + * @param jws + * @returns + */ + export const decode = (jws: string): DecodedObj => { + const parts = jws.split("."); + const headersEnc = parts.at(0); + const payloadEnc = parts.at(1); + + if (parts.length != 3 || isNil(headersEnc) || isNil(payloadEnc)) { + // TODO error + // throw new InvalidJWTString(); + throw new Error(); + } + + const headers = base64url.baseDecode(headersEnc); + const payload = base64url.baseDecode(payloadEnc); + + return { + header: JSON.parse(Buffer.from(headers).toString()), + payload: JSON.parse(Buffer.from(payload).toString()), + signature: parts[2], + data: `${headersEnc}.${payloadEnc}`, + }; + }; +} diff --git a/src/pollux/Pollux.ts b/src/pollux/Pollux.ts index 6021ab75a..496e4043f 100644 --- a/src/pollux/Pollux.ts +++ b/src/pollux/Pollux.ts @@ -1,4 +1,5 @@ import { uuid } from "@stablelib/uuid"; +import { base58btc } from "multiformats/bases/base58"; import type * as Anoncreds from "anoncreds-browser"; import * as jsonld from 'jsonld'; import { Castor } from "../domain/buildingBlocks/Castor"; @@ -356,7 +357,6 @@ export default class Pollux implements IPollux { } }); - const subject = credential.subject; if (!privateKey.isSignable()) { throw new CastorError.InvalidKeyError("Cannot sign the proof challenge with this key.") } @@ -365,6 +365,10 @@ export default class Pollux implements IPollux { throw new PolluxError.InvalidCredentialError("Cannot create proofs with this type of credential.") } + const subject = credential.subject; + const issuerDID = DID.fromString(subject); + const kid = await this.getSigningKid(issuerDID, privateKey); + const payload: JWTPresentationPayload = { iss: subject, aud: domain, @@ -374,9 +378,10 @@ export default class Pollux implements IPollux { } const jws = await this.JWT.sign({ - issuerDID: DID.fromString(subject), + issuerDID, privateKey, - payload + payload, + header: { kid } }); const presentationSubmission: PresentationSubmission = { @@ -911,9 +916,11 @@ export default class Pollux implements IPollux { if (!keyPair) { throw new Error("Required keyPair "); } + + const kid = await this.getSigningKid(did, keyPair.privateKey); const challenge = offer.options.challenge; const domain = offer.options.domain; - + const signedJWT = await this.JWT.sign({ issuerDID: did, privateKey: keyPair.privateKey, @@ -924,7 +931,8 @@ export default class Pollux implements IPollux { "@context": ["https://www.w3.org/2018/presentations/v1"], type: ["VerifiablePresentation"], }, - } + }, + header: { kid } }); return signedJWT as ProcessedCredentialOfferPayloads[Types]; } @@ -936,8 +944,11 @@ export default class Pollux implements IPollux { if (!keyPair) { throw new Error("Required keyPair "); } + + const kid = await this.getSigningKid(did, keyPair.privateKey); const challenge = offer.options.challenge; const domain = offer.options.domain; + const signedJWT = await this.JWT.sign({ issuerDID: did, privateKey: keyPair.privateKey, @@ -948,8 +959,10 @@ export default class Pollux implements IPollux { "@context": ["https://www.w3.org/2018/presentations/v1"], type: ["VerifiablePresentation"], }, - } + }, + header: { kid }, }); + return signedJWT as ProcessedCredentialOfferPayloads[Types]; } @@ -1094,6 +1107,8 @@ export default class Pollux implements IPollux { const jwtPresentationRequest = presentationRequest const presReqJson: JWTJson = jwtPresentationRequest.toJSON() as any; const presReqOptions = presReqJson.options; + const kid = await this.getSigningKid(options.did, options.privateKey); + const signedJWT = await this.JWT.sign({ issuerDID: options.did, privateKey: options.privateKey, @@ -1102,7 +1117,8 @@ export default class Pollux implements IPollux { aud: presReqOptions.domain, nonce: presReqOptions.challenge, vp: credential.presentation() - } + }, + header: { kid } }); return signedJWT; @@ -1146,4 +1162,25 @@ export default class Pollux implements IPollux { throw new PolluxError.InvalidPresentationProofArgs(); } + + + /** + * try to match the privateKey with a dids verificationMethod + * returning the relevant key id + * + * @param did + * @param privateKey + * @returns {string} kid (key identifier) + */ + private async getSigningKid(did: DID, privateKey: PrivateKey) { + const pubKey = privateKey.publicKey(); + const encoded = base58btc.encode(pubKey.to.Buffer()); + const document = await this.castor.resolveDID(did.toString()); + + const signingKey = document.verificationMethods.find(key => { + return key.publicKeyMultibase === encoded; + }); + + return signingKey?.id; + } } diff --git a/src/pollux/utils/JWT.ts b/src/pollux/utils/JWT.ts index 6b8fbfcf5..71e04beee 100644 --- a/src/pollux/utils/JWT.ts +++ b/src/pollux/utils/JWT.ts @@ -1,21 +1,29 @@ -import * as didJWT from "did-jwt"; import { JWTCredential } from "../../pollux/models/JWTVerifiableCredential"; import { JWTCore } from "./jwt/JWTCore"; -import { JWTInstanceType, JWTSignOptions, JWTVerifyOptions } from "./jwt/types"; -import { decodeJWS } from "./decodeJWS"; import { base64url } from "multiformats/bases/base64"; -import { isNil } from "../../utils"; - -export class JWT extends JWTCore { - public type = JWTInstanceType.JWT; +import { JsonObj, isNil } from "../../utils"; +import * as Domain from "../../domain"; +export class JWT extends JWTCore { async decode(jws: string) { - return decodeJWS(jws); + return Domain.JWT.decode(jws); + } + + async sign(options: { + issuerDID: Domain.DID, + privateKey: Domain.PrivateKey, + payload: Partial, + header?: JsonObj, + }): Promise { + const { issuerDID, privateKey, payload, header } = options; + return Domain.JWT.sign(issuerDID, privateKey, payload, header); } - async verify( - options: JWTVerifyOptions - ): Promise { + async verify(options: { + jws: string; + issuerDID: Domain.DID, + holderDID?: Domain.DID, + }): Promise { try { const { issuerDID, jws, holderDID } = options; const resolved = await this.resolve(issuerDID.toString()); @@ -54,20 +62,4 @@ export class JWT extends JWTCore { return false; } } - - async sign( - options: JWTSignOptions - ): Promise { - const { issuerDID, privateKey, payload } = options; - if (!privateKey.isSignable()) { - throw new Error("Key is not signable"); - } - const { signAlg, signer } = this.getSKConfig(privateKey); - const jwt = await didJWT.createJWT( - payload, - { issuer: issuerDID.toString(), signer }, - { alg: signAlg } - ); - return jwt; - } } diff --git a/src/pollux/utils/SDJWT.ts b/src/pollux/utils/SDJWT.ts index cef8fa30f..efd5bc098 100644 --- a/src/pollux/utils/SDJWT.ts +++ b/src/pollux/utils/SDJWT.ts @@ -1,24 +1,24 @@ -import { SDJwtVcInstance, } from '@sd-jwt/sd-jwt-vc'; +import { SDJwtVcInstance, SdJwtVcPayload, } from '@sd-jwt/sd-jwt-vc'; import type { DisclosureFrame, Extensible, PresentationFrame } from '@sd-jwt/types'; import { JWTCore } from "./jwt/JWTCore"; -import { JWTInstanceType, JWTSignOptions, JWTVerifyOptions } from "./jwt/types"; -import { JWTObject, PublicKey, PrivateKey } from '../../domain'; -import { decodeJWS } from './decodeJWS'; import { SDJWTCredential } from '../models/SDJWTVerifiableCredential'; +import * as Domain from '../../domain'; - -export class SDJWT extends JWTCore { - public type = JWTInstanceType.SDJWT; - - async decode(jws: string): Promise { - return decodeJWS(jws) +export class SDJWT extends JWTCore { + async decode(jws: string) { + return Domain.JWT.decode(jws); } - public createDisclosureFrameFor(config: DisclosureFrame): DisclosureFrame { - return config; + createDisclosureFrameFor(config: DisclosureFrame): DisclosureFrame { + return config; } - async verify(options: JWTVerifyOptions): Promise { + async verify(options: { + issuerDID: Domain.DID, + jws: string, + requiredClaimKeys?: string[], + requiredKeyBindings?: boolean + }): Promise { const { issuerDID, jws } = options; const resolved = await this.resolve(issuerDID.toString()); const verificationMethods = resolved.didDocument?.verificationMethod; @@ -30,7 +30,7 @@ export class SDJWT extends JWTCore { throw new Error("Invalid issuer"); } for (const verificationMethod of verificationMethods) { - const pk: PublicKey | undefined = this.getPKInstance(verificationMethod) + const pk: Domain.PublicKey | undefined = this.getPKInstance(verificationMethod) if (pk && pk.canVerify()) { const sdjwt = new SDJwtVcInstance(this.getPKConfig(pk)); try { @@ -49,22 +49,23 @@ export class SDJWT extends JWTCore { return false; } - async sign(options: JWTSignOptions): Promise { + async sign(options: { + issuerDID: Domain.DID, + privateKey: Domain.PrivateKey, + payload: SdJwtVcPayload, + disclosureFrame: DisclosureFrame + }): Promise { const sdjwt = new SDJwtVcInstance(this.getSKConfig(options.privateKey)); return sdjwt.issue(options.payload, options.disclosureFrame) } - async createPresentationFor( - options: { - jws: string, - privateKey: PrivateKey, - frame?: PresentationFrame | undefined - } - ) { - const sdjwt = new SDJwtVcInstance( - this.getSKConfig(options.privateKey) - ); - return sdjwt.present(options.jws, options.frame) + async createPresentationFor(options: { + jws: string, + privateKey: Domain.PrivateKey, + frame?: PresentationFrame | undefined + }) { + const sdjwt = new SDJwtVcInstance(this.getSKConfig(options.privateKey)); + return sdjwt.present(options.jws, options.frame) } } \ No newline at end of file diff --git a/src/pollux/utils/jwt/JWTCore.ts b/src/pollux/utils/jwt/JWTCore.ts index c05fd6b5e..3323a04ca 100644 --- a/src/pollux/utils/jwt/JWTCore.ts +++ b/src/pollux/utils/jwt/JWTCore.ts @@ -1,11 +1,7 @@ import * as didResolver from "did-resolver"; -import type { Extensible } from '@sd-jwt/types'; import { base64url } from "multiformats/bases/base64"; import { base58btc } from 'multiformats/bases/base58'; - import { Castor, AlsoKnownAs, Controller, VerificationMethods, Services, PublicKey, PrivateKey, Signer, Hasher, Verifier, Curve, Apollo, KeyProperties, KeyTypes } from "../../../domain"; -import { JWTDecodeResponse, JWTInstanceType, JWTSignOptions, JWTVerifyOptions } from "./types"; - import { defaultHashConfig, defaultSaltGen } from "./config"; import { VerificationKeyType } from "../../../castor/types"; @@ -15,25 +11,11 @@ import { VerificationKeyType } from "../../../castor/types"; * Wraps signing and verifying functionality with all our supported algorithms * Works for both secp256k1(ECDSA) and ed25519(EdDSA) */ -export abstract class JWTCore { - abstract verify( - options: JWTVerifyOptions - ): Promise; - - abstract sign( - options: JWTSignOptions - ): Promise; - - abstract decode(jws: string): JWTDecodeResponse - abstract type: JWTInstanceType; - - public castor: Castor; - public apollo: Apollo; - - constructor(apollo: Apollo, castor: Castor) { - this.apollo = apollo; - this.castor = castor; - } +export abstract class JWTCore { + constructor( + public readonly apollo: Apollo, + public readonly castor: Castor + ) {} public async resolve(did: string): Promise { const resolved = await this.castor.resolveDID(did); diff --git a/src/pollux/utils/jwt/types.ts b/src/pollux/utils/jwt/types.ts deleted file mode 100644 index 38deeedfd..000000000 --- a/src/pollux/utils/jwt/types.ts +++ /dev/null @@ -1,54 +0,0 @@ -import { JWTPayload } from "did-jwt"; -import { SdJwtVcPayload } from "@sd-jwt/sd-jwt-vc"; -import { DisclosureFrame } from '@sd-jwt/types'; -import { SDJwtInstance } from '@sd-jwt/core'; -import { - DID, - JWTObject, - PrivateKey, -} from "../../../domain"; -import { Extensible } from "did-resolver"; - -export enum JWTInstanceType { - JWT = "JWT", - SDJWT = "SDJWT" -} - -export type JWTVerifyOptions< - T extends JWTInstanceType -> = T extends JWTInstanceType.JWT ? - { - issuerDID: DID, - holderDID?: DID, - jws: string - } : - { - issuerDID: DID, - jws: string, - requiredClaimKeys?: string[], - requiredKeyBindings?: boolean - } - -export type JWTSignOptions< - T extends JWTInstanceType, - E extends Extensible -> = T extends JWTInstanceType.JWT ? - { - issuerDID: DID, - privateKey: PrivateKey, - payload: Partial - } : - { - issuerDID: DID, - privateKey: PrivateKey, - payload: SdJwtVcPayload, - disclosureFrame: DisclosureFrame - } - - - -export type JWTDecodeResponse< - T extends JWTInstanceType -> = T extends JWTInstanceType.JWT ? - Promise : - ReturnType['verify']> \ No newline at end of file diff --git a/tests/agent/Agent.test.ts b/tests/agent/Agent.test.ts index fcd83f937..3205e10b3 100644 --- a/tests/agent/Agent.test.ts +++ b/tests/agent/Agent.test.ts @@ -85,7 +85,7 @@ describe("Agent Tests", () => { })); sandbox = sinon.createSandbox(); const apollo: Apollo = new Apollo(); - castor = CastorMock; + castor = new Castor(apollo); const httpManager: Api = { request: async () => new ApiResponse(new Uint8Array(), 200), }; diff --git a/tests/domain/JWT.test.ts b/tests/domain/JWT.test.ts new file mode 100644 index 000000000..37accb999 --- /dev/null +++ b/tests/domain/JWT.test.ts @@ -0,0 +1,79 @@ +import { expect } from "chai"; +import { base64url } from "multiformats/bases/base64"; +import { JWT } from "../../src/domain"; +import { Domain, Secp256k1PrivateKey } from "../../src"; +import * as Fixtures from "../fixtures"; + +describe("Domain - JWT", () => { + test("decode", async () => { + const header = { a: 1 }; + const payload = { b: 2 }; + const signature = "c3"; + + const b64Header = base64url.baseEncode(Buffer.from(JSON.stringify(header))); + const b64Payload = base64url.baseEncode(Buffer.from(JSON.stringify(payload))); + const jws = `${b64Header}.${b64Payload}.${signature}`; + + const result = await JWT.decode(jws); + + expect(result).to.be.an("object"); + expect(result.header).to.deep.eq(header); + expect(result.payload).to.deep.eq(payload); + expect(result.signature).to.deep.eq(signature); + }); + + test("sign - creates JWS string", async () => { + const result = await JWT.sign( + Fixtures.DIDs.prismDIDDefault, + Fixtures.Keys.secp256K1.privateKey, + { a: 1, b: 2 } + ); + + expect(result).to.be.a("string"); + expect(result.split(".")).to.have.length(3); + }); + + describe("round trip", () => { + describe("sign > decode", () => { + const issuerDID = Domain.DID.from('did:prism:9e93a84d492c62e03ab114e0b7a7b4a6880cd0e079f358d2196dc9c312dadb90:Co0CCooCElwKB21hc3RlcjAQAUJPCglzZWNwMjU2azESIBG7LMd7RA5-ckcPQICROrUbKx35x4aFAXjt_zIoWKAbGiD9WlLNP0Lr7JyQ7Q6uoY-m2TnygmAf8EBBTHGYzxm4exJkCg9hdXRoZW50aWNhdGlvbjAQBEJPCglzZWNwMjU2azESIBG7LMd7RA5-ckcPQICROrUbKx35x4aFAXjt_zIoWKAbGiD9WlLNP0Lr7JyQ7Q6uoY-m2TnygmAf8EBBTHGYzxm4exJECghpc3N1aW5nMBACSjYKB0VkMjU1MTkSKzh0dUVjUDRsZFhMQlV6US1YdEpDS1AwUC14QU5acV9SUnZQSDBIYXFWTjg'); + const privateKey = Secp256k1PrivateKey.from.String("8bfd5ff83034bbc004950de2b3a02cdafbbff9faebcb63640c895959a2d3da24", "hex"); + + test("headers - default values", async () => { + const jws = await JWT.sign(issuerDID, privateKey, {}); + const decoded = await JWT.decode(jws); + + expect(decoded.header).to.deep.eq({ alg: 'ES256K', typ: 'JWT' }); + }); + + test("headers - default values", async () => { + const header = { kid: "keyId" }; + const jws = await JWT.sign(issuerDID, privateKey, {}, header); + const decoded = await JWT.decode(jws); + + expect(decoded.header).to.deep.eq({ alg: 'ES256K', typ: 'JWT', ...header }); + }); + + test("payload - expected values", async () => { + const payload = { round: "trip" }; + + const jws = await JWT.sign(issuerDID, privateKey, payload); + const decoded = await JWT.decode(jws); + + // iss added by default + expect(decoded.payload).to.have.property("iss", issuerDID.toString()); + expect(decoded.payload).to.have.property("round", payload.round); + }); + + test("signature - verifies", async () => { + const jws = await JWT.sign(issuerDID, privateKey, { shouldbe: true }); + const decoded = await JWT.decode(jws); + const verified = await privateKey.publicKey().verify( + Buffer.from(decoded.data), + Buffer.from(base64url.baseDecode(decoded.signature)) + ); + + expect(verified).to.be.true; + }); + }); + }); +}); diff --git a/tests/pollux/JWT.test.ts b/tests/pollux/JWT.test.ts new file mode 100644 index 000000000..aa1673a44 --- /dev/null +++ b/tests/pollux/JWT.test.ts @@ -0,0 +1,66 @@ +import { expect } from "chai"; +import { base64url } from "multiformats/bases/base64"; +import { JWT } from "../../src/pollux/utils/JWT"; +import { Domain, Secp256k1PrivateKey } from "../../src"; +import * as Fixtures from "../fixtures"; + +describe("Domain - JWT", () => { + let sut: JWT; + + beforeEach(() => { + const apolloMock = {} as any; + const castorMock = {} as any; + sut = new JWT(apolloMock, castorMock); + }); + + test("decode", async () => { + const header = { a: 1 }; + const payload = { b: 2 }; + const signature = "c3"; + + const b64Header = base64url.baseEncode(Buffer.from(JSON.stringify(header))); + const b64Payload = base64url.baseEncode(Buffer.from(JSON.stringify(payload))); + const jws = `${b64Header}.${b64Payload}.${signature}`; + + const result = await sut.decode(jws); + + expect(result).to.be.an("object"); + expect(result.header).to.deep.eq(header); + expect(result.payload).to.deep.eq(payload); + expect(result.signature).to.deep.eq(signature); + }); + + test("sign - creates JWS string", async () => { + const result = await sut.sign({ + issuerDID: Fixtures.DIDs.prismDIDDefault, + privateKey: Fixtures.Keys.secp256K1.privateKey, + payload: { a: 1, b: 2 } + }); + + expect(result).to.be.a("string"); + expect(result.split(".")).to.have.length(3); + }); + + describe("round trip", () => { + test("sign > decode - expected values and verifies", async () => { + const issuerDID = Domain.DID.from('did:prism:9e93a84d492c62e03ab114e0b7a7b4a6880cd0e079f358d2196dc9c312dadb90:Co0CCooCElwKB21hc3RlcjAQAUJPCglzZWNwMjU2azESIBG7LMd7RA5-ckcPQICROrUbKx35x4aFAXjt_zIoWKAbGiD9WlLNP0Lr7JyQ7Q6uoY-m2TnygmAf8EBBTHGYzxm4exJkCg9hdXRoZW50aWNhdGlvbjAQBEJPCglzZWNwMjU2azESIBG7LMd7RA5-ckcPQICROrUbKx35x4aFAXjt_zIoWKAbGiD9WlLNP0Lr7JyQ7Q6uoY-m2TnygmAf8EBBTHGYzxm4exJECghpc3N1aW5nMBACSjYKB0VkMjU1MTkSKzh0dUVjUDRsZFhMQlV6US1YdEpDS1AwUC14QU5acV9SUnZQSDBIYXFWTjg'); + const privateKey = Secp256k1PrivateKey.from.String("8bfd5ff83034bbc004950de2b3a02cdafbbff9faebcb63640c895959a2d3da24", "hex"); + const header = { kid: 123, abc: "456" }; + const payload = { round: "trip" }; + const jws = await sut.sign({ issuerDID, privateKey, payload, header }); + + const decoded = await sut.decode(jws); + + expect(decoded).to.be.an("object"); + expect(decoded.header).to.deep.eq({ alg: 'ES256K', typ: 'JWT', ...header }); + expect(decoded.payload).to.have.property("round", payload.round); + expect(decoded.payload).to.have.property("iss", issuerDID.toString()); + + const verified = await privateKey.publicKey().verify( + Buffer.from(decoded.data), + Buffer.from(base64url.baseDecode(decoded.signature)) + ); + expect(verified).to.be.true; + }); + }); +}); diff --git a/tests/pollux/Pollux.test.ts b/tests/pollux/Pollux.test.ts index 441b98419..d5435efaa 100644 --- a/tests/pollux/Pollux.test.ts +++ b/tests/pollux/Pollux.test.ts @@ -14,8 +14,6 @@ import Pollux from "../../src/pollux/Pollux"; import { AnonCredsCredential, AnonCredsRecoveryId } from "../../src/pollux/models/AnonCredsVerifiableCredential"; import { PresentationRequest } from "../../src/pollux/models/PresentationRequest"; import * as Fixtures from "../fixtures"; -import { JWTCore } from "../../src/pollux/utils/jwt/JWTCore"; -import { JWTInstanceType } from "../../src/pollux/utils/jwt/types"; import { SDJWT } from "../../src/pollux/utils/SDJWT"; import { JWT } from "../../src/pollux/utils/JWT"; import { SDJWTCredential } from "../../src/pollux/models/SDJWTVerifiableCredential"; @@ -37,15 +35,15 @@ type JWTVerificationTestCase = { challenge?: string, apollo: Apollo, castor: Castor, - jwt: JWTCore, + jwt: JWT, pollux: Pollux, issuer: DID, holder: DID, holderPrv: PrivateKey, issuerPrv: PrivateKey, subject: Record, - claims: Claims -} + claims: Claims; +}; type AnoncredsVerificationTestCase = { @@ -54,8 +52,8 @@ type AnoncredsVerificationTestCase = { castor: Castor, pollux: Pollux, claims: PresentationClaims, - credential: Credential -} + credential: Credential; +}; async function createAnoncredsVerificationTestCase(options: AnoncredsVerificationTestCase) { @@ -77,7 +75,7 @@ async function createAnoncredsVerificationTestCase(options: AnoncredsVerificatio return { presentationDefinition, presentationSubmissionJSON, - } + }; } async function createJWTVerificationTestCase(options: JWTVerificationTestCase) { @@ -96,7 +94,7 @@ async function createJWTVerificationTestCase(options: JWTVerificationTestCase) { const currentDate = new Date(); const nextMonthDate = new Date(currentDate); nextMonthDate.setMonth(currentDate.getMonth() + 1); - const issuanceDate = currentDate.getTime() + const issuanceDate = currentDate.getTime(); const expirationDate = nextMonthDate.getTime(); const payload: JWTCredentialPayload = { @@ -111,13 +109,13 @@ async function createJWTVerificationTestCase(options: JWTVerificationTestCase) { issuanceDate: new Date(issuanceDate).toISOString(), credentialSubject: subject, } - } + }; const signedJWT = await jwt.sign({ issuerDID: issuer, privateKey: issuerPrv, payload - }) + }); const jwtCredential = JWTCredential.fromJWS(signedJWT); const presentationDefinition = await pollux.createPresentationDefinitionRequest( @@ -131,10 +129,10 @@ async function createJWTVerificationTestCase(options: JWTVerificationTestCase) { }) ); - const disclosed = await pollux.revealCredentialFields(jwtCredential, ['course']) + const disclosed = await pollux.revealCredentialFields(jwtCredential, ['course']); expect(disclosed).to.not.be.undefined; - expect(Object.keys(disclosed).length).to.gte(1) + expect(Object.keys(disclosed).length).to.gte(1); const presentationSubmissionJSON = await pollux.createPresentationSubmission( presentationDefinition, @@ -146,7 +144,7 @@ async function createJWTVerificationTestCase(options: JWTVerificationTestCase) { presentationDefinition, presentationSubmissionJSON, issuedJWS: signedJWT - } + }; } describe("Pollux", () => { @@ -230,12 +228,12 @@ describe("Pollux", () => { expect( pollux.parseCredential(Buffer.from(JSON.stringify({ claims: { name: 'any' } })), { type: CredentialType.Unknown }) ).to.eventually.be.rejected; - }) + }); it("Should throw an error if the credential unknown type is undefined", async () => { expect( pollux.parseCredential(Buffer.from(JSON.stringify({ claims: { name: 'any' } }))) ).to.eventually.be.rejected; - }) + }); describe("AnonCreds", () => { const encodeToBuffer = (cred: object) => { const json = JSON.stringify(cred); @@ -690,11 +688,11 @@ describe("Pollux", () => { expect(result.values) .to.have.property("age") - .to.deep.equal(Fixtures.Credentials.Anoncreds.credentialIssued.values.age) + .to.deep.equal(Fixtures.Credentials.Anoncreds.credentialIssued.values.age); expect(result.values) .to.have.property("name") - .to.deep.equal(Fixtures.Credentials.Anoncreds.credentialIssued.values.name) + .to.deep.equal(Fixtures.Credentials.Anoncreds.credentialIssued.values.name); }); }); @@ -702,7 +700,7 @@ describe("Pollux", () => { describe("JWT SDK Verification", () => { let apollo: Apollo; let castor: Castor; - let jwt: JWTCore; + let jwt: JWT; let pollux: Pollux; beforeEach(async () => { @@ -715,17 +713,17 @@ describe("Pollux", () => { apollo = new Apollo(); castor = new Castor(apollo); - jwt = new JWT(apollo, castor) + jwt = new JWT(apollo, castor); pollux = new Pollux( apollo, castor, undefined, jwt - ) + ); - await pollux.start() + await pollux.start(); - }) + }); describe("JWT", () => { @@ -773,7 +771,7 @@ describe("Pollux", () => { [ sk.publicKey() ] - ) + ); const payload = { issuerDID: issuerDID, @@ -785,11 +783,11 @@ describe("Pollux", () => { }, disclosureFrame: {}, privateKey: sk - } - expect(sdjwt.sign(payload)).to.eventually.be.rejectedWith("Cannot sign with this key") + }; + expect(sdjwt.sign(payload)).to.eventually.be.rejectedWith("Cannot sign with this key"); - }) + }); test("Ed25519 ok", async () => { @@ -818,7 +816,7 @@ describe("Pollux", () => { [ sk.publicKey() ] - ) + ); const credential = await sdjwt.sign({ issuerDID: issuerDID, payload: { @@ -844,10 +842,10 @@ describe("Pollux", () => { { type: CredentialType.SDJWT } - ) + ); - const isCorrectCredential = parseCredential instanceof SDJWTCredential - expect(isCorrectCredential).to.eq(true) + const isCorrectCredential = parseCredential instanceof SDJWTCredential; + expect(isCorrectCredential).to.eq(true); const presentation = await sdjwt.createPresentationFor( { @@ -855,7 +853,7 @@ describe("Pollux", () => { frame: { firstname: true, id: true }, privateKey: sk } - ) + ); const verified = await sdjwt.verify({ issuerDID: issuerDID, @@ -863,9 +861,9 @@ describe("Pollux", () => { requiredClaimKeys: ['firstname', 'id'] }); - expect(verified).to.equal(true) + expect(verified).to.equal(true); - }) + }); test("Secp256k1 ok", async () => { @@ -887,7 +885,7 @@ describe("Pollux", () => { const issuerDID = await castor.createPrismDID( sk.publicKey(), [] - ) + ); const credential = await sdjwt.sign({ issuerDID: issuerDID, payload: { @@ -906,14 +904,14 @@ describe("Pollux", () => { frame: { firstname: true, id: true }, privateKey: sk } - ) + ); const verified = await sdjwt.verify({ issuerDID: issuerDID, jws: presentation, requiredClaimKeys: ['firstname', 'id'] }); - expect(verified).to.equal(true) + expect(verified).to.equal(true); const pr = new PresentationRequest( AttachmentFormats.SDJWT, Fixtures.Credentials.SDJWT.presentationRequest @@ -930,57 +928,57 @@ describe("Pollux", () => { { type: CredentialType.SDJWT } - ) + ); const result = await pollux.createPresentationProof(pr, parseCredential, { did: issuerDID, privateKey: sk }); expect(result).not.to.be.null; - }) + }); - }) + }); it("Should throw an error a non signable key is used", async () => { - const issuer = DID.fromString("did:issuer:123") + const issuer = DID.fromString("did:issuer:123"); const payload: JWTCredentialPayload = { iss: issuer.toString(), sub: undefined as any, nbf: false as any, exp: 2134564321, vc: {} as any - } + }; expect(jwt.sign({ issuerDID: issuer, privateKey: Fixtures.Keys.x25519.privateKey, payload: payload, - })).to.eventually.be.rejectedWith("Key is not signable") - }) + })).to.eventually.be.rejectedWith("Key is not signable"); + }); it("Should throw an error when nbf is not number in jwt credential", async () => { - const issuer = DID.fromString("did:issuer:123") + const issuer = DID.fromString("did:issuer:123"); const payload: JWTCredentialPayload = { iss: issuer.toString(), sub: undefined as any, nbf: false as any, exp: 2134564321, vc: {} as any - } + }; const jwtString = await jwt.sign({ issuerDID: issuer, privateKey: Fixtures.Keys.secp256K1.privateKey, payload: payload, - }) + }); assert.throws( () => { - const a = JWTCredential.fromJWS(jwtString) - JWTCredential.fromJWS(jwtString) + const a = JWTCredential.fromJWS(jwtString); + JWTCredential.fromJWS(jwtString); }, PolluxError.InvalidCredentialError, "Invalid nbf in credential payload should be number" ); - }) + }); it("Should throw an error when nbf is not number in jwt credential, not specifying is okey", async () => { const issuer = DID.fromString("did:issuer:123"); @@ -990,16 +988,16 @@ describe("Pollux", () => { sub: undefined as any, nbf: false as any, vc: {} as any - } + }; const invalidJWTString = await jwt.sign({ issuerDID: issuer, privateKey: Fixtures.Keys.secp256K1.privateKey, payload: invalidPayload, - }) + }); assert.throws( () => { - JWTCredential.fromJWS(invalidJWTString) + JWTCredential.fromJWS(invalidJWTString); }, PolluxError.InvalidCredentialError, "Invalid nbf in credential payload should be number" @@ -1009,17 +1007,17 @@ describe("Pollux", () => { iss: issuer.toString(), sub: undefined as any, vc: {} as any - } + }; const validJWTString = await jwt.sign({ issuerDID: issuer, privateKey: Fixtures.Keys.secp256K1.privateKey, payload: validPayload, - }) + }); - JWTCredential.fromJWS(validJWTString) + JWTCredential.fromJWS(validJWTString); - }) + }); it("Should throw an error when exp is not number in jwt credential, not specifying is okey", async () => { const issuer = DID.fromString("did:issuer:123"); @@ -1029,16 +1027,16 @@ describe("Pollux", () => { sub: undefined as any, exp: false as any, vc: {} as any - } + }; const invalidJWTString = await jwt.sign({ issuerDID: issuer, privateKey: Fixtures.Keys.secp256K1.privateKey, payload: invalidPayload, - }) + }); assert.throws( () => { - JWTCredential.fromJWS(invalidJWTString) + JWTCredential.fromJWS(invalidJWTString); }, PolluxError.InvalidCredentialError, "Invalid exp in credential payload should be number" @@ -1048,17 +1046,17 @@ describe("Pollux", () => { iss: issuer.toString(), sub: undefined as any, vc: {} as any - } + }; const validJWTString = await jwt.sign({ issuerDID: issuer, privateKey: Fixtures.Keys.secp256K1.privateKey, payload: validPayload, - }) + }); - JWTCredential.fromJWS(validJWTString) + JWTCredential.fromJWS(validJWTString); - }) + }); it("Should throw an error when sub is not string in jwt credential, not specifying is okey", async () => { @@ -1068,16 +1066,16 @@ describe("Pollux", () => { iss: issuer.toString(), sub: false as any, vc: {} as any - } + }; const invalidJWTString = await jwt.sign({ issuerDID: issuer, privateKey: Fixtures.Keys.secp256K1.privateKey, payload: invalidPayload, - }) + }); assert.throws( () => { - JWTCredential.fromJWS(invalidJWTString) + JWTCredential.fromJWS(invalidJWTString); }, PolluxError.InvalidCredentialError, "Invalid sub in credential payload should be string" @@ -1086,15 +1084,15 @@ describe("Pollux", () => { const validPayload = { iss: issuer.toString(), vc: {} as any - } + }; const validJWTString = await jwt.sign({ issuerDID: issuer, privateKey: Fixtures.Keys.secp256K1.privateKey, payload: validPayload, - }) + }); - JWTCredential.fromJWS(validJWTString) + JWTCredential.fromJWS(validJWTString); }); @@ -1103,16 +1101,16 @@ describe("Pollux", () => { const invalidPayload: Partial = { iss: issuer.toString(), vp: {} as any - } + }; const invalidJWTPresentationString = await jwt.sign({ issuerDID: issuer, privateKey: Fixtures.Keys.secp256K1.privateKey, payload: invalidPayload, - }) - const credential = JWTCredential.fromJWS(invalidJWTPresentationString) + }); + const credential = JWTCredential.fromJWS(invalidJWTPresentationString); assert.throws( () => { - credential.verifiableCredential() + credential.verifiableCredential(); }, PolluxError.InvalidCredentialError, "Invalid payload is not VC" @@ -1120,52 +1118,52 @@ describe("Pollux", () => { const validCredential = JWTCredential.fromJWS( Fixtures.Credentials.JWT.credentialPayloadEncoded - ) + ); - validCredential.verifiableCredential() - }) + validCredential.verifiableCredential(); + }); it("should throw an error when calling subject on a presentation", async () => { const issuer = DID.fromString("did:issuer:123"); const invalidPayload: Partial = { iss: issuer.toString(), vp: {} as any - } + }; const invalidJWTPresentationString = await jwt.sign({ issuerDID: issuer, privateKey: Fixtures.Keys.secp256K1.privateKey, payload: invalidPayload, - }) - const credential = JWTCredential.fromJWS(invalidJWTPresentationString) + }); + const credential = JWTCredential.fromJWS(invalidJWTPresentationString); assert.throws( () => { - credential.subject + credential.subject; }, PolluxError.InvalidCredentialError, "Subject is only available in a VC" ); - }) + }); it("should throw an error when calling presentation on a presentation", async () => { const issuer = DID.fromString("did:issuer:123"); const invalidPayload: Partial = { iss: issuer.toString(), vp: {} as any - } + }; const invalidJWTPresentationString = await jwt.sign({ issuerDID: issuer, privateKey: Fixtures.Keys.secp256K1.privateKey, payload: invalidPayload, - }) - const credential = JWTCredential.fromJWS(invalidJWTPresentationString) + }); + const credential = JWTCredential.fromJWS(invalidJWTPresentationString); assert.throws( () => { - credential.presentation() + credential.presentation(); }, PolluxError.InvalidCredentialError, "Invalid payload is not VC" ); - }) + }); it("Should throw an error when aud is not string in jwt presentation, not specifying is okey", async () => { const issuer = DID.fromString("did:issuer:123"); @@ -1174,16 +1172,16 @@ describe("Pollux", () => { iss: issuer.toString(), aud: false as any, vp: {} as any - } + }; const invalidJWTString = await jwt.sign({ issuerDID: issuer, privateKey: Fixtures.Keys.secp256K1.privateKey, payload: invalidPayload, - }) + }); assert.throws( () => { - JWTCredential.fromJWS(invalidJWTString) + JWTCredential.fromJWS(invalidJWTString); }, PolluxError.InvalidCredentialError, "Invalid aud in presentation payload should be string" @@ -1192,17 +1190,17 @@ describe("Pollux", () => { const validPayload = { iss: issuer.toString(), vp: {} as any - } + }; const validJWTString = await jwt.sign({ issuerDID: issuer, privateKey: Fixtures.Keys.secp256K1.privateKey, payload: validPayload, - }) + }); - JWTCredential.fromJWS(validJWTString) + JWTCredential.fromJWS(validJWTString); - }) + }); it("Should throw an error when exp is not string in jwt presentation, not specifying is okey", async () => { const issuer = DID.fromString("did:issuer:123"); @@ -1211,16 +1209,16 @@ describe("Pollux", () => { iss: issuer.toString(), exp: false as any, vp: {} as any - } + }; const invalidJWTString = await jwt.sign({ issuerDID: issuer, privateKey: Fixtures.Keys.secp256K1.privateKey, payload: invalidPayload, - }) + }); assert.throws( () => { - JWTCredential.fromJWS(invalidJWTString) + JWTCredential.fromJWS(invalidJWTString); }, PolluxError.InvalidCredentialError, "Invalid exp in presentation payload should be number" @@ -1229,17 +1227,17 @@ describe("Pollux", () => { const validPayload = { iss: issuer.toString(), vp: {} as any - } + }; const validJWTString = await jwt.sign({ issuerDID: issuer, privateKey: Fixtures.Keys.secp256K1.privateKey, payload: validPayload, - }) + }); - JWTCredential.fromJWS(validJWTString) + JWTCredential.fromJWS(validJWTString); - }) + }); it("Should throw an error when nbf is not string in jwt presentation, not specifying is okey", async () => { const issuer = DID.fromString("did:issuer:123"); @@ -1248,16 +1246,16 @@ describe("Pollux", () => { iss: issuer.toString(), nbf: false as any, vp: {} as any - } + }; const invalidJWTString = await jwt.sign({ issuerDID: issuer, privateKey: Fixtures.Keys.secp256K1.privateKey, payload: invalidPayload, - }) + }); assert.throws( () => { - JWTCredential.fromJWS(invalidJWTString) + JWTCredential.fromJWS(invalidJWTString); }, PolluxError.InvalidCredentialError, "Invalid nbf in presentation payload should be number" @@ -1266,17 +1264,17 @@ describe("Pollux", () => { const validPayload = { iss: issuer.toString(), vp: {} as any - } + }; const validJWTString = await jwt.sign({ issuerDID: issuer, privateKey: Fixtures.Keys.secp256K1.privateKey, payload: validPayload, - }) + }); - JWTCredential.fromJWS(validJWTString) + JWTCredential.fromJWS(validJWTString); - }) + }); it("Should throw an error when vp is not object in jwt presentation", async () => { const issuer = DID.fromString("did:issuer:123"); @@ -1284,22 +1282,22 @@ describe("Pollux", () => { const invalidPayload: Partial = { iss: issuer.toString(), vp: false as any - } + }; const invalidJWTString = await jwt.sign({ issuerDID: issuer, privateKey: Fixtures.Keys.secp256K1.privateKey, payload: invalidPayload, - }) + }); assert.throws( () => { - JWTCredential.fromJWS(invalidJWTString) + JWTCredential.fromJWS(invalidJWTString); }, PolluxError.InvalidCredentialError, "Invalid vp in presentation payload should be an object" ); - }) + }); it("Should throw an error when nonce is not string in jwt presentation, not specifying is okey", async () => { @@ -1309,16 +1307,16 @@ describe("Pollux", () => { iss: issuer.toString(), nonce: false as any, vp: {} as any - } + }; const invalidJWTString = await jwt.sign({ issuerDID: issuer, privateKey: Fixtures.Keys.secp256K1.privateKey, payload: invalidPayload, - }) + }); assert.throws( () => { - JWTCredential.fromJWS(invalidJWTString) + JWTCredential.fromJWS(invalidJWTString); }, PolluxError.InvalidCredentialError, "Invalid nonce in presentation payload should be string" @@ -1327,17 +1325,17 @@ describe("Pollux", () => { const validPayload = { iss: issuer.toString(), vp: {} as any - } + }; const validJWTString = await jwt.sign({ issuerDID: issuer, privateKey: Fixtures.Keys.secp256K1.privateKey, payload: validPayload, - }) + }); - JWTCredential.fromJWS(validJWTString) + JWTCredential.fromJWS(validJWTString); - }) + }); it("Should throw an error when aud is not string in jwt credential, not specifying is okey", async () => { const issuer = DID.fromString("did:issuer:123"); @@ -1346,16 +1344,16 @@ describe("Pollux", () => { iss: issuer.toString(), aud: false as any, vc: {} as any - } + }; const invalidJWTString = await jwt.sign({ issuerDID: issuer, privateKey: Fixtures.Keys.secp256K1.privateKey, payload: invalidPayload, - }) + }); assert.throws( () => { - JWTCredential.fromJWS(invalidJWTString) + JWTCredential.fromJWS(invalidJWTString); }, PolluxError.InvalidCredentialError, "Invalid aud in credential payload should be string" @@ -1364,17 +1362,17 @@ describe("Pollux", () => { const validPayload = { iss: issuer.toString(), vc: {} as any - } + }; const validJWTString = await jwt.sign({ issuerDID: issuer, privateKey: Fixtures.Keys.secp256K1.privateKey, payload: validPayload, - }) + }); - JWTCredential.fromJWS(validJWTString) + JWTCredential.fromJWS(validJWTString); - }) + }); it("Should throw an error when vc is not object in jwt credential", async () => { const issuer = DID.fromString("did:issuer:123"); @@ -1382,16 +1380,16 @@ describe("Pollux", () => { const invalidPayload: Partial = { iss: issuer.toString(), vc: false as any - } + }; const invalidJWTString = await jwt.sign({ issuerDID: issuer, privateKey: Fixtures.Keys.secp256K1.privateKey, payload: invalidPayload, - }) + }); assert.throws( () => { - JWTCredential.fromJWS(invalidJWTString) + JWTCredential.fromJWS(invalidJWTString); }, PolluxError.InvalidCredentialError, "Invalid vc in credential payload should be an object" @@ -1400,17 +1398,17 @@ describe("Pollux", () => { const validPayload = { iss: issuer.toString(), vc: {} as any - } + }; const validJWTString = await jwt.sign({ issuerDID: issuer, privateKey: Fixtures.Keys.secp256K1.privateKey, payload: validPayload, - }) + }); - JWTCredential.fromJWS(validJWTString) + JWTCredential.fromJWS(validJWTString); - }) + }); @@ -1440,12 +1438,12 @@ describe("Pollux", () => { expect(presentation_definition.format).haveOwnProperty("jwt"); - expect(Array.isArray(presentation_definition.input_descriptors)).to.eq(true) - expect(presentation_definition.input_descriptors.length).to.eq(1) + expect(Array.isArray(presentation_definition.input_descriptors)).to.eq(true); + expect(presentation_definition.input_descriptors.length).to.eq(1); expect(presentation_definition.input_descriptors.at(0)).haveOwnProperty('constraints'); expect(presentation_definition.input_descriptors.at(0)?.constraints.fields.length).to.eq(2); - expect(presentation_definition.input_descriptors.at(0)?.constraints.fields[0].path.at(0)).to.eq('$.vc.credentialSubject.name') - expect(presentation_definition.input_descriptors.at(0)?.constraints.fields[1].path.at(0)).to.eq('$.vc.issuer') + expect(presentation_definition.input_descriptors.at(0)?.constraints.fields[0].path.at(0)).to.eq('$.vc.credentialSubject.name'); + expect(presentation_definition.input_descriptors.at(0)?.constraints.fields[1].path.at(0)).to.eq('$.vc.issuer'); }); @@ -1453,33 +1451,33 @@ describe("Pollux", () => { const issuerDID = await castor.createPrismDID( Fixtures.Keys.secp256K1.privateKey.publicKey(), [] - ) + ); const payload: JWTCredentialPayload = { iss: issuerDID.toString(), sub: issuerDID.toString(), nbf: 23456543222, exp: 2134564321, vc: {} as any - } + }; const signed = await jwt.sign({ issuerDID: issuerDID, privateKey: Fixtures.Keys.secp256K1.privateKey, payload: payload, - }) + }); const decoded = await jwt.decode(signed); expect(decoded).to.haveOwnProperty("header"); - expect(decoded.header).to.deep.equal({ alg: JWT_ALG.ES256K, typ: "JWT" }) + expect(decoded.header).to.deep.equal({ alg: JWT_ALG.ES256K, typ: "JWT" }); const verified = await jwt.verify({ issuerDID: issuerDID, jws: signed - }) + }); - expect(verified).to.equal(true) - }) + expect(verified).to.equal(true); + }); it("Should create and verify an Ed25519 prism did JWS", async () => { const issuerSeed = apollo.createRandomSeed().seed; @@ -1499,29 +1497,29 @@ describe("Pollux", () => { [ sk.publicKey() ] - ) + ); const payload: JWTCredentialPayload = { iss: issuerDID.toString(), sub: issuerDID.toString(), nbf: 23456543222, exp: 2134564321, vc: {} as any - } + }; const signed = await jwt.sign({ issuerDID: issuerDID, privateKey: sk, payload: payload, - }) + }); const decoded = await jwt.decode(signed); expect(decoded).to.haveOwnProperty("header"); - expect(decoded.header).to.deep.equal({ alg: JWT_ALG.EdDSA, typ: "JWT" }) + expect(decoded.header).to.deep.equal({ alg: JWT_ALG.EdDSA, typ: "JWT" }); const verified = await jwt.verify({ issuerDID: issuerDID, holderDID: issuerDID, jws: signed - }) - expect(verified).to.equal(true) - }) + }); + expect(verified).to.equal(true); + }); it("Should create and fail verifying an Secp256k1 prism did JWS with wrong issuer", async () => { const issuerSeed = apollo.createRandomSeed().seed; @@ -1533,54 +1531,54 @@ describe("Pollux", () => { const issuerDID = await castor.createPrismDID( sk.publicKey(), [] - ) + ); const payload: JWTCredentialPayload = { iss: issuerDID.toString(), sub: issuerDID.toString(), nbf: 23456543222, exp: 2134564321, vc: {} as any - } + }; const signed = await jwt.sign({ issuerDID: issuerDID, privateKey: sk, payload: payload, - }) + }); const verified = await jwt.verify({ issuerDID: DID.fromString("did:test:12345"), jws: signed - }) - expect(verified).to.equal(false) - }) + }); + expect(verified).to.equal(false); + }); it("Should create and fail verifying an Secp256k1 prism did JWS with wrong issuer", async () => { const issuerDID = await castor.createPrismDID( Fixtures.Keys.secp256K1.privateKey.publicKey(), [] - ) + ); const payload: JWTCredentialPayload = { iss: issuerDID.toString(), sub: "did:test:12345", nbf: 23456543222, exp: 2134564321, vc: {} as any - } + }; const signed = await jwt.sign({ issuerDID: issuerDID, privateKey: Fixtures.Keys.secp256K1.privateKey, payload: payload, - }) + }); const verified = await jwt.verify({ issuerDID: issuerDID, holderDID: DID.fromString("did:test:123457"), jws: signed - }) + }); - expect(verified).to.equal(false) + expect(verified).to.equal(false); - }) + }); it("Should reject creating a PresentationDefinitionRequest is no AnoncredsPresentationOptions instance is sent", async () => { expect( @@ -1638,7 +1636,7 @@ describe("Pollux", () => { expect(presentation.requested_predicates.age.name).to.equal("age"); expect(presentation.requested_predicates.age.p_type).to.equal(">="); expect(presentation.requested_predicates.age.p_value).to.equal(18); - }) + }); it("Should Verify false when the presentation is signed with holder keys that don't match", async () => { const issuerSeed = apollo.createRandomSeed().seed; @@ -1665,11 +1663,11 @@ describe("Pollux", () => { const issuerDID = await castor.createPrismDID( issuerPrv.publicKey() - ) + ); const holderDID = await castor.createPrismDID( holderPrv.publicKey() - ) + ); const challenge = 'sign this'; @@ -1703,7 +1701,7 @@ describe("Pollux", () => { })).to.eventually.be.rejectedWith( `Verification failed for credential (${issuedJWS.slice(0, 10)}...): reason -> Invalid Holder Presentation JWS Signature` ); - }) + }); it("Should Verify false when the Credential Subject does not match", async () => { const issuerSeed = apollo.createRandomSeed().seed; @@ -1724,11 +1722,11 @@ describe("Pollux", () => { const issuerDID = await castor.createPrismDID( issuerPrv.publicKey() - ) + ); const holderDID = await castor.createPrismDID( holderPrv.publicKey() - ) + ); const { presentationDefinition, @@ -1759,7 +1757,7 @@ describe("Pollux", () => { })).to.eventually.be.rejectedWith( `Verification failed for credential (${issuedJWS.slice(0, 10)}...): reason -> Invalid Claim: Expected the $.credentialSubject.course field to be "Identus Training course Certification 2024" but got "Identus Training course Certification 2023"` ); - }) + }); it("Should throw an error if presentationSubmission is not an object", async () => { expect(pollux.verifyPresentationSubmission(null as any, { @@ -1767,7 +1765,7 @@ describe("Pollux", () => { })).to.eventually.be.rejectedWith( `Verification format is invalid: reason -> Invalid Submission, only JWT or Anoncreds are supported` ); - }) + }); it("Should throw an error if the actual presentationSubmission is not an object", async () => { expect(pollux.verifyPresentationSubmission({ presentation_submission: null, verifiablePresentation: null } as any, { @@ -1775,7 +1773,7 @@ describe("Pollux", () => { })).to.eventually.be.rejectedWith( `Verification format is invalid: reason -> Invalid Submission, only JWT or Anoncreds are supported` ); - }) + }); it("Should throw an error if the actual presentationSubmission options presentationDefinitionRequest is not an undefined", async () => { expect(pollux.verifyPresentationSubmission( @@ -1786,7 +1784,7 @@ describe("Pollux", () => { )).to.eventually.be.rejectedWith( `VerifyPresentationSubmission options are invalid` ); - }) + }); it("Should Verify false when the Credential subject does not provide required field", async () => { const issuerSeed = apollo.createRandomSeed().seed; @@ -1807,11 +1805,11 @@ describe("Pollux", () => { const issuerDID = await castor.createPrismDID( issuerPrv.publicKey() - ) + ); const holderDID = await castor.createPrismDID( holderPrv.publicKey() - ) + ); const { presentationDefinition, @@ -1842,7 +1840,7 @@ describe("Pollux", () => { })).to.eventually.be.rejectedWith( `Verification failed for credential (${issuedJWS.slice(0, 10)}...): reason -> Invalid Claim: Expected one of the paths $.vc.credentialSubject.course, $.credentialSubject.course to exist.` ); - }) + }); it("Should Verify true when the presentation and the credential are completely valid", async () => { const issuerSeed = apollo.createRandomSeed().seed; @@ -1862,11 +1860,11 @@ describe("Pollux", () => { const issuerDID = await castor.createPrismDID( issuerPrv.publicKey() - ) + ); const holderDID = await castor.createPrismDID( holderPrv.publicKey() - ) + ); const { presentationDefinition, @@ -1893,8 +1891,8 @@ describe("Pollux", () => { }); expect(pollux.verifyPresentationSubmission(presentationSubmissionJSON, { presentationDefinitionRequest: presentationDefinition - })).to.eventually.equal(true) - }) + })).to.eventually.equal(true); + }); it("Should Reject Creating a Presentation with a Credential that doesn't have the requested field 'email'", async () => { const credential = new AnonCredsCredential(Fixtures.Credentials.Anoncreds.credential); @@ -1902,7 +1900,7 @@ describe("Pollux", () => { sandbox.stub(pollux as any, "fetchSchema").resolves(Fixtures.Credentials.Anoncreds.schema); sandbox.stub(pollux as any, "fetchCredentialDefinition").resolves(Fixtures.Credentials.Anoncreds.credentialDefinition); - const issuerDID = DID.fromString('did:web:xyz') + const issuerDID = DID.fromString('did:web:xyz'); expect(createAnoncredsVerificationTestCase({ @@ -1937,7 +1935,7 @@ describe("Pollux", () => { 'AnoncredsError Credential value not found for attribute "email"' ); - }) + }); it("Should Reject Creating a Presentation with a Credential that doesn't have predicates", async () => { const credential = new AnonCredsCredential(Fixtures.Credentials.Anoncreds.credential); @@ -1963,8 +1961,8 @@ describe("Pollux", () => { 'AnoncredsError No credential mapping or self-attested attributes presented' ); - }) - }) + }); + }); it("Should Reject Creating a Presentation with a Credential that doesn't have valid predicates", async () => { const credential = new AnonCredsCredential(Fixtures.Credentials.Anoncreds.credential); @@ -1972,7 +1970,7 @@ describe("Pollux", () => { sandbox.stub(pollux as any, "fetchSchema").resolves(Fixtures.Credentials.Anoncreds.schema); sandbox.stub(pollux as any, "fetchCredentialDefinition").resolves(Fixtures.Credentials.Anoncreds.credentialDefinition); - const issuerDID = DID.fromString('did:web:xyz') + const issuerDID = DID.fromString('did:web:xyz'); expect(createAnoncredsVerificationTestCase({ @@ -2001,7 +1999,7 @@ describe("Pollux", () => { 'AnoncredsError Error: Invalid structure\nCaused by: Predicate is not satisfied\n' ); - }) + }); it("Should Verify to true when an Anoncreds Presentation submission with all valid attributes and predicates are used", async () => { const credential = new AnonCredsCredential(Fixtures.Credentials.Anoncreds.credential); @@ -2010,14 +2008,14 @@ describe("Pollux", () => { sandbox.stub(pollux as any, "fetchSchema").resolves(Fixtures.Credentials.Anoncreds.schema); sandbox.stub(pollux as any, "fetchCredentialDefinition").resolves(Fixtures.Credentials.Anoncreds.credentialDefinition); - const issuerDID = DID.fromString('did:web:xyz') + const issuerDID = DID.fromString('did:web:xyz'); - const disclosed = await pollux.revealCredentialFields(credential, ['name'], Fixtures.Credentials.Anoncreds.linkSecret.secret) + const disclosed = await pollux.revealCredentialFields(credential, ['name'], Fixtures.Credentials.Anoncreds.linkSecret.secret); expect(disclosed).to.not.be.undefined; expect(disclosed).to.haveOwnProperty("name"); expect(disclosed.name).to.eq("test"); - expect(pollux.revealCredentialFields(credential, ['name'])).to.eventually.be.rejected + expect(pollux.revealCredentialFields(credential, ['name'])).to.eventually.be.rejected; const { @@ -2045,12 +2043,12 @@ describe("Pollux", () => { }, } } - }) + }); expect(pollux.verifyPresentationSubmission(presentationSubmissionJSON, { presentationDefinitionRequest: presentationDefinition - })).to.eventually.equal(true) - }) + })).to.eventually.equal(true); + }); it("Should Verify to false when an Anoncreds Presentation submission with invalid attributes and predicates are used", async () => { sandbox.stub(pollux as any, "fetchSchema").resolves(Fixtures.Credentials.Anoncreds.schema); @@ -2079,8 +2077,8 @@ describe("Pollux", () => { ); expect(pollux.verifyPresentationSubmission(Fixtures.Credentials.Anoncreds.underAgeSubmission, { presentationDefinitionRequest: presentationDefinition - })).to.eventually.equal(false) - }) + })).to.eventually.equal(false); + }); it("Should Reject Creating an Anoncreds Presentation Submission using an invalid LinkSecret", async () => { sandbox.stub(pollux as any, "fetchSchema").resolves(Fixtures.Credentials.Anoncreds.schema); @@ -2096,7 +2094,7 @@ describe("Pollux", () => { 'Required a valid link secret for a Anoncreds Presentation submission' ); - }) + }); it("Should Reject Creating an Anoncreds Presentation Submission using an invalid presentationDefinition", async () => { sandbox.stub(pollux as any, "fetchSchema").resolves(Fixtures.Credentials.Anoncreds.schema); @@ -2111,14 +2109,14 @@ describe("Pollux", () => { )).to.eventually.be.rejectedWith( 'Serialization Error: invalid type: unit value, expected struct PresentationRequestPayload' ); - }) + }); it("Should Reject Creating an Anoncreds Presentation Submission using a wrong JWT Credential", async () => { sandbox.stub(pollux as any, "fetchSchema").resolves(Fixtures.Credentials.Anoncreds.schema); sandbox.stub(pollux as any, "fetchCredentialDefinition").resolves(Fixtures.Credentials.Anoncreds.credentialDefinition); - const credential = new JWTCredential(Fixtures.Credentials.JWT.credentialPayload) - + const credential = new JWTCredential(Fixtures.Credentials.JWT.credentialPayload); + expect(pollux.createPresentationSubmission( Fixtures.Credentials.Anoncreds.presentationRequest, credential, @@ -2127,5 +2125,5 @@ describe("Pollux", () => { 'Required a valid Anoncreds Credential for Anoncreds Presentation submission' ); - }) + }); }); diff --git a/tests/utils/api.test.ts b/tests/utils/api.test.ts index 1d49b5540..9dd3f1dd3 100644 --- a/tests/utils/api.test.ts +++ b/tests/utils/api.test.ts @@ -3,7 +3,7 @@ import { ApiError } from "../../src/domain"; import Server from "./server"; describe("Api test", () => { - const url = 'http://127.0.0.1:3000'; + const url = 'http://127.0.0.1:3333'; // loopback reflects request data in response body const urlLB = `${url}/loopback`; // json returns request body as response body diff --git a/tests/utils/server.js b/tests/utils/server.js index c3b75b891..8167ca295 100644 --- a/tests/utils/server.js +++ b/tests/utils/server.js @@ -62,7 +62,7 @@ const makeServer = async () => { }); }); - const PORT = 3000; + const PORT = 3333; server.listen(PORT, log(`Listening on localhost:${PORT}...`)); server.on('error', (error) => {