Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
8a0c467
fix(micronode): correct settled-amount sign and validate master on co…
Kukks Aug 18, 2026
0829a53
fix(electrum): validate server TLS cert, verify tx ids, correct outpu…
Kukks Aug 18, 2026
2630378
chore(mcp): use default certificate validation for greenfield client
Kukks Aug 18, 2026
69c7496
fix(lnurlverify): require valid preimage before marking invoice paid
Kukks Aug 18, 2026
6eeef45
fix(blink): require valid preimage before marking ln-address invoice …
Kukks Aug 18, 2026
90ba821
chore(dynamicratelimits): validate antiforgery token on settings post
Kukks Aug 18, 2026
3bfe46f
chore(electrum): restore default server connection handling
Kukks Aug 18, 2026
b71dffe
fix(dataerasure): update invoice metadata call and erase-loop lifecycle
Kukks Aug 18, 2026
10237b7
chore: bump patched plugin versions and require BTCPay 2.4.2
Kukks Aug 18, 2026
33ad1ec
chore(electrum): attribute each tx output to its own tracked address
Kukks Aug 18, 2026
29d0fa7
fix(dataerasure): scope erase loop to its own cancellation source
Kukks Aug 18, 2026
6bb53b5
chore(lnurlverify): normalize preimage before storing
Kukks Aug 18, 2026
dca1c31
fix(blink): require a known amount before reporting paid
Kukks Aug 18, 2026
8adba91
Merge master into maintenance
Kukks Aug 18, 2026
d61b890
chore(nip05): bump NNostr.Client to 0.0.55 and version to 1.1.21
Kukks Aug 19, 2026
5393a32
fix(dataerasure): single long-lived worker, no per-set cts race or di…
Kukks Aug 19, 2026
7ce67af
fix(electrum): mark every co-paid tracked address as used
Kukks Aug 19, 2026
927bc79
fix(nip05): adapt zap metadata write to current invoice API
Kukks Aug 19, 2026
4193c4f
fix(dataerasure): persist only cutoff progress against latest settings
Kukks Aug 19, 2026
8d18fb1
fix(electrum): make co-paid gap extension best-effort
Kukks Aug 19, 2026
f65ed4c
chore: bump btcpayserver submodule to v2.4.2
Kukks Aug 19, 2026
d616b6a
fix(prism): drop unmatched payment group so the match loop can't spin
Kukks Aug 19, 2026
b8213b0
fix(bringin): validate order amount before creating payout
Kukks Aug 19, 2026
d6f4814
fix(sideshift): validate coin identifiers before caching
Kukks Aug 19, 2026
bb359a8
fix(prism): persist payout reconciliation even when no new payout is …
Kukks Aug 19, 2026
9bb5a5b
fix(bringin): authenticate callback code before entering edit mode
Kukks Aug 19, 2026
8c023fa
fix(fileseller): release downloads only on settled invoice states
Kukks Aug 19, 2026
b2b5895
fix(prism): require caller role on target store for store-prism desti…
Kukks Aug 19, 2026
84e1aa8
fix(conference): validate antiforgery token on controller posts
Kukks Aug 19, 2026
88f5d20
fix(bitcoinswitch): isolate per-socket sends with a timeout
Kukks Aug 19, 2026
b7d0330
fix(bringin): reject non-positive exchange rate
Kukks Aug 19, 2026
20b82dd
fix(prism): pin opensats checkout link to prevent server-side request…
Kukks Aug 19, 2026
d5177d7
chore(ci): populate plugin builder slugs; deprecate Subscriptions
Kukks Aug 19, 2026
07fd1ee
fix(tickettailor): bound the ticket issuance loop
Kukks Aug 19, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
<PropertyGroup>
<Product>Bitcoin Switch</Product>
<Description>Control harwdare using the POS as a switch</Description>
<Version>1.0.3</Version>
<Version>1.0.4</Version>
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
</PropertyGroup>
<!-- Plugin development properties -->
Expand Down
21 changes: 16 additions & 5 deletions Plugins/BTCPayServer.Plugins.BitcoinSwitch/BitcoinSwitchService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -174,11 +174,22 @@
return;
foreach (var socket in sockets)
{
await socket.SendAsync(
new ArraySegment<byte>(buffer),
WebSocketMessageType.Text,
true,
cancellationToken);
// Isolate each socket with its own timeout so one stalled or faulted
// listener can't block or abort delivery to the real device.
try
{
using var sendCts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
sendCts.CancelAfter(TimeSpan.FromSeconds(5));
await socket.SendAsync(
new ArraySegment<byte>(buffer),
WebSocketMessageType.Text,
true,
sendCts.Token);
}
catch (Exception ex)
{
Logs.PayServer.LogWarning(ex, "Failed to send BitcoinSwitch command to a socket; continuing");
}
}

}
Expand All @@ -193,7 +204,7 @@
/// <summary>
/// Parses a settings string like "25-5000.0,delay 1000,23-200.0" into a sequence of actions.
/// </summary>
private List<SwitchAction>? ParseActions(string settings)

Check warning on line 207 in Plugins/BTCPayServer.Plugins.BitcoinSwitch/BitcoinSwitchService.cs

View workflow job for this annotation

GitHub Actions / Build & unit test

The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.

Check warning on line 207 in Plugins/BTCPayServer.Plugins.BitcoinSwitch/BitcoinSwitchService.cs

View workflow job for this annotation

GitHub Actions / Build & unit test

The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.
{
try
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
<PropertyGroup>
<Product>Blink</Product>
<Description>Blink Lightning support</Description>
<Version>1.1.1</Version>
<Version>1.1.2</Version>
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
<RootNamespace>BTCPayServer.Plugins.Blink</RootNamespace>
</PropertyGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -622,7 +622,6 @@ internal enum VerifyOutcome
private LightningInvoice BuildInvoice(string paymentHash, TrackedInvoice tracked, bool settled, string? preimage)
{
var bolt11 = BOLT11PaymentRequest.Parse(tracked.Bolt11, _network);
var status = DetermineStatus(settled, tracked.ExpiresAt, DateTimeOffset.UtcNow);

// The authoritative payment hash is the verify key (the `paymentHash` argument = BTCPay's
// invoice Id), NOT the hash parsed from the returned `pr`. blink-lnurl-server's verify
Expand All @@ -642,11 +641,13 @@ private LightningInvoice BuildInvoice(string paymentHash, TrackedInvoice tracked
var reportedBolt11 = bolt11Matches ? tracked.Bolt11 : null;
var reportedAmount = bolt11Matches ? bolt11.MinimumAmount : null;

// BTCPay validates the preimage: it must be 64 hex chars and SHA256(preimage)==paymentHash.
// If invalid, drop it (the payment is still recorded, just without a preimage).
// Require a valid preimage (64 hex chars, SHA256(preimage)==paymentHash) before reporting the
// invoice as paid; a settled flag without that proof is not trusted.
var validPreimage = settled ? ValidatePreimage(paymentHash, preimage) : null;
if (settled && preimage is not null && validPreimage is null)
_logger.LogWarning("Blink preimage for {PaymentHash} did not validate against the payment hash; discarding.", paymentHash);
if (settled && validPreimage is null)
_logger.LogWarning("Blink reported {PaymentHash} settled without a valid preimage; not marking paid.", paymentHash);
var paid = validPreimage is not null && reportedAmount is not null;
var status = DetermineStatus(paid, tracked.ExpiresAt, DateTimeOffset.UtcNow);

return new LightningInvoice
{
Expand All @@ -655,10 +656,10 @@ private LightningInvoice BuildInvoice(string paymentHash, TrackedInvoice tracked
BOLT11 = reportedBolt11,
// Amount is parsed from the BOLT11; BTCPay requires a non-null amount to record payment.
Amount = reportedAmount,
AmountReceived = settled ? reportedAmount : null,
AmountReceived = paid ? reportedAmount : null,
Status = status,
Preimage = validPreimage,
PaidAt = settled ? DateTimeOffset.UtcNow : null,
PaidAt = paid ? DateTimeOffset.UtcNow : null,
Comment thread
coderabbitai[bot] marked this conversation as resolved.
ExpiresAt = tracked.ExpiresAt
};
}
Expand Down
2 changes: 1 addition & 1 deletion Plugins/BTCPayServer.Plugins.Blink/BlinkPlugin.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ public class BlinkPlugin : BaseBTCPayServerPlugin
{
public override IBTCPayServerPlugin.PluginDependency[] Dependencies { get; } =
{
new() { Identifier = nameof(BTCPayServer), Condition = ">=2.3.7" }
new() { Identifier = nameof(BTCPayServer), Condition = ">=2.4.2" }

};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
<PropertyGroup>
<Product>Bringin</Product>
<Description>Euro Offramp</Description>
<Version>1.0.6</Version>
<Version>1.0.7</Version>
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
</PropertyGroup>
<!-- Plugin development properties -->
Expand Down
8 changes: 6 additions & 2 deletions Plugins/BTCPayServer.Plugins.Bringin/BringinController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,13 @@ public async Task<IActionResult> Edit()
[IgnoreAntiforgeryToken]
public async Task<IActionResult> Callback(string storeId, string code, [FromBody]BringinVerificationUpdate content)
{
// Authenticate the shared code against read-only settings BEFORE any state change: Update()
// takes the store edit lock, so validating first stops an anonymous caller from holding it.
var settings = await _bringinService.Get(storeId);
if (settings?.Code != code) return BadRequest();
if (content.verificationStatus != "APPROVED") return BadRequest("Verification not approved");

var vm = await _bringinService.Update(storeId);
if(vm.Code != code) return BadRequest();
if(content.verificationStatus != "APPROVED") return BadRequest("Verification not approved");

if (string.IsNullOrEmpty(vm.ApiKey) && !string.IsNullOrEmpty(content.apikey))
{
Expand Down
9 changes: 9 additions & 0 deletions Plugins/BTCPayServer.Plugins.Bringin/BringinService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,8 @@ private async Task<bool> CheckIfNewPayoutsNeeded(string storeId, BringinStoreSet
if (methodSetting.Value.FiatThreshold)
{
var rate = await bringinClient.GetRate();
if (rate.BringinPrice <= 0)
throw new Exception($"Bringin returned an invalid exchange rate ({rate.BringinPrice}).");
thresholdAmount = methodSetting.Value.Threshold / rate.BringinPrice;
}

Expand Down Expand Up @@ -279,6 +281,8 @@ await _storeRepository.UpdateSetting(storeId, BringinStoreSettings.BringinSettin
{

var rate = await bringinClient.GetRate();
if (rate.BringinPrice <= 0)
throw new Exception($"Bringin returned an invalid exchange rate ({rate.BringinPrice}).");
var thresholdAmount = supportedMethod.FiatMinimumAmount / rate.BringinPrice;
if (amountBtc.ToDecimal(MoneyUnit.BTC) <= thresholdAmount)
{
Expand All @@ -294,6 +298,11 @@ await _storeRepository.UpdateSetting(storeId, BringinStoreSettings.BringinSettin
PaymentMethod = supportedMethod.bringinMethod
};
var order = await bringinClient.PlaceOrder(request);
// The Bringin response is untrusted: reject a non-positive amount or one larger than requested
// before it becomes a pre-approved payout, so a hostile response can't claim more than intended.
if (order.Amount <= 0 || order.Amount > amountBtc.Satoshi)
throw new Exception(
$"Bringin returned an invalid order amount ({order.Amount} sats) for a {amountBtc.Satoshi} sats request.");
var orderMoney = Money.Satoshis(order.Amount);

if (!payout)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
<PropertyGroup>
<Product>Conference</Product>
<Description>Manage conference merchant stores, POS terminals, and sales reporting from a single app</Description>
<Version>1.2.0</Version>
<Version>1.2.1</Version>
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
</PropertyGroup>
<!-- Plugin development properties -->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ namespace BTCPayServer.Plugins.Conference;

[Authorize(AuthenticationSchemes = AuthenticationSchemes.Cookie)]
[Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Cookie)]
[AutoValidateAntiforgeryToken]
public class ConferenceController : Controller
{
private readonly AppService _appService;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
<PropertyGroup>
<Product>Data Erasure</Product>
<Description>Allows you to erase user data from invoices after a period of time.</Description>
<Version>1.0.5</Version>
<Version>1.0.6</Version>
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
</PropertyGroup>
<!-- Plugin development properties -->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ public class DataErasurePlugin : BaseBTCPayServerPlugin
{
public override IBTCPayServerPlugin.PluginDependency[] Dependencies { get; } =
{
new() { Identifier = nameof(BTCPayServer), Condition = ">=2.4.1" }
new() { Identifier = nameof(BTCPayServer), Condition = ">=2.4.2" }
};
public override void Execute(IServiceCollection applicationBuilder)
{
Expand Down
Loading
Loading