Introduce cheat mode (#2965)

This commit is contained in:
Nicolas Dorier
2021-10-11 12:32:09 +09:00
committed by GitHub
parent e842a00402
commit d7a7382d00
14 changed files with 111 additions and 54 deletions

View File

@@ -85,7 +85,7 @@ namespace BTCPayServer.Tests
public HashSet<string> Chains { get; set; } = new HashSet<string>() { "BTC" };
public bool UseLightning { get; set; }
public bool AllowAdminRegistration { get; set; } = true;
public bool CheatMode { get; set; } = true;
public bool DisableRegistration { get; set; } = false;
public async Task StartAsync()
{
@@ -128,8 +128,8 @@ namespace BTCPayServer.Tests
config.AppendLine($"lbtc.explorer.url={LBTCNBXplorerUri.AbsoluteUri}");
config.AppendLine($"lbtc.explorer.cookiefile=0");
}
if (AllowAdminRegistration)
config.AppendLine("allow-admin-registration=1");
if (CheatMode)
config.AppendLine("cheatmode=1");
config.AppendLine($"torrcfile={TestUtils.GetTestDataFullPath("Tor/torrc")}");
config.AppendLine($"socksendpoint={SocksEndpoint}");

View File

@@ -1,4 +1,5 @@
using System;
using BTCPayServer.Configuration;
using System.IO;
using System.Linq;
using System.Net;
@@ -68,7 +69,6 @@ namespace BTCPayServer.Configuration
BundleJsCss = conf.GetOrDefault<bool>("bundlejscss", true);
DockerDeployment = conf.GetOrDefault<bool>("dockerdeployment", true);
AllowAdminRegistration = conf.GetOrDefault<bool>("allow-admin-registration", false);
TorrcFile = conf.GetOrDefault<string>("torrcfile", null);
TorServices = conf.GetOrDefault<string>("torservices", null)
@@ -146,10 +146,14 @@ namespace BTCPayServer.Configuration
DisableRegistration = conf.GetOrDefault<bool>("disable-registration", true);
PluginRemote = conf.GetOrDefault("plugin-remote", "btcpayserver/btcpayserver-plugins");
RecommendedPlugins = conf.GetOrDefault("recommended-plugins", "").ToLowerInvariant().Split('\r','\n','\t',' ').Where(s => !string.IsNullOrEmpty(s)).Distinct().ToArray();
CheatMode = conf.GetOrDefault("cheatmode", false);
if (CheatMode && this.NetworkType == ChainName.Mainnet)
throw new ConfigException($"cheatmode can't be used on mainnet");
}
public string PluginRemote { get; set; }
public string[] RecommendedPlugins { get; set; }
public bool CheatMode { get; set; }
private SSHSettings ParseSSHConfiguration(IConfiguration conf)
{
@@ -193,7 +197,6 @@ namespace BTCPayServer.Configuration
get;
set;
}
public bool AllowAdminRegistration { get; set; }
public SSHSettings SSHSettings
{
get;

View File

@@ -24,7 +24,6 @@ namespace BTCPayServer.Configuration
app.Option("--testnet | -testnet", $"Use testnet (deprecated, use --network instead)", CommandOptionType.BoolValue);
app.Option("--regtest | -regtest", $"Use regtest (deprecated, use --network instead)", CommandOptionType.BoolValue);
app.Option("--signet | -signet", $"Use signet (deprecated, use --network instead)", CommandOptionType.BoolValue);
app.Option("--allow-admin-registration", $"For debug only, will show a checkbox when a new user register to add himself as admin. (default: false)", CommandOptionType.BoolValue);
app.Option("--chains | -c", $"Chains to support as a comma separated (default: btc; available: {chains})", CommandOptionType.SingleValue);
app.Option("--postgres", $"Connection string to a PostgreSQL database", CommandOptionType.SingleValue);
app.Option("--mysql", $"Connection string to a MySQL database", CommandOptionType.SingleValue);
@@ -49,6 +48,7 @@ namespace BTCPayServer.Configuration
app.Option("--plugin-remote", "Which github repository to fetch the available plugins list (default:btcpayserver/btcpayserver-plugins)", CommandOptionType.SingleValue);
app.Option("--recommended-plugins", "Plugins which would be marked as recommended to be installed. Separated by newline or space", CommandOptionType.MultipleValue);
app.Option("--xforwardedproto", "If specified, set X-Forwarded-Proto to the specified value, this may be useful if your reverse proxy handle https but is not configured to add X-Forwarded-Proto (example: --xforwardedproto https)", CommandOptionType.SingleValue);
app.Option("--cheatmode", "Add elements in the UI to facilitate dev-time testing (Default false)", CommandOptionType.BoolValue);
foreach (var network in provider.GetAll().OfType<BTCPayNetwork>())
{
var crypto = network.CryptoCode.ToLowerInvariant();

View File

@@ -411,7 +411,6 @@ namespace BTCPayServer.Controllers
if (policies.LockSubscription && !User.IsInRole(Roles.ServerAdmin))
return RedirectToAction(nameof(HomeController.Index), "Home");
ViewData["ReturnUrl"] = returnUrl;
ViewData["AllowIsAdmin"] = _Options.AllowAdminRegistration;
return View();
}
@@ -429,7 +428,6 @@ namespace BTCPayServer.Controllers
ViewData["ReturnUrl"] = returnUrl;
ViewData["Logon"] = logon.ToString(CultureInfo.InvariantCulture).ToLowerInvariant();
ViewData["AllowIsAdmin"] = _Options.AllowAdminRegistration;
var policies = await _SettingsRepository.GetSettingAsync<PoliciesSettings>() ?? new PoliciesSettings();
if (policies.LockSubscription && !User.IsInRole(Roles.ServerAdmin))
return RedirectToAction(nameof(HomeController.Index), "Home");
@@ -441,7 +439,7 @@ namespace BTCPayServer.Controllers
if (result.Succeeded)
{
var admin = await _userManager.GetUsersInRoleAsync(Roles.ServerAdmin);
if (admin.Count == 0 || (model.IsAdmin && _Options.AllowAdminRegistration))
if (admin.Count == 0 || (model.IsAdmin && _Options.CheatMode))
{
await _RoleManager.CreateAsync(new IdentityRole(Roles.ServerAdmin));
await _userManager.AddToRoleAsync(user, Roles.ServerAdmin);

View File

@@ -20,7 +20,6 @@ using BTCPayServer.Models;
using BTCPayServer.Models.InvoicingModels;
using BTCPayServer.Payments;
using BTCPayServer.Payments.Lightning;
using BTCPayServer.Plugins.CoinSwitch;
using BTCPayServer.Rating;
using BTCPayServer.Security;
using BTCPayServer.Services.Invoices;
@@ -38,6 +37,7 @@ using NBXplorer;
using Newtonsoft.Json.Linq;
using BitpayCreateInvoiceRequest = BTCPayServer.Models.BitpayCreateInvoiceRequest;
using StoreData = BTCPayServer.Data.StoreData;
using BTCPayServer.Services;
namespace BTCPayServer.Controllers
{
@@ -45,11 +45,9 @@ namespace BTCPayServer.Controllers
{
[HttpPost]
[Route("i/{invoiceId}/test-payment")]
public async Task<IActionResult> TestPayment(string invoiceId, FakePaymentRequest request)
[CheatModeRoute]
public async Task<IActionResult> TestPayment(string invoiceId, FakePaymentRequest request, [FromServices] Cheater cheater)
{
if (_NetworkProvider.NetworkType != ChainName.Regtest) return Conflict();
var credentialString = "server=http://127.0.0.1:43782;ceiwHEbqWI83:DwubwWsoo3";
var invoice = await _InvoiceRepository.GetInvoice(invoiceId);
var store = await _StoreRepository.FindStore(invoice.StoreId);
@@ -57,7 +55,6 @@ namespace BTCPayServer.Controllers
//var network = invoice.Networks.GetNetwork(invoice.Currency);
var cryptoCode = "BTC";
var network = _NetworkProvider.GetNetwork<BTCPayNetwork>(cryptoCode);
var ExplorerNode = new RPCClient(RPCCredentialString.Parse(credentialString), network.NBitcoinNetwork);
var paymentMethodId = store.GetDefaultPaymentId(_NetworkProvider);
//var network = NetworkProvider.GetNetwork<BTCPayNetwork>("BTC");
@@ -73,7 +70,7 @@ namespace BTCPayServer.Controllers
var paymentMethod = invoice.GetPaymentMethod(paymentMethodId);
var rate = paymentMethod.Rate;
FakePaymentResponse.Txid = ExplorerNode.SendToAddress(bitcoinAddressObj, new Money(BtcAmount, MoneyUnit.BTC)).ToString();
FakePaymentResponse.Txid = cheater.CashCow.SendToAddress(bitcoinAddressObj, new Money(BtcAmount, MoneyUnit.BTC)).ToString();
// TODO The value of totalDue is wrong. How can we get the real total due? invoice.Price is only correct if this is the 2nd payment, not for a 3rd or 4th payment.
var totalDue = invoice.Price;
@@ -96,17 +93,16 @@ namespace BTCPayServer.Controllers
[HttpPost]
[Route("i/{invoiceId}/expire")]
public async Task<IActionResult> TestExpireNow(string invoiceId)
[CheatModeRoute]
public async Task<IActionResult> TestExpireNow(string invoiceId, [FromServices] Cheater cheater)
{
if (_NetworkProvider.NetworkType != ChainName.Regtest) return Conflict();
var invoice = await _InvoiceRepository.GetInvoice(invoiceId);
ExpireInvoiceResponse expireInvoiceResponse = new ExpireInvoiceResponse();
// TODO complete this
try
{
await _InvoiceRepository.UpdateInvoiceExpiry(invoiceId, DateTimeOffset.Now);
await cheater.UpdateInvoiceExpiry(invoiceId, DateTimeOffset.Now);
expireInvoiceResponse.SuccessMessage = "Invoice is now expired.";
}
catch (Exception e)

View File

@@ -118,7 +118,6 @@ namespace BTCPayServer.Controllers
[HttpGet]
public async Task<IActionResult> CreateUser()
{
ViewData["AllowIsAdmin"] = _Options.AllowAdminRegistration;
ViewData["AllowRequestEmailConfirmation"] = (await _SettingsRepository.GetPolicies()).RequiresConfirmedEmail;
return View();
@@ -128,10 +127,9 @@ namespace BTCPayServer.Controllers
[HttpPost]
public async Task<IActionResult> CreateUser(RegisterFromAdminViewModel model)
{
ViewData["AllowIsAdmin"] = _Options.AllowAdminRegistration;
var requiresConfirmedEmail = (await _SettingsRepository.GetPolicies()).RequiresConfirmedEmail;
ViewData["AllowRequestEmailConfirmation"] = requiresConfirmedEmail;
if (!_Options.AllowAdminRegistration)
if (!_Options.CheatMode)
model.IsAdmin = false;
if (ModelState.IsValid)
{

View File

@@ -0,0 +1,20 @@
using System;
using Microsoft.Extensions.DependencyInjection;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc.ActionConstraints;
using BTCPayServer.Services;
namespace BTCPayServer.Filters
{
public class CheatModeRouteAttribute : Attribute, IActionConstraint
{
public int Order => 100;
public bool Accept(ActionConstraintContext context)
{
return context.RouteContext.HttpContext.RequestServices.GetRequiredService<BTCPayServerEnvironment>().CheatMode;
}
}
}

View File

@@ -54,6 +54,7 @@ using NBXplorer.DerivationStrategy;
using Newtonsoft.Json;
using NicolasDorier.RateLimits;
using Serilog;
using NBitcoin.RPC;
#if ALTCOINS
using BTCPayServer.Services.Altcoins.Monero;
using BTCPayServer.Services.Altcoins.Ethereum;
@@ -438,6 +439,11 @@ namespace BTCPayServer.Hosting
services.AddSingleton<IObjectModelValidator, SkippableObjectValidatorProvider>();
services.SkipModelValidation<RootedKeyPath>();
if (configuration.GetOrDefault<bool>("cheatmode", false))
{
services.AddSingleton<Cheater>();
}
return services;
}

View File

@@ -22,7 +22,8 @@
"BTCPAY_SOCKSENDPOINT": "localhost:9050",
"BTCPAY_UPDATEURL": "",
"BTCPAY_DOCKERDEPLOYMENT": "true",
"BTCPAY_RECOMMENDED-PLUGINS": "BTCPayServer.Plugins.Test"
"BTCPAY_RECOMMENDED-PLUGINS": "BTCPayServer.Plugins.Test",
"BTCPAY_CHEATMODE": "true"
},
"applicationUrl": "http://127.0.0.1:14142/"
},
@@ -55,7 +56,8 @@
"BTCPAY_TORRCFILE": "../BTCPayServer.Tests/TestData/Tor/torrc",
"BTCPAY_SOCKSENDPOINT": "localhost:9050",
"BTCPAY_DOCKERDEPLOYMENT": "true",
"BTCPAY_RECOMMENDED-PLUGINS": "BTCPayServer.Plugins.Test"
"BTCPAY_RECOMMENDED-PLUGINS": "BTCPayServer.Plugins.Test",
"BTCPAY_CHEATMODE": "true"
},
"applicationUrl": "https://localhost:14142/"
},
@@ -90,7 +92,8 @@
"BTCPAY_TORRCFILE": "../BTCPayServer.Tests/TestData/Tor/torrc",
"BTCPAY_SOCKSENDPOINT": "localhost:9050",
"BTCPAY_DOCKERDEPLOYMENT": "true",
"BTCPAY_RECOMMENDED-PLUGINS": "BTCPayServer.Plugins.Test"
"BTCPAY_RECOMMENDED-PLUGINS": "BTCPayServer.Plugins.Test",
"BTCPAY_CHEATMODE": "true"
},
"applicationUrl": "https://localhost:14142/"
}

View File

@@ -2,9 +2,11 @@ using System;
using System.Linq;
using System.Reflection;
using System.Text;
using BTCPayServer.Configuration;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Options;
using NBitcoin;
namespace BTCPayServer.Services
@@ -13,7 +15,7 @@ namespace BTCPayServer.Services
{
readonly IHttpContextAccessor httpContext;
readonly TorServices torServices;
public BTCPayServerEnvironment(IWebHostEnvironment env, BTCPayNetworkProvider provider, IHttpContextAccessor httpContext, TorServices torServices)
public BTCPayServerEnvironment(IWebHostEnvironment env, BTCPayNetworkProvider provider, IHttpContextAccessor httpContext, TorServices torServices, BTCPayServerOptions opts)
{
this.httpContext = httpContext;
Version = typeof(BTCPayServerEnvironment).GetTypeInfo().Assembly.GetCustomAttribute<AssemblyFileVersionAttribute>().Version;
@@ -31,6 +33,7 @@ namespace BTCPayServer.Services
Environment = env;
NetworkType = provider.NetworkType;
this.torServices = torServices;
CheatMode = opts.CheatMode;
}
public IWebHostEnvironment Environment
{
@@ -43,6 +46,7 @@ namespace BTCPayServer.Services
public string OnionUrl => this.torServices.Services.Where(s => s.ServiceType == TorServiceType.BTCPayServer)
.Select(s => $"http://{s.OnionHost}").FirstOrDefault();
public bool CheatMode { get; set; }
public ChainName NetworkType { get; set; }
public string Version
{

View File

@@ -0,0 +1,39 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using BTCPayServer.Configuration;
using BTCPayServer.Data;
using NBitcoin;
using NBitcoin.RPC;
namespace BTCPayServer.Services
{
public class Cheater
{
private readonly ApplicationDbContextFactory _applicationDbContextFactory;
public Cheater(BTCPayServerOptions opts, ApplicationDbContextFactory applicationDbContextFactory)
{
CashCow = new RPCClient(RPCCredentialString.Parse("server=http://127.0.0.1:43782;ceiwHEbqWI83:DwubwWsoo3"), Bitcoin.Instance.GetNetwork(opts.NetworkType));
_applicationDbContextFactory = applicationDbContextFactory;
}
public RPCClient CashCow
{
get;
set;
}
public async Task UpdateInvoiceExpiry(string invoiceId, DateTimeOffset dateTimeOffset)
{
using (var ctx = _applicationDbContextFactory.CreateContext())
{
var invoiceData = await ctx.Invoices.FindAsync(invoiceId).ConfigureAwait(false);
if (invoiceData == null)
return;
// TODO change the expiry time. But how?
await ctx.SaveChangesAsync().ConfigureAwait(false);
}
}
}
}

View File

@@ -133,18 +133,6 @@ namespace BTCPayServer.Services.Invoices
await ctx.SaveChangesAsync().ConfigureAwait(false);
}
}
public async Task UpdateInvoiceExpiry(string invoiceId, DateTimeOffset dateTimeOffset)
{
using (var ctx = _ContextFactory.CreateContext())
{
var invoiceData = await ctx.Invoices.FindAsync(invoiceId).ConfigureAwait(false);
if (invoiceData == null)
return;
// TODO change the expiry time. But how?
await ctx.SaveChangesAsync().ConfigureAwait(false);
}
}
public async Task ExtendInvoiceMonitor(string invoiceId)
{

View File

@@ -1,4 +1,4 @@
@model RegisterViewModel
@model RegisterViewModel
@inject BTCPayServer.Services.BTCPayServerEnvironment env
@{
ViewData["Title"] = "Register";
@@ -51,7 +51,7 @@
<input asp-for="ConfirmPassword" class="form-control" required />
<span asp-validation-for="ConfirmPassword" class="text-danger"></span>
</div>
@if (ViewData["AllowIsAdmin"] is true)
@if (env.CheatMode)
{
<div class="form-group form-check">
<input asp-for="IsAdmin" type="checkbox" class="form-check-input"/>

View File

@@ -1,6 +1,7 @@
@addTagHelper *, BundlerMinifier.TagHelpers
@inject BTCPayServer.Services.LanguageService langService
@inject BTCPayNetworkProvider BTCPayNetworkProvider
@inject BTCPayServer.Services.BTCPayServerEnvironment env
@inject PaymentMethodHandlerDictionary PaymentMethodHandlerDictionary
@using NBitcoin
@model PaymentModel
@@ -39,6 +40,7 @@
body {
background: rgba(25, 25, 25, 0.9);
}
.close-icon {
display: flex;
}
@@ -95,12 +97,12 @@
$("#DefaultLang").val(startingLanguage);
var languageSelectorPrettyDropdown = initDropdown("#DefaultLang");
languageSelectorPrettyDropdown.change(function() {
languageSelectorPrettyDropdown.change(function () {
changeLanguage(languageSelectorPrettyDropdown.val());
});
languageSelectorPrettyDropdown.keypress(function(event) {
if (event.keyCode == 13) {
languageSelectorPrettyDropdown.keypress(function (event) {
if (event.keyCode == 13) {
languageSelectorPrettyDropdown.click();
}
});
@@ -119,7 +121,7 @@
<div class="powered__by__btcpayserver">
Powered by <a target="_blank" href="https://github.com/btcpayserver/btcpayserver" rel="noreferrer noopener">BTCPay Server</a>
</div>
@if (BTCPayNetworkProvider.NetworkType == ChainName.Regtest)
@if (env.CheatMode)
{
<partial name="Checkout-Testing" />
}
@@ -240,7 +242,7 @@
closePaymentMethodDialog: function(currencyId) {
vex.closeAll();
this.changeCurrency(currencyId);
},
},
changeCurrency: function (currency) {
if (currency !== null && this.srvModel.paymentMethodId !== currency) {
this.changingCurrencies = true;
@@ -248,7 +250,7 @@
this.fetchData();
this.closePaymentMethodDialog(null);
}
},
},
close: function(){
$("invoice").fadeOut(300, function () {
window.parent.postMessage("close", "*");
@@ -314,7 +316,7 @@
}
watcher();
}, 2000);
}
}
watcher();
},
fetchData: function(){
@@ -346,7 +348,7 @@
this.endDate = newEnd;
// updating ui
this.srvModel = jsonData;
eventBus.$emit("data-fetched", this.srvModel);
if (this.invoicePaid && jsonData.redirectAutomatically && jsonData.merchantRefLink) {
this.loading = true;
@@ -387,10 +389,10 @@
});
</script>
@foreach (var paymentMethodHandler in PaymentMethodHandlerDictionary.Select(handler => handler.GetCheckoutUISettings()).Where(settings => settings != null))
{
<partial name="@paymentMethodHandler.ExtensionPartial" model="@Model"/>
}
@await Component.InvokeAsync("UiExtensionPoint" , new { location="checkout-end", model = Model})
@foreach (var paymentMethodHandler in PaymentMethodHandlerDictionary.Select(handler => handler.GetCheckoutUISettings()).Where(settings => settings != null))
{
<partial name="@paymentMethodHandler.ExtensionPartial" model="@Model" />
}
@await Component.InvokeAsync("UiExtensionPoint", new { location = "checkout-end", model = Model })
</body>
</html>