Files
metin-launcher/src/Metin2Launcher/Config/LauncherConfig.cs
Jan Nedbal a134e7548f launcher: swap placeholder key for real production public key
Replace the MVP placeholder Ed25519 public key with the real one that
corresponds to ~/.config/metin/launcher-signing-key on the release
machine. Update README to document where the private half lives and
how rotation works. Private key is not committed anywhere; the only
code path that touches it is scripts/sign-manifest.py in m2dev-client.
2026-04-14 11:21:07 +02:00

39 lines
1.9 KiB
C#

namespace Metin2Launcher.Config;
/// <summary>
/// Hardcoded configuration for the launcher MVP.
/// These values are deliberately not loaded from a config file — they are compile-time
/// constants so a tampered local config cannot redirect updates.
/// </summary>
public static class LauncherConfig
{
public const string ManifestUrl = "https://updates.jakubkadlec.dev/manifest.json";
public const string SignatureUrl = "https://updates.jakubkadlec.dev/manifest.json.sig";
public const string BlobBaseUrl = "https://updates.jakubkadlec.dev/files";
public const string VelopackFeedUrl = "https://updates.jakubkadlec.dev/launcher";
public const string GameExecutable = "Metin2.exe";
/// <summary>
/// Ed25519 public key used to verify the manifest signature.
///
/// The matching private key lives offline in ~/.config/metin/launcher-signing-key
/// (chmod 600) on the release machine and is never committed to any repo.
/// Manifests are signed with scripts/sign-manifest.py in the m2dev-client repo.
/// Rotation is done by shipping a new launcher binary that embeds the new public
/// key; see docs/update-manager.md for the rotation flow.
/// </summary>
public const string PublicKeyHex = "1d2b63751ea0e0354d28e7eb4ec175919a01518b0bcf5878f0a3aa8e7c6ce2bc";
public static readonly TimeSpan ManifestFetchTimeout = TimeSpan.FromSeconds(10);
public static readonly TimeSpan BlobFetchTimeout = TimeSpan.FromSeconds(60);
public static readonly TimeSpan TotalUpdateTimeout = TimeSpan.FromMinutes(30);
public const int MaxBlobRetries = 3;
/// <summary>Name of the directory under the client root that holds launcher state.</summary>
public const string StateDirName = ".updates";
/// <summary>Name of the staging directory under the state directory.</summary>
public const string StagingDirName = "staging";
}