using System.Diagnostics.CodeAnalysis; using System.Security.Cryptography; namespace DataTransfer.Client.Shared; /// Generates and parses the one-time codes used to pair two participants. public static class ConnectionCode { public const int Length = 10; // Ambiguous characters (0/O, 1/I) are excluded. 32 symbols ^ 10 = 50 bits of entropy. private const string Alphabet = "ABCDEFGHJKLMNPQRSTUVWXYZ23456789"; public static string Generate() => RandomNumberGenerator.GetString(Alphabet, Length); /// Accepts user input case-insensitively, ignoring whitespace and dashes. public static bool TryNormalize(string? input, [NotNullWhen(true)] out string? code) { code = null; if (string.IsNullOrWhiteSpace(input)) { return false; } Span buffer = stackalloc char[Length]; var count = 0; foreach (var c in input) { if (char.IsWhiteSpace(c) || c == '-') { continue; } var upper = char.ToUpperInvariant(c); if (count == Length || !Alphabet.Contains(upper)) { return false; } buffer[count++] = upper; } if (count != Length) { return false; } code = new string(buffer); return true; } public static string Format(string code) => code.Length == Length ? $"{code[..5]}-{code[5..]}" : code; }