"use strict";
/*
 * @adonisjs/encryption
 *
 * (c) Harminder Virk <virk@adonisjs.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
Object.defineProperty(exports, "__esModule", { value: true });
exports.MessageVerifier = void 0;
/// <reference path="../../adonis-typings/encryption.ts" />
const crypto_1 = require("crypto");
const utils_1 = require("@poppinss/utils");
const helpers_1 = require("@poppinss/utils/build/helpers");
const Hmac_1 = require("../Hmac");
/**
 * Message verifier is similar to the encryption. However, the actual payload
 * is not encrypted and just base64 encoded. This is helpful when you are
 * not concerned about the confidentiality of the data, but just want to
 * make sure that is not tampered after encoding.
 */
class MessageVerifier {
    constructor(secret) {
        this.secret = secret;
        /**
         * The key for signing and encrypting values. It is derived
         * from the user provided secret.
         */
        this.cryptoKey = (0, crypto_1.createHash)('sha256').update(this.secret).digest();
        /**
         * Use `dot` as a separator for joining encrypted value, iv and the
         * hmac hash. The idea is borrowed from JWT's in which each part
         * of the payload is concatenated with a dot.
         */
        this.separator = '.';
    }
    /**
     * Signs a value with the secret key. The signed value is not encrypted, but just
     * signed for avoiding tampering to the original message.
     *
     * Any `JSON.stringify` valid value is accepted by this method.
     */
    sign(value, expiresAt, purpose) {
        if (value === null || value === undefined) {
            throw new utils_1.Exception('"MessageVerifier.sign" cannot sign null or undefined values', 500, 'E_RUNTIME_EXCEPTION');
        }
        const encoded = helpers_1.base64.urlEncode(new helpers_1.MessageBuilder().build(value, expiresAt, purpose));
        return `${encoded}${this.separator}${new Hmac_1.Hmac(this.cryptoKey).generate(encoded)}`;
    }
    /**
     * Unsign a previously signed value with an optional purpose
     */
    unsign(value, purpose) {
        if (typeof value !== 'string') {
            throw new utils_1.Exception('"MessageVerifier.unsign" expects a string value', 500, 'E_RUNTIME_EXCEPTION');
        }
        /**
         * Ensure value is in correct format
         */
        const [encoded, hash] = value.split(this.separator);
        if (!encoded || !hash) {
            return null;
        }
        /**
         * Ensure value can be decoded
         */
        const decoded = helpers_1.base64.urlDecode(encoded);
        if (!decoded) {
            return null;
        }
        const isValid = new Hmac_1.Hmac(this.cryptoKey).compare(encoded, hash);
        return isValid ? new helpers_1.MessageBuilder().verify(decoded, purpose) : null;
    }
}
exports.MessageVerifier = MessageVerifier;
