using System.Security.Cryptography; using System.Text; using DodoSSH.Client.Session; namespace DodoSSH.Client.App.Platform; /// /// What a platform key store calls the hardware key behind one profile's device unlock. /// /// /// /// ◆ One key per profile, because the key outlives the file and is shared by name. The CNG key and /// the Secure Enclave keychain item are found by name in a store that belongs to the user, not to the /// profile directory. While every profile used the same name, the release build and the nightly — which /// keeps apart precisely so neither can damage the other — shared one /// key: signing out of either deleted it, and the other's device unlock silently stopped working. /// /// /// The default profile keeps the name it has always had, so an existing install's sealed key still /// opens. Every other profile gets that name with a digest of its directory on the end — a digest rather /// than the directory's own name, because a portable copy can live in any folder and two such folders can /// end in the same name. /// /// internal static class DeviceKeyNames { /// The name of the key behind ' device unlock. /// The profile. /// The name every profile used before names were per profile. internal static string For(ClientPaths paths, string legacy) { ArgumentNullException.ThrowIfNull(paths); var directory = Normalise(paths.DataDirectory); if (string.Equals(directory, Normalise(ClientPaths.Default.DataDirectory), StringComparison.OrdinalIgnoreCase)) { return legacy; } var digest = SHA256.HashData(Encoding.UTF8.GetBytes(directory.ToUpperInvariant())); return $"{legacy}.{Convert.ToHexStringLower(digest.AsSpan(0, 8))}"; } private static string Normalise(string directory) => Path.TrimEndingDirectorySeparator(Path.GetFullPath(directory)); }