Auto load wallet on start up if available and deprecate password

Co-authored-by: Deverick <5827364+deverickapollo@users.noreply.github.com>
This commit is contained in:
napoly 2026-01-13 18:53:53 +01:00
parent 50d3a23c7b
commit f30d55072e
25 changed files with 320 additions and 95 deletions

4
.gitattributes vendored
View file

@ -6,4 +6,6 @@
# Denote all files that are truly binary and should not be modified.
*.png binary
*.jpg binary
*.jpg binary
*.keys binary
wallet binary

View file

@ -9,6 +9,7 @@
<ItemGroup>
<PackageReference Include="Docker.DotNet" Version="3.125.15" />
<PackageReference Include="Mono.Posix.NETStandard" Version="1.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.14.1" />
<PackageReference Include="Microsoft.Playwright" Version="1.52.0" />
<PackageReference Include="xunit" Version="2.9.3" />
@ -32,6 +33,12 @@
<ProjectReference Include="..\Plugins\Monero\BTCPayServer.Plugins.Monero.csproj" />
</ItemGroup>
<ItemGroup>
<Content Include="Resources\**\*">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>
<ItemDefinitionGroup>
<ProjectReference>
<Properties>StaticWebAssetsEnabled=false</Properties>

View file

@ -5,20 +5,26 @@ using BTCPayServer.Tests;
using Microsoft.Extensions.Logging;
using Mono.Unix.Native;
using Npgsql;
using static Mono.Unix.Native.Syscall;
namespace BTCPayServer.Plugins.IntegrationTests.Monero;
public static class IntegrationTestUtils
{
private static readonly ILogger Logger = LoggerFactory
.Create(builder => builder.AddConsole())
.CreateLogger("IntegrationTestUtils");
private static readonly string ContainerWalletDir =
Environment.GetEnvironmentVariable("BTCPAY_XMR_WALLET_DAEMON_WALLETDIR") ?? "/wallet";
public static async Task CleanUpAsync(PlaywrightTester playwrightTester)
{
MoneroRPCProvider moneroRpcProvider = playwrightTester.Server.PayTester.GetService<MoneroRPCProvider>();
MoneroRpcProvider moneroRpcProvider = playwrightTester.Server.PayTester.GetService<MoneroRpcProvider>();
if (moneroRpcProvider.IsAvailable("XMR"))
{
await moneroRpcProvider.CloseWallet("XMR");
@ -26,7 +32,7 @@ public static class IntegrationTestUtils
if (playwrightTester.Server.PayTester.InContainer)
{
moneroRpcProvider.DeleteWallet();
DeleteWalletInContainer();
await DropDatabaseAsync(
"btcpayserver",
"Host=postgres;Port=5432;Username=postgres;Database=postgres");
@ -62,6 +68,101 @@ public static class IntegrationTestUtils
}
}
public static async Task CopyWalletFilesToMoneroRpcDirAsync(PlaywrightTester playwrightTester, String walletDir)
{
Logger.LogInformation("Starting to copy wallet files");
if (playwrightTester.Server.PayTester.InContainer)
{
CopyWalletFilesInContainer(walletDir);
}
else
{
await CopyWalletFilesToLocalDocker(walletDir);
}
}
private static void CopyWalletFilesInContainer(String walletDir)
{
try
{
CopyWalletFile("wallet", walletDir);
CopyWalletFile("wallet.keys", walletDir);
CopyWalletFile("password", walletDir);
}
catch (Exception ex)
{
Logger.LogError(ex, "Failed to copy wallet files to the Monero directory.");
}
}
private static void CopyWalletFile(string name, string walletDir)
{
var resourceWalletDir = Path.Combine(AppContext.BaseDirectory, "Resources", walletDir);
var src = Path.Combine(resourceWalletDir, name);
var dst = Path.Combine(ContainerWalletDir, name);
if (!File.Exists(src))
{
return;
}
File.Copy(src, dst, overwrite: true);
// monero ownership
if (chown(dst, 980, 980) == 0)
{
return;
}
Logger.LogError("chown failed for {File}. errno={Errno}", dst, Stdlib.GetLastError());
}
private static async Task CopyWalletFilesToLocalDocker(String walletDir)
{
try
{
var fullWalletDir = Path.Combine(AppContext.BaseDirectory, "Resources", walletDir);
await RunProcessAsync("docker",
$"cp \"{Path.Combine(fullWalletDir, "wallet")}\" xmr_wallet:/wallet/wallet");
await RunProcessAsync("docker",
$"cp \"{Path.Combine(fullWalletDir, "wallet.keys")}\" xmr_wallet:/wallet/wallet.keys");
await RunProcessAsync("docker",
$"cp \"{Path.Combine(fullWalletDir, "password")}\" xmr_wallet:/wallet/password");
await RunProcessAsync("docker",
"exec xmr_wallet chown monero:monero /wallet/wallet /wallet/wallet.keys /wallet/password");
}
catch (Exception ex)
{
Logger.LogError(ex, "Failed to copy wallet files to the Monero directory.");
}
}
static async Task RunProcessAsync(string fileName, string args)
{
var psi = new ProcessStartInfo
{
FileName = fileName,
Arguments = args,
RedirectStandardOutput = true,
RedirectStandardError = true,
UseShellExecute = false
};
using var process = Process.Start(psi)!;
await process.WaitForExitAsync();
if (process.ExitCode != 0)
{
throw new Exception(await process.StandardError.ReadToEndAsync());
}
}
private static async Task RemoveWalletFromLocalDocker()
{
try
@ -101,4 +202,33 @@ public static class IntegrationTestUtils
Logger.LogError(ex, "Wallet cleanup via Docker failed.");
}
}
private static void DeleteWalletInContainer()
{
try
{
var walletFile = Path.Combine(ContainerWalletDir, "wallet");
var keysFile = walletFile + ".keys";
var passwordFile = Path.Combine(ContainerWalletDir, "password");
if (File.Exists(walletFile))
{
File.Delete(walletFile);
}
if (File.Exists(keysFile))
{
File.Delete(keysFile);
}
if (File.Exists(passwordFile))
{
File.Delete(passwordFile);
}
}
catch (Exception ex)
{
Logger.LogError(ex, "Failed to delete wallet files in directory {Dir}", ContainerWalletDir);
}
}
}

View file

@ -44,7 +44,6 @@ public class MoneroPluginIntegrationTest(ITestOutputHelper helper) : MoneroAndBi
await s.Page.Locator("input#PrivateViewKey")
.FillAsync("1bfa03b0c78aa6bc8292cf160ec9875657d61e889c41d0ebe5c54fd3a2c4b40e");
await s.Page.Locator("input#RestoreHeight").FillAsync("0");
await s.Page.Locator("input#WalletPassword").FillAsync("pass123");
await s.Page.ClickAsync("button[name='command'][value='set-wallet-details']");
await s.Page.CheckAsync("#Enabled");
await s.Page.SelectOptionAsync("#SettlementConfirmationThresholdChoice", "2");
@ -119,7 +118,6 @@ public class MoneroPluginIntegrationTest(ITestOutputHelper helper) : MoneroAndBi
await s.Page.Locator("input#PrivateViewKey")
.FillAsync("1bfa03b0c78aa6bc8292cf160ec9875657d61e889c41d0ebe5c54fd3a2c4b40e");
await s.Page.Locator("input#RestoreHeight").FillAsync("0");
await s.Page.Locator("input#WalletPassword").FillAsync("pass123");
await s.Page.ClickAsync("button[name='command'][value='set-wallet-details']");
var errorText = await s.Page
.Locator("div.validation-summary-errors li")
@ -136,12 +134,12 @@ public class MoneroPluginIntegrationTest(ITestOutputHelper helper) : MoneroAndBi
await using var s = CreatePlaywrightTester();
await s.StartAsync();
MoneroRPCProvider moneroRpcProvider = s.Server.PayTester.GetService<MoneroRPCProvider>();
MoneroRpcProvider moneroRpcProvider = s.Server.PayTester.GetService<MoneroRpcProvider>();
await moneroRpcProvider.WalletRpcClients["XMR"].SendCommandAsync<GenerateFromKeysRequest, GenerateFromKeysResponse>("generate_from_keys", new GenerateFromKeysRequest
{
PrimaryAddress = "43Pnj6ZKGFTJhaLhiecSFfLfr64KPJZw7MyGH73T6PTDekBBvsTAaWEUSM4bmJqDuYLizhA13jQkMRPpz9VXBCBqQQb6y5L",
PrivateViewKey = "1bfa03b0c78aa6bc8292cf160ec9875657d61e889c41d0ebe5c54fd3a2c4b40e",
WalletFileName = "view_wallet",
WalletFileName = "wallet",
Password = ""
});
await moneroRpcProvider.CloseWallet("XMR");
@ -154,13 +152,49 @@ public class MoneroPluginIntegrationTest(ITestOutputHelper helper) : MoneroAndBi
await s.Page.Locator("input#PrivateViewKey")
.FillAsync("1bfa03b0c78aa6bc8292cf160ec9875657d61e889c41d0ebe5c54fd3a2c4b40e");
await s.Page.Locator("input#RestoreHeight").FillAsync("0");
await s.Page.Locator("input#WalletPassword").FillAsync("pass123");
await s.Page.ClickAsync("button[name='command'][value='set-wallet-details']");
var errorText = await s.Page
.Locator("div.validation-summary-errors li")
.InnerTextAsync();
Assert.Equal("Could not generate view wallet from keys: Wallet already exists.", errorText);
await IntegrationTestUtils.CleanUpAsync(s);
}
[Fact]
public async Task ShouldLoadViewWalletOnStartUpIfExists()
{
await using var s = CreatePlaywrightTester();
await IntegrationTestUtils.CopyWalletFilesToMoneroRpcDirAsync(s, "wallet");
await s.StartAsync();
await s.RegisterNewUser(true);
await s.CreateNewStore();
await s.Page.Locator("a.nav-link[href*='monerolike/XMR']").ClickAsync();
var walletRpcIsAvailable = await s.Page
.Locator("li.list-group-item:text('Wallet RPC available: True')")
.InnerTextAsync();
Assert.Contains("Wallet RPC available: True", walletRpcIsAvailable);
await IntegrationTestUtils.CleanUpAsync(s);
}
[Fact]
public async Task ShouldLoadViewWalletWithPasswordOnStartUpIfExists()
{
await using var s = CreatePlaywrightTester();
await IntegrationTestUtils.CopyWalletFilesToMoneroRpcDirAsync(s, "wallet_password");
await s.StartAsync();
await s.RegisterNewUser(true);
await s.CreateNewStore();
await s.Page.Locator("a.nav-link[href*='monerolike/XMR']").ClickAsync();
var walletRpcIsAvailable = await s.Page
.Locator("li.list-group-item:text('Wallet RPC available: True')")
.InnerTextAsync();
Assert.Contains("Wallet RPC available: True", walletRpcIsAvailable);
await IntegrationTestUtils.CleanUpAsync(s);
}

View file

@ -0,0 +1 @@
pass123

View file

@ -1,6 +1,6 @@
MIT License
Copyright (c) 2017-2025 btcpayserver
Copyright (c) 2017-2026 btcpayserver
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View file

@ -1,7 +1,7 @@
{
"Identifier": "BTCPayServer.Plugins.Monero",
"Name": "BTCPay Server: Monero support plugin",
"Version": "1.0.1.0",
"Version": "1.1.0",
"Description": "This plugin extends BTCPay Server to enable users to receive payments via Monero.",
"SystemPlugin": false,
"Dependencies": [

View file

@ -33,12 +33,12 @@ namespace BTCPayServer.Plugins.Monero.Controllers
{
private readonly MoneroLikeConfiguration _MoneroLikeConfiguration;
private readonly StoreRepository _StoreRepository;
private readonly MoneroRPCProvider _MoneroRpcProvider;
private readonly MoneroRpcProvider _MoneroRpcProvider;
private readonly PaymentMethodHandlerDictionary _handlers;
private IStringLocalizer StringLocalizer { get; }
public UIMoneroLikeStoreController(MoneroLikeConfiguration moneroLikeConfiguration,
StoreRepository storeRepository, MoneroRPCProvider moneroRpcProvider,
StoreRepository storeRepository, MoneroRpcProvider moneroRpcProvider,
PaymentMethodHandlerDictionary handlers,
IStringLocalizer stringLocalizer)
{
@ -219,9 +219,8 @@ namespace BTCPayServer.Plugins.Monero.Controllers
{
PrimaryAddress = viewModel.PrimaryAddress,
PrivateViewKey = viewModel.PrivateViewKey,
WalletFileName = "view_wallet",
RestoreHeight = viewModel.RestoreHeight,
Password = viewModel.WalletPassword
WalletFileName = "wallet",
RestoreHeight = viewModel.RestoreHeight
});
if (response?.Error != null)
{
@ -286,7 +285,7 @@ namespace BTCPayServer.Plugins.Monero.Controllers
public class MoneroLikePaymentMethodViewModel : IValidatableObject
{
public MoneroRPCProvider.MoneroLikeSummary Summary { get; set; }
public MoneroRpcProvider.MoneroLikeSummary Summary { get; set; }
public string CryptoCode { get; set; }
public string NewAccountLabel { get; set; }
public long AccountIndex { get; set; }
@ -300,8 +299,6 @@ namespace BTCPayServer.Plugins.Monero.Controllers
public string PrivateViewKey { get; set; }
[Display(Name = "Restore Height")]
public int RestoreHeight { get; set; }
[Display(Name = "Wallet Password")]
public string WalletPassword { get; set; }
[Display(Name = "Consider the invoice settled when the payment transaction …")]
public MoneroLikeSettlementThresholdChoice SettlementConfirmationThresholdChoice { get; set; }
[Display(Name = "Required Confirmations"), Range(0, 100)]

View file

@ -75,9 +75,10 @@ public class MoneroPlugin : BaseBTCPayServerPlugin
PreAuthenticate = true
};
});
services.AddSingleton<MoneroRPCProvider>();
services.AddSingleton<MoneroRpcProvider>();
services.AddHostedService<MoneroLikeSummaryUpdaterHostedService>();
services.AddHostedService<MoneroListener>();
services.AddHostedService<MoneroLoadUpService>();
services.AddSingleton(provider =>
(IPaymentMethodHandler)ActivatorUtilities.CreateInstance(provider, typeof(MoneroLikePaymentMethodHandler), network));
services.AddSingleton(provider =>

View file

@ -17,11 +17,11 @@ namespace BTCPayServer.Plugins.Monero.Payments
private readonly MoneroLikeSpecificBtcPayNetwork _network;
public MoneroLikeSpecificBtcPayNetwork Network => _network;
public JsonSerializer Serializer { get; }
private readonly MoneroRPCProvider _moneroRpcProvider;
private readonly MoneroRpcProvider _moneroRpcProvider;
public PaymentMethodId PaymentMethodId { get; }
public MoneroLikePaymentMethodHandler(MoneroLikeSpecificBtcPayNetwork network, MoneroRPCProvider moneroRpcProvider)
public MoneroLikePaymentMethodHandler(MoneroLikeSpecificBtcPayNetwork network, MoneroRpcProvider moneroRpcProvider)
{
PaymentMethodId = PaymentTypes.CHAIN.GetPaymentMethodId(network.CryptoCode);
_network = network;

View file

@ -0,0 +1,10 @@
using Newtonsoft.Json;
namespace BTCPayServer.Plugins.Monero.RPC.Models
{
public class OpenWalletRequest
{
[JsonProperty("filename")] public string Filename { get; set; }
[JsonProperty("password")] public string Password { get; set; }
}
}

View file

@ -0,0 +1,12 @@
using Newtonsoft.Json;
namespace BTCPayServer.Plugins.Monero.RPC.Models
{
public class OpenWalletResponse
{
[JsonProperty("id")] public string Id { get; set; }
[JsonProperty("jsonrpc")] public string Jsonrpc { get; set; }
[JsonProperty("result")] public object Result { get; set; }
[JsonProperty("error")] public ErrorResponse Error { get; set; }
}
}

View file

@ -12,13 +12,13 @@ namespace BTCPayServer.Plugins.Monero.Services
{
public class MoneroLikeSummaryUpdaterHostedService : IHostedService
{
private readonly MoneroRPCProvider _MoneroRpcProvider;
private readonly MoneroRpcProvider _MoneroRpcProvider;
private readonly MoneroLikeConfiguration _moneroLikeConfiguration;
public Logs Logs { get; }
private CancellationTokenSource _Cts;
public MoneroLikeSummaryUpdaterHostedService(MoneroRPCProvider moneroRpcProvider, MoneroLikeConfiguration moneroLikeConfiguration, Logs logs)
public MoneroLikeSummaryUpdaterHostedService(MoneroRpcProvider moneroRpcProvider, MoneroLikeConfiguration moneroLikeConfiguration, Logs logs)
{
_MoneroRpcProvider = moneroRpcProvider;
_moneroLikeConfiguration = moneroLikeConfiguration;

View file

@ -29,7 +29,7 @@ namespace BTCPayServer.Plugins.Monero.Services
{
private readonly InvoiceRepository _invoiceRepository;
private readonly EventAggregator _eventAggregator;
private readonly MoneroRPCProvider _moneroRpcProvider;
private readonly MoneroRpcProvider _moneroRpcProvider;
private readonly MoneroLikeConfiguration _MoneroLikeConfiguration;
private readonly BTCPayNetworkProvider _networkProvider;
private readonly ILogger<MoneroListener> _logger;
@ -39,7 +39,7 @@ namespace BTCPayServer.Plugins.Monero.Services
public MoneroListener(InvoiceRepository invoiceRepository,
EventAggregator eventAggregator,
MoneroRPCProvider moneroRpcProvider,
MoneroRpcProvider moneroRpcProvider,
MoneroLikeConfiguration moneroLikeConfiguration,
BTCPayNetworkProvider networkProvider,
ILogger<MoneroListener> logger,
@ -62,12 +62,12 @@ namespace BTCPayServer.Plugins.Monero.Services
{
base.SubscribeToEvents();
Subscribe<MoneroEvent>();
Subscribe<MoneroRPCProvider.MoneroDaemonStateChange>();
Subscribe<MoneroRpcProvider.MoneroDaemonStateChange>();
}
protected override async Task ProcessEvent(object evt, CancellationToken cancellationToken)
{
if (evt is MoneroRPCProvider.MoneroDaemonStateChange stateChange)
if (evt is MoneroRpcProvider.MoneroDaemonStateChange stateChange)
{
if (_moneroRpcProvider.IsAvailable(stateChange.CryptoCode))
{

View file

@ -0,0 +1,78 @@
using System;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using BTCPayServer.Plugins.Monero.RPC.Models;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
namespace BTCPayServer.Plugins.Monero.Services;
public class MoneroLoadUpService : IHostedService
{
private const string CryptoCode = "XMR";
private readonly ILogger<MoneroLoadUpService> _logger;
private readonly MoneroRpcProvider _moneroRpcProvider;
public MoneroLoadUpService(ILogger<MoneroLoadUpService> logger, MoneroRpcProvider moneroRpcProvider)
{
_moneroRpcProvider = moneroRpcProvider;
_logger = logger;
}
[Obsolete("Remove optional password parameter")]
public async Task StartAsync(CancellationToken cancellationToken)
{
try
{
_logger.LogInformation("Attempt to load existing wallet");
string walletDir = _moneroRpcProvider.GetWalletDirectory(CryptoCode);
if (!string.IsNullOrEmpty(walletDir))
{
string password = await TryToGetPassword(walletDir, cancellationToken);
await _moneroRpcProvider.WalletRpcClients[CryptoCode]
.SendCommandAsync<OpenWalletRequest, OpenWalletResponse>("open_wallet",
new OpenWalletRequest { Filename = "wallet", Password = password }, cancellationToken);
await _moneroRpcProvider.UpdateSummary(CryptoCode);
_logger.LogInformation("Existing wallet successfully loaded");
}
else
{
_logger.LogInformation("No wallet directory configured, skipping wallet migration");
}
}
catch (Exception ex)
{
_logger.LogError("Failed to load {CryptoCode} wallet. Error Message: {ErrorMessage}", CryptoCode,
ex.Message);
}
}
[Obsolete("Password is obsolete due to the inability to fully separate the password file from the wallet file.")]
private async Task<string> TryToGetPassword(string walletDir, CancellationToken cancellationToken)
{
string password = "";
string passwordFile = Path.Combine(walletDir, "password");
if (File.Exists(passwordFile))
{
password = await File.ReadAllTextAsync(passwordFile, cancellationToken);
password = password.Trim();
}
else
{
_logger.LogInformation("No password file found - ignoring");
}
return password;
}
public Task StopAsync(CancellationToken cancellationToken)
{
return Task.CompletedTask;
}
}

View file

@ -1,7 +1,6 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Immutable;
using System.IO;
using System.Net.Http;
using System.Threading.Tasks;
@ -9,32 +8,25 @@ using BTCPayServer.Plugins.Monero.Configuration;
using BTCPayServer.Plugins.Monero.RPC;
using BTCPayServer.Plugins.Monero.RPC.Models;
using Microsoft.Extensions.Logging;
using NBitcoin;
namespace BTCPayServer.Plugins.Monero.Services
{
public class MoneroRPCProvider
public class MoneroRpcProvider
{
private readonly MoneroLikeConfiguration _moneroLikeConfiguration;
private readonly EventAggregator _eventAggregator;
public ImmutableDictionary<string, JsonRpcClient> DaemonRpcClients;
public ImmutableDictionary<string, JsonRpcClient> WalletRpcClients;
private readonly ILogger<MoneroRPCProvider> _logger;
private readonly ConcurrentDictionary<string, MoneroLikeSummary> _summaries = new();
public ConcurrentDictionary<string, MoneroLikeSummary> Summaries { get; } = new();
public ConcurrentDictionary<string, MoneroLikeSummary> Summaries => _summaries;
public MoneroRPCProvider(MoneroLikeConfiguration moneroLikeConfiguration,
public MoneroRpcProvider(MoneroLikeConfiguration moneroLikeConfiguration,
EventAggregator eventAggregator,
ILogger<MoneroRPCProvider> logger,
IHttpClientFactory httpClientFactory)
{
_moneroLikeConfiguration = moneroLikeConfiguration;
_eventAggregator = eventAggregator;
_logger = logger;
DaemonRpcClients =
_moneroLikeConfiguration.MoneroLikeConfigurationItems.ToImmutableDictionary(pair => pair.Key,
pair => new JsonRpcClient(pair.Value.DaemonRpcUri, pair.Value.Username, pair.Value.Password,
@ -49,7 +41,7 @@ namespace BTCPayServer.Plugins.Monero.Services
public bool IsAvailable(string cryptoCode)
{
cryptoCode = cryptoCode.ToUpperInvariant();
return _summaries.ContainsKey(cryptoCode) && IsAvailable(_summaries[cryptoCode]);
return Summaries.ContainsKey(cryptoCode) && IsAvailable(Summaries[cryptoCode]);
}
private bool IsAvailable(MoneroLikeSummary summary)
@ -69,43 +61,12 @@ namespace BTCPayServer.Plugins.Monero.Services
"close_wallet", JsonRpcClient.NoRequestModel.Instance);
}
public void DeleteWallet()
public string GetWalletDirectory(string cryptoCode)
{
if (!_moneroLikeConfiguration.MoneroLikeConfigurationItems.TryGetValue("XMR", out var configItem))
{
_logger.LogWarning("DeleteWallet: No XMR configuration found.");
return;
}
if (string.IsNullOrEmpty(configItem.WalletDirectory))
{
_logger.LogWarning("DeleteWallet: WalletDirectory is null or empty for XMR configuration.");
return;
}
try
{
var walletFile = Path.Combine(configItem.WalletDirectory, "view_wallet");
var keysFile = walletFile + ".keys";
var passwordFile = Path.Combine(configItem.WalletDirectory, "password");
if (File.Exists(walletFile))
{
File.Delete(walletFile);
}
if (File.Exists(keysFile))
{
File.Delete(keysFile);
}
if (File.Exists(passwordFile))
{
File.Delete(passwordFile);
}
}
catch (Exception ex)
{
_logger.LogError(ex, "Failed to delete wallet files in directory {Dir}",
configItem.WalletDirectory);
}
cryptoCode = cryptoCode.ToUpperInvariant();
return !_moneroLikeConfiguration.MoneroLikeConfigurationItems.TryGetValue(cryptoCode, out var configItem)
? null
: configItem.WalletDirectory;
}
public async Task<MoneroLikeSummary> UpdateSummary(string cryptoCode)
@ -146,9 +107,9 @@ namespace BTCPayServer.Plugins.Monero.Services
summary.WalletAvailable = false;
}
var changed = !_summaries.ContainsKey(cryptoCode) || IsAvailable(cryptoCode) != IsAvailable(summary);
var changed = !Summaries.ContainsKey(cryptoCode) || IsAvailable(cryptoCode) != IsAvailable(summary);
_summaries.AddOrReplace(cryptoCode, summary);
Summaries.AddOrReplace(cryptoCode, summary);
if (changed)
{
_eventAggregator.Publish(new MoneroDaemonStateChange() { Summary = summary, CryptoCode = cryptoCode });

View file

@ -9,9 +9,9 @@ namespace BTCPayServer.Plugins.Monero.Services
{
public class MoneroSyncSummaryProvider : ISyncSummaryProvider
{
private readonly MoneroRPCProvider _moneroRpcProvider;
private readonly MoneroRpcProvider _moneroRpcProvider;
public MoneroSyncSummaryProvider(MoneroRPCProvider moneroRpcProvider)
public MoneroSyncSummaryProvider(MoneroRpcProvider moneroRpcProvider)
{
_moneroRpcProvider = moneroRpcProvider;
}
@ -42,6 +42,6 @@ namespace BTCPayServer.Plugins.Monero.Services
}
}
public MoneroRPCProvider.MoneroLikeSummary Summary { get; set; }
public MoneroRpcProvider.MoneroLikeSummary Summary { get; set; }
}
}

View file

@ -52,11 +52,6 @@
<input type="number" class="form-control" asp-for="RestoreHeight" required>
<span asp-validation-for="RestoreHeight" class="text-danger"></span>
</div>
<div class="form-group p-2">
<label asp-for="WalletPassword" class="form-label">Wallet Password</label>
<input type="password" class="form-control" asp-for="WalletPassword" required>
<span asp-validation-for="WalletPassword" class="text-danger"></span>
</div>
<div class="card-footer text-right">
<button name="command" value="set-wallet-details" class="btn btn-secondary" type="submit">Set Wallet Details</button>
</div>

View file

@ -1,8 +1,5 @@
@using BTCPayServer
@using BTCPayServer.Data
@using BTCPayServer.Plugins.Monero.Services
@using Microsoft.AspNetCore.Identity
@inject MoneroRPCProvider MoneroRpcProvider
@inject MoneroRpcProvider MoneroRpcProvider
@inject SignInManager<ApplicationUser> SignInManager;
@if (SignInManager.IsSignedIn(User) && User.IsInRole(Roles.ServerAdmin) && MoneroRpcProvider.Summaries.Any())

View file

@ -4,10 +4,10 @@
We currently support the following versions of the Monero plugin for BTCPayServer:
| Version | Supported |
| ------- | ------------------ |
| 2.x | ✅ Yes |
| 1.x | ❌ No |
| Version | Supported |
|---------|-------------|
| 1.1.x | ✅ Yes |
| 1.0.x | ❌ No |
## Reporting a Vulnerability

@ -1 +1 @@
Subproject commit 335c906b811b8f131a5973ef3e9cdcac99017654
Subproject commit 3f52aa7fd9faf8bb99343572b3dae305037db2ba