import {
  Hmac
} from "./chunk-2MF2TUNL.js";
import {
  E_INSECURE_ENCRYPTER_KEY,
  E_MISSING_ENCRYPTER_KEY,
  E_MISSING_ENCRYPTER_KEYS
} from "./chunk-2UOFQLYL.js";
import {
  base64UrlDecode,
  base64UrlEncode
} from "./chunk-OD6CXVQX.js";

// src/message_verifier.ts
import { createHash } from "crypto";
import { MessageBuilder } from "@poppinss/utils";
import { RuntimeException } from "@poppinss/utils/exception";
var MessageVerifier = class {
  /**
   * The keys for signing and verifying values. They are derived
   * from the user provided secrets.
   */
  #cryptoKeys;
  /**
   * 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.
   */
  #separator = ".";
  constructor(secrets) {
    if (secrets.length === 0) {
      throw new E_MISSING_ENCRYPTER_KEYS();
    }
    this.#cryptoKeys = secrets.map((secret) => {
      const revealedSecret = typeof secret === "string" ? secret : secret.release();
      if (!revealedSecret) {
        throw new E_MISSING_ENCRYPTER_KEY();
      }
      if (revealedSecret.length < 16) {
        throw new E_INSECURE_ENCRYPTER_KEY();
      }
      return createHash("sha256").update(revealedSecret).digest();
    });
  }
  /**
   * Sign a given piece of value using the app secret. A wide range of
   * data types are supported.
   *
   * - String
   * - Arrays
   * - Objects
   * - Booleans
   * - Numbers
   * - Dates
   *
   * You can optionally define a purpose for which the value was signed and
   * mentioning a different purpose/no purpose during unsign will fail.
   */
  sign(payload, expiresIn, purpose) {
    if (payload === null || payload === void 0) {
      throw new RuntimeException(`Cannot sign "${payload}" value`);
    }
    const encoded = base64UrlEncode(new MessageBuilder().build(payload, expiresIn, purpose));
    return `${encoded}${this.#separator}${new Hmac(this.#cryptoKeys[0]).generate(encoded)}`;
  }
  /**
   * Unsign a previously signed value with an optional purpose
   */
  unsign(payload, purpose) {
    if (typeof payload !== "string") {
      return null;
    }
    const parts = payload.split(this.#separator);
    if (parts.length !== 2) {
      return null;
    }
    const [encoded, hash] = parts;
    if (!encoded || !hash) {
      return null;
    }
    const decoded = base64UrlDecode(encoded, "utf8");
    if (!decoded) {
      return null;
    }
    for (const cryptoKey of this.#cryptoKeys) {
      const isValid = new Hmac(cryptoKey).compare(encoded, hash);
      if (isValid) {
        return new MessageBuilder().verify(decoded, purpose);
      }
    }
    return null;
  }
};

export {
  MessageVerifier
};
/*
 * @boringnode/encryption
 *
 * @license MIT
 * @copyright Boring Node
 */
//# sourceMappingURL=chunk-XKOJ2IWX.js.map