@sphereon/wellknown-dids-client
Version:
Well-known DID client allows to create and verify DID Domain configuration resources
371 lines • 42.2 kB
JavaScript
"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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