"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.DiditWebhookService = void 0;
const common_1 = require("@nestjs/common");
const config_1 = require("@nestjs/config");
const crypto = require("crypto");
let DiditWebhookService = class DiditWebhookService {
    constructor(configService) {
        this.configService = configService;
    }
    getSecret() {
        const secret = this.configService.get('DIDIT_WEBHOOK_SECRET_KEY') ||
            this.configService.get('WEBHOOK_SECRET_KEY') ||
            '';
        if (!secret) {
            throw new common_1.UnauthorizedException('Missing DIDIT_WEBHOOK_SECRET_KEY (set in env to verify Didit webhooks)');
        }
        return secret;
    }
    isFreshTimestamp(timestampHeader) {
        const incomingTime = parseInt(timestampHeader, 10);
        if (!Number.isFinite(incomingTime))
            return false;
        const currentTime = Math.floor(Date.now() / 1000);
        return Math.abs(currentTime - incomingTime) <= 300;
    }
    shortenFloats(data) {
        if (Array.isArray(data))
            return data.map((v) => this.shortenFloats(v));
        if (data !== null && typeof data === 'object') {
            return Object.fromEntries(Object.entries(data).map(([key, value]) => [key, this.shortenFloats(value)]));
        }
        if (typeof data === 'number' && !Number.isInteger(data) && data % 1 === 0) {
            return Math.trunc(data);
        }
        return data;
    }
    sortKeys(obj) {
        if (Array.isArray(obj))
            return obj.map((v) => this.sortKeys(v));
        if (obj !== null && typeof obj === 'object') {
            return Object.keys(obj)
                .sort()
                .reduce((result, key) => {
                result[key] = this.sortKeys(obj[key]);
                return result;
            }, {});
        }
        return obj;
    }
    timingSafeEqualHex(a, b) {
        const aa = Buffer.from(String(a || ''), 'utf8');
        const bb = Buffer.from(String(b || ''), 'utf8');
        if (aa.length !== bb.length)
            return false;
        return crypto.timingSafeEqual(aa, bb);
    }
    verify(headers, jsonBody) {
        const secretKey = this.getSecret();
        const timestamp = headers.timestamp;
        if (!timestamp || !this.isFreshTimestamp(timestamp)) {
            throw new common_1.UnauthorizedException('Invalid or stale X-Timestamp');
        }
        const signatureV2 = headers.signatureV2;
        const signatureSimple = headers.signatureSimple;
        if (signatureV2) {
            const processed = this.shortenFloats(jsonBody);
            const canonicalJson = JSON.stringify(this.sortKeys(processed));
            const expected = crypto.createHmac('sha256', secretKey).update(canonicalJson, 'utf8').digest('hex');
            if (this.timingSafeEqualHex(expected, signatureV2)) {
                return { verified: true, method: 'X-Signature-V2' };
            }
        }
        if (signatureSimple) {
            const canonicalString = [
                jsonBody?.timestamp ?? '',
                jsonBody?.session_id ?? '',
                jsonBody?.status ?? '',
                jsonBody?.webhook_type ?? '',
            ].join(':');
            const expected = crypto
                .createHmac('sha256', secretKey)
                .update(canonicalString, 'utf8')
                .digest('hex');
            if (this.timingSafeEqualHex(expected, signatureSimple)) {
                return { verified: true, method: 'X-Signature-Simple' };
            }
        }
        throw new common_1.UnauthorizedException('Invalid Didit webhook signature');
    }
};
exports.DiditWebhookService = DiditWebhookService;
exports.DiditWebhookService = DiditWebhookService = __decorate([
    (0, common_1.Injectable)(),
    __metadata("design:paramtypes", [config_1.ConfigService])
], DiditWebhookService);
//# sourceMappingURL=didit-webhook.service.js.map