/// <summary> /// Can be used to write out server specific configuration, to handle extensionless files etc. /// </summary> /// <param name="target"></param> /// <param name="answerPath"></param> /// <param name="token"></param> private void WriteWebConfig(Http01ChallengeValidationDetails challenge) { if (_path == null) { throw new InvalidOperationException(); } if (_options.CopyWebConfig == true) { try { var partialPath = challenge.HttpResourcePath.Split('/').Last(); var destination = CombinePath(_path, challenge.HttpResourcePath.Replace(partialPath, "web.config")); if (!_filesWritten.Contains(destination)) { var content = GetWebConfig().Value; if (content != null) { _log.Debug("Writing web.config"); WriteFile(destination, content); _filesWritten.Add(destination); } } } catch (Exception ex) { _log.Warning("Unable to write web.config: {ex}", ex.Message);; } } }
/// <summary> /// Warm up the target site, giving the application a little /// time to start up before the validation request comes in. /// Mostly relevant to classic FileSystem validation /// </summary> /// <param name="uri"></param> private async Task <string> WarmupSite(Http01ChallengeValidationDetails challenge) { using var client = _proxy.GetHttpClient(false); var response = await client.GetAsync(challenge.HttpResourceUrl); return(await response.Content.ReadAsStringAsync()); }
/// <summary> /// Handle http challenge /// </summary> public async override Task PrepareChallenge(ValidationContext context, Http01ChallengeValidationDetails challenge) { // Should always have a value, confirmed by RenewalExecutor // check only to satifiy the compiler if (context.TargetPart != null) { Refresh(context.TargetPart); } await WriteAuthorizationFile(challenge); await WriteWebConfig(challenge); _log.Information("Answer should now be browsable at {answerUri}", challenge.HttpResourceUrl); if (_runLevel.HasFlag(RunLevel.Test) && _renewal.New) { if (await _input.PromptYesNo("[--test] Try in default browser?", false)) { Process.Start(new ProcessStartInfo { FileName = challenge.HttpResourceUrl, UseShellExecute = true }); await _input.Wait(); } } string?foundValue = null; try { var value = await WarmupSite(challenge); if (Equals(value, challenge.HttpResourceValue)) { _log.Information("Preliminary validation looks good, but the ACME server will be more thorough"); } else { _log.Warning("Preliminary validation failed, the server answered '{value}' instead of '{expected}'. The ACME server might have a different perspective", foundValue ?? "(null)", challenge.HttpResourceValue); } } catch (HttpRequestException hrex) { _log.Warning("Preliminary validation failed because '{hrex}'", hrex.Message); } catch (Exception ex) { _log.Error(ex, "Preliminary validation failed"); } }
/// <summary> /// Should create any directory structure needed and write the file for authorization /// </summary> /// <param name="answerPath">where the answerFile should be located</param> /// <param name="fileContents">the contents of the file to write</param> private void WriteAuthorizationFile(Http01ChallengeValidationDetails challenge) { if (_path == null) { throw new InvalidOperationException(); } var path = CombinePath(_path, challenge.HttpResourcePath); WriteFile(path, challenge.HttpResourceValue); if (!_filesWritten.Contains(path)) { _filesWritten.Add(path); } }
/// <summary> /// Should create any directory structure needed and write the file for authorization /// </summary> /// <param name="answerPath">where the answerFile should be located</param> /// <param name="fileContents">the contents of the file to write</param> private async Task WriteAuthorizationFile(Http01ChallengeValidationDetails challenge) { if (_path == null) { throw new InvalidOperationException("No path specified for HttpValidation"); } var path = CombinePath(_path, challenge.HttpResourcePath); await WriteFile(path, challenge.HttpResourceValue); if (!_filesWritten.Contains(path)) { _filesWritten.Add(path); } }