UNPKG

@sphereon/wellknown-dids-client

Version:

Well-known DID client allows to create and verify DID Domain configuration resources

371 lines 42.2 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.WellKnownDidVerifier = void 0; const ssi_types_1 = require("@sphereon/ssi-types"); const constants_1 = require("../constants"); const types_1 = require("../types"); const utils_1 = require("../utils"); class WellKnownDidVerifier { /** Verifier constructor */ constructor(config) { this.config = config; } /** * Verifies the domain linkage from a DID document. * * @param args The arguments for verifying domain linkage. * @return {IDomainLinkageValidation}, The validation result. */ verifyDomainLinkage(args) { var _a; return __awaiter(this, void 0, void 0, function* () { if (!args.verifySignatureCallback && (!this.config || !((_a = this.config) === null || _a === void 0 ? void 0 : _a.verifySignatureCallback))) { return Promise.reject(Error(constants_1.WDCErrors.MUST_SUPPLY_VERIFY_SIGNATURE_CALLBACK)); } // DID document should have a service property if (!args.didDocument.service) return Promise.reject({ status: types_1.ValidationStatusEnum.INVALID, message: constants_1.WDCErrors.PROPERTY_SERVICE_NOT_PRESENT }); // Service property should contain 'LinkedDomains' types const linkedDomainsEndpointDescriptors = args.didDocument.service.filter((service) => service.type = types_1.ServiceTypesEnum.LINKED_DOMAINS); if (linkedDomainsEndpointDescriptors.length === 0) return Promise.reject({ status: types_1.ValidationStatusEnum.INVALID, message: constants_1.WDCErrors.PROPERTY_SERVICE_NOT_CONTAIN_ANY_SERVICE_WITH_TYPE + `${types_1.ServiceTypesEnum.LINKED_DOMAINS}` }); const descriptorValidations = linkedDomainsEndpointDescriptors.map((descriptor) => { if (descriptor.id.startsWith('#')) { descriptor.id = `${args.didDocument.id}${descriptor.id}`; } return this.verifyEndpointDescriptor({ descriptor, verifySignatureCallback: args.verifySignatureCallback, onlyVerifyServiceDid: args.onlyVerifyServiceDid }); }); return yield Promise.allSettled(descriptorValidations) .then((results) => { return { status: results.find((result) => result.status === types_1.PromiseStatusEnum.REJECTED || result.value.status === types_1.ValidationStatusEnum.INVALID) ? types_1.ValidationStatusEnum.INVALID : types_1.ValidationStatusEnum.VALID, endpointDescriptors: results.map((result) => result.status === types_1.PromiseStatusEnum.FULFILLED ? result.value : result.reason) }; }); }); } /** * Verifies the endpoint descriptor. * * @param args The arguments to verify the descriptor. * @return {IDescriptorValidation}, The validation result. */ verifyEndpointDescriptor(args) { var _a; return __awaiter(this, void 0, void 0, function* () { if (!args.verifySignatureCallback && (!this.config || !((_a = this.config) === null || _a === void 0 ? void 0 : _a.verifySignatureCallback))) { return Promise.reject(Error(constants_1.WDCErrors.MUST_SUPPLY_VERIFY_SIGNATURE_CALLBACK)); } return this.verifyEndpointDescriptorStructure(args.descriptor).then(() => __awaiter(this, void 0, void 0, function* () { const resourceValidations = this.getOrigins(args.descriptor) .map((origin) => (0, utils_1.fetchWellKnownDidConfiguration)(origin) .then((didConfigurationResource) => { var _a; return this.verifyResource({ configuration: didConfigurationResource, did: (((_a = this.config) === null || _a === void 0 ? void 0 : _a.onlyVerifyServiceDid) || args.onlyVerifyServiceDid) ? args.descriptor.id : undefined, verifySignatureCallback: args.verifySignatureCallback }); })); return yield Promise.allSettled(resourceValidations) .then((results) => { return { status: results.find((result) => result.status === types_1.PromiseStatusEnum.REJECTED || result.value.status === types_1.ValidationStatusEnum.INVALID) ? types_1.ValidationStatusEnum.INVALID : types_1.ValidationStatusEnum.VALID, resources: results.map((result) => result.status === types_1.PromiseStatusEnum.FULFILLED ? result.value : result.reason) }; }); })); }); } /** * Verifies the DID configuration resource. * * @param args The arguments to verify the resource. * @return {IResourceValidation}, The validation result. */ verifyResource(args) { var _a; return __awaiter(this, void 0, void 0, function* () { if (!args.verifySignatureCallback && (!this.config || !((_a = this.config) === null || _a === void 0 ? void 0 : _a.verifySignatureCallback))) { return Promise.reject(Error(constants_1.WDCErrors.MUST_SUPPLY_VERIFY_SIGNATURE_CALLBACK)); } if (args.configuration && args.origin) { return Promise.reject(Error(constants_1.WDCErrors.CANT_SUPPLY_BOTH_CONFIGURATION_AND_ORIGIN)); } if (!args.configuration && !args.origin) { return Promise.reject(Error(constants_1.WDCErrors.NO_DID_CONFIGURATION_RESOURCE_OR_ORIGIN_SUPPLIED)); } let did; if (args.did) { did = (0, ssi_types_1.parseDid)(args.did).did; } if (args.origin) { if (new URL(args.origin).protocol !== 'https:') return Promise.reject(constants_1.WDCErrors.ORIGIN_NOT_SECURE); } const didConfigurationResource = args.configuration // @ts-ignore: We know for sure the config is present // eslint-disable-next-line @typescript-eslint/no-non-null-assertion ? yield (0, utils_1.verifyResourceStructure)(args.configuration).then(() => args.configuration) // @ts-ignore: We know for sure the origin is present // eslint-disable-next-line @typescript-eslint/no-non-null-assertion : yield (0, utils_1.fetchWellKnownDidConfiguration)(args.origin); const credentialValidations = didConfigurationResource.linked_dids .filter((item) => { if (!did) return true; let credential; if (typeof item === 'string') { try { credential = (0, utils_1.decodeToken)(item, false).vc; } catch (error) { return true; } } else { credential = item; } return credential.credentialSubject.id === did; }) .map((credential) => this.verifyDomainLinkageCredential({ credential, verifySignatureCallback: args.verifySignatureCallback })); if (credentialValidations.length === 0) return Promise.reject({ status: types_1.ValidationStatusEnum.INVALID, message: constants_1.WDCErrors.NO_CREDENTIALS_FOUND_FOR_DID + `${args.did}` }); return Promise.allSettled(credentialValidations) .then((results) => { return { status: results.find((result) => result.status === types_1.PromiseStatusEnum.REJECTED) ? types_1.ValidationStatusEnum.INVALID : types_1.ValidationStatusEnum.VALID, credentials: results.map((result) => result.status === types_1.PromiseStatusEnum.FULFILLED ? result.value : result.reason) }; }); }); } /** * Verifies the domain linkage credential. * * @param args The domain linkage credential. Types can be JWT or JSONLD. * @return {ICredentialValidation}, The validation result. */ verifyDomainLinkageCredential(args) { var _a; return __awaiter(this, void 0, void 0, function* () { if (!args.verifySignatureCallback && (!this.config || !((_a = this.config) === null || _a === void 0 ? void 0 : _a.verifySignatureCallback))) { return Promise.reject(Error(constants_1.WDCErrors.MUST_SUPPLY_VERIFY_SIGNATURE_CALLBACK)); } if (typeof args.credential === 'string') { return this.verifyJsonWebTokenProofFormat(args.credential) .then(() => this.verifyDomainLinkageCredentialStructure((0, utils_1.decodeToken)(args.credential, false).vc)) .then(() => args.verifySignatureCallback ? args.verifySignatureCallback({ credential: args.credential, proofFormat: types_1.ProofFormatTypesEnum.JSON_WEB_TOKEN }) // @ts-ignore: We know for sure the config is present // eslint-disable-next-line @typescript-eslint/no-non-null-assertion : this.config.verifySignatureCallback({ credential: args.credential, proofFormat: types_1.ProofFormatTypesEnum.JSON_WEB_TOKEN })) .then((verificationResult) => { if (!verificationResult.verified) return Promise.reject({ status: types_1.ValidationStatusEnum.INVALID, message: constants_1.WDCErrors.SIGNATURE_IS_INVALID }); return { status: types_1.ValidationStatusEnum.VALID }; }); } return this.verifyDomainLinkageCredentialStructure(args.credential) .then(() => args.verifySignatureCallback ? args.verifySignatureCallback({ credential: args.credential, proofFormat: types_1.ProofFormatTypesEnum.JSON_LD }) // @ts-ignore: We know for sure the config is present // eslint-disable-next-line @typescript-eslint/no-non-null-assertion : this.config.verifySignatureCallback({ credential: args.credential, proofFormat: types_1.ProofFormatTypesEnum.JSON_LD })) .then((verificationResult) => { if (!verificationResult.verified) return Promise.reject({ status: types_1.ValidationStatusEnum.INVALID, message: constants_1.WDCErrors.SIGNATURE_IS_INVALID }); return { status: types_1.ValidationStatusEnum.VALID }; }); }); } /** * Verifies the endpoint descriptor object structure. * * @param descriptor The endpoint descriptor. */ verifyEndpointDescriptorStructure(descriptor) { return __awaiter(this, void 0, void 0, function* () { // The object MUST contain an id property if (!descriptor.id) return Promise.reject({ status: types_1.ValidationStatusEnum.INVALID, message: constants_1.WDCErrors.PROPERTY_ID_NOT_PRESENT_IN_SERVICE }); // The object id property value MUST be a valid DID URL reference try { (0, ssi_types_1.parseDid)(descriptor.id); } catch (error) { return Promise.reject({ status: types_1.ValidationStatusEnum.INVALID, message: constants_1.WDCErrors.PROPERTY_ID_NOT_VALID_DID_URL }); } // The object MUST contain a type property if (!descriptor.type) return Promise.reject({ status: types_1.ValidationStatusEnum.INVALID, message: constants_1.WDCErrors.PROPERTY_TYPE_NOT_PRESENT_IN_SERVICE }); // The object type property value MUST be the string "LinkedDomains". if (descriptor.type !== types_1.ServiceTypesEnum.LINKED_DOMAINS) return Promise.reject({ status: types_1.ValidationStatusEnum.INVALID, message: constants_1.WDCErrors.PROPERTY_TYPE_NOT_CONTAIN_VALID_LINKED_DOMAIN }); // The object MUST contain a serviceEndpoint property if (!descriptor.serviceEndpoint) return Promise.reject({ status: types_1.ValidationStatusEnum.INVALID, message: constants_1.WDCErrors.PROPERTY_SERVICE_ENDPOINT_NOT_PRESENT_IN_SERVICE }); if (typeof descriptor.serviceEndpoint === 'string') { // The object serviceEndpoint property can be a string and the value MUST be an origin string if (new URL(descriptor.serviceEndpoint).origin !== descriptor.serviceEndpoint) return Promise.reject({ status: types_1.ValidationStatusEnum.INVALID, message: constants_1.WDCErrors.PROPERTY_SERVICE_ENDPOINT_NOT_CONTAIN_VALID_ORIGIN }); if (new URL(descriptor.serviceEndpoint).protocol !== 'https:') return Promise.reject({ status: types_1.ValidationStatusEnum.INVALID, message: constants_1.WDCErrors.PROPERTY_ORIGIN_NOT_SECURE }); } if (typeof descriptor.serviceEndpoint === 'object') { // The object serviceEndpoint property can be an object which MUST contain an origins property if (!Object.prototype.hasOwnProperty.call(descriptor.serviceEndpoint, 'origins')) return Promise.reject({ status: types_1.ValidationStatusEnum.INVALID, message: constants_1.WDCErrors.PROPERTY_SERVICE_ENDPOINT_NOT_CONTAIN_ORIGIN }); // The object serviceEndpoint property should have origins if (descriptor.serviceEndpoint.origins.length === 0) return Promise.reject({ status: types_1.ValidationStatusEnum.INVALID, message: constants_1.WDCErrors.PROPERTY_ORIGIN_NOT_CONTAIN_ANY_ORIGIN }); // The origins should be valid for (const origin of descriptor.serviceEndpoint.origins) { if (new URL(origin).origin !== origin) return Promise.reject({ status: types_1.ValidationStatusEnum.INVALID, message: constants_1.WDCErrors.PROPERTY_ORIGIN_CONTAIN_INVALID_ORIGIN }); if (new URL(origin).protocol !== 'https:') return Promise.reject({ status: types_1.ValidationStatusEnum.INVALID, message: constants_1.WDCErrors.PROPERTY_ORIGIN_NOT_SECURE }); } } }); } /** * Verifies the structure of a JWT domain linkage credential. * * @param token The JWT token. */ verifyJsonWebTokenProofFormat(token) { return __awaiter(this, void 0, void 0, function* () { yield this.verifyJsonWebTokenProofHeaderStructure((0, utils_1.decodeToken)(token, true)); yield this.verifyJsonWebTokenProofPayloadStructure((0, utils_1.decodeToken)(token, false)); }); } /** * Verifies the structure of a JWT domain linkage credential header. * * @param header The JWT header. */ verifyJsonWebTokenProofHeaderStructure(header) { return __awaiter(this, void 0, void 0, function* () { // Property kid MUST be present in the JWT Header if (!header.kid) return Promise.reject({ status: types_1.ValidationStatusEnum.INVALID, message: constants_1.WDCErrors.PROPERTY_KID_NOT_PRESENT_IN_JWT_HEADER }); // Property alg MUST be present in the JWT Header if (!header.alg) return Promise.reject({ status: types_1.ValidationStatusEnum.INVALID, message: constants_1.WDCErrors.PROPERTY_ALG_NOT_PRESENT_IN_JWT_HEADER }); // Additional members MUST NOT be present in the header if (Object.getOwnPropertyNames(header).filter(property => !['kid', 'alg'].includes(property)).length > 0) return Promise.reject({ status: types_1.ValidationStatusEnum.INVALID, message: constants_1.WDCErrors.JWT_HEADER_CONTAINS_ADDITIONAL_PROPS }); }); } /** * Verifies the structure of a JWT domain linkage credential payload. * * @param payload The JWT payload. */ verifyJsonWebTokenProofPayloadStructure(payload) { return __awaiter(this, void 0, void 0, function* () { // Property iss MUST be present in the JWT Payload if (!payload.iss) return Promise.reject({ status: types_1.ValidationStatusEnum.INVALID, message: constants_1.WDCErrors.PROPERTY_ISS_NOT_PRESENT_IN_JWT_PAYLOAD }); // Property sub MUST be present in the JWT Payload if (!payload.sub) return Promise.reject({ status: types_1.ValidationStatusEnum.INVALID, message: constants_1.WDCErrors.PROPERTY_SUB_NOT_PRESENT_IN_JWT_PAYLOAD }); // Property vc MUST be present in the JWT Payload if (!payload.vc) return Promise.reject({ status: types_1.ValidationStatusEnum.INVALID, message: constants_1.WDCErrors.PROPERTY_VC_NOT_PRESENT_IN_JWT_PAYLOAD }); // Property iss MUST be equal to credentialSubject.id. if (payload.vc.credentialSubject && payload.vc.credentialSubject.id !== payload.iss) return Promise.reject({ status: types_1.ValidationStatusEnum.INVALID, message: constants_1.WDCErrors.PROPERTY_ISS_NOT_MATCH_CREDENTIAL_SUBJECT_ID_IN_JWT_PAYLOAD }); // Property sub MUST be equal to credentialSubject.id. if (payload.vc.credentialSubject && payload.vc.credentialSubject.id !== payload.sub) return Promise.reject({ status: types_1.ValidationStatusEnum.INVALID, message: constants_1.WDCErrors.PROPERTY_SUB_NOT_MATCH_CREDENTIAL_SUBJECT_ID_IN_JWT_PAYLOAD }); // Additional members MUST NOT be present in the payload if (Object.getOwnPropertyNames(payload).filter(property => !['exp', 'iss', 'nbf', 'sub', 'vc'].includes(property)).length > 0) return Promise.reject({ status: types_1.ValidationStatusEnum.INVALID, message: constants_1.WDCErrors.JWT_PAYLOAD_CONTAINS_ADDITIONAL_PROPS }); }); } /** * Verifies the structure of a domain linkage credential. * * @param credential The domain linkage credential. */ verifyDomainLinkageCredentialStructure(credential) { return __awaiter(this, void 0, void 0, function* () { // Property issuanceDate MUST be present. if (!credential.issuanceDate) return Promise.reject({ status: types_1.ValidationStatusEnum.INVALID, message: constants_1.WDCErrors.PROPERTY_ISSUANCE_DATE_NOT_PRESENT_IN_CREDENTIAL }); // Property issuanceDate MUST be a valid date. if ( /*typeof credential.issuanceDate === 'string' && */isNaN(Date.parse(credential.issuanceDate))) return Promise.reject({ status: types_1.ValidationStatusEnum.INVALID, message: constants_1.WDCErrors.PROPERTY_ISSUANCE_DATE_NOT_VALID }); // Property expirationDate MUST be present. if (!credential.expirationDate) return Promise.reject({ status: types_1.ValidationStatusEnum.INVALID, message: constants_1.WDCErrors.PROPERTY_EXPIRATION_DATE_NOT_PRESENT_IN_CREDENTIAL }); // Property expirationDate MUST be a valid date. if ( /*typeof credential.expirationDate === 'string' && */isNaN(Date.parse(credential.expirationDate))) return Promise.reject({ status: types_1.ValidationStatusEnum.INVALID, message: constants_1.WDCErrors.PROPERTY_EXPIRATION_DATE_NOT_VALID }); // Property credentialSubject MUST be present. if (!credential.credentialSubject) return Promise.reject({ status: types_1.ValidationStatusEnum.INVALID, message: constants_1.WDCErrors.PROPERTY_CREDENTIAL_SUBJECT_NOT_PRESENT_IN_CREDENTIAL }); // Property credentialSubject.id MUST be present. if (!credential.credentialSubject.id) return Promise.reject({ status: types_1.ValidationStatusEnum.INVALID, message: constants_1.WDCErrors.PROPERTY_CREDENTIAL_SUBJECT_ID_NOT_PRESENT_IN_CREDENTIAL }); // Property credentialSubject.id MUST be a DID. try { (0, ssi_types_1.parseDid)(credential.credentialSubject.id); } catch (error) { return Promise.reject({ status: types_1.ValidationStatusEnum.INVALID, message: constants_1.WDCErrors.PROPERTY_CREDENTIAL_SUBJECT_ID_NOT_VALID_DID }); } // The credentialSubject.id value MUST be equal to the issuer of the Domain Linkage Credential. if (credential.issuer && credential.credentialSubject.id !== credential.issuer) return Promise.reject({ status: types_1.ValidationStatusEnum.INVALID, message: constants_1.WDCErrors.PROPERTY_CREDENTIAL_SUBJECT_ID_NOT_MATCH_ISSUER }); // Property credentialSubject.origin MUST be present. if (!credential.credentialSubject.origin) return Promise.reject({ status: types_1.ValidationStatusEnum.INVALID, message: constants_1.WDCErrors.PROPERTY_CREDENTIAL_SUBJECT_ORIGIN_NOT_PRESENT_IN_CREDENTIAL }); // Property credentialSubject.origin MUST be a domain Origin. try { if (new URL(credential.credentialSubject.origin).origin !== credential.credentialSubject.origin) return Promise.reject({ status: types_1.ValidationStatusEnum.INVALID, message: constants_1.WDCErrors.PROPERTY_CREDENTIAL_SUBJECT_ORIGIN_NOT_VALID }); } catch (error) { return Promise.reject({ status: types_1.ValidationStatusEnum.INVALID, message: constants_1.WDCErrors.PROPERTY_CREDENTIAL_SUBJECT_ORIGIN_NOT_VALID }); } }); } /** * Retrieves the origins of an endpoint descriptor. * * @param descriptor The endpoint descriptor. */ getOrigins(descriptor) { if (typeof descriptor.serviceEndpoint === 'string') { return [descriptor.serviceEndpoint]; } else { // This break with did-resolver@3 // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore return descriptor.serviceEndpoint.origins; } } } exports.WellKnownDidVerifier = WellKnownDidVerifier; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiV2VsbEtub3duRGlkVmVyaWZpZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9saWIvdmVyaWZpZXIvV2VsbEtub3duRGlkVmVyaWZpZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7O0FBQUEsbURBQStDO0FBRy9DLDRDQUF5QztBQUN6QyxvQ0FzQmtCO0FBQ2xCLG9DQUlrQjtBQUVsQixNQUFhLG9CQUFvQjtJQUcvQiwyQkFBMkI7SUFDM0IsWUFBWSxNQUF3QjtRQUNsQyxJQUFJLENBQUMsTUFBTSxHQUFHLE1BQU0sQ0FBQTtJQUN0QixDQUFDO0lBRUQ7Ozs7O09BS0c7SUFDVSxtQkFBbUIsQ0FBQyxJQUE4Qjs7O1lBQzdELElBQUksQ0FBQyxJQUFJLENBQUMsdUJBQXVCLElBQUksQ0FBQyxDQUFDLElBQUksQ0FBQyxNQUFNLElBQUksQ0FBQyxDQUFBLE1BQUEsSUFBSSxDQUFDLE1BQU0sMENBQUUsdUJBQXVCLENBQUEsQ0FBQyxFQUFFO2dCQUM1RixPQUFPLE9BQU8sQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLHFCQUFTLENBQUMscUNBQXFDLENBQUMsQ0FBQyxDQUFBO2FBQzlFO1lBRUQsOENBQThDO1lBQzlDLElBQUksQ0FBQyxJQUFJLENBQUMsV0FBVyxDQUFDLE9BQU87Z0JBQUUsT0FBTyxPQUFPLENBQUMsTUFBTSxDQUFDLEVBQUUsTUFBTSxFQUFFLDRCQUFvQixDQUFDLE9BQU8sRUFBRSxPQUFPLEVBQUUscUJBQVMsQ0FBQyw0QkFBNEIsRUFBRSxDQUFDLENBQUE7WUFFL0ksd0RBQXdEO1lBQ3hELE1BQU0sZ0NBQWdDLEdBQTJCLElBQUksQ0FBQyxXQUFXLENBQUMsT0FBTyxDQUFDLE1BQU0sQ0FBQyxDQUFDLE9BQXdCLEVBQUUsRUFBRSxDQUFDLE9BQU8sQ0FBQyxJQUFJLEdBQUcsd0JBQWdCLENBQUMsY0FBYyxDQUFDLENBQUE7WUFDOUssSUFBSSxnQ0FBZ0MsQ0FBQyxNQUFNLEtBQUssQ0FBQztn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