mirror of
https://github.com/Such-Software/smirk-backend-core.git
synced 2026-10-17 07:21:32 +02:00
Premium could invoice through exactly one processor, so an operator running BTCPay for BTC, LTC and Grin could not also take Monero or Wownero: BTCPay has no Wownero support, and this operator runs Monero through its own checkout rather than the BTCPay plugin. xmrcheckout and wowcheckout implement the same two Greenfield invoice routes, accept the same `token` auth and report the same statuses, so the existing adapter serves them unchanged. What was missing was more than one of them. Each is now an optional rail with its own URL, store and key (PAYMENT_XMRCHECKOUT_* and PAYMENT_WOWCHECKOUT_*), all three values or none, and a half-configured rail refuses to start and names itself rather than advertising a coin that cannot be paid. The invoice row already recorded which provider minted it; activation now polls that one, never whichever is primary today. An invoice whose rail was switched off is refused and left unconsumed, so turning the rail back on lets the user redeem what they paid. A client that names a rail the instance does not offer is refused rather than handed an invoice in a different coin; a client that names none gets the primary, which is how every client before this behaved. Registration is untouched and keeps the primary. /capabilities lists the rails and their assets, primary first, from config alone, so it never depends on a processor being reachable. PAYMENT_ASSETS labels the primary. Checkout rails also get an exact confirmationsRequired, which BTCPay Server is not sent since it only has speedPolicy buckets.
239 lines
11 KiB
Rust
239 lines
11 KiB
Rust
//! OpenAPI specification assembly.
|
|
//!
|
|
//! `ApiDoc` aggregates the annotated handlers into the spec that is the single
|
|
//! source of truth for the API contract and the wallet's generated TypeScript
|
|
//! client. Add a path here once its handler carries `#[utoipa::path(...)]` and
|
|
//! its request/response types derive `utoipa::ToSchema`.
|
|
|
|
use utoipa::OpenApi;
|
|
|
|
#[derive(OpenApi)]
|
|
#[openapi(
|
|
info(
|
|
title = "smirk-backend-core",
|
|
version = "0.3.0",
|
|
description = "Open, self-hostable backend for the Smirk non-custodial multi-chain wallet."
|
|
),
|
|
modifiers(&SecurityAddon),
|
|
paths(
|
|
crate::api::health::health,
|
|
crate::api::capabilities::capabilities,
|
|
crate::api::prices::prices,
|
|
crate::api::auth::pow_challenge,
|
|
crate::api::auth::extension_register,
|
|
crate::api::auth::check_restore,
|
|
crate::api::auth::payment_invoice,
|
|
crate::api::auth::refresh_token,
|
|
crate::api::auth::logout,
|
|
crate::api::auth::get_me,
|
|
crate::api::auth::nostr_login,
|
|
crate::api::auth::nostr_register_challenge,
|
|
crate::api::auth::nostr_register,
|
|
crate::api::auth::nostr_link_challenge,
|
|
crate::api::auth::nostr_link,
|
|
crate::api::website::website_challenge,
|
|
crate::api::website::website_verify,
|
|
crate::api::users::set_username,
|
|
crate::api::users::get_my_username,
|
|
crate::api::users::lookup_username,
|
|
crate::api::users::register_key,
|
|
crate::api::users::get_user_keys,
|
|
crate::api::users::get_user_key_for_asset,
|
|
crate::api::wallet::btc_ltc::balance,
|
|
crate::api::wallet::btc_ltc::utxos,
|
|
crate::api::wallet::btc_ltc::history,
|
|
crate::api::wallet::btc_ltc::balance_multi,
|
|
crate::api::wallet::btc_ltc::utxos_multi,
|
|
crate::api::wallet::btc_ltc::history_multi,
|
|
crate::api::wallet::btc_ltc::tip,
|
|
crate::api::wallet::btc_ltc::fee,
|
|
crate::api::wallet::btc_ltc::broadcast,
|
|
crate::api::wallet::xmr_wow::register,
|
|
crate::api::wallet::xmr_wow::provision_subaddrs,
|
|
crate::api::wallet::xmr_wow::balance,
|
|
crate::api::wallet::xmr_wow::history,
|
|
crate::api::wallet::xmr_wow::unspent_outs,
|
|
crate::api::wallet::xmr_wow::random_outs,
|
|
crate::api::wallet::xmr_wow::submit_tx,
|
|
crate::api::wallet::xmr_wow::height,
|
|
crate::api::wallet::xmr_wow::confirmations,
|
|
crate::api::wallet::grin::scan,
|
|
crate::api::wallet::grin::height,
|
|
crate::api::wallet::grin::broadcast,
|
|
crate::api::wallet::grin::address_user,
|
|
crate::api::wallet::grin_relay::create,
|
|
crate::api::wallet::grin_relay::pending,
|
|
crate::api::wallet::grin_relay::get_relay,
|
|
crate::api::wallet::grin_relay::respond,
|
|
crate::api::wallet::grin_relay::finalize,
|
|
crate::api::wallet::grin_relay::cancel,
|
|
crate::api::wallet::heights::heights,
|
|
crate::api::nip05::well_known_nostr,
|
|
crate::api::premium::invoice,
|
|
crate::api::premium::activate,
|
|
crate::api::premium::status,
|
|
crate::api::tips::create_social_tip,
|
|
crate::api::tips::get_sent_social_tips,
|
|
crate::api::tips::get_received_social_tips,
|
|
crate::api::tips::get_claimable_social_tips,
|
|
crate::api::tips::get_public_social_tip,
|
|
crate::api::tips::cancel_social_tip,
|
|
crate::api::tips::attach_funding,
|
|
crate::api::tips::claim_social_tip,
|
|
crate::api::tips::confirm_sweep,
|
|
crate::api::tips::clawback_social_tip,
|
|
),
|
|
components(schemas(
|
|
crate::api::health::HealthResponse,
|
|
crate::api::capabilities::CapabilitiesResponse,
|
|
crate::api::capabilities::ChainCapabilities,
|
|
crate::api::capabilities::ChainCapability,
|
|
crate::api::capabilities::FeatureCapabilities,
|
|
crate::api::capabilities::RestoreCapability,
|
|
crate::api::capabilities::RegistrationCapability,
|
|
crate::api::capabilities::MessagingCapability,
|
|
crate::api::capabilities::PremiumCapability,
|
|
crate::api::capabilities::PremiumPlanInfo,
|
|
crate::api::capabilities::PremiumRailInfo,
|
|
crate::api::capabilities::FeedCapability,
|
|
crate::api::prices::PricesResponse,
|
|
crate::api::auth::AuthResponse,
|
|
crate::api::auth::UserInfo,
|
|
crate::api::auth::AssetPublicKey,
|
|
crate::api::auth::ExtensionRegisterRequest,
|
|
crate::api::auth::CheckRestoreRequest,
|
|
crate::api::auth::CheckRestoreResponse,
|
|
crate::api::auth::PaymentInvoiceRequest,
|
|
crate::api::auth::PaymentInvoiceResponse,
|
|
crate::api::auth::RefreshTokenRequest,
|
|
crate::api::auth::LogoutRequest,
|
|
crate::api::auth::LogoutResponse,
|
|
crate::api::auth::NostrLinkChallengeResponse,
|
|
crate::api::auth::NostrLinkRequest,
|
|
crate::api::auth::NostrLinkResponse,
|
|
crate::api::auth::NostrRegisterRequest,
|
|
crate::api::website::WebsiteChallengeRequest,
|
|
crate::api::website::WebsiteChallengeResponse,
|
|
crate::api::website::AssetSignature,
|
|
crate::api::website::WebsiteVerifyRequest,
|
|
crate::api::users::SetUsernameRequest,
|
|
crate::api::users::SetUsernameResponse,
|
|
crate::api::users::MyUsernameResponse,
|
|
crate::api::users::PublicKeysInfo,
|
|
crate::api::users::LookupUsernameResponse,
|
|
crate::api::users::RegisterKeyRequest,
|
|
crate::api::users::UserKeyInfo,
|
|
crate::api::users::UserKeysResponse,
|
|
crate::api::wallet::btc_ltc::AddressRequest,
|
|
crate::api::wallet::btc_ltc::BalanceResponse,
|
|
crate::api::wallet::btc_ltc::Utxo,
|
|
crate::api::wallet::btc_ltc::UtxosResponse,
|
|
crate::api::wallet::btc_ltc::HistoryEntry,
|
|
crate::api::wallet::btc_ltc::HistoryResponse,
|
|
crate::api::wallet::btc_ltc::MultiAddressRequest,
|
|
crate::api::wallet::btc_ltc::MultiBalanceResponse,
|
|
crate::api::wallet::btc_ltc::TaggedUtxo,
|
|
crate::api::wallet::btc_ltc::MultiUtxosResponse,
|
|
crate::api::wallet::btc_ltc::TaggedHistoryEntry,
|
|
crate::api::wallet::btc_ltc::MultiHistoryResponse,
|
|
crate::api::wallet::btc_ltc::AssetRequest,
|
|
crate::api::wallet::btc_ltc::TipResponse,
|
|
crate::api::wallet::btc_ltc::FeeRequest,
|
|
crate::api::wallet::btc_ltc::FeeResponse,
|
|
crate::api::wallet::btc_ltc::BroadcastRequest,
|
|
crate::api::wallet::btc_ltc::BroadcastResponse,
|
|
crate::api::wallet::xmr_wow::ViewRequest,
|
|
crate::api::wallet::xmr_wow::RegisterRequest,
|
|
crate::api::wallet::xmr_wow::ProvisionRequest,
|
|
crate::api::wallet::xmr_wow::ProvisionResponse,
|
|
crate::api::wallet::xmr_wow::RandomOutsRequest,
|
|
crate::api::wallet::xmr_wow::SubmitRequest,
|
|
crate::api::wallet::xmr_wow::LwsAssetRequest,
|
|
crate::api::wallet::xmr_wow::ConfirmationsRequest,
|
|
crate::api::wallet::xmr_wow::LwsBalanceResponse,
|
|
crate::api::wallet::xmr_wow::SubaddrIndexDto,
|
|
crate::api::wallet::xmr_wow::SpentOutputDto,
|
|
crate::api::wallet::xmr_wow::TxDto,
|
|
crate::api::wallet::xmr_wow::LwsHistoryResponse,
|
|
crate::api::wallet::xmr_wow::UnspentOutputDto,
|
|
crate::api::wallet::xmr_wow::UnspentOutsResponse,
|
|
crate::api::wallet::xmr_wow::RandomOutputDto,
|
|
crate::api::wallet::xmr_wow::AmountOutsDto,
|
|
crate::api::wallet::xmr_wow::RandomOutsResponse,
|
|
crate::api::wallet::xmr_wow::HeightResponse,
|
|
crate::api::wallet::xmr_wow::ConfirmationsResponse,
|
|
crate::api::wallet::xmr_wow::OkResponse,
|
|
crate::api::wallet::grin::GrinScanRequest,
|
|
crate::api::wallet::grin::GrinOutput,
|
|
crate::api::wallet::grin::GrinScanResponse,
|
|
crate::api::wallet::grin::GrinHeightResponse,
|
|
crate::api::wallet::grin::GrinBroadcastRequest,
|
|
crate::api::wallet::grin::GrinBroadcastResponse,
|
|
crate::api::wallet::grin::GrinAddressUserResponse,
|
|
crate::api::wallet::grin_relay::CreateRelayRequest,
|
|
crate::api::wallet::grin_relay::RespondRelayRequest,
|
|
crate::api::wallet::grin_relay::FinalizeRelayRequest,
|
|
crate::api::wallet::grin_relay::SlateIdRequest,
|
|
crate::api::wallet::grin_relay::RelayEntry,
|
|
crate::api::wallet::grin_relay::PendingRelaysResponse,
|
|
crate::api::wallet::heights::HeightsResponse,
|
|
crate::api::nip05::WellKnownResponse,
|
|
crate::api::premium::InvoiceReq,
|
|
crate::api::premium::InvoiceResp,
|
|
crate::api::premium::ActivateReq,
|
|
crate::api::premium::StatusResp,
|
|
crate::api::tips::CreateSocialTipRequest,
|
|
crate::api::tips::CreateSocialTipResponse,
|
|
crate::api::tips::SentTip,
|
|
crate::api::tips::SocialTipsResponse,
|
|
crate::api::tips::PublicTipInfo,
|
|
crate::api::tips::CancelTipResponse,
|
|
crate::api::tips::AttachFundingRequest,
|
|
crate::api::tips::ClaimTipResponse,
|
|
crate::api::tips::ConfirmSweepRequest,
|
|
crate::api::tips::ConfirmSweepResponse,
|
|
crate::api::tips::ClawbackTipResponse,
|
|
)),
|
|
tags(
|
|
(name = "system", description = "Service health and metadata."),
|
|
(name = "prices", description = "Fiat price feed (cached; per-feed configurable; feature-flagged)."),
|
|
(name = "auth", description = "Wallet authentication: registration, restore, refresh, sessions, Nostr identity."),
|
|
(name = "btc_ltc", description = "Bitcoin/Litecoin chain access via Electrum (balance, UTXOs, history, tip, fee, broadcast)."),
|
|
(name = "xmr_wow", description = "Monero/Wownero chain access via LWS (register, balance, history, unspent/random outs, submit, height, confirmations)."),
|
|
(name = "grin", description = "Grin view-only chain access (rewind_hash scan, tip height, broadcast)."),
|
|
(name = "grin_relay", description = "Grin slatepack relay: async non-custodial mailbox for interactive Grin transfers (feature-flagged)."),
|
|
(name = "premium", description = "Premium subscription: mint a tier invoice, activate on settlement, read status (feature-flagged)."),
|
|
(name = "tips", description = "Public social tips: create/fund/claim/clawback share-URL tips (feature-flagged).")
|
|
)
|
|
)]
|
|
pub struct ApiDoc;
|
|
|
|
/// Registers the `bearer_auth` security scheme (HTTP Bearer / JWT). Routes that
|
|
/// resolve a session via `extract_user_id_from_token` annotate themselves with
|
|
/// `security(("bearer_auth" = []))`; public routes (auth bootstrap, lookups,
|
|
/// system) carry no `security` and are documented as open. Without this the
|
|
/// generated spec/client could not tell which endpoints require a token.
|
|
struct SecurityAddon;
|
|
|
|
impl utoipa::Modify for SecurityAddon {
|
|
fn modify(&self, openapi: &mut utoipa::openapi::OpenApi) {
|
|
use utoipa::openapi::security::{HttpAuthScheme, HttpBuilder, SecurityScheme};
|
|
let components = openapi
|
|
.components
|
|
.as_mut()
|
|
.expect("components are registered by the derive");
|
|
components.add_security_scheme(
|
|
"bearer_auth",
|
|
SecurityScheme::Http(
|
|
HttpBuilder::new()
|
|
.scheme(HttpAuthScheme::Bearer)
|
|
.bearer_format("JWT")
|
|
.description(Some(
|
|
"Session access token issued by the /auth/* endpoints.",
|
|
))
|
|
.build(),
|
|
),
|
|
);
|
|
}
|
|
}
|