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 { DidCommModuleConfig } from "./DidCommModuleConfig.mjs";
import { __decorateParam } from "../../../_virtual/_@oxc-project_runtime@0.94.0/helpers/decorateParam.mjs";
import { DidCommDocumentService } from "./services/DidCommDocumentService.mjs";
import { getResolvedDidcommServiceWithSigningKeyId } from "./modules/connections/services/helpers.mjs";
import { DidCommOutOfBandRole } from "./modules/oob/domain/DidCommOutOfBandRole.mjs";
import { DidCommOutOfBandRepository } from "./modules/oob/repository/DidCommOutOfBandRepository.mjs";
import { DidCommOutOfBandRecordMetadataKeys } from "./modules/oob/repository/outOfBandRecordMetadataTypes.mjs";
import { DidCommForwardMessage } from "./modules/routing/messages/DidCommForwardMessage.mjs";
import { DidCommMediatorRoutingRepository } from "./modules/routing/repository/DidCommMediatorRoutingRepository.mjs";
import { AgentContext, CredoError, InjectionSymbols, JsonEncoder, Kms, RecordNotFoundError, TypedArrayEncoder, inject, injectable } from "@credo-ts/core";

//#region ../didcomm/src/DidCommEnvelopeService.ts
var _ref;
let DidCommEnvelopeService = class DidCommEnvelopeService$1 {
	constructor(logger, didcommDocumentService) {
		this.logger = logger;
		this.didcommDocumentService = didcommDocumentService;
	}
	async encryptDidcommV1Message(agentContext, message, recipientKeys, senderKey) {
		const kms = agentContext.dependencyManager.resolve(Kms.KeyManagementApi);
		const contentEncryptionKey = kms.randomBytes({ length: 32 });
		const recipients = [];
		for (const recipientKey of recipientKeys) {
			let encryptedSender = void 0;
			if (senderKey) {
				const { encrypted: encrypted$2 } = await kms.encrypt({
					key: { keyAgreement: {
						algorithm: "ECDH-HSALSA20",
						externalPublicJwk: recipientKey.convertTo(Kms.X25519PublicJwk).toJson()
					} },
					encryption: { algorithm: "XSALSA20-POLY1305" },
					data: TypedArrayEncoder.fromString(TypedArrayEncoder.toBase58(senderKey.publicKey.publicKey))
				});
				encryptedSender = TypedArrayEncoder.toBase64URL(encrypted$2);
			}
			const { encrypted: encrypted$1, iv: iv$1 } = await kms.encrypt({
				key: { keyAgreement: {
					algorithm: "ECDH-HSALSA20",
					externalPublicJwk: recipientKey.convertTo(Kms.X25519PublicJwk).toJson(),
					keyId: senderKey?.keyId
				} },
				data: contentEncryptionKey,
				encryption: { algorithm: "XSALSA20-POLY1305" }
			});
			recipients.push({
				encrypted_key: TypedArrayEncoder.toBase64URL(encrypted$1),
				header: {
					kid: TypedArrayEncoder.toBase58(recipientKey.publicKey.publicKey),
					iv: iv$1 ? TypedArrayEncoder.toBase64URL(iv$1) : void 0,
					sender: encryptedSender
				}
			});
		}
		const protectedString = JsonEncoder.toBase64URL({
			enc: "xchacha20poly1305_ietf",
			typ: "JWM/1.0",
			alg: senderKey ? "Authcrypt" : "Anoncrypt",
			recipients
		});
		const { encrypted, iv, tag } = await kms.encrypt({
			encryption: {
				algorithm: "C20P",
				aad: TypedArrayEncoder.fromString(protectedString)
			},
			data: JsonEncoder.toBuffer(message),
			key: { privateJwk: {
				kty: "oct",
				k: TypedArrayEncoder.toBase64URL(contentEncryptionKey)
			} }
		});
		if (!iv || !tag) throw new CredoError("Expected 'iv' and 'tag' to be defined");
		return {
			ciphertext: TypedArrayEncoder.toBase64URL(encrypted),
			iv: TypedArrayEncoder.toBase64URL(iv),
			tag: TypedArrayEncoder.toBase64URL(tag),
			protected: protectedString
		};
	}
	async decryptDidcommV1Message(agentContext, encryptedMessage) {
		const kms = agentContext.dependencyManager.resolve(Kms.KeyManagementApi);
		const protectedJson = JsonEncoder.fromBase64(encryptedMessage.protected);
		const alg = protectedJson.alg;
		if (alg !== "Anoncrypt" && alg !== "Authcrypt") throw new CredoError(`Unsupported pack algorithm: ${alg}`);
		if (protectedJson.enc !== "xchacha20poly1305_ietf") throw new CredoError(`Unsupported enc algorithm: ${protectedJson.enc}`);
		let recipientKey = null;
		let recipient = null;
		for (const _recipient of protectedJson.recipients) {
			recipientKey = await this.extractOurRecipientKeyWithKeyId(agentContext, _recipient);
			if (recipientKey) recipient = _recipient;
		}
		if (!recipientKey || !recipient) throw new CredoError("No corresponding recipient key found");
		if (alg === "Authcrypt" && (!recipient.header.sender || !recipient.header.iv)) throw new CredoError("Sender and iv header values are required for Authcrypt");
		let senderPublicJwk = void 0;
		if (recipient.header.sender) {
			const { data } = await kms.decrypt({
				key: { keyAgreement: {
					algorithm: "ECDH-HSALSA20",
					keyId: recipientKey.keyId
				} },
				decryption: { algorithm: "XSALSA20-POLY1305" },
				encrypted: TypedArrayEncoder.fromBase64(recipient.header.sender)
			});
			senderPublicJwk = Kms.PublicJwk.fromPublicKey({
				crv: "Ed25519",
				kty: "OKP",
				publicKey: TypedArrayEncoder.fromBase58(TypedArrayEncoder.toUtf8String(data))
			});
		}
		const { data: contentEncryptionKey } = await kms.decrypt({
			decryption: {
				algorithm: "XSALSA20-POLY1305",
				iv: recipient.header.iv ? TypedArrayEncoder.fromBase64(recipient.header.iv) : void 0
			},
			encrypted: TypedArrayEncoder.fromBase64(recipient.encrypted_key),
			key: { keyAgreement: {
				algorithm: "ECDH-HSALSA20",
				keyId: recipientKey.keyId,
				externalPublicJwk: senderPublicJwk?.convertTo(Kms.X25519PublicJwk).toJson()
			} }
		});
		const { data: message } = await kms.decrypt({
			decryption: {
				algorithm: "C20P",
				iv: TypedArrayEncoder.fromBase64(encryptedMessage.iv),
				tag: TypedArrayEncoder.fromBase64(encryptedMessage.tag),
				aad: TypedArrayEncoder.fromString(encryptedMessage.protected)
			},
			key: { privateJwk: {
				kty: "oct",
				k: TypedArrayEncoder.toBase64URL(contentEncryptionKey)
			} },
			encrypted: TypedArrayEncoder.fromBase64(encryptedMessage.ciphertext)
		});
		return {
			plaintextMessage: JsonEncoder.fromBuffer(message),
			senderKey: senderPublicJwk,
			recipientKey
		};
	}
	async packMessage(agentContext, payload, keys) {
		const didcommConfig = agentContext.dependencyManager.resolve(DidCommModuleConfig);
		const { routingKeys, senderKey } = keys;
		let recipientKeys = keys.recipientKeys;
		const message = payload.toJSON({ useDidSovPrefixWhereAllowed: didcommConfig.useDidSovPrefixWhereAllowed });
		this.logger.debug(`Pack outbound message ${message["@type"]}`);
		let encryptedMessage = await this.encryptDidcommV1Message(agentContext, message, recipientKeys, senderKey);
		for (const routingKey of routingKeys) {
			const forwardMessage = new DidCommForwardMessage({
				to: TypedArrayEncoder.toBase58(recipientKeys[0].publicKey.publicKey),
				message: encryptedMessage
			});
			recipientKeys = [routingKey];
			this.logger.debug("Forward message created", forwardMessage);
			const forwardJson = forwardMessage.toJSON({ useDidSovPrefixWhereAllowed: didcommConfig.useDidSovPrefixWhereAllowed });
			encryptedMessage = await this.encryptDidcommV1Message(agentContext, forwardJson, [routingKey]);
		}
		this.logger.debug(`Packed outbound message ${message["@type"]}`, { routingKeys: routingKeys.map((routingKey) => routingKey.fingerprint) });
		return encryptedMessage;
	}
	async unpackMessage(agentContext, encryptedMessage) {
		return await this.decryptDidcommV1Message(agentContext, encryptedMessage);
	}
	async extractOurRecipientKeyWithKeyId(agentContext, recipient) {
		const kms = agentContext.resolve(Kms.KeyManagementApi);
		const publicKey = Kms.PublicJwk.fromPublicKey({
			kty: "OKP",
			crv: "Ed25519",
			publicKey: TypedArrayEncoder.fromBase58(recipient.header.kid)
		});
		try {
			const { didDocument, keys } = await this.didcommDocumentService.resolveCreatedDidDocumentWithKeysByRecipientKey(agentContext, publicKey);
			const verificationMethod = didDocument.findVerificationMethodByPublicKey(publicKey);
			const kmsKeyId = keys?.find(({ didDocumentRelativeKeyId }) => verificationMethod.id.endsWith(didDocumentRelativeKeyId))?.kmsKeyId;
			agentContext.config.logger.debug(`Found did '${didDocument.id}' for recipient key '${publicKey.fingerprint}' for incoming didcomm message`);
			publicKey.keyId = kmsKeyId ?? publicKey.legacyKeyId;
			return publicKey;
		} catch (error) {
			const mediatorRoutingRepository = agentContext.dependencyManager.resolve(DidCommMediatorRoutingRepository);
			if (error instanceof RecordNotFoundError) {
				const mediatorRoutingRecord = await mediatorRoutingRepository.findSingleByQuery(agentContext, { routingKeyFingerprints: [publicKey.fingerprint] });
				if (mediatorRoutingRecord) {
					agentContext.config.logger.debug(`Found mediator routing record with id '${mediatorRoutingRecord.id}' for recipient key '${publicKey.fingerprint}' for incoming didcomm message`);
					const routingKey = mediatorRoutingRecord.routingKeysWithKeyId.find((routingKey$1) => publicKey.equals(routingKey$1));
					if (!routingKey) throw new CredoError(`Expected to find key with fingerprint '${publicKey.fingerprint}' in routing keys of mediator routing record '${mediatorRoutingRecord.id}'`);
					if (routingKey) return routingKey;
				}
				const outOfBandRecord = await agentContext.dependencyManager.resolve(DidCommOutOfBandRepository).findSingleByQuery(agentContext, { $or: [{
					role: DidCommOutOfBandRole.Sender,
					recipientKeyFingerprints: [publicKey.fingerprint]
				}, {
					role: DidCommOutOfBandRole.Receiver,
					recipientRoutingKeyFingerprint: publicKey.fingerprint
				}] });
				if (outOfBandRecord?.role === DidCommOutOfBandRole.Sender) {
					agentContext.config.logger.debug(`Found out of band record with id '${outOfBandRecord.id}' and role '${outOfBandRecord.role}' for recipient key '${publicKey.fingerprint}' for incoming didcomm message`);
					for (const service of outOfBandRecord.outOfBandInvitation.getInlineServices()) {
						const _recipientKey = getResolvedDidcommServiceWithSigningKeyId(service, outOfBandRecord.invitationInlineServiceKeys).recipientKeys.find((recipientKey) => recipientKey.equals(publicKey));
						if (_recipientKey) return _recipientKey;
					}
				} else if (outOfBandRecord?.role === DidCommOutOfBandRole.Receiver) {
					agentContext.config.logger.debug(`Found out of band record with id '${outOfBandRecord.id}' and role '${outOfBandRecord.role}' for recipient key '${publicKey.fingerprint}' for incoming didcomm message`);
					const recipieintRouting = outOfBandRecord.metadata.get(DidCommOutOfBandRecordMetadataKeys.RecipientRouting);
					if (recipieintRouting?.recipientKeyFingerprint === publicKey.fingerprint) {
						publicKey.keyId = recipieintRouting.recipientKeyId ?? publicKey.legacyKeyId;
						return publicKey;
					}
				}
				if (await kms.getPublicKey({ keyId: publicKey.legacyKeyId }).catch((error$1) => {
					if (error$1 instanceof Kms.KeyManagementKeyNotFoundError) return null;
					throw error$1;
				})) {
					agentContext.config.logger.debug(`Found public key with legacy key id '${publicKey.legacyKeyId}' for recipient key '${publicKey.fingerprint}' for incoming didcomm message`);
					publicKey.keyId = publicKey.legacyKeyId;
					return publicKey;
				}
			}
		}
		return null;
	}
};
DidCommEnvelopeService = __decorate([
	injectable(),
	__decorateParam(0, inject(InjectionSymbols.Logger)),
	__decorateMetadata("design:paramtypes", [Object, typeof (_ref = typeof DidCommDocumentService !== "undefined" && DidCommDocumentService) === "function" ? _ref : Object])
], DidCommEnvelopeService);

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