using System.Security.Cryptography;
namespace ReleaseBuilder.Build;
public static partial class Command
{
///
/// Setup of the current runtime information
///
private class RuntimeConfig
{
///
/// Constructs a new
///
/// The release info to use
/// The keyfile password to use
/// The sign keys
/// The changelog news
/// The command input
public RuntimeConfig(ReleaseInfo releaseInfo, IEnumerable signKeys, string keyfilePassword, string changelogNews, CommandInput input)
{
ReleaseInfo = releaseInfo;
SignKeys = signKeys;
KeyfilePassword = keyfilePassword;
ChangelogNews = changelogNews;
Input = input;
}
///
/// The cached password for the pfx file
///
private string? _pfxPassword = null;
///
/// The commandline input
///
private CommandInput Input { get; }
///
/// The release info for this run
///
public ReleaseInfo ReleaseInfo { get; }
///
/// The keyfile password for this run
///
public IEnumerable SignKeys { get; }
///
/// The primary password
///
public string KeyfilePassword { get; }
///
/// The changelog news
///
public string ChangelogNews { get; }
///
/// Gets the PFX password and throws if not possible
///
public string PfxPassword
=> string.IsNullOrWhiteSpace(_pfxPassword)
? _pfxPassword = GetAuthenticodePassword(KeyfilePassword)
: _pfxPassword;
///
/// Cache value for checking if authenticode signing is enabled
///
private bool? _useAuthenticodeSigning;
///
/// Checks if Authenticode signing should be enabled
///
public void ToggleAuthenticodeSigning()
{
if (!_useAuthenticodeSigning.HasValue)
{
if (Input.DisableAuthenticode)
{
_useAuthenticodeSigning = false;
return;
}
if (Program.Configuration.IsAuthenticodePossible())
_useAuthenticodeSigning = true;
else
{
if (ConsoleHelper.ReadInput("Configuration missing for osslsigncode, continue without signing executables?", "Y", "n") == "Y")
{
_useAuthenticodeSigning = false;
return;
}
throw new Exception("Configuration is not set up for osslsigncode");
}
}
}
///
/// Cache value for checking if codesign is possible
///
private bool? _useCodeSignSigning;
///
/// Checks if codesign is enabled
///
public void ToggleSignCodeSigning()
{
if (!_useCodeSignSigning.HasValue)
{
if (Input.DisableSignCode)
{
_useCodeSignSigning = false;
return;
}
if (!OperatingSystem.IsMacOS())
_useCodeSignSigning = false;
else if (Program.Configuration.IsCodeSignPossible())
_useCodeSignSigning = true;
else
{
if (ConsoleHelper.ReadInput("Configuration missing for signcode, continue without signing executables?", "Y", "n") == "Y")
{
_useCodeSignSigning = false;
return;
}
throw new Exception("Configuration is not set up for signcode");
}
}
}
///
/// Cache value for checking if docker build is enabled
///
private bool? _dockerBuild;
///
/// Checks if docker build is enabled
///
public async Task ToggleDockerBuild()
{
if (!_dockerBuild.HasValue)
{
try
{
var res = await ProcessHelper.ExecuteWithOutput([Program.Configuration.Commands.Docker!, "ps"], suppressStdErr: true);
_dockerBuild = true;
}
catch
{
if (ConsoleHelper.ReadInput("Docker does not seem to be running, continue without docker builds?", "Y", "n") == "Y")
{
_dockerBuild = false;
return;
}
throw new Exception("Docker is not running, and is required for building Docker images");
}
}
}
///
/// Cache value for checking if notarize is enabled
///
private bool? _useNotarizeSigning;
///
/// Checks if notarize signing is enabled
///
public void ToggleNotarizeSigning()
{
if (!_useNotarizeSigning.HasValue)
{
if (Input.DisableNotarizeSigning)
{
_useNotarizeSigning = false;
return;
}
if (!OperatingSystem.IsMacOS())
_useNotarizeSigning = false;
else if (Program.Configuration.IsNotarizePossible())
_useNotarizeSigning = true;
else
{
if (ConsoleHelper.ReadInput("Configuration missing for notarize, continue without notarizing executables?", "Y", "n") == "Y")
{
_useNotarizeSigning = false;
return;
}
throw new Exception("Configuration is not set up for notarize");
}
}
}
///
/// Cache value for checking if GPG signing is enabled
///
private bool? _useGpgSigning;
///
/// Checks if GPG signing is enabled
///
public void ToggleGpgSigning()
{
if (!_useGpgSigning.HasValue)
{
if (Input.DisableGpgSigning)
{
_useGpgSigning = false;
return;
}
if (Program.Configuration.IsGpgPossible())
_useGpgSigning = true;
else
{
if (ConsoleHelper.ReadInput("Configuration missing for gpg, continue without gpg signing packages?", "Y", "n") == "Y")
{
_useGpgSigning = false;
return;
}
throw new Exception("Configuration is not set up for gpg");
}
}
}
///
/// Cache value for checking if S3 upload is enabled
///
private bool? _useS3Upload;
///
/// Checks if S3 upload is enabled
///
public void ToggleS3Upload()
{
if (!_useS3Upload.HasValue)
{
if (Input.DisableS3Upload)
{
_useS3Upload = false;
return;
}
if (Program.Configuration.IsAwsUploadPossible())
_useS3Upload = true;
else
{
if (ConsoleHelper.ReadInput("Configuration missing for awscli, continue without uploading to S3?", "Y", "n") == "Y")
{
_useS3Upload = false;
return;
}
throw new Exception("Configuration is not set up for awscli");
}
}
}
///
/// Cache value for checking if Github upload is enabled
///
private bool? _useGithubUpload;
///
/// Checks if Github upload is enabled
///
/// The release channel to use
public void ToggleGithubUpload(ReleaseChannel channel)
{
if (!_useGithubUpload.HasValue)
{
if (Input.DisableGithubUpload || channel == ReleaseChannel.Debug || channel == ReleaseChannel.Nightly)
{
_useGithubUpload = false;
return;
}
if (Program.Configuration.IsGithubUploadPossible())
_useGithubUpload = true;
else
{
if (ConsoleHelper.ReadInput("Configuration is missing a Github token, continue without uploading to Github?", "Y", "n") == "Y")
{
_useGithubUpload = false;
return;
}
throw new Exception("Configuration is not set up for github releases");
}
}
}
///
/// Cache value for checking if update server reload is enabled
///
private bool? _useUpdateServerReload;
///
/// Checks if update server reload is enabled
///
public void ToggleUpdateServerReload()
{
if (!_useUpdateServerReload.HasValue)
{
if (Input.DisableUpdateServerReload)
{
_useUpdateServerReload = false;
return;
}
if (Program.Configuration.IsUpdateServerReloadPossible())
_useUpdateServerReload = true;
else
{
if (ConsoleHelper.ReadInput("Configuration missing for update server, continue without reloading the update server?", "Y", "n") == "Y")
{
_useUpdateServerReload = false;
return;
}
throw new Exception("Configuration is not set up for update server");
}
}
}
///
/// Cache value for checking if forum posting is enabled
///
private bool? _useDiscourseAnnounce;
///
/// Checks if forum posting is enabled
///
/// The release channel to use
public void ToogleDiscourseAnnounce(ReleaseChannel channel)
{
if (!_useDiscourseAnnounce.HasValue)
{
if (Input.DisableDiscordAnnounce || channel == ReleaseChannel.Debug || channel == ReleaseChannel.Nightly)
{
_useDiscourseAnnounce = false;
return;
}
if (Program.Configuration.IsDiscourseAnnouncePossible())
_useDiscourseAnnounce = true;
else
{
if (ConsoleHelper.ReadInput("Configuration missing for forum posting, continue without posting to the forum?", "Y", "n") == "Y")
{
_useDiscourseAnnounce = false;
return;
}
throw new Exception("Configuration is not set up for forum posting");
}
}
}
///
/// Returns a value indicating if codesign is enabled
///
public bool UseCodeSignSigning => _useCodeSignSigning!.Value;
///
/// Returns a value indicating if authenticode signing is enabled
///
public bool UseAuthenticodeSigning => _useAuthenticodeSigning!.Value;
///
/// Returns a value indicating if notarize is enabled
///
public bool UseNotarizeSigning => _useNotarizeSigning!.Value;
///
/// Returns a value indicating if GPG signing is enabled
///
public bool UseGPGSigning => _useGpgSigning!.Value;
///
/// Returns a value indicating if docker build is enabled
///
public bool UseDockerBuild => _dockerBuild!.Value;
///
/// Returns a value indicating if S3 upload is enabled
///
public bool UseS3Upload => _useS3Upload!.Value;
///
/// Returns a value indicating if Github upload is enabled
///
public bool UseGithubUpload => _useGithubUpload!.Value;
///
/// Returns a value indicating if update server reload is enabled
///
public bool UseUpdateServerReload => _useUpdateServerReload!.Value;
///
/// Returns a value indicating if forum posting is enabled
///
public bool UseForumPosting => _useDiscourseAnnounce!.Value;
///
/// Gets the MacOS app bundle name
///
public string MacOSAppName => Input.MacOSAppName;
///
/// The docker repository to use
///
public string DockerRepo => Input.DockerRepo;
///
/// Gets a value indicating if pushing should be enabled
///
public bool PushToDocker => !Input.DisableDockerPush;
///
/// Decrypts the password file and returns the PFX password
///
/// Password for the password file
/// The Authenticode password
private string GetAuthenticodePassword(string keyfilepassword)
=> EncryptionHelper.DecryptPasswordFile(Program.Configuration.ConfigFiles.AuthenticodePasswordFile, keyfilepassword).Trim();
///
/// Performs authenticode signing if enabled
///
/// The file to sign
/// An awaitable task
public Task AuthenticodeSign(string file)
=> UseAuthenticodeSigning
? ProcessRunner.OsslCodeSign(
Program.Configuration.Commands.OsslSignCode!,
Program.Configuration.ConfigFiles.AuthenticodePfxFile,
PfxPassword,
file)
: Task.CompletedTask;
///
/// Performs codesign on the given file
///
/// The file to sign
/// The entitlements to apply
/// An awaitable task
public Task Codesign(string file, string entitlements)
=> UseCodeSignSigning
? ProcessRunner.MacOSCodeSign(
Program.Configuration.Commands.Codesign!,
Program.Configuration.ConfigFiles.CodesignIdentity,
entitlements,
file
)
: Task.CompletedTask;
///
/// Performs productsign on the given file
///
/// The file to sign
/// An awaitable task
public Task Productsign(string file)
=> UseCodeSignSigning
? ProcessRunner.MacOSProductSign(
Program.Configuration.Commands.Productsign!,
Program.Configuration.ConfigFiles.CodesignIdentity,
file
)
: Task.CompletedTask;
}
}