

import { CredoError } from "../../../error/CredoError.mjs";
import "../../../error/index.mjs";
import { injectable } from "../../../plugins/index.mjs";
import { __decorateMetadata } from "../../../_virtual/_@oxc-project_runtime@0.94.0/helpers/decorateMetadata.mjs";
import { __decorate } from "../../../_virtual/_@oxc-project_runtime@0.94.0/helpers/decorate.mjs";
import { MessageValidator } from "../../../utils/MessageValidator.mjs";
import { JsonTransformer } from "../../../utils/JsonTransformer.mjs";
import { asArray } from "../../../utils/array.mjs";
import { nowInSeconds } from "../../../utils/timestamp.mjs";
import "../../../utils/index.mjs";
import { JwtPayload } from "../../../crypto/jose/jwt/JwtPayload.mjs";
import { JwsService } from "../../../crypto/JwsService.mjs";
import { getPublicJwkFromVerificationMethod } from "../../dids/domain/key-type/keyDidMapping.mjs";
import { W3cV2JwtVerifiableCredential } from "./W3cV2JwtVerifiableCredential.mjs";
import "../../../crypto/index.mjs";
import { W3cV2JwtVerifiablePresentation } from "./W3cV2JwtVerifiablePresentation.mjs";
import { extractKeyFromHolderBinding } from "../../sd-jwt-vc/utils.mjs";
import { extractHolderFromPresentationCredentials, getVerificationMethodForJwt, validateAndResolveVerificationMethod } from "../v2-jwt-utils.mjs";

//#region src/modules/vc/jwt-vc/W3cV2JwtCredentialService.ts
var _ref;
let W3cV2JwtCredentialService = class W3cV2JwtCredentialService$1 {
	constructor(jwsService) {
		this.jwsService = jwsService;
	}
	/**
	* Signs a credential
	*/
	async signCredential(agentContext, options) {
		MessageValidator.validateSync(options.credential);
		const jwtPayload = new JwtPayload({ additionalClaims: JsonTransformer.toJSON(options.credential) });
		jwtPayload.iat = nowInSeconds();
		jwtPayload.additionalClaims.cnf = options.holder ? (await extractKeyFromHolderBinding(agentContext, options.holder)).cnf : void 0;
		const publicJwk = await validateAndResolveVerificationMethod(agentContext, options.verificationMethod, ["assertionMethod"]);
		const jwt = await this.jwsService.createJwsCompact(agentContext, {
			payload: jwtPayload,
			keyId: publicJwk.keyId,
			protectedHeaderOptions: {
				typ: "vc+jwt",
				alg: options.alg,
				kid: options.verificationMethod
			}
		});
		return W3cV2JwtVerifiableCredential.fromCompact(jwt);
	}
	/**
	* Verifies the signature(s) of a credential
	*
	* @param credential the credential to be verified
	* @returns the verification result
	*/
	async verifyCredential(agentContext, options) {
		const validationResults = {
			isValid: false,
			validations: {}
		};
		try {
			let credential;
			try {
				if (options.credential instanceof W3cV2JwtVerifiableCredential) options.credential.validate();
				credential = options.credential instanceof W3cV2JwtVerifiableCredential ? options.credential : W3cV2JwtVerifiableCredential.fromCompact(options.credential);
				credential.jwt.payload.validate();
				validationResults.validations.dataModel = { isValid: true };
			} catch (error) {
				validationResults.validations.dataModel = {
					isValid: false,
					error
				};
				return validationResults;
			}
			const issuerVerificationMethod = await getVerificationMethodForJwt(agentContext, credential, ["assertionMethod"]);
			const issuerPublicKey = getPublicJwkFromVerificationMethod(issuerVerificationMethod);
			let signatureResult = void 0;
			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 CredoError("Invalid JWS signature")
				};
				else validationResults.validations.signature = { isValid: true };
			} catch (error) {
				validationResults.validations.signature = {
					isValid: false,
					error
				};
			}
			if (credential.resolvedCredential.issuerId !== issuerVerificationMethod.controller) validationResults.validations.issuerIsSigner = {
				isValid: false,
				error: new CredoError(`Credential is signed using verification method ${issuerVerificationMethod.id}, while the issuer of the credential is '${credential.resolvedCredential.issuerId}'`)
			};
			else validationResults.validations.issuerIsSigner = { isValid: true };
			if (!signatureResult?.jwsSigners.some((jwsSigner) => jwsSigner.jwk.fingerprint === issuerPublicKey.fingerprint)) validationResults.validations.issuerIsSigner = {
				isValid: false,
				error: new CredoError("Credential is not signed by the issuer of the credential")
			};
			else validationResults.validations.issuerIsSigner = { isValid: true };
			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) {
		MessageValidator.validateSync(options.presentation);
		const jwtPayload = new JwtPayload({ additionalClaims: JsonTransformer.toJSON(options.presentation) });
		jwtPayload.additionalClaims.nonce = options.challenge;
		jwtPayload.aud = options.domain;
		const holder = await extractHolderFromPresentationCredentials(agentContext, options.presentation);
		const jwt = await this.jwsService.createJwsCompact(agentContext, {
			payload: jwtPayload,
			keyId: holder.publicJwk.keyId,
			protectedHeaderOptions: {
				typ: "vp+jwt",
				alg: holder.alg,
				kid: holder?.cnf?.kid
			}
		});
		return W3cV2JwtVerifiablePresentation.fromCompact(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 W3cV2JwtVerifiablePresentation) options.presentation.validate();
				presentation = options.presentation instanceof W3cV2JwtVerifiablePresentation ? options.presentation : W3cV2JwtVerifiablePresentation.fromCompact(options.presentation);
				presentation.jwt.payload.validate();
				if (options.challenge !== presentation.jwt.payload.additionalClaims.nonce) throw new CredoError(`JWT payload 'nonce' does not match challenge '${options.challenge}'`);
				const audArray = asArray(presentation.jwt.payload.aud);
				if (options.domain && !audArray.includes(options.domain)) throw new 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 getVerificationMethodForJwt(agentContext, presentation, ["authentication"]);
			const proverPublicKey = getPublicJwkFromVerificationMethod(proverVerificationMethod);
			let signatureResult = void 0;
			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 CredoError("Invalid JWS signature on presentation")
				};
				else validationResults.validations.presentationSignature = { isValid: true };
			} catch (error) {
				validationResults.validations.presentationSignature = {
					isValid: false,
					error
				};
			}
			if (presentation.resolvedPresentation.holderId && proverVerificationMethod.controller !== presentation.resolvedPresentation.holderId) validationResults.validations.holderIsSigner = {
				isValid: false,
				error: new CredoError(`Presentation is signed using verification method ${proverVerificationMethod.id}, while the holder of the presentation is '${presentation.resolvedPresentation.holderId}'`)
			};
			else validationResults.validations.holderIsSigner = { isValid: true };
			const credentials = asArray(presentation.resolvedPresentation.verifiableCredential);
			validationResults.validations.credentials = await Promise.all(credentials.map(async (credential) => {
				if (!(credential.envelopedCredential instanceof W3cV2JwtVerifiableCredential)) return {
					isValid: false,
					error: new CredoError("Credential is not of format JWT. Presentations in JWT format can only contain credentials in JWT format."),
					validations: {}
				};
				const credentialResult = await this.verifyCredential(agentContext, { credential: credential.envelopedCredential });
				let credentialSubjectAuthentication;
				const credentialSubjectIds = credential.resolvedCredential.credentialSubjectIds;
				const presentationAuthenticatesCredentialSubject = credentialSubjectIds.some((subjectId) => proverVerificationMethod.controller === subjectId);
				if (credentialSubjectIds.length > 0 && !presentationAuthenticatesCredentialSubject) credentialSubjectAuthentication = {
					isValid: false,
					error: new 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;
		}
	}
};
W3cV2JwtCredentialService = __decorate([injectable(), __decorateMetadata("design:paramtypes", [typeof (_ref = typeof JwsService !== "undefined" && JwsService) === "function" ? _ref : Object])], W3cV2JwtCredentialService);

//#endregion
export { W3cV2JwtCredentialService };
//# sourceMappingURL=W3cV2JwtCredentialService.mjs.map