diff options
Diffstat (limited to 'src/main.lib/Plugins/ValidationPlugins/Dns/Script')
5 files changed, 309 insertions, 0 deletions
diff --git a/src/main.lib/Plugins/ValidationPlugins/Dns/Script/Script.cs b/src/main.lib/Plugins/ValidationPlugins/Dns/Script/Script.cs new file mode 100644 index 0000000..7bd9e4d --- /dev/null +++ b/src/main.lib/Plugins/ValidationPlugins/Dns/Script/Script.cs @@ -0,0 +1,78 @@ +using PKISharp.WACS.Clients; +using PKISharp.WACS.Clients.DNS; +using PKISharp.WACS.DomainObjects; +using PKISharp.WACS.Services; + +namespace PKISharp.WACS.Plugins.ValidationPlugins.Dns +{ + internal class Script : DnsValidation<ScriptOptions, Script> + { + private readonly ScriptClient _scriptClient; + + internal const string DefaultCreateArguments = "create {Identifier} {RecordName} {Token}"; + internal const string DefaultDeleteArguments = "delete {Identifier} {RecordName} {Token}"; + + public Script( + ScriptOptions options, + LookupClientProvider dnsClient, + ILogService log, + string identifier) : + base(dnsClient, log, options, identifier) + { + _scriptClient = new ScriptClient(log); + } + + public override void CreateRecord(string recordName, string token) + { + var script = _options.Script ?? _options.CreateScript; + if (!string.IsNullOrWhiteSpace(script)) + { + var args = DefaultCreateArguments; + if (!string.IsNullOrWhiteSpace(_options.CreateScriptArguments)) + { + args = _options.CreateScriptArguments; + } + _scriptClient.RunScript(script, ProcessArguments(recordName, token, args, script.EndsWith(".ps1"))); + } + else + { + _log.Error("No create script configured"); + } + } + + public override void DeleteRecord(string recordName, string token) + { + var script = _options.Script ?? _options.DeleteScript; + if (!string.IsNullOrWhiteSpace(script)) + { + var args = DefaultDeleteArguments; + if (!string.IsNullOrWhiteSpace(_options.DeleteScriptArguments)) + { + args = _options.DeleteScriptArguments; + } + _scriptClient.RunScript(script, ProcessArguments(recordName, token, args, script.EndsWith(".ps1"))); + } + else + { + _log.Warning("No delete script configured, validation record remains"); + } + } + + private string ProcessArguments(string recordName, string token, string args, bool escapeToken) + { + var ret = args; + ret = ret.Replace("{Identifier}", _identifier); + ret = ret.Replace("{RecordName}", recordName); + // Some tokens start with - which confuses Powershell. We did not want to + // make a breaking change for .bat or .exe files, so instead escape the + // token with double quotes, as Powershell discards the quotes anyway and + // thus it's functionally equivalant. + if (escapeToken && (ret.Contains(" {Token} ") || ret.EndsWith(" {Token}"))) + { + ret.Replace("{Token}", "\"{Token}\""); + } + ret = ret.Replace("{Token}", token); + return ret; + } + } +} diff --git a/src/main.lib/Plugins/ValidationPlugins/Dns/Script/ScriptArguments.cs b/src/main.lib/Plugins/ValidationPlugins/Dns/Script/ScriptArguments.cs new file mode 100644 index 0000000..c73a963 --- /dev/null +++ b/src/main.lib/Plugins/ValidationPlugins/Dns/Script/ScriptArguments.cs @@ -0,0 +1,11 @@ +namespace PKISharp.WACS.Plugins.ValidationPlugins.Dns +{ + class ScriptArguments + { + public string DnsScript { get; set; } + public string DnsCreateScript { get; set; } + public string DnsCreateScriptArguments { get; set; } + public string DnsDeleteScript { get; set; } + public string DnsDeleteScriptArguments { get; set; } + } +} diff --git a/src/main.lib/Plugins/ValidationPlugins/Dns/Script/ScriptArgumentsProvider.cs b/src/main.lib/Plugins/ValidationPlugins/Dns/Script/ScriptArgumentsProvider.cs new file mode 100644 index 0000000..2fb7a1a --- /dev/null +++ b/src/main.lib/Plugins/ValidationPlugins/Dns/Script/ScriptArgumentsProvider.cs @@ -0,0 +1,41 @@ +using Fclp; +using PKISharp.WACS.Configuration; +using PKISharp.WACS.Services; + +namespace PKISharp.WACS.Plugins.ValidationPlugins.Dns +{ + class ScriptArgumentsProvider : BaseArgumentsProvider<ScriptArguments> + { + public override string Name => "Script"; + public override string Group => "Validation"; + public override string Condition => "--validationmode dns-01 --validation dnsscript"; + + public override void Configure(FluentCommandLineParser<ScriptArguments> parser) + { + parser.Setup(o => o.DnsScript) + .As("dnsscript") + .WithDescription("Path to script that creates and deletes validation records, depending on its parameters. If this parameter is provided then --dnscreatescript and --dnsdeletescript are ignored."); + parser.Setup(o => o.DnsCreateScript) + .As("dnscreatescript") + .WithDescription("Path to script that creates the validation TXT record."); + parser.Setup(o => o.DnsCreateScriptArguments) + .As("dnscreatescriptarguments") + .WithDescription($"Default parameters passed to the script are {Script.DefaultCreateArguments}, but that can be customized using this argument."); + parser.Setup(o => o.DnsDeleteScript) + .As("dnsdeletescript") + .WithDescription("Path to script to remove TXT record."); + parser.Setup(o => o.DnsDeleteScriptArguments) + .As("dnsdeletescriptarguments") + .WithDescription($"Default parameters passed to the script are {Script.DefaultDeleteArguments}, but that can be customized using this argument."); + } + + public override bool Active(ScriptArguments current) + { + return !string.IsNullOrEmpty(current.DnsScript) || + !string.IsNullOrEmpty(current.DnsCreateScript) || + !string.IsNullOrEmpty(current.DnsDeleteScript) || + !string.IsNullOrEmpty(current.DnsDeleteScriptArguments) || + !string.IsNullOrEmpty(current.DnsCreateScriptArguments); + } + } +} diff --git a/src/main.lib/Plugins/ValidationPlugins/Dns/Script/ScriptOptions.cs b/src/main.lib/Plugins/ValidationPlugins/Dns/Script/ScriptOptions.cs new file mode 100644 index 0000000..4ad3f5a --- /dev/null +++ b/src/main.lib/Plugins/ValidationPlugins/Dns/Script/ScriptOptions.cs @@ -0,0 +1,19 @@ +using PKISharp.WACS.Plugins.Base; +using PKISharp.WACS.Plugins.Base.Options; + +namespace PKISharp.WACS.Plugins.ValidationPlugins.Dns +{ + [Plugin("8f1da72e-f727-49f0-8546-ef69e5ecec32")] + class ScriptOptions : ValidationPluginOptions<Script> + { + public override string Name => "DnsScript"; + public override string Description => "Create verification records with your own script"; + public override string ChallengeType { get => Constants.Dns01ChallengeType; } + + public string Script { get; set; } + public string CreateScript { get; set; } + public string CreateScriptArguments { get; set; } + public string DeleteScript { get; set; } + public string DeleteScriptArguments { get; set; } + } +} diff --git a/src/main.lib/Plugins/ValidationPlugins/Dns/Script/ScriptOptionsFactory.cs b/src/main.lib/Plugins/ValidationPlugins/Dns/Script/ScriptOptionsFactory.cs new file mode 100644 index 0000000..4ed53f4 --- /dev/null +++ b/src/main.lib/Plugins/ValidationPlugins/Dns/Script/ScriptOptionsFactory.cs @@ -0,0 +1,160 @@ +using PKISharp.WACS.DomainObjects; +using PKISharp.WACS.Extensions; +using PKISharp.WACS.Plugins.Base.Factories; +using PKISharp.WACS.Services; +using System; +using System.Collections.Generic; + +namespace PKISharp.WACS.Plugins.ValidationPlugins.Dns +{ + internal class ScriptOptionsFactory : ValidationPluginOptionsFactory<Script, ScriptOptions> + { + private readonly ILogService _log; + private readonly IArgumentsService _arguments; + + public ScriptOptionsFactory(ILogService log, IArgumentsService arguments) : base(Constants.Dns01ChallengeType) + { + _log = log; + _arguments = arguments; + } + + public override ScriptOptions Aquire(Target target, IInputService input, RunLevel runLevel) + { + var args = _arguments.GetArguments<ScriptArguments>(); + var ret = new ScriptOptions(); + var createScript = ""; + do + { + createScript = _arguments.TryGetArgument(args.DnsCreateScript, input, "Path to script that creates DNS records"); + } + while (!createScript.ValidFile(_log)); + + var deleteScript = ""; + input.ChooseFromList( + "How to delete records after validation", + new List<Choice<Action>>() + { + Choice.Create<Action>(() => { deleteScript = createScript; }, "Using the same script"), + Choice.Create<Action>(() => { + do { + deleteScript = _arguments.TryGetArgument(args.DnsDeleteScript, input, "Path to script that deletes DNS records"); + } + while (!deleteScript.ValidFile(_log)); + }, "Using a different script"), + Choice.Create<Action>(() => { }, "Do not delete") + }).Invoke(); + + ProcessScripts(ret, null, createScript, deleteScript); + + input.Show("{Identifier}", "Domain that's being validated"); + input.Show("{RecordName}", "Full TXT record name"); + input.Show("{Token}", "Expected value in the TXT record"); + var createArgs = _arguments.TryGetArgument(args.DnsCreateScriptArguments, input, $"Input parameters for create script, or enter for default \"{Script.DefaultCreateArguments}\""); + var deleteArgs = ""; + if (!string.IsNullOrWhiteSpace(ret.DeleteScript) || + !string.IsNullOrWhiteSpace(ret.Script)) + { + deleteArgs = _arguments.TryGetArgument(args.DnsDeleteScriptArguments, input, $"Input parameters for delete script, or enter for default \"{Script.DefaultDeleteArguments}\""); + } + ProcessArgs(ret, createArgs, deleteArgs); + + return ret; + } + + public override ScriptOptions Default(Target target) + { + var args = _arguments.GetArguments<ScriptArguments>(); + var ret = new ScriptOptions(); + ProcessScripts(ret, args.DnsScript, args.DnsCreateScript, args.DnsDeleteScript); + if (!string.IsNullOrEmpty(ret.Script)) + { + if (!ret.Script.ValidFile(_log)) + { + _log.Error($"Invalid argument --{nameof(args.DnsScript).ToLower()}"); + return null; + } + } + else + { + if (!ret.CreateScript.ValidFile(_log)) + { + _log.Error($"Invalid argument --{nameof(args.DnsCreateScript).ToLower()}"); + return null; + } + if (!string.IsNullOrEmpty(ret.DeleteScript)) + { + if (!ret.DeleteScript.ValidFile(_log)) + { + _log.Error($"Invalid argument --{nameof(args.DnsDeleteScript).ToLower()}"); + return null; + } + } + } + + ProcessArgs(ret, args.DnsCreateScriptArguments, args.DnsDeleteScriptArguments); + return ret; + } + + /// <summary> + /// Choose the right script to run + /// </summary> + /// <param name="options"></param> + /// <param name="commonInput"></param> + /// <param name="createInput"></param> + /// <param name="deleteInput"></param> + private void ProcessScripts(ScriptOptions options, string commonInput, string createInput, string deleteInput) + { + if (!string.IsNullOrWhiteSpace(commonInput)) + { + if(!string.IsNullOrWhiteSpace(createInput)) + { + _log.Warning($"Ignoring --dnscreatescript because --dnsscript was provided"); + } + if (!string.IsNullOrWhiteSpace(deleteInput)) + { + _log.Warning("Ignoring --dnsdeletescript because --dnsscript was provided"); + } + } + + + if (string.IsNullOrWhiteSpace(commonInput) && + string.Equals(createInput, deleteInput, StringComparison.CurrentCultureIgnoreCase)) + { + commonInput = createInput; + } + if (!string.IsNullOrWhiteSpace(commonInput)) + { + options.Script = commonInput; + } + else + { + options.CreateScript = string.IsNullOrWhiteSpace(createInput) ? null : createInput; + options.DeleteScript = string.IsNullOrWhiteSpace(deleteInput) ? null : deleteInput; + } + } + + private void ProcessArgs(ScriptOptions options, string createInput, string deleteInput) + { + if (!string.IsNullOrWhiteSpace(createInput) && + createInput != Script.DefaultCreateArguments) + { + options.CreateScriptArguments = createInput; + } + if (!string.IsNullOrWhiteSpace(options.DeleteScript) || + !string.IsNullOrWhiteSpace(options.Script)) + { + if (!string.IsNullOrWhiteSpace(deleteInput) && + deleteInput != Script.DefaultDeleteArguments) + { + options.DeleteScriptArguments = deleteInput; + } + } + } + + public override bool CanValidate(Target target) + { + return true; + } + } + +} |