"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.decryptAndVerifyMessage = exports.getDecryptedPrivateKey = exports.getEip712Signature = exports.getEip191Signature = exports.getEncryptedRequestCore = exports.getEncryptedRequest = exports.decryptFeeds = exports.signMessageWithPGPCore = exports.signMessageWithPGP = exports.encryptAndSignCore = exports.encryptAndSign = void 0;
const tslib_1 = require("tslib");
const PGP = require("./pgp");
const AES = require("./aes");
const CryptoJS = require("crypto-js");
const user_1 = require("../../user");
const helpers_1 = require("../../helpers");
const user_2 = require("../../user");
const service_1 = require("./service");
const constants_1 = require("../../constants");
const signature_1 = require("./signature");
const pgp_1 = require("./pgp");
const aes_1 = require("./aes");
const getEncryptedSecret_1 = require("./getEncryptedSecret");
const getGroup_1 = require("../getGroup");
const SIG_TYPE_V2 = 'eip712v2';
const encryptAndSign = ({ plainText, keys, privateKeyArmored, secretKey, }) => tslib_1.__awaiter(void 0, void 0, void 0, function* () {
    return yield (0, exports.encryptAndSignCore)({
        plainText,
        keys,
        privateKeyArmored,
        secretKey,
        pgpHelper: PGP.PGPHelper,
    });
});
exports.encryptAndSign = encryptAndSign;
const encryptAndSignCore = ({ plainText, keys, privateKeyArmored, secretKey, pgpHelper, }) => tslib_1.__awaiter(void 0, void 0, void 0, function* () {
    const cipherText = AES.aesEncrypt({ plainText, secretKey });
    const encryptedSecret = yield pgpHelper.pgpEncrypt({
        plainText: secretKey,
        keys: keys,
    });
    const signature = yield pgpHelper.sign({
        message: cipherText,
        signingKey: privateKeyArmored,
    });
    return {
        cipherText,
        encryptedSecret,
        signature,
        sigType: 'pgp',
        encType: 'pgp',
    };
});
exports.encryptAndSignCore = encryptAndSignCore;
const signMessageWithPGP = ({ message, privateKeyArmored, }) => tslib_1.__awaiter(void 0, void 0, void 0, function* () {
    return yield (0, exports.signMessageWithPGPCore)({
        message,
        privateKeyArmored,
        pgpHelper: PGP.PGPHelper,
    });
});
exports.signMessageWithPGP = signMessageWithPGP;
const signMessageWithPGPCore = ({ message, privateKeyArmored, pgpHelper, }) => tslib_1.__awaiter(void 0, void 0, void 0, function* () {
    const signature = yield pgpHelper.sign({
        message: message,
        signingKey: privateKeyArmored,
    });
    return {
        signature,
        sigType: 'pgp',
    };
});
exports.signMessageWithPGPCore = signMessageWithPGPCore;
const decryptFeeds = ({ feeds, connectedUser, pgpPrivateKey, env = constants_1.default.ENV.PROD, }) => tslib_1.__awaiter(void 0, void 0, void 0, function* () {
    let otherPeer;
    let signatureValidationPubliKey; // To do signature verification it depends on who has sent the message
    for (const feed of feeds) {
        let gotOtherPeer = false;
        if (feed.msg.encType !== 'PlainText') {
            if (!pgpPrivateKey) {
                throw Error('Decrypted private key is necessary');
            }
            if (feed.msg.fromCAIP10 !== connectedUser.wallets.split(',')[0]) {
                if (!gotOtherPeer) {
                    otherPeer = yield (0, user_2.get)({ account: feed.msg.fromCAIP10, env });
                    gotOtherPeer = true;
                }
                signatureValidationPubliKey = otherPeer.publicKey;
            }
            else {
                signatureValidationPubliKey = connectedUser.publicKey;
            }
            feed.msg = yield (0, exports.decryptAndVerifyMessage)(feed.msg, signatureValidationPubliKey, pgpPrivateKey, env);
        }
    }
    return feeds;
});
exports.decryptFeeds = decryptFeeds;
const getEncryptedRequest = (receiverAddress, senderCreatedUser, message, isGroup, env, group, secretKey) => tslib_1.__awaiter(void 0, void 0, void 0, function* () {
    return yield (0, exports.getEncryptedRequestCore)(receiverAddress, senderCreatedUser, message, isGroup, env, group, secretKey, PGP.PGPHelper);
});
exports.getEncryptedRequest = getEncryptedRequest;
const getEncryptedRequestCore = (receiverAddress, senderCreatedUser, message, isGroup, env, group, secretKey, pgpHelper) => tslib_1.__awaiter(void 0, void 0, void 0, function* () {
    if (!isGroup) {
        const receiverCreatedUser = yield (0, user_1.get)({
            account: receiverAddress,
            env,
        });
        if (!(receiverCreatedUser === null || receiverCreatedUser === void 0 ? void 0 : receiverCreatedUser.publicKey)) {
            if (!(0, helpers_1.isValidETHAddress)(receiverAddress)) {
                throw new Error(`Invalid receiver address!`);
            }
            yield (0, service_1.createUserService)({
                user: receiverAddress,
                publicKey: '',
                encryptedPrivateKey: '',
                env,
            });
            // If the user is being created here, that means that user don't have a PGP keys. So this intent will be in plaintext
            const { signature } = yield (0, exports.signMessageWithPGPCore)({
                message: message,
                privateKeyArmored: senderCreatedUser.privateKey,
                pgpHelper: pgpHelper,
            });
            return {
                message: message,
                encryptionType: 'PlainText',
                aesEncryptedSecret: '',
                signature: signature,
            };
        }
        else {
            // It's possible for a user to be created but the PGP keys still not created
            if (!receiverCreatedUser.publicKey.includes('-----BEGIN PGP PUBLIC KEY BLOCK-----')) {
                const { signature } = yield (0, exports.signMessageWithPGPCore)({
                    message: message,
                    privateKeyArmored: senderCreatedUser.privateKey,
                    pgpHelper: pgpHelper,
                });
                return {
                    message: message,
                    encryptionType: 'PlainText',
                    aesEncryptedSecret: '',
                    signature: signature,
                };
            }
            else {
                const { cipherText, encryptedSecret, signature } = yield (0, exports.encryptAndSignCore)({
                    plainText: message,
                    keys: [receiverCreatedUser.publicKey, senderCreatedUser.publicKey],
                    privateKeyArmored: senderCreatedUser.privateKey,
                    secretKey,
                    pgpHelper: pgpHelper,
                });
                return {
                    message: cipherText,
                    encryptionType: 'pgp',
                    aesEncryptedSecret: encryptedSecret,
                    signature: signature,
                };
            }
        }
    }
    else if (group) {
        if (group.isPublic) {
            const { signature } = yield (0, exports.signMessageWithPGPCore)({
                message: message,
                privateKeyArmored: senderCreatedUser.privateKey,
                pgpHelper: pgpHelper,
            });
            return {
                message: message,
                encryptionType: 'PlainText',
                aesEncryptedSecret: '',
                signature: signature,
            };
        }
        else {
            // Private Groups
            // 1. Private Groups with session keys
            if (group.sessionKey && group.encryptedSecret) {
                const cipherText = AES.aesEncrypt({
                    plainText: message,
                    secretKey,
                });
                const signature = yield pgpHelper.sign({
                    message: cipherText,
                    signingKey: senderCreatedUser.privateKey,
                });
                return {
                    message: cipherText,
                    encryptionType: 'pgpv1:group',
                    aesEncryptedSecret: null,
                    signature: signature,
                };
            }
            else {
                // do a getGroupCall to get keys of all members
                const groupWithMembers = yield (0, getGroup_1.getGroup)({
                    chatId: group.chatId,
                    env: env,
                });
                const publicKeys = groupWithMembers.members.map((member) => member.publicKey);
                const { cipherText, encryptedSecret, signature } = yield (0, exports.encryptAndSignCore)({
                    plainText: message,
                    keys: publicKeys,
                    privateKeyArmored: senderCreatedUser.privateKey,
                    secretKey,
                    pgpHelper: pgpHelper,
                });
                return {
                    message: cipherText,
                    encryptionType: 'pgp',
                    aesEncryptedSecret: encryptedSecret,
                    signature: signature,
                };
            }
        }
    }
    else {
        throw new Error('Unable to find Group Data');
    }
});
exports.getEncryptedRequestCore = getEncryptedRequestCore;
const getEip191Signature = (wallet, message, version = 'v1') => tslib_1.__awaiter(void 0, void 0, void 0, function* () {
    if (!(wallet === null || wallet === void 0 ? void 0 : wallet.signer)) {
        console.warn('This method is deprecated. Provide signer in the function');
        // sending random signature for making it backward compatible
        return { signature: 'xyz', sigType: 'a' };
    }
    const _signer = wallet === null || wallet === void 0 ? void 0 : wallet.signer;
    // EIP191 signature
    const pushSigner = new helpers_1.Signer(_signer);
    const signature = yield pushSigner.signMessage(message);
    const sigType = version === 'v1' ? 'eip191' : 'eip191v2';
    return { verificationProof: `${sigType}:${signature}` };
});
exports.getEip191Signature = getEip191Signature;
const getEip712Signature = (wallet, hash, isDomainEmpty) => tslib_1.__awaiter(void 0, void 0, void 0, function* () {
    if (!(wallet === null || wallet === void 0 ? void 0 : wallet.signer)) {
        console.warn('This method is deprecated. Provide signer in the function');
        // sending random signature for making it backward compatible
        return { signature: 'xyz', sigType: 'a' };
    }
    const typeInformation = (0, signature_1.getTypeInformation)();
    const _signer = wallet === null || wallet === void 0 ? void 0 : wallet.signer;
    const pushSigner = new helpers_1.Signer(_signer);
    let chainId;
    try {
        chainId = yield pushSigner.getChainId();
    }
    catch (err) {
        chainId = 1;
    }
    const domain = (0, signature_1.getDomainInformation)(chainId);
    // sign a message using EIP712
    const signedMessage = yield pushSigner.signTypedData(isDomainEmpty ? {} : domain, typeInformation, { data: hash }, 'Data');
    const verificationProof = isDomainEmpty
        ? `${SIG_TYPE_V2}:${signedMessage}`
        : `${SIG_TYPE_V2}:${chainId}:${signedMessage}`;
    return { verificationProof };
});
exports.getEip712Signature = getEip712Signature;
function getDecryptedPrivateKey(wallet, user, address) {
    return tslib_1.__awaiter(this, void 0, void 0, function* () {
        let decryptedPrivateKey;
        if (wallet.signer) {
            decryptedPrivateKey = yield (0, helpers_1.decryptPGPKey)({
                signer: wallet.signer,
                encryptedPGPPrivateKey: user.encryptedPrivateKey,
            });
        }
        else {
            decryptedPrivateKey = yield (0, helpers_1.decryptWithWalletRPCMethod)(user.encryptedPrivateKey, address);
        }
        return decryptedPrivateKey;
    });
}
exports.getDecryptedPrivateKey = getDecryptedPrivateKey;
/**
 * Decrypts and verifies a Push Chat Message
 * @param message encrypted chat message
 * @param pgpPublicKey pgp public key of signer of message - used for verification
 * @param pgpPrivateKey pgp private key of receiver - used for decryption
 */
const decryptAndVerifyMessage = (message, pgpPublicKey, pgpPrivateKey, env) => tslib_1.__awaiter(void 0, void 0, void 0, function* () {
    /**
     * VERIFICATION
     * If verification proof is present then check that else check messageContent Signature
     */
    if (message.verificationProof &&
        message.verificationProof.split(':')[0] === 'pgpv2') {
        const bodyToBeHashed = {
            fromDID: message.fromDID,
            toDID: message.fromDID,
            fromCAIP10: message.fromCAIP10,
            toCAIP10: message.toCAIP10,
            messageObj: message.messageObj,
            messageType: message.messageType,
            encType: message.encType,
            encryptedSecret: message.encryptedSecret,
        };
        const hash = CryptoJS.SHA256(JSON.stringify(bodyToBeHashed)).toString();
        const signature = message.verificationProof.split(':')[1];
        yield (0, pgp_1.verifySignature)({
            messageContent: hash,
            signatureArmored: signature,
            publicKeyArmored: pgpPublicKey,
        });
    }
    else if (message.verificationProof &&
        message.verificationProof.split(':')[0] === 'pgpv3') {
        const bodyToBeHashed = {
            fromDID: message.fromDID,
            toDID: message.fromDID,
            fromCAIP10: message.fromCAIP10,
            toCAIP10: message.toCAIP10,
            messageObj: message.messageObj,
            messageType: message.messageType,
            encType: message.encType,
            sessionKey: message.sessionKey,
            encryptedSecret: message.encryptedSecret,
        };
        const hash = CryptoJS.SHA256(JSON.stringify(bodyToBeHashed)).toString();
        const signature = message.verificationProof.split(':')[1];
        yield (0, pgp_1.verifySignature)({
            messageContent: hash,
            signatureArmored: signature,
            publicKeyArmored: pgpPublicKey,
        });
    }
    else {
        if (message.link == null) {
            const bodyToBeHashed = {
                fromDID: message.fromDID,
                toDID: message.toDID,
                messageContent: message.messageContent,
                messageType: message.messageType,
            };
            const hash = CryptoJS.SHA256(JSON.stringify(bodyToBeHashed)).toString();
            try {
                yield (0, pgp_1.verifySignature)({
                    messageContent: hash,
                    signatureArmored: message.signature,
                    publicKeyArmored: pgpPublicKey,
                });
            }
            catch (err) {
                yield (0, pgp_1.verifySignature)({
                    messageContent: message.messageContent,
                    signatureArmored: message.signature,
                    publicKeyArmored: pgpPublicKey,
                });
            }
        }
        else {
            yield (0, pgp_1.verifySignature)({
                messageContent: message.messageContent,
                signatureArmored: message.signature,
                publicKeyArmored: pgpPublicKey,
            });
        }
    }
    /**
     * DECRYPTION
     * 1. Decrypt AES Key
     * 2. Decrypt messageObj.message, messageObj.meta , messageContent
     */
    const decryptedMessage = Object.assign({}, message);
    try {
        /**
         * Get encryptedSecret from Backend using sessionKey for this encryption type
         */
        if (message.encType === 'pgpv1:group') {
            message.encryptedSecret = yield (0, getEncryptedSecret_1.getEncryptedSecret)({
                sessionKey: message.sessionKey,
                env,
            });
        }
        const secretKey = yield (0, pgp_1.pgpDecrypt)({
            cipherText: message.encryptedSecret,
            toPrivateKeyArmored: pgpPrivateKey,
        });
        decryptedMessage.messageContent = (0, aes_1.aesDecrypt)({
            cipherText: message.messageContent,
            secretKey,
        });
        if (message.messageObj) {
            decryptedMessage.messageObj = JSON.parse((0, aes_1.aesDecrypt)({
                cipherText: message.messageObj,
                secretKey,
            }));
        }
    }
    catch (err) {
        decryptedMessage.messageContent = decryptedMessage.messageObj =
            'Unable to Decrypt Message';
    }
    return decryptedMessage;
});
exports.decryptAndVerifyMessage = decryptAndVerifyMessage;
//# sourceMappingURL=crypto.js.map