"use strict";
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 __metadata = (this && this.__metadata) || function (k, v) {
    if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.DynamicCredentialResolverService = void 0;
const backend_common_1 = require("@n8n/backend-common");
const db_1 = require("@n8n/db");
const decorators_1 = require("@n8n/decorators");
const di_1 = require("@n8n/di");
const n8n_core_1 = require("n8n-core");
const n8n_workflow_1 = require("n8n-workflow");
const active_workflow_manager_1 = require("../../../active-workflow-manager");
const credential_resolver_registry_service_1 = require("./credential-resolver-registry.service");
const resolver_config_expression_service_1 = require("./resolver-config-expression.service");
const credential_resolver_repository_1 = require("../database/repositories/credential-resolver.repository");
const credential_resolver_not_found_error_1 = require("../errors/credential-resolver-not-found.error");
let DynamicCredentialResolverService = class DynamicCredentialResolverService {
    constructor(logger, repository, registry, cipher, expressionService, workflowRepository, activeWorkflowManager) {
        this.logger = logger;
        this.repository = repository;
        this.registry = registry;
        this.cipher = cipher;
        this.expressionService = expressionService;
        this.workflowRepository = workflowRepository;
        this.activeWorkflowManager = activeWorkflowManager;
        this.logger = this.logger.scoped('dynamic-credentials');
    }
    async create(params) {
        await this.validateConfig(params.type, params.config);
        const encryptedConfig = this.encryptConfig(params.config);
        const resolver = this.repository.create({
            name: params.name,
            type: params.type,
            config: encryptedConfig,
        });
        const saved = await this.repository.save(resolver);
        this.logger.debug(`Created credential resolver "${saved.name}" (${saved.id})`);
        return this.withDecryptedConfig(saved);
    }
    async findAll() {
        const resolvers = await this.repository.find();
        return resolvers.map((resolver) => this.withDecryptedConfig(resolver));
    }
    getAvailableTypes() {
        return this.registry.getAllResolvers();
    }
    async findById(id) {
        const resolver = await this.repository.findOneBy({ id });
        if (!resolver) {
            throw new credential_resolver_not_found_error_1.DynamicCredentialResolverNotFoundError(id);
        }
        return this.withDecryptedConfig(resolver);
    }
    async update(id, params) {
        const existing = await this.repository.findOneBy({ id });
        if (!existing) {
            throw new credential_resolver_not_found_error_1.DynamicCredentialResolverNotFoundError(id);
        }
        if (params.type !== undefined) {
            existing.type = params.type;
            if (params.config === undefined) {
                const existingConfig = this.decryptConfig(existing.config);
                await this.validateConfig(existing.type, existingConfig);
            }
        }
        if (params.config !== undefined) {
            await this.validateConfig(existing.type, params.config);
            existing.config = this.encryptConfig(params.config);
        }
        if (params.name !== undefined) {
            existing.name = params.name;
        }
        if (params.clearCredentials === true) {
            const resolver = this.registry.getResolverByTypename(existing.type);
            if (!resolver) {
                throw new decorators_1.CredentialResolverValidationError(`Unknown resolver type: ${existing.type}`);
            }
            if ('deleteAllSecrets' in resolver && typeof resolver.deleteAllSecrets === 'function') {
                await resolver.deleteAllSecrets({
                    resolverId: id,
                    resolverName: resolver.metadata.name,
                    configuration: this.decryptConfig(existing.config),
                });
            }
        }
        const saved = await this.repository.save(existing);
        this.logger.debug(`Updated credential resolver "${saved.name}" (${saved.id})`);
        return this.withDecryptedConfig(saved);
    }
    async findAffectedWorkflows(id) {
        const existing = await this.repository.findOneBy({ id });
        if (!existing) {
            throw new credential_resolver_not_found_error_1.DynamicCredentialResolverNotFoundError(id);
        }
        return await this.workflowRepository.findByCredentialResolverId(id);
    }
    async delete(id) {
        const existing = await this.repository.findOneBy({ id });
        if (!existing) {
            throw new credential_resolver_not_found_error_1.DynamicCredentialResolverNotFoundError(id);
        }
        const affectedWorkflows = await this.workflowRepository.findActiveByCredentialResolverId(id);
        const { manager } = this.repository;
        await manager.transaction(async (trx) => {
            await this.workflowRepository.clearCredentialResolverId(id, trx);
            await trx.remove(existing);
        });
        this.logger.debug(`Deleted credential resolver "${existing.name}" (${id})`);
        for (const workflowId of affectedWorkflows) {
            try {
                await this.activeWorkflowManager.remove(workflowId);
                await this.activeWorkflowManager.add(workflowId, 'update');
            }
            catch (error) {
                this.logger.warn(`Failed to reactivate workflow "${workflowId}" after resolver deletion, deactivating it`, { error });
                await this.workflowRepository.update(workflowId, {
                    active: false,
                    activeVersionId: null,
                });
            }
        }
    }
    async validateConfig(type, config) {
        const resolverImplementation = this.registry.getResolverByTypename(type);
        if (!resolverImplementation) {
            throw new decorators_1.CredentialResolverValidationError(`Unknown resolver type: ${type}`);
        }
        let resolvedConfig = config;
        try {
            resolvedConfig = await this.expressionService.resolve(config);
        }
        catch (error) {
            throw new decorators_1.CredentialResolverValidationError(`Invalid expression in resolver config: ${error instanceof Error ? error.message : String(error)}`);
        }
        await resolverImplementation.validateOptions(resolvedConfig);
    }
    encryptConfig(config) {
        return this.cipher.encrypt(config);
    }
    decryptConfig(encryptedConfig) {
        const decryptedData = this.cipher.decrypt(encryptedConfig);
        try {
            return (0, n8n_workflow_1.jsonParse)(decryptedData);
        }
        catch {
            throw new n8n_workflow_1.UnexpectedError('Credential resolver config could not be decrypted. The likely reason is that a different "encryptionKey" was used to encrypt the data.');
        }
    }
    withDecryptedConfig(resolver) {
        resolver.decryptedConfig = this.decryptConfig(resolver.config);
        return resolver;
    }
};
exports.DynamicCredentialResolverService = DynamicCredentialResolverService;
exports.DynamicCredentialResolverService = DynamicCredentialResolverService = __decorate([
    (0, di_1.Service)(),
    __metadata("design:paramtypes", [backend_common_1.Logger,
        credential_resolver_repository_1.DynamicCredentialResolverRepository,
        credential_resolver_registry_service_1.DynamicCredentialResolverRegistry,
        n8n_core_1.Cipher,
        resolver_config_expression_service_1.ResolverConfigExpressionService,
        db_1.WorkflowRepository,
        active_workflow_manager_1.ActiveWorkflowManager])
], DynamicCredentialResolverService);
//# sourceMappingURL=credential-resolver.service.js.map