Can configure multiple dynamic dns

This commit is contained in:
nicolas.dorier 2019-07-25 18:29:18 +09:00
parent db57b5ae80
commit 63472d54d7
No known key found for this signature in database
GPG Key ID: 6618763EF09186FE
7 changed files with 195 additions and 56 deletions

View File

@ -146,6 +146,9 @@
<Content Update="Views\Home\BitpayTranslator.cshtml">
<Pack>$(IncludeRazorContentInPack)</Pack>
</Content>
<Content Update="Views\Server\DynamicDnsServices.cshtml">
<Pack>$(IncludeRazorContentInPack)</Pack>
</Content>
<Content Update="Views\Server\LightningChargeServices.cshtml">
<Pack>$(IncludeRazorContentInPack)</Pack>
</Content>

View File

@ -548,7 +548,7 @@ namespace BTCPayServer.Controllers
result.OtherExternalServices.Add(new ServicesViewModel.OtherExternalService()
{
Name = "Dynamic DNS",
Link = this.Url.Action(nameof(DynamicDnsService))
Link = this.Url.Action(nameof(DynamicDnsServices))
});
foreach (var torService in _torServices.Services)
{
@ -806,37 +806,99 @@ namespace BTCPayServer.Controllers
return RedirectToAction(nameof(Service), new { cryptoCode = cryptoCode, serviceName = serviceName, nonce = nonce });
}
[Route("server/services/dynamic-dns")]
public async Task<IActionResult> DynamicDnsService()
public async Task<IActionResult> DynamicDnsServices()
{
var settings = (await _SettingsRepository.GetSettingAsync<DynamicDnsSettings>()) ?? new DynamicDnsSettings();
return View(settings.Services.Select(s => new DynamicDnsViewModel()
{
Settings = s
}).ToArray());
}
[Route("server/services/dynamic-dns/{hostname}")]
public async Task<IActionResult> DynamicDnsServices(string hostname)
{
var settings = (await _SettingsRepository.GetSettingAsync<DynamicDnsSettings>()) ?? new DynamicDnsSettings();
var service = settings.Services.FirstOrDefault(s => s.Hostname.Equals(hostname, StringComparison.OrdinalIgnoreCase));
if (service == null)
return NotFound();
var vm = new DynamicDnsViewModel();
vm.Settings = settings;
return View(vm);
vm.Modify = true;
vm.Settings = service;
return View(nameof(DynamicDnsService), vm);
}
[Route("server/services/dynamic-dns")]
[HttpPost]
public async Task<IActionResult> DynamicDnsService(DynamicDnsViewModel viewModel, string command = null)
{
if (!ModelState.IsValid)
{
return View(viewModel);
}
if (command == "Save")
{
var settings = (await _SettingsRepository.GetSettingAsync<DynamicDnsSettings>()) ?? new DynamicDnsSettings();
var i = settings.Services.FindIndex(d => d.Hostname.Equals(viewModel.Settings.Hostname, StringComparison.OrdinalIgnoreCase));
if (i != -1)
{
ModelState.AddModelError(nameof(viewModel.Settings.Hostname), "This hostname already exists");
return View(viewModel);
}
string errorMessage = await viewModel.Settings.SendUpdateRequest(HttpClientFactory.CreateClient());
if (errorMessage == null)
{
StatusMessage = $"The Dynamic DNS has been successfully queried, your configuration is saved";
viewModel.Settings.LastUpdated = DateTimeOffset.UtcNow;
settings.Services.Add(viewModel.Settings);
await _SettingsRepository.UpdateSetting(settings);
return RedirectToAction(nameof(DynamicDnsServices));
}
else
{
ModelState.AddModelError(string.Empty, errorMessage);
return View(viewModel);
}
}
else
{
return View(new DynamicDnsViewModel() { Settings = new DynamicDnsService() });
}
}
[Route("server/services/dynamic-dns/{hostname}")]
[HttpPost]
public async Task<IActionResult> DynamicDnsService(DynamicDnsViewModel viewModel, string hostname, string command = null)
{
var settings = (await _SettingsRepository.GetSettingAsync<DynamicDnsSettings>()) ?? new DynamicDnsSettings();
var i = settings.Services.FindIndex(d => d.Hostname.Equals(hostname, StringComparison.OrdinalIgnoreCase));
if (i == -1)
return NotFound();
if (viewModel.Settings.Password == null)
viewModel.Settings.Password = settings.Services[i].Password;
if (!viewModel.Settings.Enabled)
{
StatusMessage = $"The Dynamic DNS service has been disabled";
viewModel.Settings.LastUpdated = null;
await _SettingsRepository.UpdateSetting(viewModel.Settings);
return RedirectToAction();
}
string errorMessage = await viewModel.Settings.SendUpdateRequest(HttpClientFactory.CreateClient());
if (errorMessage == null)
{
StatusMessage = $"The Dynamic DNS has been successfully queried, your configuration is saved";
viewModel.Settings.LastUpdated = DateTimeOffset.UtcNow;
await _SettingsRepository.UpdateSetting(viewModel.Settings);
}
else
{
StatusMessage = errorMessage;
string errorMessage = await viewModel.Settings.SendUpdateRequest(HttpClientFactory.CreateClient());
if (errorMessage == null)
{
StatusMessage = $"The Dynamic DNS has been successfully queried, your configuration is saved";
viewModel.Settings.LastUpdated = DateTimeOffset.UtcNow;
}
else
{
ModelState.AddModelError(string.Empty, errorMessage);
return View(viewModel);
}
}
return RedirectToAction();
settings.Services[i] = viewModel.Settings;
await _SettingsRepository.UpdateSetting(settings);
this.RouteData.Values.Remove(nameof(hostname));
return RedirectToAction(nameof(DynamicDnsServices));
}
[Route("server/services/ssh")]

View File

@ -35,27 +35,30 @@ namespace BTCPayServer.HostedServices
using (var timeout = CancellationTokenSource.CreateLinkedTokenSource(Cancellation))
{
var settings = await SettingsRepository.GetSettingAsync<DynamicDnsSettings>();
if (settings?.Enabled is true && (settings.LastUpdated is null ||
(DateTimeOffset.UtcNow - settings.LastUpdated) > Period))
foreach (var service in settings.Services)
{
timeout.CancelAfter(TimeSpan.FromSeconds(20.0));
try
if (service?.Enabled is true && (service.LastUpdated is null ||
(DateTimeOffset.UtcNow - service.LastUpdated) > Period))
{
var errorMessage = await settings.SendUpdateRequest(HttpClientFactory.CreateClient());
if (errorMessage == null)
timeout.CancelAfter(TimeSpan.FromSeconds(20.0));
try
{
Logs.PayServer.LogInformation("Dynamic DNS service successfully refresh the DNS record");
settings.LastUpdated = DateTimeOffset.UtcNow;
await SettingsRepository.UpdateSetting(settings);
var errorMessage = await service.SendUpdateRequest(HttpClientFactory.CreateClient());
if (errorMessage == null)
{
Logs.PayServer.LogInformation("Dynamic DNS service successfully refresh the DNS record");
service.LastUpdated = DateTimeOffset.UtcNow;
await SettingsRepository.UpdateSetting(settings);
}
else
{
Logs.PayServer.LogWarning($"Dynamic DNS service is enabled but the request to the provider failed: {errorMessage}");
}
}
else
catch (OperationCanceledException) when (timeout.IsCancellationRequested)
{
Logs.PayServer.LogWarning($"Dynamic DNS service is enabled but the request to the provider failed: {errorMessage}");
}
}
catch (OperationCanceledException) when (timeout.IsCancellationRequested)
{
}
}
}
using (var delayCancel = CancellationTokenSource.CreateLinkedTokenSource(Cancellation))

View File

@ -19,8 +19,8 @@ namespace BTCPayServer.Models.ServerViewModels
public string Name { get; set; }
public string Url { get; set; }
}
public DynamicDnsSettings Settings { get; set; }
public bool Modify { get; set; }
public DynamicDnsService Settings { get; set; }
public string LastUpdated
{
get

View File

@ -5,7 +5,6 @@ using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using BTCPayServer.Hosting;
@ -15,15 +14,21 @@ using Newtonsoft.Json;
namespace BTCPayServer.Services
{
public class DynamicDnsSettings
{
public List<DynamicDnsService> Services { get; set; } = new List<DynamicDnsService>();
}
public class DynamicDnsService
{
[Display(Name = "Url of the Dynamic DNS service you are using")]
[Required]
public string ServiceUrl { get; set; }
public string Login { get; set; }
[DataType(DataType.Password)]
public string Password { get; set; }
[Display(Name = "Your dynamic DNS hostname")]
[Required]
public string Hostname { get; set; }
public bool Enabled { get; set; }
public bool Enabled { get; set; } = true;
[JsonConverter(typeof(NBitcoin.JsonConverters.DateTimeToUnixTimeConverter))]
public DateTimeOffset? LastUpdated { get; set; }
@ -54,7 +59,7 @@ namespace BTCPayServer.Services
HttpRequestMessage webRequest = new HttpRequestMessage();
if (!Uri.TryCreate(ServiceUrl, UriKind.Absolute, out var uri) || uri.HostNameType == UriHostNameType.Unknown)
{
throw new FormatException($"Invalid {ServiceUrl}");
throw new FormatException($"Invalid service url");
}
var builder = new UriBuilder(uri);

View File

@ -4,20 +4,21 @@
}
<h4>Dynamic DNS Settings</h4>
<h4>Dynamic DNS Service</h4>
<partial name="_StatusMessage" for="@TempData["TempDataProperty-StatusMessage"]" />
@if (!this.ViewContext.ModelState.IsValid)
{
<div class="row">
<div class="col-md-8">
<div asp-validation-summary="All" class="text-danger"></div>
</div>
</div>
}
<div class="row">
<div class="col-md-8">
<div class="form-group">
<p>
<span>Dynamic DNS service allows you to have a stable DNS name pointing to your server, even if your IP address change regulary. <br />
This is recommended if you are hosting BTCPayServer at home and wish to have a clearnet HTTPS address to access your server.</span>
</p>
<p>Note that you need to properly configure your NAT and BTCPayServer install to get HTTPS certificate.</p>
</div>
<form method="post">
<div class="form-group">
<input type="hidden" asp-for="Modify" />
<div class="form-group">
<label asp-for="Settings.ServiceUrl"></label>
<input id="ServiceUrl" asp-for="Settings.ServiceUrl" class="form-control" placeholder="Url" />
@ -31,14 +32,22 @@
</div>
<div class="form-group">
<label asp-for="Settings.Hostname"></label>
<input asp-for="Settings.Hostname" class="form-control" placeholder="Hostname" />
<p class="form-text text-muted">
<span>The DNS record has been refreshed: </span>
@if (Model.LastUpdated != null)
{
<span>@Model.LastUpdated</span>
}
</p>
@if (Model.Modify)
{
<input asp-for="Settings.Hostname" class="form-control" readonly placeholder="Hostname" />
<p class="form-text text-muted">
<span>The DNS record has been refreshed: </span>
@if (Model.LastUpdated != null)
{
<span>@Model.LastUpdated</span>
}
</p>
}
else
{
<input asp-for="Settings.Hostname" class="form-control" placeholder="Hostname" />
<span asp-validation-for="Settings.Hostname" class="text-danger"></span>
}
</div>
<div class="form-group">
<label asp-for="Settings.Login"></label>
@ -48,11 +57,13 @@
<label asp-for="Settings.Password"></label>
<input asp-for="Settings.Password" class="form-control" placeholder="Password" />
</div>
<div class="form-group">
<label asp-for="Settings.Enabled"></label>
<input asp-for="Settings.Enabled" class="form-check-inline" type="checkbox" />
</div>
@if (Model.Modify)
{
<div class="form-group">
<label asp-for="Settings.Enabled"></label>
<input asp-for="Settings.Enabled" class="form-check-inline" type="checkbox" />
</div>
}
<button name="command" class="btn btn-primary" type="submit" value="Save">Save</button>
</div>
</form>

View File

@ -0,0 +1,55 @@
@model BTCPayServer.Models.ServerViewModels.DynamicDnsViewModel[]
@{
ViewData.SetActivePageAndTitle(ServerNavPages.Services);
}
<h4>Dynamic DNS Settings</h4>
<partial name="_StatusMessage" for="@TempData["TempDataProperty-StatusMessage"]" />
<div class="row">
<div class="col-md-8">
<div class="form-group">
<p>
<span>
Dynamic DNS service allows you to have a stable DNS name pointing to your server, even if your IP address change regulary. <br />
This is recommended if you are hosting BTCPayServer at home and wish to have a clearnet HTTPS address to access your server.
</span>
</p>
<p>Note that you need to properly configure your NAT and BTCPayServer install to get HTTPS certificate.</p>
</div>
<form method="post" asp-action="DynamicDnsService">
<button class="btn btn-primary" type="submit"><span class="fa fa-plus"></span> Add Dynamic DNS</button>
</form>
<table class="table table-sm table-responsive-md">
<thead>
<tr>
<th>Hostname</th>
<th>Last updated</th>
<th style="text-align:center;">Enabled</th>
<th style="text-align:right">Actions</th>
</tr>
</thead>
<tbody>
@foreach (var service in Model)
{
<tr>
<td>@service.Settings.Hostname</td>
<td>@service.LastUpdated</td>
<td style="text-align:center;">
@if(service.Settings.Enabled)
{
<span class="fa fa-check"></span>
}
else
{
<span class="fa fa-times"></span>
}
</td>
<td><a asp-action="DynamicDnsService" asp-route-hostname="@service.Settings.Hostname">Edit</a> <span> - </span> <a asp-action="DynamicDnsServiceDelete" asp-route-hostname="@service.Settings.Hostname">Remove</a></td>
</tr>
}
</tbody>
</table>
</div>
</div>