

const require_rolldown_runtime = require('../../_virtual/rolldown_runtime.js');
const require_CredoError = require('../../error/CredoError.js');
require('../../error/index.js');
const require_decorateMetadata = require('../../_virtual/_@oxc-project_runtime@0.94.0/helpers/decorateMetadata.js');
const require_decorate = require('../../_virtual/_@oxc-project_runtime@0.94.0/helpers/decorate.js');
require('../../agent/index.js');
const require_Hasher = require('../../crypto/hashes/Hasher.js');
const require_TypedArrayEncoder = require('../../utils/TypedArrayEncoder.js');
const require_timestamp = require('../../utils/timestamp.js');
require('../../utils/index.js');
const require_KeyManagementApi = require('../kms/KeyManagementApi.js');
require('../kms/index.js');
const require_X509Certificate = require('../x509/X509Certificate.js');
const require_X509Service = require('../x509/X509Service.js');
const require_X509ModuleConfig = require('../x509/X509ModuleConfig.js');
require('../x509/index.js');
const require_JwtPayload = require('../../crypto/jose/jwt/JwtPayload.js');
const require_keyDidMapping = require('../dids/domain/key-type/keyDidMapping.js');
const require_parse = require('../dids/domain/parse.js');
require('../dids/index.js');
const require_ClaimFormat = require('../vc/models/ClaimFormat.js');
require('../../crypto/index.js');
const require_utils = require('./utils.js');
require('../vc/index.js');
const require_domain = require('../../utils/domain.js');
const require_fetch = require('../../utils/fetch.js');
const require_SdJwtVcError = require('./SdJwtVcError.js');
const require_decodeSdJwtVc = require('./decodeSdJwtVc.js');
const require_disclosureFrame = require('./disclosureFrame.js');
const require_SdJwtVcRecord = require('./repository/SdJwtVcRecord.js');
const require_SdJwtVcRepository = require('./repository/SdJwtVcRepository.js');
require('./repository/index.js');
let tsyringe = require("tsyringe");
tsyringe = require_rolldown_runtime.__toESM(tsyringe);
let __sd_jwt_decode = require("@sd-jwt/decode");
__sd_jwt_decode = require_rolldown_runtime.__toESM(__sd_jwt_decode);
let __sd_jwt_present = require("@sd-jwt/present");
__sd_jwt_present = require_rolldown_runtime.__toESM(__sd_jwt_present);
let __sd_jwt_sd_jwt_vc = require("@sd-jwt/sd-jwt-vc");
__sd_jwt_sd_jwt_vc = require_rolldown_runtime.__toESM(__sd_jwt_sd_jwt_vc);

//#region src/modules/sd-jwt-vc/SdJwtVcService.ts
var _ref;
let SdJwtVcService = class SdJwtVcService$1 {
	constructor(sdJwtVcRepository) {
		this.sdJwtVcRepository = sdJwtVcRepository;
	}
	async sign(agentContext, options) {
		const { payload, disclosureFrame, hashingAlgorithm } = options;
		if (hashingAlgorithm && hashingAlgorithm !== "sha-256") throw new require_SdJwtVcError.SdJwtVcError(`Unsupported hashing algorithm used: ${hashingAlgorithm}`);
		const issuer = await this.extractKeyFromIssuer(agentContext, options.issuer, true);
		const holderBinding = options.holder ? await require_utils.extractKeyFromHolderBinding(agentContext, options.holder) : void 0;
		const header = {
			alg: issuer.alg,
			typ: options.headerType ?? "dc+sd-jwt",
			kid: issuer.kid,
			x5c: issuer.x5c?.map((cert) => cert.toString("base64"))
		};
		const sdjwt = new __sd_jwt_sd_jwt_vc.SDJwtVcInstance({
			...this.getBaseSdJwtConfig(agentContext),
			signer: require_utils.getSdJwtSigner(agentContext, issuer.publicJwk),
			hashAlg: "sha-256",
			signAlg: issuer.alg
		});
		if (!payload.vct || typeof payload.vct !== "string") throw new require_SdJwtVcError.SdJwtVcError("Missing required parameter 'vct'");
		const compact = await sdjwt.issue({
			...payload,
			cnf: holderBinding?.cnf,
			iss: issuer.iss,
			iat: require_timestamp.nowInSeconds(),
			vct: payload.vct
		}, disclosureFrame, { header });
		const prettyClaims = await sdjwt.getClaims(compact);
		const sdjwtPayload = (await sdjwt.decode(compact)).jwt?.payload;
		if (!sdjwtPayload) throw new require_SdJwtVcError.SdJwtVcError("Invalid sd-jwt-vc state.");
		return {
			compact,
			prettyClaims,
			header,
			payload: sdjwtPayload,
			claimFormat: require_ClaimFormat.ClaimFormat.SdJwtDc,
			encoded: compact
		};
	}
	fromCompact(compactSdJwtVc, typeMetadata) {
		return require_decodeSdJwtVc.decodeSdJwtVc(compactSdJwtVc, typeMetadata);
	}
	applyDisclosuresForPayload(compactSdJwtVc, requestedPayload) {
		const decoded = (0, __sd_jwt_decode.decodeSdJwtSync)(compactSdJwtVc, require_Hasher.Hasher.hash);
		const presentationFrame = require_disclosureFrame.buildDisclosureFrameForPayload(requestedPayload) ?? {};
		if (decoded.kbJwt) throw new require_SdJwtVcError.SdJwtVcError("Cannot apply limit disclosure on an sd-jwt with key binding jwt");
		const requiredDisclosures = (0, __sd_jwt_present.selectDisclosures)(decoded.jwt.payload, decoded.disclosures.map((d) => ({
			digest: d.digestSync({
				alg: "sha-256",
				hasher: require_Hasher.Hasher.hash
			}),
			encoded: d.encode(),
			key: d.key,
			salt: d.salt,
			value: d.value
		})), presentationFrame);
		const [jwt] = compactSdJwtVc.split("~");
		return require_decodeSdJwtVc.decodeSdJwtVc(`${jwt}~${requiredDisclosures.length > 0 ? `${requiredDisclosures.map((d) => d.encoded).join("~")}~` : ""}`);
	}
	async present(agentContext, { compactSdJwtVc, presentationFrame, verifierMetadata, additionalPayload }) {
		const sdjwt = new __sd_jwt_sd_jwt_vc.SDJwtVcInstance(this.getBaseSdJwtConfig(agentContext));
		const holderBinding = require_utils.parseHolderBindingFromCredential((await sdjwt.decode(compactSdJwtVc)).jwt?.payload);
		if (!holderBinding && verifierMetadata) throw new require_SdJwtVcError.SdJwtVcError("Verifier metadata provided, but credential has no 'cnf' claim to create a KB-JWT from");
		const holder = holderBinding ? await require_utils.extractKeyFromHolderBinding(agentContext, holderBinding, true) : void 0;
		sdjwt.config({
			kbSigner: holder ? require_utils.getSdJwtSigner(agentContext, holder.publicJwk) : void 0,
			kbSignAlg: holder?.alg
		});
		return await sdjwt.present(compactSdJwtVc, presentationFrame, { kb: verifierMetadata ? { payload: {
			iat: verifierMetadata.issuedAt,
			nonce: verifierMetadata.nonce,
			aud: verifierMetadata.audience,
			...additionalPayload
		} } : void 0 });
	}
	assertValidX5cJwtIssuer(agentContext, iss, leafCertificate) {
		if (!iss.startsWith("https://") && !(iss.startsWith("http://") && agentContext.config.allowInsecureHttpUrls)) throw new require_SdJwtVcError.SdJwtVcError("The X509 certificate issuer must be a HTTPS URI.");
		if (!leafCertificate.sanUriNames?.includes(iss) && !leafCertificate.sanDnsNames?.includes(require_domain.getDomainFromUrl(iss))) throw new require_SdJwtVcError.SdJwtVcError(`The 'iss' claim in the payload does not match a 'SAN-URI' name and the domain extracted from the HTTPS URI does not match a 'SAN-DNS' name in the x5c certificate.`);
	}
	async verify(agentContext, { compactSdJwtVc, keyBinding, requiredClaimKeys, fetchTypeMetadata, trustedCertificates }) {
		const sdjwt = new __sd_jwt_sd_jwt_vc.SDJwtVcInstance({ ...this.getBaseSdJwtConfig(agentContext) });
		const verificationResult = { isValid: false };
		let sdJwtVc;
		let _error = void 0;
		try {
			sdJwtVc = await sdjwt.decode(compactSdJwtVc);
			if (!sdJwtVc.jwt) throw new require_CredoError.CredoError("Invalid sd-jwt-vc");
		} catch (error) {
			return {
				isValid: false,
				verification: verificationResult,
				error
			};
		}
		const returnSdJwtVc = {
			payload: sdJwtVc.jwt.payload,
			header: sdJwtVc.jwt.header,
			compact: compactSdJwtVc,
			prettyClaims: await sdJwtVc.getClaims(require_decodeSdJwtVc.sdJwtVcHasher),
			kbJwt: sdJwtVc.kbJwt ? {
				payload: sdJwtVc.kbJwt.payload,
				header: sdJwtVc.kbJwt.header
			} : void 0,
			claimFormat: require_ClaimFormat.ClaimFormat.SdJwtDc,
			encoded: compactSdJwtVc
		};
		try {
			const credentialIssuer = await this.parseIssuerFromCredential(agentContext, sdJwtVc, returnSdJwtVc, trustedCertificates);
			const issuer = await this.extractKeyFromIssuer(agentContext, credentialIssuer);
			const holderBinding = require_utils.parseHolderBindingFromCredential(sdJwtVc.jwt.payload);
			const holder = holderBinding ? await require_utils.extractKeyFromHolderBinding(agentContext, holderBinding) : void 0;
			sdjwt.config({
				verifier: require_utils.getSdJwtVerifier(agentContext, issuer.publicJwk),
				kbVerifier: holder ? require_utils.getSdJwtVerifier(agentContext, holder.publicJwk) : void 0
			});
			const requiredKeys = requiredClaimKeys ? [...requiredClaimKeys, "vct"] : ["vct"];
			try {
				await sdjwt.verify(compactSdJwtVc, requiredKeys, keyBinding !== void 0);
				verificationResult.isSignatureValid = true;
				verificationResult.areRequiredClaimsIncluded = true;
				verificationResult.isStatusValid = true;
			} catch (error) {
				_error = error;
				verificationResult.isSignatureValid = false;
				verificationResult.areRequiredClaimsIncluded = false;
				verificationResult.isStatusValid = false;
			}
			if (sdJwtVc.jwt.header?.typ !== "vc+sd-jwt" && sdJwtVc.jwt.header?.typ !== "dc+sd-jwt") {
				verificationResult.areRequiredClaimsIncluded = false;
				_error = new require_SdJwtVcError.SdJwtVcError(`SD-JWT VC header 'typ' must be 'dc+sd-jwt' or 'vc+sd-jwt'`);
			}
			try {
				require_JwtPayload.JwtPayload.fromJson(returnSdJwtVc.payload).validate();
				verificationResult.isValidJwtPayload = true;
			} catch (error) {
				_error = error;
				verificationResult.isValidJwtPayload = false;
			}
			try {
				if (keyBinding) {
					if (!sdJwtVc.kbJwt || !sdJwtVc.kbJwt.payload) throw new require_SdJwtVcError.SdJwtVcError("Keybinding is required for verification of the sd-jwt-vc");
					if (sdJwtVc.kbJwt.payload.aud !== keyBinding.audience) throw new require_SdJwtVcError.SdJwtVcError("The key binding JWT does not contain the expected audience");
					if (sdJwtVc.kbJwt.payload.nonce !== keyBinding.nonce) throw new require_SdJwtVcError.SdJwtVcError("The key binding JWT does not contain the expected nonce");
					verificationResult.isKeyBindingValid = true;
					verificationResult.containsExpectedKeyBinding = true;
					verificationResult.containsRequiredVcProperties = true;
				}
			} catch (error) {
				_error = error;
				verificationResult.isKeyBindingValid = false;
				verificationResult.containsExpectedKeyBinding = false;
				verificationResult.containsRequiredVcProperties = false;
			}
			try {
				const vct = returnSdJwtVc.payload?.vct;
				if (fetchTypeMetadata && typeof vct === "string" && vct.startsWith("https://")) {
					const vctElements = vct.split("/");
					vctElements.splice(3, 0, ".well-known/vct");
					const vctUrl = vctElements.join("/");
					const response = await agentContext.config.agentDependencies.fetch(vctUrl);
					if (response.ok) returnSdJwtVc.typeMetadata = await response.json();
				}
			} catch (_error$1) {}
		} catch (error) {
			verificationResult.isValid = false;
			return {
				isValid: false,
				error,
				verification: verificationResult,
				sdJwtVc: returnSdJwtVc
			};
		}
		const { isValid: _,...allVerifications } = verificationResult;
		verificationResult.isValid = Object.values(allVerifications).every((verification) => verification === true);
		if (_error) return {
			isValid: false,
			error: _error,
			sdJwtVc: returnSdJwtVc,
			verification: verificationResult
		};
		return {
			isValid: true,
			verification: verificationResult,
			sdJwtVc: returnSdJwtVc
		};
	}
	async store(agentContext, compactSdJwtVc) {
		const sdJwtVcRecord = new require_SdJwtVcRecord.SdJwtVcRecord({ compactSdJwtVc });
		await this.sdJwtVcRepository.save(agentContext, sdJwtVcRecord);
		return sdJwtVcRecord;
	}
	async getById(agentContext, id) {
		return await this.sdJwtVcRepository.getById(agentContext, id);
	}
	async getAll(agentContext) {
		return await this.sdJwtVcRepository.getAll(agentContext);
	}
	async findByQuery(agentContext, query, queryOptions) {
		return await this.sdJwtVcRepository.findByQuery(agentContext, query, queryOptions);
	}
	async deleteById(agentContext, id) {
		await this.sdJwtVcRepository.deleteById(agentContext, id);
	}
	async update(agentContext, sdJwtVcRecord) {
		await this.sdJwtVcRepository.update(agentContext, sdJwtVcRecord);
	}
	async extractKeyFromIssuer(agentContext, issuer, forSigning = false) {
		if (issuer.method === "did") {
			const parsedDid = require_parse.parseDid(issuer.didUrl);
			if (!parsedDid.fragment) throw new require_SdJwtVcError.SdJwtVcError(`didUrl '${issuer.didUrl}' does not contain a '#'. Unable to derive key from did document`);
			let publicJwk;
			if (forSigning) publicJwk = await require_utils.resolveSigningPublicJwkFromDidUrl(agentContext, issuer.didUrl);
			else {
				const { verificationMethod } = await require_utils.resolveDidUrl(agentContext, issuer.didUrl);
				publicJwk = require_keyDidMapping.getPublicJwkFromVerificationMethod(verificationMethod);
			}
			const supportedSignatureAlgorithms = publicJwk.supportedSignatureAlgorithms;
			if (supportedSignatureAlgorithms.length === 0) throw new require_SdJwtVcError.SdJwtVcError(`No supported JWA signature algorithms found for key ${publicJwk.jwkTypehumanDescription}`);
			return {
				alg: supportedSignatureAlgorithms[0],
				publicJwk,
				iss: parsedDid.did,
				kid: `#${parsedDid.fragment}`
			};
		}
		if (issuer.method === "x5c") {
			const leafCertificate = issuer.x5c[0];
			if (!leafCertificate) throw new require_SdJwtVcError.SdJwtVcError("Empty 'x5c' array provided");
			if (forSigning && !leafCertificate.publicJwk.hasKeyId) throw new require_SdJwtVcError.SdJwtVcError("Expected leaf certificate in 'x5c' array to have a key id configured.");
			const publicJwk = leafCertificate.publicJwk;
			const supportedSignatureAlgorithms = publicJwk.supportedSignatureAlgorithms;
			if (supportedSignatureAlgorithms.length === 0) throw new require_SdJwtVcError.SdJwtVcError(`No supported JWA signature algorithms found for key ${publicJwk.jwkTypehumanDescription}`);
			const alg = supportedSignatureAlgorithms[0];
			this.assertValidX5cJwtIssuer(agentContext, issuer.issuer, leafCertificate);
			return {
				publicJwk,
				iss: issuer.issuer,
				x5c: issuer.x5c,
				alg
			};
		}
		throw new require_SdJwtVcError.SdJwtVcError("Unsupported credential issuer. Only 'did' and 'x5c' is supported at the moment.");
	}
	async parseIssuerFromCredential(agentContext, sdJwtVc, credoSdJwtVc, _trustedCertificates) {
		const x509Config = agentContext.dependencyManager.resolve(require_X509ModuleConfig.X509ModuleConfig);
		if (!sdJwtVc.jwt?.payload) throw new require_SdJwtVcError.SdJwtVcError("Credential not exist");
		if (!sdJwtVc.jwt?.payload.iss) throw new require_SdJwtVcError.SdJwtVcError("Credential does not contain an issuer");
		const iss = sdJwtVc.jwt.payload.iss;
		if (sdJwtVc.jwt.header?.x5c) {
			if (!Array.isArray(sdJwtVc.jwt.header.x5c)) throw new require_SdJwtVcError.SdJwtVcError("Invalid x5c header in credential. Not an array.");
			if (sdJwtVc.jwt.header.x5c.length === 0) throw new require_SdJwtVcError.SdJwtVcError("Invalid x5c header in credential. Empty array.");
			if (sdJwtVc.jwt.header.x5c.some((x5c) => typeof x5c !== "string")) throw new require_SdJwtVcError.SdJwtVcError("Invalid x5c header in credential. Not an array of strings.");
			let trustedCertificates = _trustedCertificates;
			const certificateChain = sdJwtVc.jwt.header.x5c.map((cert) => require_X509Certificate.X509Certificate.fromEncodedCertificate(cert));
			if (!trustedCertificates) trustedCertificates = await x509Config.getTrustedCertificatesForVerification?.(agentContext, {
				certificateChain,
				verification: {
					type: "credential",
					credential: credoSdJwtVc
				}
			}) ?? x509Config.trustedCertificates;
			if (!trustedCertificates) throw new require_SdJwtVcError.SdJwtVcError("No trusted certificates configured for X509 certificate chain validation. Issuer cannot be verified.");
			await require_X509Service.X509Service.validateCertificateChain(agentContext, {
				certificateChain: sdJwtVc.jwt.header.x5c,
				trustedCertificates
			});
			return {
				method: "x5c",
				x5c: certificateChain,
				issuer: iss
			};
		}
		if (iss.startsWith("did:")) {
			if (!sdJwtVc.jwt?.header) throw new require_SdJwtVcError.SdJwtVcError("Credential does not contain a header");
			if (!sdJwtVc.jwt.header.kid) throw new require_SdJwtVcError.SdJwtVcError("Credential does not contain a kid in the header");
			const issuerKid = sdJwtVc.jwt.header.kid;
			let didUrl;
			if (issuerKid.startsWith("#")) didUrl = `${iss}${issuerKid}`;
			else if (issuerKid.startsWith("did:")) {
				const didFromKid = require_parse.parseDid(issuerKid);
				if (didFromKid.did !== iss) throw new require_SdJwtVcError.SdJwtVcError(`kid in header is an absolute DID URL, but the did (${didFromKid.did}) does not match with the 'iss' did (${iss})`);
				didUrl = issuerKid;
			} else throw new require_SdJwtVcError.SdJwtVcError("Invalid issuer kid for did. Only absolute or relative (starting with #) did urls are supported.");
			return {
				method: "did",
				didUrl
			};
		}
		throw new require_SdJwtVcError.SdJwtVcError("Unsupported 'iss' value. Only did is supported at the moment.");
	}
	getBaseSdJwtConfig(agentContext) {
		const kms = agentContext.resolve(require_KeyManagementApi.KeyManagementApi);
		return {
			hasher: require_decodeSdJwtVc.sdJwtVcHasher,
			statusListFetcher: this.getStatusListFetcher(agentContext),
			saltGenerator: (length) => require_TypedArrayEncoder.TypedArrayEncoder.toBase64URL(kms.randomBytes({ length })).slice(0, length)
		};
	}
	getStatusListFetcher(agentContext) {
		return async (uri) => {
			const response = await require_fetch.fetchWithTimeout(agentContext.config.agentDependencies.fetch, uri, { headers: { Accept: "application/statuslist+jwt" } });
			if (!response.ok) throw new require_CredoError.CredoError(`Received invalid response with status ${response.status} when fetching status list from ${uri}. ${await response.text()}`);
			return await response.text();
		};
	}
};
SdJwtVcService = require_decorate.__decorate([(0, tsyringe.injectable)(), require_decorateMetadata.__decorateMetadata("design:paramtypes", [typeof (_ref = typeof require_SdJwtVcRepository.SdJwtVcRepository !== "undefined" && require_SdJwtVcRepository.SdJwtVcRepository) === "function" ? _ref : Object])], SdJwtVcService);

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