namespace ReleaseBuilder.Build; public static partial class Command { /// /// Implementation of the gpg sign command /// private static class GpgSign { /// /// Performs a GPG sign operation on the files /// /// The files to sign /// The runtime configuration /// An awaitable task public static async Task SignReleaseFiles(IEnumerable files, RuntimeConfig rtcfg) { var (gpgid, passphrase) = GetGpgIdAndPassphrase(rtcfg); foreach (var file in files) foreach (var armored in new[] { true, false }) await ProcessHelper.Execute( [ Program.Configuration.Commands.Gpg!, "--pinentry-mode", "loopback", "--passphrase-fd", "0", "--batch", "--yes", armored ? "--armor" : string.Empty, "-u", gpgid, "--output", file + (armored ? "sig.asc" : ".sig"), "--detach-sign", file ], workingDirectory: Path.GetDirectoryName(file), writeStdIn: (stdin) => stdin.WriteLineAsync(passphrase) ); } /// /// Gets the GPG ID and passphrase from the keyfile /// /// The runtime configuration /// The GPG ID and passphrase static (string GpgId, string GpgPassphrase) GetGpgIdAndPassphrase(RuntimeConfig rtcfg) { using var ms = new MemoryStream(); using var fs = File.OpenRead(Program.Configuration.ConfigFiles.GpgKeyfile); SharpAESCrypt.SharpAESCrypt.Decrypt(rtcfg.KeyfilePassword, fs, ms); var parts = System.Text.Encoding.UTF8.GetString(ms.ToArray()).Split('\n', 2, StringSplitOptions.RemoveEmptyEntries); return (parts[0], parts[1]); } } }