"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 () {
    var ownKeys = function(o) {
        ownKeys = Object.getOwnPropertyNames || function (o) {
            var ar = [];
            for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
            return ar;
        };
        return ownKeys(o);
    };
    return function (mod) {
        if (mod && mod.__esModule) return mod;
        var result = {};
        if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
        __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 CertificateSignerService_1;
Object.defineProperty(exports, "__esModule", { value: true });
exports.CertificateSignerService = void 0;
const common_1 = require("@nestjs/common");
const ssh_key_generator_service_1 = require("./ssh-key-generator.service");
const ca_manager_service_1 = require("./ca-manager.service");
const node_fs_1 = require("node:fs");
const node_child_process_1 = require("node:child_process");
const node_util_1 = require("node:util");
const path = __importStar(require("node:path"));
const os = __importStar(require("node:os"));
const execAsync = (0, node_util_1.promisify)(node_child_process_1.exec);
/**
 * Internal service for generating ephemeral SSH certificates
 * Used only by the terminal service for WebSocket SSH connections
 * @internal
 */
let CertificateSignerService = CertificateSignerService_1 = class CertificateSignerService {
    constructor(keyGenerator, caManager) {
        this.keyGenerator = keyGenerator;
        this.caManager = caManager;
        this.logger = new common_1.Logger(CertificateSignerService_1.name);
    }
    /**
     * Generate ephemeral certificate for internal SSH connections
     * This is ONLY called internally by the terminal service
     * Never expose this via REST API as it returns private keys
     */
    async generateEphemeralCertificate(tenantId, ttlSeconds = 180) {
        this.logger.debug(`Generating ephemeral certificate for tenant ${tenantId || 'global'}, TTL: ${ttlSeconds}s`);
        // Generate ephemeral keypair (never stored, only in memory)
        const ephemeralKeyPair = await this.keyGenerator.generateKeyPair('ed25519');
        // Get CA private key for this tenant
        const caPrivateKey = await this.caManager.getCAPrivateKey(tenantId);
        // Standard principals for server access
        const principals = ['root', 'ubuntu', 'admin'];
        // Sign the ephemeral public key with tenant's CA
        const certificate = await this.signPublicKeyWithCA(ephemeralKeyPair.publicKey, caPrivateKey, principals, ttlSeconds);
        const expiresAt = new Date();
        expiresAt.setSeconds(expiresAt.getSeconds() + ttlSeconds);
        return {
            certificate,
            privateKey: ephemeralKeyPair.privateKey,
            publicKey: ephemeralKeyPair.publicKey,
            fingerprint: ephemeralKeyPair.fingerprint,
            expiresAt,
            tenantId,
        };
    }
    /**
     * Sign public key with CA (internal helper)
     */
    async signPublicKeyWithCA(publicKey, caPrivateKey, principals, validitySeconds) {
        let tempDir = null;
        try {
            tempDir = await node_fs_1.promises.mkdtemp(path.join(os.tmpdir(), 'flui-ca-'));
            const caKeyPath = path.join(tempDir, 'ca');
            const pubKeyPath = path.join(tempDir, 'ephemeral.pub');
            const certPath = path.join(tempDir, 'ephemeral-cert.pub');
            await node_fs_1.promises.writeFile(caKeyPath, caPrivateKey, { mode: 0o600 });
            await node_fs_1.promises.writeFile(pubKeyPath, publicKey);
            const principalsStr = principals.join(',');
            const timestamp = Date.now();
            const command = `ssh-keygen -s "${caKeyPath}" -I "flui-ephemeral-${timestamp}" -n "${principalsStr}" -V "+${validitySeconds}s" "${pubKeyPath}"`;
            this.logger.debug(`Executing ssh-keygen signing command...`);
            this.logger.debug(`Command: ${command}`);
            // Execute ssh-keygen and capture output
            const { stdout, stderr } = await execAsync(command, { cwd: tempDir });
            if (stdout)
                this.logger.debug(`ssh-keygen stdout: ${stdout}`);
            if (stderr)
                this.logger.debug(`ssh-keygen stderr: ${stderr}`);
            // Read the generated certificate
            const certificate = await node_fs_1.promises.readFile(certPath, 'utf-8');
            const certStats = await node_fs_1.promises.stat(certPath);
            this.logger.debug(`Certificate file size: ${certStats.size} bytes`);
            this.logger.debug(`Certificate preview (first 200 chars): ${certificate.substring(0, 200)}...`);
            // Validate the certificate using ssh-keygen -L
            try {
                const validateCommand = `ssh-keygen -L -f "${certPath}"`;
                const { stdout: certInfo } = await execAsync(validateCommand, {
                    cwd: tempDir,
                });
                this.logger.debug(`Certificate validation info:\n${certInfo}`);
            }
            catch (validateError) {
                this.logger.warn(`Failed to validate certificate: ${validateError.message}`);
            }
            return certificate.trim();
        }
        catch (error) {
            this.logger.error('Failed to sign certificate:', error.message);
            throw error;
        }
        finally {
            if (tempDir) {
                try {
                    await node_fs_1.promises.rm(tempDir, { recursive: true, force: true });
                }
                catch (cleanupError) {
                    this.logger.warn(`Failed to cleanup temp directory: ${cleanupError.message}`);
                }
            }
        }
    }
};
exports.CertificateSignerService = CertificateSignerService;
exports.CertificateSignerService = CertificateSignerService = CertificateSignerService_1 = __decorate([
    (0, common_1.Injectable)(),
    __metadata("design:paramtypes", [ssh_key_generator_service_1.SSHKeyGeneratorService,
        ca_manager_service_1.CAManagerService])
], CertificateSignerService);
