"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.
 */
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.MessageBuilder = void 0;
const ms_1 = __importDefault(require("ms"));
const safeParse_1 = require("../safeParse");
const safeStringify_1 = require("../safeStringify");
/**
 * Message builder exposes an API to JSON.stringify values by encoding purpose
 * and expiryDate inside them. It returns a readable string, which is the
 * output of `JSON.stringify`.
 *
 * Why use this over `JSON.stringify`?
 *
 * - It protects you from JSON poisioning
 * - Allows encoding expiry dates to the message. It means, the message builer is
 *   helpful, when you want to encode a message and pass it around, but also control
 *   the TTL of the message
 * - Allows encoding purpose. Again, useful for distribution.
 */
class MessageBuilder {
    getExpiryDate(expiresIn) {
        if (!expiresIn) {
            return undefined;
        }
        const expiryMs = typeof expiresIn === 'string' ? (0, ms_1.default)(expiresIn) : expiresIn;
        if (expiryMs === undefined || expiryMs === null) {
            throw new Error(`Invalid value for expiresIn "${expiresIn}"`);
        }
        return new Date(Date.now() + expiryMs);
    }
    /**
     * Returns a boolean telling, if message has been expired or not
     */
    isExpired(message) {
        if (!message.expiryDate) {
            return false;
        }
        try {
            const expiryDate = new Date(message.expiryDate);
            return isNaN(expiryDate.getTime()) || expiryDate < new Date();
        }
        catch (error) {
            return true;
        }
    }
    /**
     * Builds a message by encoding expiry and purpose inside it
     */
    build(message, expiresIn, purpose) {
        const expiryDate = this.getExpiryDate(expiresIn);
        return (0, safeStringify_1.safeStringify)({ message, purpose, expiryDate });
    }
    /**
     * Verifies the message for expiry and purpose
     */
    verify(message, purpose) {
        const parsed = (0, safeParse_1.safeParse)(message);
        /**
         * Safe parse returns the value as it is when unable to JSON.parse it. However, in
         * our case if value was correctly parsed, it should never match the input
         */
        if (parsed === message) {
            return null;
        }
        /**
         * Missing ".message" property
         */
        if (!parsed.message) {
            return null;
        }
        /**
         * Ensure purposes are same.
         */
        if (parsed.purpose !== purpose) {
            return null;
        }
        /**
         * Ensure isn't expired
         */
        if (this.isExpired(parsed)) {
            return null;
        }
        return parsed.message;
    }
}
exports.MessageBuilder = MessageBuilder;
