namespace DodoSSH.Api.Features.Identity;

/// <summary>
/// Bounds the server enforces on an enrollment request.
/// </summary>
/// <remarks>
/// These are sanity limits, not policy. The server cannot read any of the material they describe,
/// so their job is to stop a buggy or hostile client writing something that is permanently
/// unusable — or permanently weak, which matters because a wrap stored here is exactly what an
/// attacker who ever obtains a database dump gets to grind against offline.
/// </remarks>
internal static class EnrollmentLimits
{
    /// <summary>The only KDF this version accepts.</summary>
    internal const string KdfAlgorithm = "argon2id";

    /// <summary>Smallest acceptable salt.</summary>
    internal const int MinimumSaltBytes = 16;

    /// <summary>Largest sensible salt.</summary>
    internal const int MaximumSaltBytes = 64;

    /// <summary>
    /// Hard floor on Argon2id memory cost, in kibibytes: 64 MiB.
    /// </summary>
    /// <remarks>
    /// Below the recommended 256 MiB, because a low-memory machine must still be able to enroll,
    /// and because the recovery-code wrap legitimately uses a cheaper profile — a printable
    /// recovery code carries far more entropy than a passphrase, so it needs less stretching.
    /// See docs/crypto.md §2.
    /// </remarks>
    internal const int MinimumKdfMemoryKibibytes = 64 * 1024;

    /// <summary>Ceiling on Argon2id memory cost, in kibibytes: 4 GiB.</summary>
    /// <remarks>
    /// A client that stores an absurd cost locks itself out of its own vault on every future
    /// device, and the server is the only place that can refuse it.
    /// </remarks>
    internal const int MaximumKdfMemoryKibibytes = 4 * 1024 * 1024;

    /// <summary>Fewest acceptable Argon2id passes.</summary>
    internal const int MinimumKdfPasses = 2;

    /// <summary>Most acceptable Argon2id passes.</summary>
    internal const int MaximumKdfPasses = 16;

    /// <summary>Lanes. libsodium supports one value and one only.</summary>
    internal const int RequiredKdfParallelism = 1;

    /// <summary>
    /// Largest accepted wrap or sealed vault key.
    /// </summary>
    /// <remarks>
    /// The secret bundle is about 200 bytes and a sealed vault key is 32, both inside a DSH1
    /// envelope. 4 KiB is generous room for growth while still refusing a client trying to use the
    /// identity tables as storage.
    /// </remarks>
    internal const int MaximumWrapBytes = 4 * 1024;

    /// <summary>Longest vault name, matching the column.</summary>
    internal const int MaximumVaultNameLength = 256;

    /// <summary>Longest device name, matching the column.</summary>
    internal const int MaximumDeviceNameLength = 256;

    /// <summary>Longest issuer, matching the column.</summary>
    internal const int MaximumIssuerLength = 512;

    /// <summary>Longest subject, matching the column.</summary>
    internal const int MaximumSubjectLength = 256;

    /// <summary>Longest email, matching the column.</summary>
    internal const int MaximumEmailLength = 320;
}
