mirror of
https://github.com/btcpayserver/btcpayserver.git
synced 2025-03-03 17:36:59 +01:00
Use Safe.Raw and Safe.Json instead of Html.Raw and the JsonHelper, move sanitization at the View level (#960)
This commit is contained in:
parent
6b355cbe1b
commit
be5597085b
32 changed files with 132 additions and 82 deletions
|
@ -34,7 +34,7 @@
|
||||||
<PackageReference Include="BuildBundlerMinifier" Version="2.9.406" />
|
<PackageReference Include="BuildBundlerMinifier" Version="2.9.406" />
|
||||||
<PackageReference Include="BundlerMinifier.Core" Version="2.9.406" />
|
<PackageReference Include="BundlerMinifier.Core" Version="2.9.406" />
|
||||||
<PackageReference Include="BundlerMinifier.TagHelpers" Version="2.9.406" />
|
<PackageReference Include="BundlerMinifier.TagHelpers" Version="2.9.406" />
|
||||||
<PackageReference Include="HtmlSanitizer" Version="4.0.207" />
|
<PackageReference Include="HtmlSanitizer" Version="4.0.217" />
|
||||||
<PackageReference Include="LedgerWallet" Version="2.0.0.3" />
|
<PackageReference Include="LedgerWallet" Version="2.0.0.3" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Logging.Filter" Version="1.1.2" />
|
<PackageReference Include="Microsoft.Extensions.Logging.Filter" Version="1.1.2" />
|
||||||
|
@ -47,7 +47,7 @@
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="12.0.2" />
|
<PackageReference Include="Newtonsoft.Json" Version="12.0.2" />
|
||||||
<PackageReference Include="NicolasDorier.CommandLine" Version="1.0.0.2" />
|
<PackageReference Include="NicolasDorier.CommandLine" Version="1.0.0.2" />
|
||||||
<PackageReference Include="NicolasDorier.CommandLine.Configuration" Version="1.0.0.3" />
|
<PackageReference Include="NicolasDorier.CommandLine.Configuration" Version="1.0.0.3" />
|
||||||
<PackageReference Include="NicolasDorier.RateLimits" Version="1.0.0.7" />
|
<PackageReference Include="NicolasDorier.RateLimits" Version="1.0.0.9" />
|
||||||
<PackageReference Include="NicolasDorier.StandardConfiguration" Version="1.0.0.18" />
|
<PackageReference Include="NicolasDorier.StandardConfiguration" Version="1.0.0.18" />
|
||||||
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="2.1.2" />
|
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="2.1.2" />
|
||||||
<PackageReference Include="OpenIddict" Version="2.0.0" />
|
<PackageReference Include="OpenIddict" Version="2.0.0" />
|
||||||
|
|
|
@ -183,7 +183,7 @@ namespace BTCPayServer.Controllers
|
||||||
{
|
{
|
||||||
Version = u2fChallenge[0].version,
|
Version = u2fChallenge[0].version,
|
||||||
Challenge = u2fChallenge[0].challenge,
|
Challenge = u2fChallenge[0].challenge,
|
||||||
Challenges = JsonConvert.SerializeObject(u2fChallenge),
|
Challenges = u2fChallenge,
|
||||||
AppId = u2fChallenge[0].appId,
|
AppId = u2fChallenge[0].appId,
|
||||||
UserId = user.Id,
|
UserId = user.Id,
|
||||||
RememberMe = rememberMe
|
RememberMe = rememberMe
|
||||||
|
|
|
@ -132,7 +132,7 @@ namespace BTCPayServer.Controllers
|
||||||
EnforceTargetAmount = vm.EnforceTargetAmount,
|
EnforceTargetAmount = vm.EnforceTargetAmount,
|
||||||
StartDate = vm.StartDate?.ToUniversalTime(),
|
StartDate = vm.StartDate?.ToUniversalTime(),
|
||||||
TargetCurrency = vm.TargetCurrency,
|
TargetCurrency = vm.TargetCurrency,
|
||||||
Description = _htmlSanitizer.Sanitize( vm.Description),
|
Description = vm.Description,
|
||||||
EndDate = vm.EndDate?.ToUniversalTime(),
|
EndDate = vm.EndDate?.ToUniversalTime(),
|
||||||
TargetAmount = vm.TargetAmount,
|
TargetAmount = vm.TargetAmount,
|
||||||
CustomCSSLink = vm.CustomCSSLink,
|
CustomCSSLink = vm.CustomCSSLink,
|
||||||
|
|
|
@ -30,7 +30,6 @@ namespace BTCPayServer.Controllers
|
||||||
EventAggregator eventAggregator,
|
EventAggregator eventAggregator,
|
||||||
BTCPayNetworkProvider networkProvider,
|
BTCPayNetworkProvider networkProvider,
|
||||||
CurrencyNameTable currencies,
|
CurrencyNameTable currencies,
|
||||||
HtmlSanitizer htmlSanitizer,
|
|
||||||
EmailSenderFactory emailSenderFactory,
|
EmailSenderFactory emailSenderFactory,
|
||||||
AppService AppService)
|
AppService AppService)
|
||||||
{
|
{
|
||||||
|
@ -39,7 +38,6 @@ namespace BTCPayServer.Controllers
|
||||||
_EventAggregator = eventAggregator;
|
_EventAggregator = eventAggregator;
|
||||||
_NetworkProvider = networkProvider;
|
_NetworkProvider = networkProvider;
|
||||||
_currencies = currencies;
|
_currencies = currencies;
|
||||||
_htmlSanitizer = htmlSanitizer;
|
|
||||||
_emailSenderFactory = emailSenderFactory;
|
_emailSenderFactory = emailSenderFactory;
|
||||||
_AppService = AppService;
|
_AppService = AppService;
|
||||||
}
|
}
|
||||||
|
@ -49,7 +47,6 @@ namespace BTCPayServer.Controllers
|
||||||
private readonly EventAggregator _EventAggregator;
|
private readonly EventAggregator _EventAggregator;
|
||||||
private BTCPayNetworkProvider _NetworkProvider;
|
private BTCPayNetworkProvider _NetworkProvider;
|
||||||
private readonly CurrencyNameTable _currencies;
|
private readonly CurrencyNameTable _currencies;
|
||||||
private readonly HtmlSanitizer _htmlSanitizer;
|
|
||||||
private readonly EmailSenderFactory _emailSenderFactory;
|
private readonly EmailSenderFactory _emailSenderFactory;
|
||||||
private AppService _AppService;
|
private AppService _AppService;
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,7 @@ using System.Globalization;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using BTCPayServer.Models;
|
||||||
using BTCPayServer.Models.ManageViewModels;
|
using BTCPayServer.Models.ManageViewModels;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
|
@ -11,6 +12,7 @@ namespace BTCPayServer.Controllers
|
||||||
{
|
{
|
||||||
public partial class ManageController
|
public partial class ManageController
|
||||||
{
|
{
|
||||||
|
private const string RecoveryCodesKey = nameof(RecoveryCodesKey);
|
||||||
private const string AuthenicatorUriFormat = "otpauth://totp/{0}:{1}?secret={2}&issuer={0}&digits=6";
|
private const string AuthenicatorUriFormat = "otpauth://totp/{0}:{1}?secret={2}&issuer={0}&digits=6";
|
||||||
|
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
|
@ -80,18 +82,8 @@ namespace BTCPayServer.Controllers
|
||||||
throw new ApplicationException($"Unable to load user with ID '{_userManager.GetUserId(User)}'.");
|
throw new ApplicationException($"Unable to load user with ID '{_userManager.GetUserId(User)}'.");
|
||||||
}
|
}
|
||||||
|
|
||||||
var unformattedKey = await _userManager.GetAuthenticatorKeyAsync(user);
|
var model = new EnableAuthenticatorViewModel();
|
||||||
if (string.IsNullOrEmpty(unformattedKey))
|
await LoadSharedKeyAndQrCodeUriAsync(user, model);
|
||||||
{
|
|
||||||
await _userManager.ResetAuthenticatorKeyAsync(user);
|
|
||||||
unformattedKey = await _userManager.GetAuthenticatorKeyAsync(user);
|
|
||||||
}
|
|
||||||
|
|
||||||
var model = new EnableAuthenticatorViewModel
|
|
||||||
{
|
|
||||||
SharedKey = FormatKey(unformattedKey),
|
|
||||||
AuthenticatorUri = GenerateQrCodeUri(user.Email, unformattedKey)
|
|
||||||
};
|
|
||||||
|
|
||||||
return View(model);
|
return View(model);
|
||||||
}
|
}
|
||||||
|
@ -100,32 +92,36 @@ namespace BTCPayServer.Controllers
|
||||||
[ValidateAntiForgeryToken]
|
[ValidateAntiForgeryToken]
|
||||||
public async Task<IActionResult> EnableAuthenticator(EnableAuthenticatorViewModel model)
|
public async Task<IActionResult> EnableAuthenticator(EnableAuthenticatorViewModel model)
|
||||||
{
|
{
|
||||||
if (!ModelState.IsValid)
|
|
||||||
{
|
|
||||||
return View(model);
|
|
||||||
}
|
|
||||||
|
|
||||||
var user = await _userManager.GetUserAsync(User);
|
var user = await _userManager.GetUserAsync(User);
|
||||||
if (user == null)
|
if (user == null)
|
||||||
{
|
{
|
||||||
throw new ApplicationException($"Unable to load user with ID '{_userManager.GetUserId(User)}'.");
|
throw new ApplicationException($"Unable to load user with ID '{_userManager.GetUserId(User)}'.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!ModelState.IsValid)
|
||||||
|
{
|
||||||
|
await LoadSharedKeyAndQrCodeUriAsync(user, model);
|
||||||
|
return View(model);
|
||||||
|
}
|
||||||
|
|
||||||
// Strip spaces and hypens
|
// Strip spaces and hypens
|
||||||
var verificationCode = model.Code.Replace(" ", string.Empty, StringComparison.InvariantCulture)
|
var verificationCode = model.Code.Replace(" ", string.Empty).Replace("-", string.Empty);
|
||||||
.Replace("-", string.Empty, StringComparison.InvariantCulture);
|
|
||||||
|
|
||||||
var is2faTokenValid = await _userManager.VerifyTwoFactorTokenAsync(
|
var is2faTokenValid = await _userManager.VerifyTwoFactorTokenAsync(
|
||||||
user, _userManager.Options.Tokens.AuthenticatorTokenProvider, verificationCode);
|
user, _userManager.Options.Tokens.AuthenticatorTokenProvider, verificationCode);
|
||||||
|
|
||||||
if (!is2faTokenValid)
|
if (!is2faTokenValid)
|
||||||
{
|
{
|
||||||
ModelState.AddModelError(nameof(model.Code), "Verification code is invalid.");
|
ModelState.AddModelError("Code", "Verification code is invalid.");
|
||||||
|
await LoadSharedKeyAndQrCodeUriAsync(user, model);
|
||||||
return View(model);
|
return View(model);
|
||||||
}
|
}
|
||||||
|
|
||||||
await _userManager.SetTwoFactorEnabledAsync(user, true);
|
await _userManager.SetTwoFactorEnabledAsync(user, true);
|
||||||
_logger.LogInformation("User with ID {UserId} has enabled 2FA with an authenticator app.", user.Id);
|
_logger.LogInformation("User with ID {UserId} has enabled 2FA with an authenticator app.", user.Id);
|
||||||
|
var recoveryCodes = await _userManager.GenerateNewTwoFactorRecoveryCodesAsync(user, 10);
|
||||||
|
TempData[RecoveryCodesKey] = recoveryCodes.ToArray();
|
||||||
|
|
||||||
return RedirectToAction(nameof(GenerateRecoveryCodes));
|
return RedirectToAction(nameof(GenerateRecoveryCodes));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -153,7 +149,20 @@ namespace BTCPayServer.Controllers
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
public async Task<IActionResult> GenerateRecoveryCodes()
|
public IActionResult GenerateRecoveryCodes()
|
||||||
|
{
|
||||||
|
var recoveryCodes = (string[])TempData[RecoveryCodesKey];
|
||||||
|
if (recoveryCodes == null)
|
||||||
|
{
|
||||||
|
return RedirectToAction(nameof(TwoFactorAuthentication));
|
||||||
|
}
|
||||||
|
|
||||||
|
var model = new GenerateRecoveryCodesViewModel {RecoveryCodes = recoveryCodes};
|
||||||
|
return View(model);
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet]
|
||||||
|
public async Task<IActionResult> GenerateRecoveryCodesWarning()
|
||||||
{
|
{
|
||||||
var user = await _userManager.GetUserAsync(User);
|
var user = await _userManager.GetUserAsync(User);
|
||||||
if (user == null)
|
if (user == null)
|
||||||
|
@ -163,16 +172,10 @@ namespace BTCPayServer.Controllers
|
||||||
|
|
||||||
if (!user.TwoFactorEnabled)
|
if (!user.TwoFactorEnabled)
|
||||||
{
|
{
|
||||||
throw new ApplicationException(
|
throw new ApplicationException($"Cannot generate recovery codes for user with ID '{user.Id}' because they do not have 2FA enabled.");
|
||||||
$"Cannot generate recovery codes for user with ID '{user.Id}' as they do not have 2FA enabled.");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var recoveryCodes = await _userManager.GenerateNewTwoFactorRecoveryCodesAsync(user, 10);
|
return View(nameof(GenerateRecoveryCodesWarning));
|
||||||
var model = new GenerateRecoveryCodesViewModel {RecoveryCodes = recoveryCodes.ToArray()};
|
|
||||||
|
|
||||||
_logger.LogInformation("User with ID {UserId} has generated new 2FA recovery codes.", user.Id);
|
|
||||||
|
|
||||||
return View(model);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private string GenerateQrCodeUri(string email, string unformattedKey)
|
private string GenerateQrCodeUri(string email, string unformattedKey)
|
||||||
|
@ -201,5 +204,19 @@ namespace BTCPayServer.Controllers
|
||||||
|
|
||||||
return result.ToString().ToLowerInvariant();
|
return result.ToString().ToLowerInvariant();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private async Task LoadSharedKeyAndQrCodeUriAsync(ApplicationUser user, EnableAuthenticatorViewModel model)
|
||||||
|
{
|
||||||
|
var unformattedKey = await _userManager.GetAuthenticatorKeyAsync(user);
|
||||||
|
if (string.IsNullOrEmpty(unformattedKey))
|
||||||
|
{
|
||||||
|
await _userManager.ResetAuthenticatorKeyAsync(user);
|
||||||
|
unformattedKey = await _userManager.GetAuthenticatorKeyAsync(user);
|
||||||
|
}
|
||||||
|
|
||||||
|
model.SharedKey = FormatKey(unformattedKey);
|
||||||
|
model.AuthenticatorUri = GenerateQrCodeUri(user.Email, unformattedKey);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,7 +41,6 @@ namespace BTCPayServer.Controllers
|
||||||
private readonly PaymentRequestService _PaymentRequestService;
|
private readonly PaymentRequestService _PaymentRequestService;
|
||||||
private readonly EventAggregator _EventAggregator;
|
private readonly EventAggregator _EventAggregator;
|
||||||
private readonly CurrencyNameTable _Currencies;
|
private readonly CurrencyNameTable _Currencies;
|
||||||
private readonly HtmlSanitizer _htmlSanitizer;
|
|
||||||
private readonly InvoiceRepository _InvoiceRepository;
|
private readonly InvoiceRepository _InvoiceRepository;
|
||||||
|
|
||||||
public PaymentRequestController(
|
public PaymentRequestController(
|
||||||
|
@ -52,7 +51,6 @@ namespace BTCPayServer.Controllers
|
||||||
PaymentRequestService paymentRequestService,
|
PaymentRequestService paymentRequestService,
|
||||||
EventAggregator eventAggregator,
|
EventAggregator eventAggregator,
|
||||||
CurrencyNameTable currencies,
|
CurrencyNameTable currencies,
|
||||||
HtmlSanitizer htmlSanitizer,
|
|
||||||
InvoiceRepository invoiceRepository)
|
InvoiceRepository invoiceRepository)
|
||||||
{
|
{
|
||||||
_InvoiceController = invoiceController;
|
_InvoiceController = invoiceController;
|
||||||
|
@ -62,7 +60,6 @@ namespace BTCPayServer.Controllers
|
||||||
_PaymentRequestService = paymentRequestService;
|
_PaymentRequestService = paymentRequestService;
|
||||||
_EventAggregator = eventAggregator;
|
_EventAggregator = eventAggregator;
|
||||||
_Currencies = currencies;
|
_Currencies = currencies;
|
||||||
_htmlSanitizer = htmlSanitizer;
|
|
||||||
_InvoiceRepository = invoiceRepository;
|
_InvoiceRepository = invoiceRepository;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -152,7 +149,7 @@ namespace BTCPayServer.Controllers
|
||||||
|
|
||||||
blob.Title = viewModel.Title;
|
blob.Title = viewModel.Title;
|
||||||
blob.Email = viewModel.Email;
|
blob.Email = viewModel.Email;
|
||||||
blob.Description = _htmlSanitizer.Sanitize(viewModel.Description);
|
blob.Description = viewModel.Description;
|
||||||
blob.Amount = viewModel.Amount;
|
blob.Amount = viewModel.Amount;
|
||||||
blob.ExpiryDate = viewModel.ExpiryDate?.ToUniversalTime();
|
blob.ExpiryDate = viewModel.ExpiryDate?.ToUniversalTime();
|
||||||
blob.Currency = viewModel.Currency;
|
blob.Currency = viewModel.Currency;
|
||||||
|
|
|
@ -126,6 +126,7 @@ namespace BTCPayServer.Hosting
|
||||||
});
|
});
|
||||||
|
|
||||||
services.TryAddSingleton<AppService>();
|
services.TryAddSingleton<AppService>();
|
||||||
|
services.TryAddTransient<Safe>();
|
||||||
services.TryAddSingleton<Ganss.XSS.HtmlSanitizer>(o =>
|
services.TryAddSingleton<Ganss.XSS.HtmlSanitizer>(o =>
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@ using System.ComponentModel;
|
||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
||||||
|
|
||||||
namespace BTCPayServer.Models.ManageViewModels
|
namespace BTCPayServer.Models.ManageViewModels
|
||||||
{
|
{
|
||||||
|
@ -15,9 +16,10 @@ namespace BTCPayServer.Models.ManageViewModels
|
||||||
[Display(Name = "Verification Code")]
|
[Display(Name = "Verification Code")]
|
||||||
public string Code { get; set; }
|
public string Code { get; set; }
|
||||||
|
|
||||||
[ReadOnly(true)]
|
[BindNever]
|
||||||
public string SharedKey { get; set; }
|
public string SharedKey { get; set; }
|
||||||
|
|
||||||
|
[BindNever]
|
||||||
public string AuthenticatorUri { get; set; }
|
public string AuthenticatorUri { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -283,10 +283,10 @@ namespace BTCPayServer.Services.Apps
|
||||||
.Where(kv => kv.Value != null)
|
.Where(kv => kv.Value != null)
|
||||||
.Select(c => new ViewPointOfSaleViewModel.Item()
|
.Select(c => new ViewPointOfSaleViewModel.Item()
|
||||||
{
|
{
|
||||||
Description = _HtmlSanitizer.Sanitize(c.GetDetailString("description")),
|
Description = c.GetDetailString("description"),
|
||||||
Id = c.Key,
|
Id = c.Key,
|
||||||
Image = _HtmlSanitizer.Sanitize(c.GetDetailString("image")),
|
Image = c.GetDetailString("image"),
|
||||||
Title = _HtmlSanitizer.Sanitize(c.GetDetailString("title") ?? c.Key),
|
Title = c.GetDetailString("title") ?? c.Key,
|
||||||
Price = c.GetDetail("price")
|
Price = c.GetDetail("price")
|
||||||
.Select(cc => new ViewPointOfSaleViewModel.Item.ItemPrice()
|
.Select(cc => new ViewPointOfSaleViewModel.Item.ItemPrice()
|
||||||
{
|
{
|
||||||
|
|
34
BTCPayServer/Services/Safe.cs
Normal file
34
BTCPayServer/Services/Safe.cs
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Ganss.XSS;
|
||||||
|
using Microsoft.AspNetCore.Html;
|
||||||
|
using Microsoft.AspNetCore.Mvc.Rendering;
|
||||||
|
|
||||||
|
namespace BTCPayServer.Services
|
||||||
|
{
|
||||||
|
public class Safe
|
||||||
|
{
|
||||||
|
private readonly IHtmlHelper _htmlHelper;
|
||||||
|
private readonly IJsonHelper _jsonHelper;
|
||||||
|
private readonly HtmlSanitizer _htmlSanitizer;
|
||||||
|
|
||||||
|
public Safe(IHtmlHelper htmlHelper, IJsonHelper jsonHelper, HtmlSanitizer htmlSanitizer)
|
||||||
|
{
|
||||||
|
_htmlHelper = htmlHelper;
|
||||||
|
_jsonHelper = jsonHelper;
|
||||||
|
_htmlSanitizer = htmlSanitizer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IHtmlContent Raw(string value)
|
||||||
|
{
|
||||||
|
return _htmlHelper.Raw(_htmlSanitizer.Sanitize(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
public IHtmlContent Json(object model)
|
||||||
|
{
|
||||||
|
return _htmlHelper.Raw(_jsonHelper.Serialize(model));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,3 +1,4 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
|
||||||
namespace BTCPayServer.Services.U2F.Models
|
namespace BTCPayServer.Services.U2F.Models
|
||||||
|
@ -18,7 +19,7 @@ namespace BTCPayServer.Services.U2F.Models
|
||||||
public string DeviceResponse { get; set; }
|
public string DeviceResponse { get; set; }
|
||||||
|
|
||||||
[Display(Name = "Challenges")]
|
[Display(Name = "Challenges")]
|
||||||
public string Challenges { get; set; }
|
public List<ServerChallenge> Challenges { get; set; }
|
||||||
|
|
||||||
[Display(Name = "Challenge")]
|
[Display(Name = "Challenge")]
|
||||||
public string Challenge { get; set; }
|
public string Challenge { get; set; }
|
||||||
|
|
|
@ -37,9 +37,9 @@
|
||||||
};
|
};
|
||||||
setTimeout(function() {
|
setTimeout(function() {
|
||||||
window.u2f.sign(
|
window.u2f.sign(
|
||||||
"@Model.AppId",
|
@Safe.Json(Model.AppId),
|
||||||
"@Model.Challenge",
|
@Safe.Json(Model.Challenge),
|
||||||
@Html.Raw(@Model.Challenges), function (data) {
|
@Safe.Json(Model.Challenges), function (data) {
|
||||||
if (data.errorCode) {
|
if (data.errorCode) {
|
||||||
$("#error-response").text(errorMap[data.errorCode]);
|
$("#error-response").text(errorMap[data.errorCode]);
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -30,17 +30,17 @@
|
||||||
@item.Price.Value
|
@item.Price.Value
|
||||||
if (item.Custom)
|
if (item.Custom)
|
||||||
{
|
{
|
||||||
Html.Raw("or more");
|
Safe.Raw("or more");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (item.Custom)
|
else if (item.Custom)
|
||||||
{
|
{
|
||||||
Html.Raw("Any amount");
|
Safe.Raw("Any amount");
|
||||||
}
|
}
|
||||||
|
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<p class="card-text overflow-hidden">@Html.Raw(item.Description)</p>
|
<p class="card-text overflow-hidden">@Safe.Raw(item.Description)</p>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
@if (Model.ViewCrowdfundViewModel.PerkCount.ContainsKey(item.Id))
|
@if (Model.ViewCrowdfundViewModel.PerkCount.ContainsKey(item.Id))
|
||||||
|
|
|
@ -131,7 +131,7 @@
|
||||||
<hr/>
|
<hr/>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-md-8 col-sm-12">
|
<div class="col-md-8 col-sm-12">
|
||||||
<div class="card-text overflow-hidden">@Html.Raw(Model.Description)</div>
|
<div class="card-text overflow-hidden">@Safe.Raw(Model.Description)</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-4 col-sm-12">
|
<div class="col-md-4 col-sm-12">
|
||||||
<partial
|
<partial
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
@if (!Context.Request.Query.ContainsKey("simple"))
|
@if (!Context.Request.Query.ContainsKey("simple"))
|
||||||
{
|
{
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
var srvModel = @Html.Raw(Json.Serialize(Model));
|
var srvModel = @Safe.Json(Model);
|
||||||
</script>
|
</script>
|
||||||
<bundle name="wwwroot/bundles/crowdfund-bundle-1.min.js"></bundle>
|
<bundle name="wwwroot/bundles/crowdfund-bundle-1.min.js"></bundle>
|
||||||
<bundle name="wwwroot/bundles/crowdfund-bundle-2.min.js"></bundle>
|
<bundle name="wwwroot/bundles/crowdfund-bundle-2.min.js"></bundle>
|
||||||
|
@ -33,7 +33,7 @@
|
||||||
@if (!string.IsNullOrEmpty(Model.EmbeddedCSS))
|
@if (!string.IsNullOrEmpty(Model.EmbeddedCSS))
|
||||||
{
|
{
|
||||||
<style>
|
<style>
|
||||||
@Html.Raw(Model.EmbeddedCSS);
|
@Safe.Raw(Model.EmbeddedCSS);
|
||||||
</style>
|
</style>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -31,7 +31,7 @@
|
||||||
{
|
{
|
||||||
<link rel="stylesheet" href="~/cart/css/style.css">
|
<link rel="stylesheet" href="~/cart/css/style.css">
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
var srvModel = @Html.Raw(Json.Serialize(Model));
|
var srvModel = @Safe.Json(Model);
|
||||||
</script>
|
</script>
|
||||||
<bundle name="wwwroot/bundles/cart-bundle.min.js" />
|
<bundle name="wwwroot/bundles/cart-bundle.min.js" />
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">×</span></button>
|
<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">×</span></button>
|
||||||
<p>You need to pay <b>@Model.Amount</b> to <b>@Model.Address</b></p>
|
<p>You need to pay <b>@Model.Amount</b> to <b>@Model.Address</b></p>
|
||||||
<div id="qrCode"></div>
|
<div id="qrCode"></div>
|
||||||
<div id="qrCodeData" data-url="@Html.Raw(Model.BitcoinUri)" style="margin-bottom:20px;"></div>
|
<div id="qrCodeData" data-url="@Model.BitcoinUri" style="margin-bottom:20px;"></div>
|
||||||
<p>
|
<p>
|
||||||
<a class="btn btn-primary" href="@Model.BitcoinUri">
|
<a class="btn btn-primary" href="@Model.BitcoinUri">
|
||||||
<span>Open in wallet</span>
|
<span>Open in wallet</span>
|
||||||
|
@ -52,7 +52,7 @@
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
new QRCode(document.getElementById("qrCode"),
|
new QRCode(document.getElementById("qrCode"),
|
||||||
{
|
{
|
||||||
text: "@Html.Raw(Model.BitcoinUri)",
|
text: @Safe.Json(Model.BitcoinUri),
|
||||||
width: 200,
|
width: 200,
|
||||||
height: 200,
|
height: 200,
|
||||||
useSVG: true
|
useSVG: true
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
<bundle name="wwwroot/bundles/checkout-bundle.min.css" />
|
<bundle name="wwwroot/bundles/checkout-bundle.min.css" />
|
||||||
|
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
var srvModel = @Html.Raw(Json.Serialize(Model));
|
var srvModel = @Safe.Json(Model);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<bundle name="wwwroot/bundles/checkout-bundle.min.js" />
|
<bundle name="wwwroot/bundles/checkout-bundle.min.js" />
|
||||||
|
@ -114,8 +114,8 @@
|
||||||
</div>
|
</div>
|
||||||
</invoice>
|
</invoice>
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
var availableLanguages = @Html.Raw(Json.Serialize(langService.GetLanguages().Select((language) => language.Code)));;
|
var availableLanguages = @Safe.Json(langService.GetLanguages().Select((language) => language.Code));;
|
||||||
var storeDefaultLang = "@Model.DefaultLang";
|
var storeDefaultLang = @Safe.Json(@Model.DefaultLang);
|
||||||
var fallbackLanguage = "en";
|
var fallbackLanguage = "en";
|
||||||
startingLanguage = computeStartingLanguage();
|
startingLanguage = computeStartingLanguage();
|
||||||
// initialization
|
// initialization
|
||||||
|
@ -123,7 +123,7 @@
|
||||||
.use(window.i18nextXHRBackend)
|
.use(window.i18nextXHRBackend)
|
||||||
.init({
|
.init({
|
||||||
backend: {
|
backend: {
|
||||||
loadPath: '@(Model.RootPath)locales/{{lng}}.json'
|
loadPath: @Safe.Json($"{Model.RootPath}locales/{{{{lng}}}}.json")
|
||||||
},
|
},
|
||||||
lng: startingLanguage,
|
lng: startingLanguage,
|
||||||
fallbackLng: fallbackLanguage,
|
fallbackLng: fallbackLanguage,
|
||||||
|
|
|
@ -39,7 +39,7 @@
|
||||||
};
|
};
|
||||||
|
|
||||||
setTimeout(function() {
|
setTimeout(function() {
|
||||||
var request = { "challenge": "@Model.Challenge", "version": "@Model.Version", "appId": "@Model.AppId" };
|
var request = { "challenge": @Safe.Json(Model.Challenge), "version": @Safe.Json(Model.Version), "appId": @Safe.Json(Model.AppId) };
|
||||||
var registerRequests = [{version: request.version, challenge: request.challenge}];
|
var registerRequests = [{version: request.version, challenge: request.challenge}];
|
||||||
u2f.register(request.appId, registerRequests, [],
|
u2f.register(request.appId, registerRequests, [],
|
||||||
function(data) {
|
function(data) {
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
<li>
|
<li>
|
||||||
<p>Scan the QR Code or enter this key <kbd>@Model.SharedKey</kbd> into your two factor authenticator app. Spaces and casing do not matter.</p>
|
<p>Scan the QR Code or enter this key <kbd>@Model.SharedKey</kbd> into your two factor authenticator app. Spaces and casing do not matter.</p>
|
||||||
<div id="qrCode"></div>
|
<div id="qrCode"></div>
|
||||||
<div id="qrCodeData" data-url="@Html.Raw(Model.AuthenticatorUri)"></div>
|
<div id="qrCodeData" data-url="@Model.AuthenticatorUri"></div>
|
||||||
<br />
|
<br />
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
|
@ -53,7 +53,7 @@
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
new QRCode(document.getElementById("qrCode"),
|
new QRCode(document.getElementById("qrCode"),
|
||||||
{
|
{
|
||||||
text: "@Html.Raw(Model.AuthenticatorUri)",
|
text: @Safe.Json(Model.AuthenticatorUri),
|
||||||
width: 200,
|
width: 200,
|
||||||
height: 200,
|
height: 200,
|
||||||
useSVG: true
|
useSVG: true
|
||||||
|
|
|
@ -31,7 +31,7 @@
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<div class="w-100 p-2">@Html.Raw(Model.Description)</div>
|
<div class="w-100 p-2">@Safe.Raw(Model.Description)</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div class="col-sm-12 col-md-12 col-lg-6">
|
<div class="col-sm-12 col-md-12 col-lg-6">
|
||||||
|
|
|
@ -22,7 +22,7 @@
|
||||||
@if (!Context.Request.Query.ContainsKey("simple"))
|
@if (!Context.Request.Query.ContainsKey("simple"))
|
||||||
{
|
{
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
var srvModel = @Html.Raw(Json.Serialize(Model));
|
var srvModel = @Safe.Json(Model);
|
||||||
</script>
|
</script>
|
||||||
<bundle name="wwwroot/bundles/payment-request-bundle-1.min.js"></bundle>
|
<bundle name="wwwroot/bundles/payment-request-bundle-1.min.js"></bundle>
|
||||||
<bundle name="wwwroot/bundles/payment-request-bundle-2.min.js"></bundle>
|
<bundle name="wwwroot/bundles/payment-request-bundle-2.min.js"></bundle>
|
||||||
|
@ -34,7 +34,7 @@
|
||||||
@if (!string.IsNullOrEmpty(Model.EmbeddedCSS))
|
@if (!string.IsNullOrEmpty(Model.EmbeddedCSS))
|
||||||
{
|
{
|
||||||
<style>
|
<style>
|
||||||
@Html.Raw(Model.EmbeddedCSS);
|
@Safe.Raw(Model.EmbeddedCSS);
|
||||||
</style>
|
</style>
|
||||||
}
|
}
|
||||||
</head>
|
</head>
|
||||||
|
|
|
@ -23,7 +23,7 @@
|
||||||
|
|
||||||
<bundle name="wwwroot/bundles/lightning-node-info-bundle.min.js" />
|
<bundle name="wwwroot/bundles/lightning-node-info-bundle.min.js" />
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
var srvModel = @Html.Raw(Json.Serialize(Model));
|
var srvModel = @Safe.Json(Model);
|
||||||
|
|
||||||
|
|
||||||
window.onload = function() {
|
window.onload = function() {
|
||||||
|
|
|
@ -54,7 +54,7 @@
|
||||||
{
|
{
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div id="qrCode"></div>
|
<div id="qrCode"></div>
|
||||||
<div id="qrCodeData" data-url="@Html.Raw(Model.ServiceLink)"></div>
|
<div id="qrCodeData" data-url="@Model.ServiceLink"></div>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
|
@ -70,7 +70,7 @@
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
new QRCode(document.getElementById("qrCode"),
|
new QRCode(document.getElementById("qrCode"),
|
||||||
{
|
{
|
||||||
text: "@Html.Raw(Model.ServiceLink)",
|
text: @Safe.Json(Model.ServiceLink),
|
||||||
width: 200,
|
width: 200,
|
||||||
height: 200,
|
height: 200,
|
||||||
useSVG: true
|
useSVG: true
|
||||||
|
|
|
@ -90,7 +90,7 @@
|
||||||
{
|
{
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div id="qrCode"></div>
|
<div id="qrCode"></div>
|
||||||
<div id="qrCodeData" data-url="@Html.Raw(Model.QRCode)"></div>
|
<div id="qrCodeData" data-url="@Model.QRCode"></div>
|
||||||
</div>
|
</div>
|
||||||
<p>See QR Code information by clicking <a href="#detailsQR" data-toggle="collapse">here</a></p>
|
<p>See QR Code information by clicking <a href="#detailsQR" data-toggle="collapse">here</a></p>
|
||||||
<div id="detailsQR" class="collapse">
|
<div id="detailsQR" class="collapse">
|
||||||
|
@ -184,7 +184,7 @@
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
new QRCode(document.getElementById("qrCode"),
|
new QRCode(document.getElementById("qrCode"),
|
||||||
{
|
{
|
||||||
text: "@Html.Raw(Model.QRCode)",
|
text: @Safe.Json(Model.QRCode),
|
||||||
width: 200,
|
width: 200,
|
||||||
height: 200,
|
height: 200,
|
||||||
useSVG: true
|
useSVG: true
|
||||||
|
|
|
@ -78,7 +78,7 @@
|
||||||
{
|
{
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div id="qrCode"></div>
|
<div id="qrCode"></div>
|
||||||
<div id="qrCodeData" data-url="@Html.Raw(Model.ServiceLink)"></div>
|
<div id="qrCodeData" data-url="@Model.ServiceLink"></div>
|
||||||
</div>
|
</div>
|
||||||
<p>See QR Code information by clicking <a href="#detailsQR" data-toggle="collapse">here</a></p>
|
<p>See QR Code information by clicking <a href="#detailsQR" data-toggle="collapse">here</a></p>
|
||||||
<div id="detailsQR" class="collapse">
|
<div id="detailsQR" class="collapse">
|
||||||
|
@ -101,7 +101,7 @@
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
new QRCode(document.getElementById("qrCode"),
|
new QRCode(document.getElementById("qrCode"),
|
||||||
{
|
{
|
||||||
text: "@Html.Raw(Model.ServiceLink)",
|
text: @Safe.Json(Model.ServiceLink),
|
||||||
width: 200,
|
width: 200,
|
||||||
height: 200,
|
height: 200,
|
||||||
useSVG: true
|
useSVG: true
|
||||||
|
|
|
@ -128,14 +128,14 @@
|
||||||
|
|
||||||
@RenderSection("Scripts", required: false)
|
@RenderSection("Scripts", required: false)
|
||||||
|
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
var expectedDomain = @Html.Raw(Json.Serialize(env.ExpectedHost));
|
var expectedDomain = @Safe.Json(env.ExpectedHost);
|
||||||
var expectedProtocol = @Html.Raw(Json.Serialize(env.ExpectedProtocol));
|
var expectedProtocol = @Safe.Json(env.ExpectedProtocol);
|
||||||
if (window.location.host != expectedDomain || window.location.protocol != expectedProtocol + ":") {
|
if (window.location.host != expectedDomain || window.location.protocol != expectedProtocol + ":") {
|
||||||
document.getElementById("badUrl").style.display = "block";
|
document.getElementById("badUrl").style.display = "block";
|
||||||
document.getElementById("browserScheme").innerText = window.location.protocol.substr(0, window.location.protocol.length -1);
|
document.getElementById("browserScheme").innerText = window.location.protocol.substr(0, window.location.protocol.length -1);
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
}
|
}
|
||||||
@if (!string.IsNullOrEmpty(parsedModel.Html))
|
@if (!string.IsNullOrEmpty(parsedModel.Html))
|
||||||
{
|
{
|
||||||
@Html.Raw(parsedModel.Html)
|
@Safe.Raw(parsedModel.Html)
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|
|
@ -209,7 +209,7 @@
|
||||||
|
|
||||||
@section Scripts {
|
@section Scripts {
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
var srvModel = @Html.Raw(Json.Serialize(Model));
|
var srvModel = @Safe.Json(Model);
|
||||||
|
|
||||||
var payButtonCtrl = new Vue({
|
var payButtonCtrl = new Vue({
|
||||||
el: '#payButtonCtrl',
|
el: '#payButtonCtrl',
|
||||||
|
|
|
@ -171,6 +171,6 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@section Scripts {
|
@section Scripts {
|
||||||
<script type="text/javascript">var defaultScript = @Html.Raw(Json.Serialize(Model.DefaultScript));</script>
|
<script type="text/javascript">var defaultScript = @Safe.Json(Model.DefaultScript);</script>
|
||||||
@await Html.PartialAsync("_ValidationScriptsPartial")
|
@await Html.PartialAsync("_ValidationScriptsPartial")
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,4 +6,5 @@
|
||||||
@using BTCPayServer.Models.InvoicingModels
|
@using BTCPayServer.Models.InvoicingModels
|
||||||
@using BTCPayServer.Models.ManageViewModels
|
@using BTCPayServer.Models.ManageViewModels
|
||||||
@using BTCPayServer.Models.StoreViewModels
|
@using BTCPayServer.Models.StoreViewModels
|
||||||
|
@inject BTCPayServer.Services.Safe Safe
|
||||||
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
|
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
|
||||||
|
|
|
@ -47,5 +47,5 @@
|
||||||
"Pay with CoinSwitch": "CoinSwitchでのお支払い",
|
"Pay with CoinSwitch": "CoinSwitchでのお支払い",
|
||||||
"Pay with Changelly": "Changellyでのお支払い",
|
"Pay with Changelly": "Changellyでのお支払い",
|
||||||
"Close": "閉じる",
|
"Close": "閉じる",
|
||||||
"NotPaid_ExtraTransaction": "The invoice hasn't been paid in full. Please send another transaction to cover amount Due."
|
"NotPaid_ExtraTransaction": "請求金額の全額が支払われていません。未払い分の別のトランザクションをお送りください。"
|
||||||
}
|
}
|
Loading…
Add table
Reference in a new issue