

const require_rolldown_runtime = require('../../../_virtual/rolldown_runtime.js');
const require_CredoError = require('../../../error/CredoError.js');
require('../../../error/index.js');
require('../../../plugins/index.js');
const require_decorateMetadata = require('../../../_virtual/_@oxc-project_runtime@0.97.0/helpers/decorateMetadata.js');
const require_decorate = require('../../../_virtual/_@oxc-project_runtime@0.97.0/helpers/decorate.js');
const require_array = require('../../../utils/array.js');
const require_did = require('../../../utils/did.js');
const require_MessageValidator = require('../../../utils/MessageValidator.js');
require('../../../utils/index.js');
const require_PublicJwk = require('../../kms/jwk/PublicJwk.js');
require('../../kms/index.js');
const require_JwsService = require('../../../crypto/JwsService.js');
const require_parse = require('../../dids/domain/parse.js');
const require_keyDidMapping = require('../../dids/domain/key-type/keyDidMapping.js');
const require_DidResolverService = require('../../dids/services/DidResolverService.js');
const require_DidsApi = require('../../dids/DidsApi.js');
require('../../dids/index.js');
const require_W3cJsonLdVerifiableCredential = require('../data-integrity/models/W3cJsonLdVerifiableCredential.js');
const require_credentialTransformer = require('./credentialTransformer.js');
const require_W3cJwtVerifiableCredential = require('./W3cJwtVerifiableCredential.js');
const require_presentationTransformer = require('./presentationTransformer.js');
const require_W3cJwtVerifiablePresentation = require('./W3cJwtVerifiablePresentation.js');
require('../data-integrity/index.js');
let tsyringe = require("tsyringe");

//#region src/modules/vc/jwt-vc/W3cJwtCredentialService.ts
var _ref;
let W3cJwtCredentialService = class W3cJwtCredentialService$1 {
	constructor(jwsService) {
		this.jwsService = jwsService;
	}
	/**
	* Signs a credential
	*/
	async signCredential(agentContext, options) {
		require_MessageValidator.MessageValidator.validateSync(options.credential);
		const jwtPayload = require_credentialTransformer.getJwtPayloadFromCredential(options.credential);
		if (!require_did.isDid(options.verificationMethod)) throw new require_CredoError.CredoError("Only did identifiers are supported as verification method");
		const publicJwk = await this.resolveVerificationMethod(agentContext, options.verificationMethod, ["assertionMethod"]);
		const jwt = await this.jwsService.createJwsCompact(agentContext, {
			payload: jwtPayload,
			keyId: publicJwk.keyId,
			protectedHeaderOptions: {
				typ: "JWT",
				alg: options.alg,
				kid: options.verificationMethod
			}
		});
		return require_W3cJwtVerifiableCredential.W3cJwtVerifiableCredential.fromSerializedJwt(jwt);
	}
	/**
	* Verifies the signature(s) of a credential
	*
	* @param credential the credential to be verified
	* @returns the verification result
	*/
	async verifyCredential(agentContext, options) {
		const verifyCredentialStatus = options.verifyCredentialStatus ?? true;
		const validationResults = {
			isValid: false,
			validations: {}
		};
		try {
			let credential;
			try {
				if (options.credential instanceof require_W3cJwtVerifiableCredential.W3cJwtVerifiableCredential) require_MessageValidator.MessageValidator.validateSync(options.credential.credential);
				credential = options.credential instanceof require_W3cJwtVerifiableCredential.W3cJwtVerifiableCredential ? options.credential : require_W3cJwtVerifiableCredential.W3cJwtVerifiableCredential.fromSerializedJwt(options.credential);
				credential.jwt.payload.validate();
				validationResults.validations.dataModel = { isValid: true };
			} catch (error) {
				validationResults.validations.dataModel = {
					isValid: false,
					error
				};
				return validationResults;
			}
			const issuerVerificationMethod = await this.getVerificationMethodForJwtCredential(agentContext, {
				credential,
				purpose: ["assertionMethod"]
			});
			const issuerPublicKey = require_keyDidMapping.getPublicJwkFromVerificationMethod(issuerVerificationMethod);
			let signatureResult;
			try {
				signatureResult = await this.jwsService.verifyJws(agentContext, {
					jws: credential.jwt.serializedJwt,
					jwsSigner: {
						method: "did",
						jwk: issuerPublicKey,
						didUrl: issuerVerificationMethod.id
					}
				});
				if (!signatureResult.isValid) validationResults.validations.signature = {
					isValid: false,
					error: new require_CredoError.CredoError("Invalid JWS signature")
				};
				else validationResults.validations.signature = { isValid: true };
			} catch (error) {
				validationResults.validations.signature = {
					isValid: false,
					error
				};
			}
			if (credential.issuerId !== issuerVerificationMethod.controller) validationResults.validations.issuerIsSigner = {
				isValid: false,
				error: new require_CredoError.CredoError(`Credential is signed using verification method ${issuerVerificationMethod.id}, while the issuer of the credential is '${credential.issuerId}'`)
			};
			else validationResults.validations.issuerIsSigner = { isValid: true };
			if (!signatureResult?.jwsSigners.some((jwsSigner) => jwsSigner.jwk.fingerprint === issuerPublicKey.fingerprint)) validationResults.validations.issuerIsSigner = {
				isValid: false,
				error: new require_CredoError.CredoError("Credential is not signed by the issuer of the credential")
			};
			else validationResults.validations.issuerIsSigner = { isValid: true };
			if (verifyCredentialStatus && !credential.credentialStatus) validationResults.validations.credentialStatus = { isValid: true };
			else if (verifyCredentialStatus && credential.credentialStatus) validationResults.validations.credentialStatus = {
				isValid: false,
				error: new require_CredoError.CredoError("Verifying credential status is not supported for JWT VCs")
			};
			validationResults.isValid = Object.values(validationResults.validations).every((v) => v.isValid);
			return validationResults;
		} catch (error) {
			validationResults.error = error;
			return validationResults;
		}
	}
	/**
	* Signs a presentation including the credentials it includes
	*
	* @param presentation the presentation to be signed
	* @returns the signed presentation
	*/
	async signPresentation(agentContext, options) {
		require_MessageValidator.MessageValidator.validateSync(options.presentation);
		const jwtPayload = require_presentationTransformer.getJwtPayloadFromPresentation(options.presentation);
		jwtPayload.additionalClaims.nonce = options.challenge;
		jwtPayload.aud = options.domain;
		const publicJwk = await this.resolveVerificationMethod(agentContext, options.verificationMethod, ["authentication"]);
		const jwt = await this.jwsService.createJwsCompact(agentContext, {
			payload: jwtPayload,
			keyId: publicJwk.keyId,
			protectedHeaderOptions: {
				typ: "JWT",
				alg: options.alg,
				kid: options.verificationMethod
			}
		});
		return require_W3cJwtVerifiablePresentation.W3cJwtVerifiablePresentation.fromSerializedJwt(jwt);
	}
	/**
	* Verifies a presentation including the credentials it includes
	*
	* @param presentation the presentation to be verified
	* @returns the verification result
	*/
	async verifyPresentation(agentContext, options) {
		const validationResults = {
			isValid: false,
			validations: {}
		};
		try {
			let presentation;
			try {
				if (options.presentation instanceof require_W3cJwtVerifiablePresentation.W3cJwtVerifiablePresentation) require_MessageValidator.MessageValidator.validateSync(options.presentation.presentation);
				presentation = options.presentation instanceof require_W3cJwtVerifiablePresentation.W3cJwtVerifiablePresentation ? options.presentation : require_W3cJwtVerifiablePresentation.W3cJwtVerifiablePresentation.fromSerializedJwt(options.presentation);
				presentation.jwt.payload.validate();
				if (options.challenge !== presentation.jwt.payload.additionalClaims.nonce) throw new require_CredoError.CredoError(`JWT payload 'nonce' does not match challenge '${options.challenge}'`);
				const audArray = require_array.asArray(presentation.jwt.payload.aud);
				if (options.domain && !audArray.includes(options.domain)) throw new require_CredoError.CredoError(`JWT payload 'aud' does not include domain '${options.domain}'`);
				validationResults.validations.dataModel = { isValid: true };
			} catch (error) {
				validationResults.validations.dataModel = {
					isValid: false,
					error
				};
				return validationResults;
			}
			const proverVerificationMethod = await this.getVerificationMethodForJwtCredential(agentContext, {
				credential: presentation,
				purpose: ["authentication"]
			});
			const proverPublicKey = require_keyDidMapping.getPublicJwkFromVerificationMethod(proverVerificationMethod);
			let signatureResult;
			try {
				signatureResult = await this.jwsService.verifyJws(agentContext, {
					jws: presentation.jwt.serializedJwt,
					allowedJwsSignerMethods: ["did"],
					jwsSigner: {
						method: "did",
						didUrl: proverVerificationMethod.id,
						jwk: proverPublicKey
					},
					trustedCertificates: []
				});
				if (!signatureResult.isValid) validationResults.validations.presentationSignature = {
					isValid: false,
					error: new require_CredoError.CredoError("Invalid JWS signature on presentation")
				};
				else validationResults.validations.presentationSignature = { isValid: true };
			} catch (error) {
				validationResults.validations.presentationSignature = {
					isValid: false,
					error
				};
			}
			if (presentation.holderId && proverVerificationMethod.controller !== presentation.holderId) validationResults.validations.holderIsSigner = {
				isValid: false,
				error: new require_CredoError.CredoError(`Presentation is signed using verification method ${proverVerificationMethod.id}, while the holder of the presentation is '${presentation.holderId}'`)
			};
			else validationResults.validations.holderIsSigner = { isValid: true };
			const credentials = require_array.asArray(presentation.presentation.verifiableCredential);
			validationResults.validations.credentials = await Promise.all(credentials.map(async (credential) => {
				if (credential instanceof require_W3cJsonLdVerifiableCredential.W3cJsonLdVerifiableCredential) return {
					isValid: false,
					error: new require_CredoError.CredoError("Credential is of format ldp_vc. presentations in jwt_vp format can only contain credentials in jwt_vc format"),
					validations: {}
				};
				const credentialResult = await this.verifyCredential(agentContext, {
					credential,
					verifyCredentialStatus: options.verifyCredentialStatus
				});
				let credentialSubjectAuthentication;
				const credentialSubjectIds = credential.credentialSubjectIds;
				const presentationAuthenticatesCredentialSubject = credentialSubjectIds.some((subjectId) => proverVerificationMethod.controller === subjectId);
				if (credentialSubjectIds.length > 0 && !presentationAuthenticatesCredentialSubject) credentialSubjectAuthentication = {
					isValid: false,
					error: new require_CredoError.CredoError("Credential has one or more credentialSubject ids, but presentation does not authenticate credential subject")
				};
				else credentialSubjectAuthentication = { isValid: true };
				return {
					...credentialResult,
					isValid: credentialResult.isValid && credentialSubjectAuthentication.isValid,
					validations: {
						...credentialResult.validations,
						credentialSubjectAuthentication
					}
				};
			}));
			validationResults.isValid = Object.values(validationResults.validations).every((v) => Array.isArray(v) ? v.every((vv) => vv.isValid) : v.isValid);
			return validationResults;
		} catch (error) {
			validationResults.error = error;
			return validationResults;
		}
	}
	async resolveVerificationMethod(agentContext, verificationMethod, allowsPurposes) {
		const dids = agentContext.resolve(require_DidsApi.DidsApi);
		const parsedDid = require_parse.parseDid(verificationMethod);
		const { didDocument, keys } = await dids.resolveCreatedDidDocumentWithKeys(parsedDid.did);
		const verificationMethodObject = didDocument.dereferenceKey(verificationMethod, allowsPurposes);
		const publicJwk = require_keyDidMapping.getPublicJwkFromVerificationMethod(verificationMethodObject);
		publicJwk.keyId = keys?.find(({ didDocumentRelativeKeyId }) => verificationMethodObject.id.endsWith(didDocumentRelativeKeyId))?.kmsKeyId ?? publicJwk.legacyKeyId;
		return publicJwk;
	}
	/**
	* This method tries to find the verification method associated with the JWT credential or presentation.
	* This verification method can then be used to verify the credential or presentation signature.
	*
	* The following methods are used to extract the verification method:
	*  - verification method is resolved based on the `kid` in the protected header
	*    - either as absolute reference (e.g. `did:example:123#key-1`)
	*    - or as relative reference to the `iss` of the JWT (e.g. `iss` is `did:example:123` and `kid` is `#key-1`)
	*  - the did document is resolved based on the `iss` field, after which the verification method is extracted based on the `alg`
	*    used to sign the JWT and the specified `purpose`. Only a single verification method may be present, and in all other cases,
	*    an error is thrown.
	*
	* The signer (`iss`) of the JWT is verified against the `controller` of the verificationMethod resolved in the did
	* document. This means if the `iss` of a credential is `did:example:123` and the controller of the verificationMethod
	* is `did:example:456`, an error is thrown to prevent the JWT from successfully being verified.
	*
	* In addition the JWT must conform to one of the following rules:
	*   - MUST be a credential and have an `iss` field and MAY have an absolute or relative `kid`
	*   - MUST not be a credential AND ONE of the following:
	*      - have an `iss` field and MAY have an absolute or relative `kid`
	*      - does not have an `iss` field and MUST have an absolute `kid`
	*/
	async getVerificationMethodForJwtCredential(agentContext, options) {
		const { credential, purpose } = options;
		const kid = credential.jwt.header.kid;
		const didResolver = agentContext.dependencyManager.resolve(require_DidResolverService.DidResolverService);
		const signerId = credential.jwt.payload.iss;
		let verificationMethod;
		if (kid?.startsWith("#")) {
			if (!signerId) throw new require_CredoError.CredoError(`JWT 'kid' MUST be absolute when when no 'iss' is present in JWT payload`);
			verificationMethod = (await didResolver.resolveDidDocument(agentContext, signerId)).dereferenceKey(`${signerId}${kid}`, purpose);
		} else if (kid && require_did.isDid(kid)) {
			const didDocument = await didResolver.resolveDidDocument(agentContext, kid);
			verificationMethod = didDocument.dereferenceKey(kid, purpose);
			if (signerId && didDocument.id !== signerId) throw new require_CredoError.CredoError(`kid '${kid}' does not match id of signer (holder/issuer) '${signerId}'`);
		} else {
			if (!signerId) throw new require_CredoError.CredoError(`JWT 'iss' MUST be present in payload when no 'kid' is specified`);
			const jwkClass = require_PublicJwk.PublicJwk.supportedPublicJwkClassForSignatureAlgorithm(credential.jwt.header.alg);
			const supportedVerificationMethodTypes = require_keyDidMapping.getSupportedVerificationMethodTypesForPublicJwk(jwkClass);
			const didDocument = await didResolver.resolveDidDocument(agentContext, signerId);
			const verificationMethods = didDocument.assertionMethod?.map((v) => typeof v === "string" ? didDocument.dereferenceVerificationMethod(v) : v).filter((v) => supportedVerificationMethodTypes.includes(v.type)) ?? [];
			if (verificationMethods.length === 0) throw new require_CredoError.CredoError(`No verification methods found for signer '${signerId}' and key type '${jwkClass.name}' for alg '${credential.jwt.header.alg}'. Unable to determine which public key is associated with the credential.`);
			if (verificationMethods.length > 1) throw new require_CredoError.CredoError(`Multiple verification methods found for signer '${signerId}' and key type '${jwkClass.name}' for alg '${credential.jwt.header.alg}'. Unable to determine which public key is associated with the credential.`);
			verificationMethod = verificationMethods[0];
		}
		if (signerId && verificationMethod.controller !== signerId) throw new require_CredoError.CredoError(`Verification method controller '${verificationMethod.controller}' does not match the signer '${signerId}'`);
		return verificationMethod;
	}
};
W3cJwtCredentialService = require_decorate.__decorate([(0, tsyringe.injectable)(), require_decorateMetadata.__decorateMetadata("design:paramtypes", [typeof (_ref = typeof require_JwsService.JwsService !== "undefined" && require_JwsService.JwsService) === "function" ? _ref : Object])], W3cJwtCredentialService);

//#endregion
Object.defineProperty(exports, 'W3cJwtCredentialService', {
  enumerable: true,
  get: function () {
    return W3cJwtCredentialService;
  }
});