Ejemplo n.º 1
0
        public override async Task <ScriptOptions> Aquire(Target target, IInputService inputService, RunLevel runLevel)
        {
            var ret  = new ScriptOptions();
            var args = _arguments.GetArguments <ScriptArguments>();

            inputService.Show("Full instructions", "https://www.win-acme.com/reference/plugins/installation/script");
            do
            {
                ret.Script = await _arguments.TryGetArgument(args?.Script, inputService, "Enter the path to the script that you want to run after renewal");
            }while (!ret.Script.ValidFile(_log));

            inputService.Show("{CertCommonName}", "Common name (primary domain name)");
            inputService.Show("{CachePassword}", ".pfx password");
            inputService.Show("{CacheFile}", ".pfx full path");
            inputService.Show("{CertFriendlyName}", "Certificate friendly name");
            inputService.Show("{CertThumbprint}", "Certificate thumbprint");
            inputService.Show("{StoreType}", $"Type of store ({CentralSslOptions.PluginName}/{CertificateStoreOptions.PluginName}/{PemFilesOptions.PluginName})");
            inputService.Show("{StorePath}", "Path to the store");
            inputService.Show("{RenewalId}", "Renewal identifier");
            inputService.Show("{OldCertCommonName}", "Common name (primary domain name) of the previously issued certificate");
            inputService.Show("{OldCertFriendlyName}", "Friendly name of the previously issued certificate");
            inputService.Show("{OldCertThumbprint}", "Thumbprint of the previously issued certificate");
            ret.ScriptParameters = await _arguments.TryGetArgument(
                args?.ScriptParameters,
                inputService,
                "Enter the parameter format string for the script, e.g. \"--hostname {CertCommonName}\"");

            return(ret);
        }
Ejemplo n.º 2
0
        public override async Task <CsrOptions> Aquire(IInputService inputService, RunLevel runLevel)
        {
            var args = _arguments.GetArguments <CsrArguments>();
            var ret  = new CsrOptions();

            do
            {
                ret.CsrFile = await _arguments.TryGetArgument(
                    args.CsrFile,
                    inputService,
                    "Enter the path to the CSR");
            }while (!ret.CsrFile.ValidFile(_log));

            string pkFile;

            do
            {
                pkFile = await _arguments.TryGetArgument(args.CsrFile,
                                                         inputService,
                                                         "Enter the path to the corresponding private key, or <ENTER> to create a certificate without one");
            }while (!(string.IsNullOrWhiteSpace(pkFile) || pkFile.ValidFile(_log)));

            if (!string.IsNullOrWhiteSpace(pkFile))
            {
                ret.PkFile = pkFile;
            }

            return(ret);
        }
Ejemplo n.º 3
0
        public override async Task <CentralSslOptions?> Aquire(IInputService input, RunLevel runLevel)
        {
            var args = _arguments.GetArguments <CentralSslArguments>();

            // Get path from command line, default setting or user input
            var path = args?.CentralSslStore;

            if (string.IsNullOrWhiteSpace(path))
            {
                path = CentralSsl.DefaultPath(_settings);
            }
            while (string.IsNullOrWhiteSpace(path) || !path.ValidPath(_log))
            {
                path = await input.RequestString("Path to Central Certificate Store");
            }

            // Get password from command line, default setting or user input
            var password = args?.PfxPassword;

            if (string.IsNullOrWhiteSpace(password))
            {
                password = CentralSsl.DefaultPassword(_settings);
            }
            if (string.IsNullOrEmpty(password))
            {
                password = await input.ReadPassword("Password to use for the .pfx files, or <Enter> for none");
            }
            return(Create(path, password, args?.KeepExisting ?? false));
        }
Ejemplo n.º 4
0
        public override async Task <IISWebOptions> Aquire(Target target, IInputService inputService, RunLevel runLevel)
        {
            var args = _arguments.GetArguments <IISWebArguments>();
            var ret  = new IISWebOptions(args);
            var ask  = true;

            if (target.IIS)
            {
                if (runLevel.HasFlag(RunLevel.Advanced))
                {
                    ask = await inputService.PromptYesNo("Use different site for installation?", false);
                }
                else
                {
                    ask = false;
                }
            }
            if (ask)
            {
                var chosen = await inputService.ChooseRequired("Choose site to create new bindings",
                                                               _iisClient.WebSites,
                                                               x => Choice.Create(x.Id, x.Name, x.Id.ToString()));

                ret.SiteId = chosen;
            }
            return(ret);
        }
        public async Task Aquire(IAzureOptionsCommon options)
        {
            var az           = _arguments.GetArguments <T>();
            var environments = new List <Choice <Func <Task> > >(
                AzureEnvironments.ResourceManagerUrls
                .OrderBy(kvp => kvp.Key)
                .Select(kvp =>
                        Choice.Create <Func <Task> >(() =>
            {
                options.AzureEnvironment = kvp.Key;
                return(Task.CompletedTask);
            },
                                                     description: kvp.Key,
                                                     @default: kvp.Key == AzureEnvironments.AzureCloud)))
            {
                Choice.Create <Func <Task> >(async() => await InputUrl(_input, options), "Use a custom resource manager url")
            };

            var chosen = await _input.ChooseFromMenu("Which Azure environment are you using?", environments);

            await chosen.Invoke();

            options.UseMsi = az.AzureUseMsi || await _input.PromptYesNo("Do you want to use a managed service identity?", true);

            if (!options.UseMsi)
            {
                // These options are only necessary for client id/secret authentication.
                options.TenantId = await _arguments.TryGetArgument(az.AzureTenantId, _input, "Directory/tenant id");

                options.ClientId = await _arguments.TryGetArgument(az.AzureClientId, _input, "Application client id");

                options.Secret = new ProtectedString(await _arguments.TryGetArgument(az.AzureSecret, _input, "Application client secret", true));
            }
        }
        public override async Task <PemFilesOptions?> Aquire(IInputService input, RunLevel runLevel)
        {
            var args = _arguments.GetArguments <PemFilesArguments>();
            var path = args?.PemFilesPath;

            if (string.IsNullOrWhiteSpace(path))
            {
                path = PemFiles.DefaultPath(_settings);
            }
            while (string.IsNullOrWhiteSpace(path) || !path.ValidPath(_log))
            {
                path = await input.RequestString("Path to folder where .pem files are stored");
            }

            // Get password from command line, default setting or user input
            var password = args?.PemPassword;

            if (string.IsNullOrWhiteSpace(password))
            {
                password = _settings.Store.PemFiles?.DefaultPassword;
            }
            if (string.IsNullOrEmpty(password))
            {
                password = await input.ReadPassword("Password to use for the private key .pem file or <Enter> for none");
            }
            return(Create(path, password));
        }
Ejemplo n.º 7
0
        public override async Task <PfxFileOptions?> Aquire(IInputService input, RunLevel runLevel)
        {
            var args = _arguments.GetArguments <PfxFileArguments>();

            // Get path from command line, default setting or user input
            var path = args?.PfxFilePath;

            if (string.IsNullOrWhiteSpace(path))
            {
                path = _settings.Store.PfxFile?.DefaultPath;
            }
            while (string.IsNullOrWhiteSpace(path) || !path.ValidPath(_log))
            {
                path = await input.RequestString("Path to folder to store the .pfx file");
            }

            // Get password from command line, default setting or user input
            var password = args?.PfxPassword;

            if (string.IsNullOrWhiteSpace(password))
            {
                password = _settings.Store.PfxFile?.DefaultPassword;
            }
            if (string.IsNullOrEmpty(password))
            {
                password = await input.ReadPassword("Password to use for the .pfx files or <Enter> for none");
            }
            return(Create(path, password));
        }
Ejemplo n.º 8
0
        public override Task <DigitalOceanOptions> Aquire(Target target, IInputService inputService, RunLevel runLevel)
        {
            var arguments = _arguments.GetArguments <DigitalOceanArguments>();

            return(Task.FromResult(new DigitalOceanOptions
            {
                ApiToken = new ProtectedString(arguments.ApiToken)
            }));
        }
Ejemplo n.º 9
0
        public override async Task <ScriptOptions> Aquire(Target target, IInputService input, RunLevel runLevel)
        {
            var args         = _arguments.GetArguments <ScriptArguments>();
            var ret          = new ScriptOptions();
            var createScript = "";

            do
            {
                createScript = await _arguments.TryGetArgument(args.DnsCreateScript, input, "Path to script that creates DNS records");
            }while (!createScript.ValidFile(_log));

            var deleteScript = "";
            var chosen       = await input.ChooseFromList(
                "How to delete records after validation",
                new List <Choice <Func <Task> > >()
            {
                Choice.Create <Func <Task> >(() => {
                    deleteScript = createScript;
                    return(Task.CompletedTask);
                }, "Using the same script"),
                Choice.Create <Func <Task> >(async() => {
                    do
                    {
                        deleteScript = await _arguments.TryGetArgument(
                            args.DnsDeleteScript,
                            input,
                            "Path to script that deletes DNS records");
                    }while (!deleteScript.ValidFile(_log));
                }, "Using a different script"),
                Choice.Create <Func <Task> >(() => Task.CompletedTask, "Do not delete")
            });

            await chosen.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 = await _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 = await _arguments.TryGetArgument(args.DnsDeleteScriptArguments, input, $"Input parameters for delete script, or enter for default \"{Script.DefaultDeleteArguments}\"");
            }
            ProcessArgs(ret, createArgs, deleteArgs);
            return(ret);
        }
Ejemplo n.º 10
0
        public override async Task <PemFilesOptions?> Aquire(IInputService input, RunLevel runLevel)
        {
            var args = _arguments.GetArguments <PemFilesArguments>();
            var path = args?.PemFilesPath;

            if (string.IsNullOrWhiteSpace(path))
            {
                path = PemFiles.DefaultPath(_settings);
            }
            while (string.IsNullOrWhiteSpace(path) || !path.ValidPath(_log))
            {
                path = await input.RequestString("Path to folder where .pem files are stored");
            }
            return(Create(path));
        }
Ejemplo n.º 11
0
        public override IISBindingOptions Default(IArgumentsService arguments)
        {
            var ret       = new IISBindingOptions();
            var args      = arguments.GetArguments <IISBindingArguments>();
            var hostName  = arguments.TryGetRequiredArgument(nameof(args.Host), args.Host).ToLower();
            var rawSiteId = args.SiteId;
            var filterSet = _helper.GetBindings(false, false);

            if (!string.IsNullOrEmpty(rawSiteId))
            {
                if (long.TryParse(rawSiteId, out long siteId))
                {
                    filterSet = filterSet.Where(x => x.SiteId == siteId).ToList();
                }
                else
                {
                    _log.Error("Invalid SiteId {siteId}", rawSiteId);
                    return(null);
                }
            }
            var chosenTarget = filterSet.Where(x => x.HostUnicode == hostName || x.HostPunycode == hostName).FirstOrDefault();

            if (chosenTarget != null)
            {
                ret.SiteId = chosenTarget.SiteId;
                ret.Host   = chosenTarget.HostUnicode;
                ret.FriendlyNameSuggestion = chosenTarget.HostUnicode;
                return(ret);
            }
            else
            {
                return(null);
            }
        }
Ejemplo n.º 12
0
        public override ScriptOptions Default(Target target, IArgumentsService arguments)
        {
            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))
                {
                    throw new ArgumentException(nameof(args.DnsCreateScript));
                }
            }
            else
            {
                if (!ret.CreateScript.ValidFile(_log))
                {
                    throw new ArgumentException(nameof(args.DnsCreateScript));
                }
                if (!string.IsNullOrEmpty(ret.DeleteScript))
                {
                    if (!ret.DeleteScript.ValidFile(_log))
                    {
                        throw new ArgumentException(nameof(args.DnsDeleteScript));
                    }
                }
            }

            ProcessArgs(ret, args.DnsCreateScriptArguments, args.DnsDeleteScriptArguments);
            return(ret);
        }
Ejemplo n.º 13
0
        public NetworkCredentialOptions(IArgumentsService arguments, IInputService input)
        {
            var args = arguments.GetArguments <NetworkCredentialArguments>();

            UserName = arguments.TryGetArgument(args.UserName, input, "Username").Result;
            Password = new ProtectedString(arguments.TryGetArgument(args.Password, input, "Password", true).Result);
        }
Ejemplo n.º 14
0
        public NetworkCredentialOptions(IArgumentsService arguments)
        {
            var args = arguments.GetArguments <NetworkCredentialArguments>();

            UserName = arguments.TryGetRequiredArgument(nameof(args.UserName), args.UserName);
            Password = new ProtectedString(arguments.TryGetRequiredArgument(nameof(args.Password), args.Password));
        }
Ejemplo n.º 15
0
        public override ScriptOptions Default(Target target, IArgumentsService arguments)
        {
            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);
        }
Ejemplo n.º 16
0
        public override Task <IISSiteOptions> Default()
        {
            var ret       = new IISSiteOptions();
            var args      = _arguments.GetArguments <IISSiteArguments>();
            var rawSiteId = _arguments.TryGetRequiredArgument(nameof(args.SiteId), args.SiteId);

            if (long.TryParse(rawSiteId, out var siteId))
            {
                var site = _siteHelper.GetSites(false).FirstOrDefault(binding => binding.Id == siteId);
                if (site != null)
                {
                    ret.SiteId = site.Id;
                    if (_optionsHelper.DefaultAdvancedOptions(args, site.Hosts, ret))
                    {
                        return(Task.FromResult(ret));
                    }
                }
                else
                {
                    _log.Error("Unable to find SiteId {siteId}", siteId);
                }
            }
            else
            {
                _log.Error("Invalid SiteId {siteId}", args.SiteId);
            }
            return(Task.FromResult(default(IISSiteOptions)));
        }
Ejemplo n.º 17
0
        public override CentralSslOptions Default(IArgumentsService arguments)
        {
            var args = arguments.GetArguments <CentralSslArguments>();
            var path = Settings.Default.DefaultCentralSslStore;

            if (string.IsNullOrWhiteSpace(path))
            {
                path = arguments.TryGetRequiredArgument(nameof(args.CentralSslStore), args.CentralSslStore);
            }

            var password = Settings.Default.DefaultCentralSslPfxPassword;

            if (string.IsNullOrWhiteSpace(args.PfxPassword))
            {
                password = args.PfxPassword;
            }

            if (path.ValidPath(_log))
            {
                return(Create(path, password, args.KeepExisting));
            }
            else
            {
                throw new Exception("Invalid path specified");
            }
        }
Ejemplo n.º 18
0
        public override CentralSslOptions Aquire(IArgumentsService arguments, IInputService input, RunLevel runLevel)
        {
            var args = arguments.GetArguments <CentralSslArguments>();

            // Get path from command line, default setting or user input
            var path = args.CentralSslStore;

            if (string.IsNullOrWhiteSpace(path))
            {
                path = Settings.Default.DefaultCentralSslStore;
            }
            while (string.IsNullOrWhiteSpace(path) || !path.ValidPath(_log))
            {
                path = input.RequestString("Path to Central Certificate Store");
            }

            // Get password from command line, default setting or user input
            var password = args.PfxPassword;

            if (string.IsNullOrWhiteSpace(password))
            {
                password = Settings.Default.DefaultCentralSslPfxPassword;
            }
            if (string.IsNullOrEmpty(password))
            {
                password = input.ReadPassword("Password to use for the PFX files, or enter for none");
            }
            return(Create(path, password, args.KeepExisting));
        }
Ejemplo n.º 19
0
        public override Task <IISBindingOptions> Default()
        {
            var ret       = new IISBindingOptions();
            var args      = _arguments.GetArguments <IISBindingArguments>();
            var hostName  = _arguments.TryGetRequiredArgument(nameof(args.Host), args.Host).ToLower();
            var rawSiteId = args.SiteId;
            var filterSet = _helper.GetBindings();

            if (!string.IsNullOrEmpty(rawSiteId))
            {
                if (long.TryParse(rawSiteId, out var siteId))
                {
                    filterSet = filterSet.Where(x => x.SiteId == siteId).ToList();
                }
                else
                {
                    _log.Error("Invalid SiteId {siteId}", rawSiteId);
                    return(Task.FromResult(default(IISBindingOptions)));
                }
            }
            var chosenTarget = filterSet.Where(x => x.HostUnicode == hostName || x.HostPunycode == hostName).FirstOrDefault();

            if (chosenTarget != null)
            {
                ret.SiteId = chosenTarget.SiteId;
                ret.Host   = chosenTarget.HostUnicode;
                return(Task.FromResult(ret));
            }
            else
            {
                return(Task.FromResult(default(IISBindingOptions)));
            }
        }
Ejemplo n.º 20
0
        public override IISWebOptions Aquire(Target target, IArgumentsService arguments, IInputService inputService, RunLevel runLevel)
        {
            var args = arguments.GetArguments <IISWebArguments>();
            var ret  = new IISWebOptions(args);
            var ask  = true;

            if (target.IIS)
            {
                if (runLevel.HasFlag(RunLevel.Advanced))
                {
                    ask = inputService.PromptYesNo("Use different site for installation?");
                }
                else
                {
                    ask = false;
                }
            }
            if (ask)
            {
                var chosen = inputService.ChooseFromList("Choose site to create new bindings",
                                                         _iisClient.WebSites,
                                                         x => new Choice <long>(x.Id)
                {
                    Description = x.Name,
                    Command     = x.Id.ToString()
                },
                                                         false);
                ret.SiteId = chosen;
            }
            return(ret);
        }
        public override IISSitesOptions Default(IArgumentsService arguments)
        {
            var ret        = new IISSitesOptions();
            var args       = arguments.GetArguments <IISSiteArguments>();
            var sites      = _helper.GetSites(false, false);
            var rawSiteIds = arguments.TryGetRequiredArgument(nameof(args.SiteId), args.SiteId);

            sites = ProcessSiteIds(ret, sites, rawSiteIds);
            if (sites == null)
            {
                return(null);
            }
            ret.ExcludeBindings = args.ExcludeBindings.ParseCsv();
            if (ret.ExcludeBindings != null)
            {
                ret.ExcludeBindings = ret.ExcludeBindings.Select(x => x.ConvertPunycode()).ToList();
            }
            var commonName = args.CommonName;

            if (!string.IsNullOrWhiteSpace(commonName))
            {
                commonName = commonName.ToLower().Trim().ConvertPunycode();
                if (sites.Any(s => s.Hosts.Contains(commonName)) &&
                    (ret.ExcludeBindings == null || !ret.ExcludeBindings.Contains(commonName)))
                {
                    ret.CommonName = commonName;
                }
                else
                {
                    _log.Error("Common name {commonName} not found or excluded", commonName);
                    return(null);
                }
            }
            return(ret);
        }
Ejemplo n.º 22
0
        /// <summary>
        /// Ask the user to accept the terms of service dictated
        /// by the ACME service operator
        /// </summary>
        /// <param name="filename"></param>
        /// <param name="content"></param>
        /// <returns></returns>
        private async Task <bool> AcceptTos(string filename, byte[] content)
        {
            var tosPath = Path.Combine(_settings.Client.ConfigurationPath, filename);

            _log.Verbose("Writing terms of service to {path}", tosPath);
            await File.WriteAllBytesAsync(tosPath, content);

            _input.CreateSpace();
            _input.Show($"Terms of service", tosPath);
            if (_arguments.GetArguments <AccountArguments>()?.AcceptTos ?? false)
            {
                return(true);
            }
            if (await _input.PromptYesNo($"Open in default application?", false))
            {
                try
                {
                    Process.Start(new ProcessStartInfo
                    {
                        FileName        = tosPath,
                        UseShellExecute = true
                    });
                }
                catch (Exception ex)
                {
                    _log.Error(ex, "Unable to start application");
                }
            }
            return(await _input.PromptYesNo($"Do you agree with the terms?", true));
        }
Ejemplo n.º 23
0
        public override IISSiteOptions Default(IArgumentsService arguments)
        {
            var ret       = new IISSiteOptions();
            var args      = arguments.GetArguments <IISSiteArguments>();
            var rawSiteId = arguments.TryGetRequiredArgument(nameof(args.SiteId), args.SiteId);

            if (long.TryParse(rawSiteId, out long siteId))
            {
                var site = _siteHelper.GetSites(false, false).FirstOrDefault(binding => binding.Id == siteId);
                if (site != null)
                {
                    ret.SiteId = site.Id;
                    if (_optionsHelper.DefaultAdvancedOptions(args, site.Hosts, RunLevel.Unattended, ret))
                    {
                        return(ret);
                    }
                }
                else
                {
                    _log.Error("Unable to find SiteId {siteId}", siteId);
                }
            }
            else
            {
                _log.Error("Invalid SiteId {siteId}", args.SiteId);
            }
            return(null);
        }
Ejemplo n.º 24
0
        public override SelfHostingOptions Default(Target target, IArgumentsService arguments)
        {
            var args = arguments.GetArguments <SelfHostingArguments>();

            return(new SelfHostingOptions()
            {
                Port = args.ValidationPort
            });
        }
Ejemplo n.º 25
0
        public override RsaOptions Default(IArgumentsService arguments)
        {
            var args = arguments.GetArguments <CsrArguments>();

            return(new RsaOptions()
            {
                OcspMustStaple = args.OcspMustStaple
            });
        }
Ejemplo n.º 26
0
        public override async Task <SelfHostingOptions?> Default(Target target)
        {
            var args = _arguments.GetArguments <SelfHostingArguments>();

            return(new SelfHostingOptions()
            {
                Port = args.ValidationPort
            });
        }
Ejemplo n.º 27
0
        public override DreamhostOptions Aquire(Target target, IArgumentsService arguments, IInputService input, RunLevel runLevel)
        {
            var args = arguments.GetArguments <DreamhostArguments>();

            return(new DreamhostOptions()
            {
                ApiKey = new ProtectedString(arguments.TryGetArgument(args.ApiKey, input, "ApiKey", true)),
            });
        }
Ejemplo n.º 28
0
        public override Task <SelfHostingOptions> Default(Target target)
        {
            var args = _arguments.GetArguments <SelfHostingArguments>();

            return(Task.FromResult(new SelfHostingOptions()
            {
                Port = args.ValidationPort
            }));
        }
Ejemplo n.º 29
0
        public override DreamhostOptions Default(Target target, IArgumentsService arguments)
        {
            var az = arguments.GetArguments <DreamhostArguments>();

            return(new DreamhostOptions()
            {
                ApiKey = new ProtectedString(arguments.TryGetRequiredArgument(nameof(az.ApiKey), az.ApiKey)),
            });
        }
Ejemplo n.º 30
0
        public override Route53Options Default(Target target, IArgumentsService arguments)
        {
            var args = arguments.GetArguments <Route53Arguments>();

            return(new Route53Options
            {
                AccessKeyId = arguments.TryGetRequiredArgument(nameof(args.Route53AccessKeyId), args.Route53AccessKeyId),
                SecretAccessKey = new ProtectedString(arguments.TryGetRequiredArgument(nameof(args.Route53SecretAccessKey), args.Route53SecretAccessKey))
            });
        }