Wire scoped API keys and add advisory settle-amount tripwire
Scoped API keys (P1): migrate 58 admin endpoints from require_admin to
require_scope so ks_ keys with Read-only/License-issuer/Support/Full-admin roles
work as intended. 12 sensitive endpoints stay master-key-only (issuer key,
provider connect/disconnect, web password, api-key CRUD, db-info, operator-name,
per-license tier change). require_scope is re-exported from api::admin so both
auth gates import from one place. Adds role-boundary tests.
Settle-amount tripwire (P1): get_invoice_status now returns
ProviderInvoiceSnapshot { status, amount }. On a confirmed settle,
audit_settle_amount (shared by the webhook and reconcile issue paths) compares
the provider-reported sat amount against the invoice's amount_sats and, on drift,
logs a warning + writes an invoice.amount_mismatch audit row, then issues anyway.
Advisory by design: a hard gate would fight an operator's BTCPay payment
tolerance, and Settled already implies paid-in-full. SAT-only — skips non-SAT
settles (fiat subscription renewals) and unparseable amounts.
This commit is contained in:
@@ -83,9 +83,9 @@ async fn tick(state: &AppState) -> anyhow::Result<()> {
|
||||
},
|
||||
};
|
||||
match provider.get_invoice_status(&inv.btcpay_invoice_id).await {
|
||||
Ok(status) => {
|
||||
Ok(snapshot) => {
|
||||
use crate::payment::ProviderInvoiceStatus::*;
|
||||
let new_status = match status {
|
||||
let new_status = match snapshot.status {
|
||||
Settled => "settled",
|
||||
Expired => "expired",
|
||||
Invalid => "invalid",
|
||||
@@ -124,6 +124,16 @@ async fn tick(state: &AppState) -> anyhow::Result<()> {
|
||||
}
|
||||
|
||||
if new_status == "settled" {
|
||||
// Same advisory amount tripwire the webhook path applies
|
||||
// (see crate::api::webhook::audit_settle_amount). Never
|
||||
// blocks issuance — logs + audits any amount/currency
|
||||
// drift from what we charged.
|
||||
crate::api::webhook::audit_settle_amount(
|
||||
state,
|
||||
&inv,
|
||||
snapshot.amount.as_ref(),
|
||||
)
|
||||
.await;
|
||||
if let Err(e) = ensure_license(state, &inv).await {
|
||||
tracing::warn!(
|
||||
error = %e,
|
||||
|
||||
Reference in New Issue
Block a user