mirror of
https://github.com/btcpayserver/btcpayserver.git
synced 2025-02-20 13:34:37 +01:00
Add suggestion list for currency inputs (#3347)
* Move tagHelpers in their own directory * Add suggestion list for currency inputs
This commit is contained in:
parent
30db0cd4f4
commit
11d6588249
15 changed files with 280 additions and 224 deletions
|
@ -143,6 +143,8 @@ namespace BTCPayServer.Services.Rates
|
|||
return currencies;
|
||||
}
|
||||
|
||||
public IEnumerable<CurrencyData> Currencies => _Currencies.Values;
|
||||
|
||||
public CurrencyData GetCurrencyData(string currency, bool useFallback)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(currency);
|
||||
|
|
|
@ -1,51 +0,0 @@
|
|||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Razor.TagHelpers;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace BTCPayServer.Security
|
||||
{
|
||||
[HtmlTargetElement(Attributes = nameof(Permission))]
|
||||
public class PermissionTagHelper : TagHelper
|
||||
{
|
||||
private readonly IAuthorizationService _authorizationService;
|
||||
private readonly IHttpContextAccessor _httpContextAccessor;
|
||||
private readonly ILogger<PermissionTagHelper> _logger;
|
||||
|
||||
public PermissionTagHelper(IAuthorizationService authorizationService, IHttpContextAccessor httpContextAccessor, ILogger<PermissionTagHelper> logger)
|
||||
{
|
||||
_authorizationService = authorizationService;
|
||||
_httpContextAccessor = httpContextAccessor;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public string Permission { get; set; }
|
||||
public string PermissionResource { get; set; }
|
||||
|
||||
public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
|
||||
{
|
||||
if (string.IsNullOrEmpty(Permission))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var key = $"{Permission}_{PermissionResource}";
|
||||
if (!_httpContextAccessor.HttpContext.Items.TryGetValue(key, out var cachedResult))
|
||||
{
|
||||
var result = await _authorizationService.AuthorizeAsync(_httpContextAccessor.HttpContext.User,
|
||||
PermissionResource,
|
||||
Permission);
|
||||
|
||||
cachedResult = result;
|
||||
_httpContextAccessor.HttpContext.Items.Add(key, result);
|
||||
|
||||
}
|
||||
if (!((AuthorizationResult)cachedResult).Succeeded)
|
||||
{
|
||||
output.SuppressOutput();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,168 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.Encodings.Web;
|
||||
using System.Threading.Tasks;
|
||||
using BTCPayServer.Configuration;
|
||||
using BTCPayServer.Security;
|
||||
using BTCPayServer.Services;
|
||||
using Microsoft.AspNetCore.Mvc.Razor.TagHelpers;
|
||||
using Microsoft.AspNetCore.Mvc.Rendering;
|
||||
using Microsoft.AspNetCore.Mvc.Routing;
|
||||
using Microsoft.AspNetCore.Mvc.ViewFeatures;
|
||||
using Microsoft.AspNetCore.Razor.TagHelpers;
|
||||
using NBitcoin;
|
||||
using NBitcoin.Crypto;
|
||||
|
||||
namespace BTCPayServer.TagHelpers
|
||||
{
|
||||
[HtmlTargetElement("srv-model")]
|
||||
public class SrvModel : TagHelper
|
||||
{
|
||||
private readonly Safe _safe;
|
||||
private readonly ContentSecurityPolicies _csp;
|
||||
|
||||
public SrvModel(Safe safe, ContentSecurityPolicies csp)
|
||||
{
|
||||
_safe = safe;
|
||||
_csp = csp;
|
||||
}
|
||||
public string VarName { get; set; } = "srvModel";
|
||||
public object Model { get; set; }
|
||||
public override void Process(TagHelperContext context, TagHelperOutput output)
|
||||
{
|
||||
output.TagName = "script";
|
||||
output.TagMode = TagMode.StartTagAndEndTag;
|
||||
output.Attributes.Add(new TagHelperAttribute("type", "text/javascript"));
|
||||
var nonce = RandomUtils.GetUInt256().ToString().Substring(0, 32);
|
||||
output.Attributes.Add(new TagHelperAttribute("nonce", nonce));
|
||||
_csp.Add("script-src", $"'nonce-{nonce}'");
|
||||
output.Content.SetHtmlContent($"var {VarName} = {_safe.Json(Model)};");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add a nonce-* so the inline-script can pass CSP rule when they are rendered server-side
|
||||
/// </summary>
|
||||
[HtmlTargetElement("script")]
|
||||
public class CSPInlineScriptTagHelper : TagHelper
|
||||
{
|
||||
private readonly ContentSecurityPolicies _csp;
|
||||
|
||||
public CSPInlineScriptTagHelper(ContentSecurityPolicies csp)
|
||||
{
|
||||
_csp = csp;
|
||||
}
|
||||
|
||||
public override void Process(TagHelperContext context, TagHelperOutput output)
|
||||
{
|
||||
if (output.Attributes.ContainsName("src"))
|
||||
return;
|
||||
if (output.Attributes.TryGetAttribute("type", out var attr))
|
||||
{
|
||||
if (attr.Value?.ToString() != "text/javascript")
|
||||
return;
|
||||
}
|
||||
var nonce = RandomUtils.GetUInt256().ToString().Substring(0, 32);
|
||||
output.Attributes.Add(new TagHelperAttribute("nonce", nonce));
|
||||
_csp.Add("script-src", $"'nonce-{nonce}'");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add 'unsafe-hashes' and sha256- to allow inline event handlers in CSP
|
||||
/// </summary>
|
||||
[HtmlTargetElement(Attributes = "onclick")]
|
||||
[HtmlTargetElement(Attributes = "onkeypress")]
|
||||
[HtmlTargetElement(Attributes = "onchange")]
|
||||
[HtmlTargetElement(Attributes = "onsubmit")]
|
||||
public class CSPEventTagHelper : TagHelper
|
||||
{
|
||||
public const string EventNames = "onclick,onkeypress,onchange,onsubmit";
|
||||
private readonly ContentSecurityPolicies _csp;
|
||||
|
||||
readonly static HashSet<string> EventSet = EventNames.Split(',')
|
||||
.ToHashSet();
|
||||
public CSPEventTagHelper(ContentSecurityPolicies csp)
|
||||
{
|
||||
_csp = csp;
|
||||
}
|
||||
public override void Process(TagHelperContext context, TagHelperOutput output)
|
||||
{
|
||||
foreach (var attr in output.Attributes)
|
||||
{
|
||||
var n = attr.Name.ToLowerInvariant();
|
||||
if (EventSet.Contains(n))
|
||||
{
|
||||
_csp.AllowUnsafeHashes(attr.Value.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Add sha256- to allow inline event handlers in CSP
|
||||
/// </summary>
|
||||
[HtmlTargetElement("template", Attributes = "csp-allow")]
|
||||
public class CSPTemplate : TagHelper
|
||||
{
|
||||
private readonly ContentSecurityPolicies _csp;
|
||||
public CSPTemplate(ContentSecurityPolicies csp)
|
||||
{
|
||||
_csp = csp;
|
||||
}
|
||||
public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
|
||||
{
|
||||
output.Attributes.RemoveAll("csp-allow");
|
||||
var childContent = await output.GetChildContentAsync();
|
||||
var content = childContent.GetContent();
|
||||
_csp.AllowInline(content);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add sha256- to allow inline event handlers in a:href=javascript:
|
||||
/// </summary>
|
||||
[HtmlTargetElement("a", Attributes = "csp-allow")]
|
||||
public class CSPA : TagHelper
|
||||
{
|
||||
private readonly ContentSecurityPolicies _csp;
|
||||
public CSPA(ContentSecurityPolicies csp)
|
||||
{
|
||||
_csp = csp;
|
||||
}
|
||||
public override void Process(TagHelperContext context, TagHelperOutput output)
|
||||
{
|
||||
output.Attributes.RemoveAll("csp-allow");
|
||||
if (output.Attributes.TryGetAttribute("href", out var attr))
|
||||
{
|
||||
var v = attr.Value.ToString();
|
||||
if (v.StartsWith("javascript:", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
_csp.AllowUnsafeHashes(v);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure that <svg><use href=/ are correctly working if rootpath is present
|
||||
[HtmlTargetElement("use", Attributes = "href")]
|
||||
public class SVGUse : UrlResolutionTagHelper
|
||||
{
|
||||
private readonly IFileVersionProvider _fileVersionProvider;
|
||||
|
||||
public SVGUse(IUrlHelperFactory urlHelperFactory, HtmlEncoder htmlEncoder, IFileVersionProvider fileVersionProvider):base(urlHelperFactory, htmlEncoder)
|
||||
{
|
||||
_fileVersionProvider = fileVersionProvider;
|
||||
}
|
||||
public override void Process(TagHelperContext context, TagHelperOutput output)
|
||||
{
|
||||
var attr = output.Attributes["href"].Value.ToString();
|
||||
attr = _fileVersionProvider.AddFileVersionToPath(ViewContext.HttpContext.Request.PathBase, attr);
|
||||
output.Attributes.SetAttribute("href", attr);
|
||||
}
|
||||
}
|
||||
}
|
29
BTCPayServer/TagHelpers/CSPA.cs
Normal file
29
BTCPayServer/TagHelpers/CSPA.cs
Normal file
|
@ -0,0 +1,29 @@
|
|||
using System;
|
||||
using BTCPayServer.Security;
|
||||
using Microsoft.AspNetCore.Razor.TagHelpers;
|
||||
namespace BTCPayServer.TagHelpers;
|
||||
|
||||
/// <summary>
|
||||
/// Add sha256- to allow inline event handlers in a:href=javascript:
|
||||
/// </summary>
|
||||
[HtmlTargetElement("a", Attributes = "csp-allow")]
|
||||
public class CSPA : TagHelper
|
||||
{
|
||||
private readonly ContentSecurityPolicies _csp;
|
||||
public CSPA(ContentSecurityPolicies csp)
|
||||
{
|
||||
_csp = csp;
|
||||
}
|
||||
public override void Process(TagHelperContext context, TagHelperOutput output)
|
||||
{
|
||||
output.Attributes.RemoveAll("csp-allow");
|
||||
if (output.Attributes.TryGetAttribute("href", out var attr))
|
||||
{
|
||||
var v = attr.Value.ToString();
|
||||
if (v.StartsWith("javascript:", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
_csp.AllowUnsafeHashes(v);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
37
BTCPayServer/TagHelpers/CSPEventTagHelper.cs
Normal file
37
BTCPayServer/TagHelpers/CSPEventTagHelper.cs
Normal file
|
@ -0,0 +1,37 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using BTCPayServer.Security;
|
||||
using Microsoft.AspNetCore.Razor.TagHelpers;
|
||||
namespace BTCPayServer.TagHelpers;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Add 'unsafe-hashes' and sha256- to allow inline event handlers in CSP
|
||||
/// </summary>
|
||||
[HtmlTargetElement(Attributes = "onclick")]
|
||||
[HtmlTargetElement(Attributes = "onkeypress")]
|
||||
[HtmlTargetElement(Attributes = "onchange")]
|
||||
[HtmlTargetElement(Attributes = "onsubmit")]
|
||||
public class CSPEventTagHelper : TagHelper
|
||||
{
|
||||
public const string EventNames = "onclick,onkeypress,onchange,onsubmit";
|
||||
private readonly ContentSecurityPolicies _csp;
|
||||
|
||||
readonly static HashSet<string> EventSet = EventNames.Split(',')
|
||||
.ToHashSet();
|
||||
public CSPEventTagHelper(ContentSecurityPolicies csp)
|
||||
{
|
||||
_csp = csp;
|
||||
}
|
||||
public override void Process(TagHelperContext context, TagHelperOutput output)
|
||||
{
|
||||
foreach (var attr in output.Attributes)
|
||||
{
|
||||
var n = attr.Name.ToLowerInvariant();
|
||||
if (EventSet.Contains(n))
|
||||
{
|
||||
_csp.AllowUnsafeHashes(attr.Value.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
33
BTCPayServer/TagHelpers/CSPInlineScriptTagHelper.cs
Normal file
33
BTCPayServer/TagHelpers/CSPInlineScriptTagHelper.cs
Normal file
|
@ -0,0 +1,33 @@
|
|||
using BTCPayServer.Security;
|
||||
using Microsoft.AspNetCore.Razor.TagHelpers;
|
||||
using NBitcoin;
|
||||
namespace BTCPayServer.TagHelpers;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Add a nonce-* so the inline-script can pass CSP rule when they are rendered server-side
|
||||
/// </summary>
|
||||
[HtmlTargetElement("script")]
|
||||
public class CSPInlineScriptTagHelper : TagHelper
|
||||
{
|
||||
private readonly ContentSecurityPolicies _csp;
|
||||
|
||||
public CSPInlineScriptTagHelper(ContentSecurityPolicies csp)
|
||||
{
|
||||
_csp = csp;
|
||||
}
|
||||
|
||||
public override void Process(TagHelperContext context, TagHelperOutput output)
|
||||
{
|
||||
if (output.Attributes.ContainsName("src"))
|
||||
return;
|
||||
if (output.Attributes.TryGetAttribute("type", out var attr))
|
||||
{
|
||||
if (attr.Value?.ToString() != "text/javascript")
|
||||
return;
|
||||
}
|
||||
var nonce = RandomUtils.GetUInt256().ToString().Substring(0, 32);
|
||||
output.Attributes.Add(new TagHelperAttribute("nonce", nonce));
|
||||
_csp.Add("script-src", $"'nonce-{nonce}'");
|
||||
}
|
||||
}
|
24
BTCPayServer/TagHelpers/CSPTemplate.cs
Normal file
24
BTCPayServer/TagHelpers/CSPTemplate.cs
Normal file
|
@ -0,0 +1,24 @@
|
|||
using System.Threading.Tasks;
|
||||
using BTCPayServer.Security;
|
||||
using Microsoft.AspNetCore.Razor.TagHelpers;
|
||||
namespace BTCPayServer.TagHelpers;
|
||||
|
||||
/// <summary>
|
||||
/// Add sha256- to allow inline event handlers in CSP
|
||||
/// </summary>
|
||||
[HtmlTargetElement("template", Attributes = "csp-allow")]
|
||||
public class CSPTemplate : TagHelper
|
||||
{
|
||||
private readonly ContentSecurityPolicies _csp;
|
||||
public CSPTemplate(ContentSecurityPolicies csp)
|
||||
{
|
||||
_csp = csp;
|
||||
}
|
||||
public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
|
||||
{
|
||||
output.Attributes.RemoveAll("csp-allow");
|
||||
var childContent = await output.GetChildContentAsync();
|
||||
var content = childContent.GetContent();
|
||||
_csp.AllowInline(content);
|
||||
}
|
||||
}
|
44
BTCPayServer/TagHelpers/CurrenciesSuggestionsTagHelper.cs
Normal file
44
BTCPayServer/TagHelpers/CurrenciesSuggestionsTagHelper.cs
Normal file
|
@ -0,0 +1,44 @@
|
|||
using BTCPayServer.Services.Rates;
|
||||
using System.Linq;
|
||||
using Microsoft.AspNetCore.Razor.TagHelpers;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace BTCPayServer.TagHelpers
|
||||
{
|
||||
[HtmlTargetElement("input", Attributes = "currency-selection")]
|
||||
public class CurrenciesSuggestionsTagHelper : TagHelper
|
||||
{
|
||||
private readonly CurrencyNameTable _currencies;
|
||||
|
||||
public CurrenciesSuggestionsTagHelper(CurrencyNameTable currencies)
|
||||
{
|
||||
_currencies = currencies;
|
||||
}
|
||||
public override void Process(TagHelperContext context, TagHelperOutput output)
|
||||
{
|
||||
output.Attributes.RemoveAll("currency-selection");
|
||||
output.PostElement.AppendHtml("<datalist id=\"currency-selection-suggestion\">");
|
||||
var currencies = _currencies.Currencies.Where(c => !c.Crypto).Select(c => c.Code).OrderBy(c => c).ToList();
|
||||
int pos = 0;
|
||||
InsertAt(currencies, "BTC", pos++);
|
||||
InsertAt(currencies, "SATS", pos++);
|
||||
InsertAt(currencies, "USD", pos++);
|
||||
InsertAt(currencies, "EUR", pos++);
|
||||
InsertAt(currencies, "JPY", pos++);
|
||||
InsertAt(currencies, "CNY", pos++);
|
||||
foreach (var curr in currencies)
|
||||
{
|
||||
output.PostElement.AppendHtml($"<option value=\"{curr}\">");
|
||||
}
|
||||
output.PostElement.AppendHtml("</datalist>");
|
||||
output.Attributes.Add("list", "currency-selection-suggestion");
|
||||
base.Process(context, output);
|
||||
}
|
||||
|
||||
private void InsertAt(List<string> currencies, string curr, int idx)
|
||||
{
|
||||
currencies.Remove(curr);
|
||||
currencies.Insert(idx, curr);
|
||||
}
|
||||
}
|
||||
}
|
50
BTCPayServer/TagHelpers/PermissionTagHelper.cs
Normal file
50
BTCPayServer/TagHelpers/PermissionTagHelper.cs
Normal file
|
@ -0,0 +1,50 @@
|
|||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Razor.TagHelpers;
|
||||
using Microsoft.Extensions.Logging;
|
||||
namespace BTCPayServer.TagHelpers;
|
||||
|
||||
|
||||
[HtmlTargetElement(Attributes = nameof(Permission))]
|
||||
public class PermissionTagHelper : TagHelper
|
||||
{
|
||||
private readonly IAuthorizationService _authorizationService;
|
||||
private readonly IHttpContextAccessor _httpContextAccessor;
|
||||
private readonly ILogger<PermissionTagHelper> _logger;
|
||||
|
||||
public PermissionTagHelper(IAuthorizationService authorizationService, IHttpContextAccessor httpContextAccessor, ILogger<PermissionTagHelper> logger)
|
||||
{
|
||||
_authorizationService = authorizationService;
|
||||
_httpContextAccessor = httpContextAccessor;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public string Permission { get; set; }
|
||||
public string PermissionResource { get; set; }
|
||||
|
||||
public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
|
||||
{
|
||||
if (string.IsNullOrEmpty(Permission))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var key = $"{Permission}_{PermissionResource}";
|
||||
if (!_httpContextAccessor.HttpContext.Items.TryGetValue(key, out var cachedResult))
|
||||
{
|
||||
var result = await _authorizationService.AuthorizeAsync(_httpContextAccessor.HttpContext.User,
|
||||
PermissionResource,
|
||||
Permission);
|
||||
|
||||
cachedResult = result;
|
||||
_httpContextAccessor.HttpContext.Items.Add(key, result);
|
||||
|
||||
}
|
||||
if (!((AuthorizationResult)cachedResult).Succeeded)
|
||||
{
|
||||
output.SuppressOutput();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
26
BTCPayServer/TagHelpers/SVGUse.cs
Normal file
26
BTCPayServer/TagHelpers/SVGUse.cs
Normal file
|
@ -0,0 +1,26 @@
|
|||
using System.Text.Encodings.Web;
|
||||
using Microsoft.AspNetCore.Mvc.Razor.TagHelpers;
|
||||
using Microsoft.AspNetCore.Mvc.Rendering;
|
||||
using Microsoft.AspNetCore.Mvc.Routing;
|
||||
using Microsoft.AspNetCore.Mvc.ViewFeatures;
|
||||
using Microsoft.AspNetCore.Razor.TagHelpers;
|
||||
|
||||
namespace BTCPayServer.TagHelpers;
|
||||
|
||||
// Make sure that <svg><use href=/ are correctly working if rootpath is present
|
||||
[HtmlTargetElement("use", Attributes = "href")]
|
||||
public class SVGUse : UrlResolutionTagHelper
|
||||
{
|
||||
private readonly IFileVersionProvider _fileVersionProvider;
|
||||
|
||||
public SVGUse(IUrlHelperFactory urlHelperFactory, HtmlEncoder htmlEncoder, IFileVersionProvider fileVersionProvider) : base(urlHelperFactory, htmlEncoder)
|
||||
{
|
||||
_fileVersionProvider = fileVersionProvider;
|
||||
}
|
||||
public override void Process(TagHelperContext context, TagHelperOutput output)
|
||||
{
|
||||
var attr = output.Attributes["href"].Value.ToString();
|
||||
attr = _fileVersionProvider.AddFileVersionToPath(ViewContext.HttpContext.Request.PathBase, attr);
|
||||
output.Attributes.SetAttribute("href", attr);
|
||||
}
|
||||
}
|
30
BTCPayServer/TagHelpers/SrvModel.cs
Normal file
30
BTCPayServer/TagHelpers/SrvModel.cs
Normal file
|
@ -0,0 +1,30 @@
|
|||
using BTCPayServer.Security;
|
||||
using BTCPayServer.Services;
|
||||
using Microsoft.AspNetCore.Razor.TagHelpers;
|
||||
using NBitcoin;
|
||||
namespace BTCPayServer.TagHelpers;
|
||||
|
||||
[HtmlTargetElement("srv-model")]
|
||||
public class SrvModel : TagHelper
|
||||
{
|
||||
private readonly Safe _safe;
|
||||
private readonly ContentSecurityPolicies _csp;
|
||||
|
||||
public SrvModel(Safe safe, ContentSecurityPolicies csp)
|
||||
{
|
||||
_safe = safe;
|
||||
_csp = csp;
|
||||
}
|
||||
public string VarName { get; set; } = "srvModel";
|
||||
public object Model { get; set; }
|
||||
public override void Process(TagHelperContext context, TagHelperOutput output)
|
||||
{
|
||||
output.TagName = "script";
|
||||
output.TagMode = TagMode.StartTagAndEndTag;
|
||||
output.Attributes.Add(new TagHelperAttribute("type", "text/javascript"));
|
||||
var nonce = RandomUtils.GetUInt256().ToString().Substring(0, 32);
|
||||
output.Attributes.Add(new TagHelperAttribute("nonce", nonce));
|
||||
_csp.Add("script-src", $"'nonce-{nonce}'");
|
||||
output.Content.SetHtmlContent($"var {VarName} = {_safe.Json(Model)};");
|
||||
}
|
||||
}
|
|
@ -27,7 +27,7 @@
|
|||
</div>
|
||||
<div class="form-group">
|
||||
<label asp-for="Currency" class="form-label"></label>
|
||||
<input asp-for="Currency" class="form-control" placeholder="Use store's default settings" />
|
||||
<input asp-for="Currency" currency-selection class="form-control" placeholder="Use store's default settings" />
|
||||
<span asp-validation-for="Currency" class="text-danger"></span>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -55,7 +55,7 @@
|
|||
</div>
|
||||
<div class="form-group">
|
||||
<label asp-for="Currency" class="form-label"></label>
|
||||
<input asp-for="Currency" class="form-control" />
|
||||
<input asp-for="Currency" currency-selection class="form-control" />
|
||||
<span asp-validation-for="Currency" class="text-danger"></span>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
@using BTCPayServer.Abstractions.Extensions
|
||||
@using BTCPayServer.Abstractions.Extensions
|
||||
@using BTCPayServer.Views.Stores
|
||||
@model BTCPayServer.Models.WalletViewModels.NewPullPaymentModel
|
||||
@{
|
||||
|
@ -27,7 +27,7 @@
|
|||
</div>
|
||||
<div class="form-group col-4">
|
||||
<label asp-for="Currency" class="form-label"></label>
|
||||
<input asp-for="Currency" class="form-control"/>
|
||||
<input asp-for="Currency" currency-selection class="form-control"/>
|
||||
<span asp-validation-for="Currency" class="text-danger"></span>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
<h3 class="mb-3">Payment</h3>
|
||||
<div class="form-group">
|
||||
<label asp-for="DefaultCurrency" class="form-label"></label>
|
||||
<input asp-for="DefaultCurrency" class="form-control" style="max-width:10ch;" />
|
||||
<input asp-for="DefaultCurrency" currency-selection class="form-control" style="max-width:10ch;" />
|
||||
<span asp-validation-for="DefaultCurrency" class="text-danger"></span>
|
||||
</div>
|
||||
<div class="form-group d-flex align-items-center">
|
||||
|
|
Loading…
Add table
Reference in a new issue