

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_decorate = require('../_virtual/_@oxc-project_runtime@0.94.0/helpers/decorate.js');
const require_KeyManagementError = require('../modules/kms/error/KeyManagementError.js');
const require_TypedArrayEncoder = require('../utils/TypedArrayEncoder.js');
const require_JsonEncoder = require('../utils/JsonEncoder.js');
require('../utils/index.js');
const require_humanDescription = require('../modules/kms/jwk/humanDescription.js');
const require_equals = require('../modules/kms/jwk/equals.js');
const require_jwa = require('../modules/kms/jwk/jwa.js');
const require_knownJwk = require('../modules/kms/jwk/knownJwk.js');
const require_PublicJwk = require('../modules/kms/jwk/PublicJwk.js');
const require_KeyManagementApi = require('../modules/kms/KeyManagementApi.js');
require('../modules/kms/index.js');
const require_X509ModuleConfig = require('../modules/x509/X509ModuleConfig.js');
const require_X509Service = require('../modules/x509/X509Service.js');
require('../modules/x509/index.js');
const require_types = require('../types.js');
const require_JwsTypes = require('./JwsTypes.js');
const require_JwtPayload = require('./jose/jwt/JwtPayload.js');
require('./jose/jwt/index.js');
let tsyringe = require("tsyringe");
tsyringe = require_rolldown_runtime.__toESM(tsyringe);

//#region src/crypto/JwsService.ts
let JwsService = class JwsService$1 {
	async createJwsBase(agentContext, options) {
		const { jwk, alg, x5c } = options.protectedHeaderOptions;
		const kms = agentContext.dependencyManager.resolve(require_KeyManagementApi.KeyManagementApi);
		const key = await kms.getPublicKey({ keyId: options.keyId });
		require_knownJwk.assertJwkAsymmetric(key);
		const publicJwk = require_PublicJwk.PublicJwk.fromPublicJwk(key);
		if (x5c) {
			if (!require_equals.assymetricPublicJwkMatches(require_X509Service.X509Service.getLeafCertificate(agentContext, { certificateChain: x5c }).publicJwk.toJson(), key)) throw new require_CredoError.CredoError("Protected header x5c does not match key for signing.");
		}
		const jwkInstance = jwk instanceof require_PublicJwk.PublicJwk ? jwk : jwk ? require_PublicJwk.PublicJwk.fromUnknown(jwk) : void 0;
		if (jwkInstance && !require_equals.assymetricPublicJwkMatches(jwkInstance.toJson(), key)) throw new require_CredoError.CredoError("Protected header JWK does not match key for signing.");
		if (!publicJwk.supportedSignatureAlgorithms.includes(alg)) throw new require_CredoError.CredoError(`alg '${alg}' is not a valid JWA signature algorithm for this jwk with ${publicJwk.jwkTypehumanDescription}. Supported algorithms are ${publicJwk.supportedSignatureAlgorithms.join(", ")}`);
		const payload = options.payload instanceof require_JwtPayload.JwtPayload ? require_JsonEncoder.JsonEncoder.toBuffer(options.payload.toJson()) : options.payload;
		const base64Payload = require_TypedArrayEncoder.TypedArrayEncoder.toBase64URL(payload);
		const base64UrlProtectedHeader = require_JsonEncoder.JsonEncoder.toBase64URL(this.buildProtected(options.protectedHeaderOptions));
		const signResult = await kms.sign({
			algorithm: alg,
			data: require_TypedArrayEncoder.TypedArrayEncoder.fromString(`${base64UrlProtectedHeader}.${base64Payload}`),
			keyId: options.keyId
		});
		return {
			base64Payload,
			base64UrlProtectedHeader,
			signature: require_TypedArrayEncoder.TypedArrayEncoder.toBase64URL(signResult.signature)
		};
	}
	async createJws(agentContext, { payload, keyId, header, protectedHeaderOptions }) {
		const { base64UrlProtectedHeader, signature, base64Payload } = await this.createJwsBase(agentContext, {
			payload,
			keyId,
			protectedHeaderOptions
		});
		return {
			protected: base64UrlProtectedHeader,
			signature,
			header,
			payload: base64Payload
		};
	}
	/**
	*  @see {@link https://www.rfc-editor.org/rfc/rfc7515#section-3.1}
	* */
	async createJwsCompact(agentContext, { payload, keyId, protectedHeaderOptions }) {
		const { base64Payload, base64UrlProtectedHeader, signature } = await this.createJwsBase(agentContext, {
			payload,
			keyId,
			protectedHeaderOptions
		});
		return `${base64UrlProtectedHeader}.${base64Payload}.${signature}`;
	}
	/**
	* Verify a JWS
	*/
	async verifyJws(agentContext, { jws, resolveJwsSigner, trustedCertificates, jwsSigner: expectedJwsSigner, allowedJwsSignerMethods = [
		"did",
		"jwk",
		"x5c"
	] }) {
		let signatures = [];
		let payload;
		if (expectedJwsSigner && !allowedJwsSignerMethods.includes(expectedJwsSigner.method)) throw new require_CredoError.CredoError(`jwsSigner provided with method '${expectedJwsSigner.method}', but allowed jws signer methods are ${allowedJwsSignerMethods.join(", ")}.`);
		if (typeof jws === "string") {
			if (!require_JwsTypes.JWS_COMPACT_FORMAT_MATCHER.test(jws)) throw new require_CredoError.CredoError(`Invalid JWS compact format for value '${jws}'.`);
			const [protectedHeader, _payload, signature] = jws.split(".");
			payload = _payload;
			signatures.push({
				header: {},
				protected: protectedHeader,
				signature
			});
		} else if ("signatures" in jws) {
			signatures = jws.signatures;
			payload = jws.payload;
		} else {
			signatures.push(jws);
			payload = jws.payload;
		}
		if (signatures.length === 0) throw new require_CredoError.CredoError("Unable to verify JWS, no signatures present in JWS.");
		const jwsFlattened = {
			signatures,
			payload
		};
		const jwsSigners = [];
		for (const jws$1 of signatures) {
			const protectedJson = require_JsonEncoder.JsonEncoder.fromBase64(jws$1.protected);
			if (!require_types.isJsonObject(protectedJson)) throw new require_CredoError.CredoError("Unable to verify JWS, protected header is not a valid JSON object.");
			if (!protectedJson.alg || typeof protectedJson.alg !== "string") throw new require_CredoError.CredoError("Unable to verify JWS, protected header alg is not provided or not a string.");
			const jwsSigner = expectedJwsSigner ?? await this.jwsSignerFromJws(agentContext, {
				jws: jws$1,
				payload,
				protectedHeader: {
					...protectedJson,
					alg: protectedJson.alg
				},
				allowedJwsSignerMethods,
				resolveJwsSigner
			});
			await this.verifyJwsSigner(agentContext, {
				jwsSigner,
				trustedCertificates
			});
			if (!jwsSigner.jwk.supportedSignatureAlgorithms.includes(protectedJson.alg)) throw new require_CredoError.CredoError(`alg '${protectedJson.alg}' is not a valid JWA signature algorithm for this jwk ${require_humanDescription.getJwkHumanDescription(jwsSigner.jwk.toJson())}. Supported algorithms are ${jwsSigner.jwk.supportedSignatureAlgorithms.join(", ")}`);
			const data = require_TypedArrayEncoder.TypedArrayEncoder.fromString(`${jws$1.protected}.${payload}`);
			const signature = require_TypedArrayEncoder.TypedArrayEncoder.fromBase64(jws$1.signature);
			jwsSigners.push(jwsSigner);
			const kms = agentContext.dependencyManager.resolve(require_KeyManagementApi.KeyManagementApi);
			try {
				const { verified } = await kms.verify({
					key: { publicJwk: jwsSigner.jwk.toJson() },
					data,
					signature,
					algorithm: protectedJson.alg
				});
				if (!verified) return {
					isValid: false,
					jwsSigners: [],
					jws: jwsFlattened
				};
			} catch (error) {
				if (error instanceof require_KeyManagementError.KeyManagementError) return {
					isValid: false,
					jwsSigners: [],
					jws: jwsFlattened
				};
				throw error;
			}
		}
		return {
			isValid: true,
			jwsSigners,
			jws: jwsFlattened
		};
	}
	buildProtected(options) {
		return {
			...options,
			alg: options.alg,
			jwk: options.jwk instanceof require_PublicJwk.PublicJwk ? options.jwk.toJson() : options.jwk,
			kid: options.kid
		};
	}
	async verifyJwsSigner(agentContext, options) {
		const { jwsSigner } = options;
		if (jwsSigner.method === "x5c") {
			const trustedCertificatesFromConfig = agentContext.dependencyManager.resolve(require_X509ModuleConfig.X509ModuleConfig).trustedCertificates ?? [];
			const trustedCertificates = options.trustedCertificates ?? trustedCertificatesFromConfig;
			if (trustedCertificates.length === 0) throw new require_CredoError.CredoError(`trustedCertificates is required when the JWS protected header contains an 'x5c' property.`);
			await require_X509Service.X509Service.validateCertificateChain(agentContext, {
				certificateChain: jwsSigner.x5c,
				trustedCertificates
			});
		}
	}
	async jwsSignerFromJws(agentContext, options) {
		const { protectedHeader, resolveJwsSigner, jws, payload, allowedJwsSignerMethods } = options;
		const alg = protectedHeader.alg;
		if (!require_jwa.isKnownJwaSignatureAlgorithm(alg)) throw new require_CredoError.CredoError(`Unsupported JWA signature algorithm '${protectedHeader.alg}'`);
		if (protectedHeader.x5c && allowedJwsSignerMethods.includes("x5c")) {
			if (!Array.isArray(protectedHeader.x5c) || protectedHeader.x5c.some((certificate) => typeof certificate !== "string")) throw new require_CredoError.CredoError("x5c header is not a valid JSON array of strings.");
			return {
				method: "x5c",
				jwk: require_X509Service.X509Service.getLeafCertificate(agentContext, { certificateChain: protectedHeader.x5c }).publicJwk,
				x5c: protectedHeader.x5c
			};
		}
		if (protectedHeader.jwk && allowedJwsSignerMethods.includes("jwk")) {
			if (!require_types.isJsonObject(protectedHeader.jwk)) throw new require_CredoError.CredoError("JWK is not a valid JSON object.");
			return {
				method: "jwk",
				jwk: require_PublicJwk.PublicJwk.fromUnknown(protectedHeader.jwk)
			};
		}
		if (!resolveJwsSigner) throw new require_CredoError.CredoError(`resolveJwsSigner is required for resolving jws signers other than 'jwk' and 'x5c'.`);
		try {
			const jwsSigner = await resolveJwsSigner({
				jws,
				protectedHeader: {
					...protectedHeader,
					alg
				},
				payload
			});
			if (!allowedJwsSignerMethods.includes(jwsSigner.method)) throw new require_CredoError.CredoError(`resolveJwsSigner returned jws signer with method '${jwsSigner.method}', but allowed jws signer methods are ${allowedJwsSignerMethods.join(", ")}.`);
			return jwsSigner;
		} catch (error) {
			throw new require_CredoError.CredoError(`Error when resolving jws signer for jws in resolveJwsSigner. ${error.message}`, { cause: error });
		}
	}
};
JwsService = require_decorate.__decorate([(0, tsyringe.injectable)()], JwsService);

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