"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
    return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __importStar = (this && this.__importStar) || function (mod) {
    if (mod && mod.__esModule) return mod;
    var result = {};
    if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
    __setModuleDefault(result, mod);
    return result;
};
var __metadata = (this && this.__metadata) || function (k, v) {
    if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var __param = (this && this.__param) || function (paramIndex, decorator) {
    return function (target, key) { decorator(target, key, paramIndex); }
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.LitProtocolFacade = void 0;
const core_1 = require("@lit-protocol/core");
const uint8arrays_1 = require("@lit-protocol/uint8arrays");
const utils_1 = require("@streamr/utils");
const ethers_1 = require("ethers");
const siwe = __importStar(require("lit-siwe"));
const tsyringe_1 = require("tsyringe");
const Authentication_1 = require("../Authentication");
const Config_1 = require("../Config");
const permission_1 = require("../permission");
const LoggerFactory_1 = require("../utils/LoggerFactory");
const GroupKey_1 = require("./GroupKey");
const logger = new utils_1.Logger(module);
const chain = 'polygon';
const LIT_PROTOCOL_CONNECT_INTERVAL = 60 * 60 * 1000; // 1h
const formEvmContractConditions = (streamRegistryChainAddress, streamId) => ([
    {
        contractAddress: streamRegistryChainAddress,
        chain,
        functionName: 'hasPermission',
        functionParams: [streamId, ':userAddress', `${(0, permission_1.streamPermissionToSolidityType)(permission_1.StreamPermission.SUBSCRIBE)}`],
        functionAbi: {
            inputs: [
                {
                    name: 'streamId',
                    type: 'string'
                },
                {
                    name: 'user',
                    type: 'address'
                },
                {
                    name: 'permissionType',
                    type: 'uint8'
                }
            ],
            name: 'hasPermission',
            outputs: [
                {
                    name: 'userHasPermission',
                    type: 'bool'
                }
            ],
            stateMutability: 'view',
            type: 'function'
        },
        returnValueTest: {
            key: 'userHasPermission',
            comparator: '=',
            value: 'true',
        },
    }
]);
const signAuthMessage = async (authentication) => {
    const domain = 'dummy.com';
    const uri = 'https://dummy.com';
    const statement = 'dummy';
    const addressInChecksumCase = ethers_1.ethers.utils.getAddress(await authentication.getAddress());
    const siweMessage = new siwe.SiweMessage({
        domain,
        uri,
        statement,
        address: addressInChecksumCase,
        version: '1',
        chainId: 1
    });
    const messageToSign = siweMessage.prepareMessage();
    const signature = await authentication.createMessageSignature(Buffer.from(messageToSign));
    return {
        sig: signature,
        derivedVia: 'web3.eth.personal.sign',
        signedMessage: messageToSign,
        address: addressInChecksumCase
    };
};
/**
 * This class only operates with Polygon production network and therefore ignores contracts config.
 */
let LitProtocolFacade = class LitProtocolFacade {
    litNodeClient;
    config;
    authentication;
    logger;
    connectLitNodeClient;
    /* eslint-disable indent */
    constructor(config, authentication, loggerFactory) {
        this.config = config;
        this.authentication = authentication;
        this.logger = loggerFactory.createLogger(module);
    }
    async getLitNodeClient() {
        if (this.litNodeClient === undefined) {
            this.litNodeClient = new core_1.LitCore({
                alertWhenUnauthorized: false,
                debug: this.config.encryption.litProtocolLogging
            });
            // Add a rate limiter to avoid calling `connect` each time we want to use lit protocol as this would cause an unnecessary handshake.
            this.connectLitNodeClient = (0, utils_1.withRateLimit)(() => this.litNodeClient.connect(), LIT_PROTOCOL_CONNECT_INTERVAL);
        }
        await this.connectLitNodeClient();
        return this.litNodeClient;
    }
    async store(streamId, symmetricKey) {
        const traceId = (0, utils_1.randomString)(5);
        this.logger.debug('Storing key', { streamId, traceId });
        try {
            const authSig = await signAuthMessage(this.authentication);
            const client = await this.getLitNodeClient();
            const encryptedSymmetricKey = await client.saveEncryptionKey({
                evmContractConditions: formEvmContractConditions(this.config.contracts.streamRegistryChainAddress, streamId),
                symmetricKey,
                authSig,
                chain
            });
            if (encryptedSymmetricKey === undefined) {
                return undefined;
            }
            const groupKeyId = (0, uint8arrays_1.uint8arrayToString)(encryptedSymmetricKey, 'base16');
            this.logger.debug('Stored key', { traceId, streamId, groupKeyId });
            return new GroupKey_1.GroupKey(groupKeyId, Buffer.from(symmetricKey));
        }
        catch (err) {
            logger.warn('Failed to store key', { traceId, err, streamId });
            return undefined;
        }
    }
    async get(streamId, groupKeyId) {
        this.logger.debug('Getting key', { groupKeyId, streamId });
        try {
            const authSig = await signAuthMessage(this.authentication);
            const client = await this.getLitNodeClient();
            const symmetricKey = await client.getEncryptionKey({
                evmContractConditions: formEvmContractConditions(this.config.contracts.streamRegistryChainAddress, streamId),
                toDecrypt: groupKeyId,
                chain,
                authSig
            });
            if (symmetricKey === undefined) {
                return undefined;
            }
            this.logger.debug('Got key', { groupKeyId, streamId });
            return new GroupKey_1.GroupKey(groupKeyId, Buffer.from(symmetricKey));
        }
        catch (err) {
            logger.warn('Failed to get key', { err, streamId, groupKeyId });
            return undefined;
        }
    }
};
exports.LitProtocolFacade = LitProtocolFacade;
exports.LitProtocolFacade = LitProtocolFacade = __decorate([
    (0, tsyringe_1.scoped)(tsyringe_1.Lifecycle.ContainerScoped),
    __param(0, (0, tsyringe_1.inject)(Config_1.ConfigInjectionToken)),
    __param(1, (0, tsyringe_1.inject)(Authentication_1.AuthenticationInjectionToken)),
    __metadata("design:paramtypes", [Object, Object, LoggerFactory_1.LoggerFactory])
], LitProtocolFacade);
//# sourceMappingURL=LitProtocolFacade.js.map