Admin only toggle + remove annoying password browser thing

This commit is contained in:
Arc
2026-05-21 14:18:28 +01:00
parent 882d861f71
commit d66e22a83e
6 changed files with 122 additions and 10 deletions
+4
View File
@@ -133,6 +133,10 @@ async def create_fiat_invoice(
raise ValueError(
f"Fiat provider '{fiat_provider_name}' is not enabled.",
)
if settings.fiat_providers_admin_only:
wallet = await get_wallet(wallet_id, conn=conn)
if not wallet or not settings.is_admin_user(wallet.user):
raise ValueError("Fiat providers are available to admins only.")
if invoice_data.unit == "sat":
raise ValueError("Fiat provider cannot be used with satoshis.")
+11
View File
@@ -770,6 +770,8 @@ class FiatProvidersSettings(
SquareFiatProvider,
RevolutFiatProvider,
):
fiat_providers_admin_only: bool = Field(default=True)
def is_fiat_provider_enabled(self, provider: str | None) -> bool:
"""
Checks if a specific fiat provider is enabled.
@@ -790,6 +792,15 @@ class FiatProvidersSettings(
"""
Returns a list of fiat payment methods allowed for the user.
"""
if self.fiat_providers_admin_only:
if not self.is_admin_user(user_id):
return []
return [
provider
for provider in ["stripe", "paypal", "square", "revolut"]
if self.is_fiat_provider_enabled(provider)
]
allowed_providers = []
if self.stripe_enabled and (
not self.stripe_limits.allowed_users
File diff suppressed because one or more lines are too long
@@ -12,6 +12,21 @@ window.app.component('lnbits-admin-fiat-providers', {
}
},
computed: {
fiatProvidersAllUsers: {
get() {
return this.formData?.fiat_providers_admin_only === false
},
set(value) {
this.formData.fiat_providers_admin_only = !value
this.formData.touch = null
}
},
fiatProviderAccessLabel() {
return this.fiatProvidersAllUsers ? 'All users' : 'Admins only'
},
secretInputStyle() {
return this.hideInputToggle ? {'-webkit-text-security': 'disc'} : {}
},
stripeWebhookUrl() {
return (
this.formData?.stripe_payment_webhook_url ||
@@ -1,5 +1,5 @@
<template id="lnbits-admin-fiat-providers">
<h6 class="q-my-none q-mb-sm">
<h6 class="q-my-none q-mb-sm row items-center q-gutter-sm">
<span v-text="$t('fiat_providers')"></span>
<q-btn
round
@@ -7,6 +7,18 @@
@click="hideInputToggle = !hideInputToggle"
:icon="hideInputToggle ? 'visibility_off' : 'visibility'"
></q-btn>
<q-toggle
dense
size="sm"
color="warning"
v-model="fiatProvidersAllUsers"
:label="fiatProviderAccessLabel"
>
<q-tooltip>
If enabled for all users, your users may pass a memo that suspends your
account with your fiat providers
</q-tooltip>
</q-toggle>
</h6>
<div class="row">
<div class="col">
@@ -46,7 +58,11 @@
<q-input
filled
class="q-mt-md"
:type="hideInputToggle ? 'password' : 'text'"
type="text"
:input-style="secretInputStyle"
autocomplete="off"
autocapitalize="off"
spellcheck="false"
v-model="formData.stripe_api_secret_key"
:label="$t('secret_key')"
></q-input>
@@ -108,7 +124,11 @@
<q-input
filled
class="q-mt-md"
:type="hideInputToggle ? 'password' : 'text'"
type="text"
:input-style="secretInputStyle"
autocomplete="off"
autocapitalize="off"
spellcheck="false"
v-model="formData.stripe_webhook_signing_secret"
:label="$t('signing_secret')"
:hint="$t('signing_secret_hint')"
@@ -325,14 +345,22 @@
<q-input
filled
class="q-mt-md"
:type="hideInputToggle ? 'password' : 'text'"
type="text"
:input-style="secretInputStyle"
autocomplete="off"
autocapitalize="off"
spellcheck="false"
v-model="formData.paypal_client_id"
:label="$t('client_id')"
></q-input>
<q-input
filled
class="q-mt-md"
:type="hideInputToggle ? 'password' : 'text'"
type="text"
:input-style="secretInputStyle"
autocomplete="off"
autocapitalize="off"
spellcheck="false"
v-model="formData.paypal_client_secret"
:label="$t('secret_key')"
></q-input>
@@ -394,7 +422,11 @@
<q-input
filled
class="q-mt-md"
:type="hideInputToggle ? 'password' : 'text'"
type="text"
:input-style="secretInputStyle"
autocomplete="off"
autocapitalize="off"
spellcheck="false"
v-model="formData.paypal_webhook_id"
:label="$t('webhook_id')"
:hint="$t('webhook_id_hint')"
@@ -611,7 +643,11 @@
<q-input
filled
class="q-mt-md"
:type="hideInputToggle ? 'password' : 'text'"
type="text"
:input-style="secretInputStyle"
autocomplete="off"
autocapitalize="off"
spellcheck="false"
v-model="formData.square_access_token"
:label="$t('access_token')"
></q-input>
@@ -688,7 +724,11 @@
<q-input
filled
class="q-mt-md"
:type="hideInputToggle ? 'password' : 'text'"
type="text"
:input-style="secretInputStyle"
autocomplete="off"
autocapitalize="off"
spellcheck="false"
v-model="formData.square_webhook_signature_key"
:label="$t('signing_secret')"
:hint="$t('square_webhook_signature_key_hint')"
@@ -900,7 +940,11 @@
<q-input
filled
class="q-mt-md"
:type="hideInputToggle ? 'password' : 'text'"
type="text"
:input-style="secretInputStyle"
autocomplete="off"
autocapitalize="off"
spellcheck="false"
v-model="formData.revolut_api_secret_key"
label="API secret key"
></q-input>
+38
View File
@@ -76,6 +76,7 @@ class MockHTTPClient:
def fiat_provider_test_settings(settings: Settings):
original_lnbits_running = settings.lnbits_running
original_allowed_currencies = settings.lnbits_allowed_currencies
original_fiat_providers_admin_only = settings.fiat_providers_admin_only
original_paypal_enabled = settings.paypal_enabled
original_square_enabled = settings.square_enabled
original_square_api_endpoint = settings.square_api_endpoint
@@ -95,12 +96,14 @@ def fiat_provider_test_settings(settings: Settings):
original_revolut_webhook_signing_secret = settings.revolut_webhook_signing_secret
original_revolut_limits = settings.revolut_limits.copy(deep=True)
settings.lnbits_allowed_currencies = []
settings.fiat_providers_admin_only = False
settings.paypal_enabled = False
settings.square_enabled = False
settings.revolut_enabled = False
yield
settings.lnbits_running = original_lnbits_running
settings.lnbits_allowed_currencies = original_allowed_currencies
settings.fiat_providers_admin_only = original_fiat_providers_admin_only
settings.paypal_enabled = original_paypal_enabled
settings.square_enabled = original_square_enabled
settings.square_api_endpoint = original_square_api_endpoint
@@ -217,6 +220,41 @@ async def test_create_wallet_fiat_invoice_allowed_users(
assert user.fiat_providers == ["revolut"]
@pytest.mark.anyio
async def test_fiat_providers_admin_only_default(
to_user: User, settings: Settings
):
original_admin_users = list(settings.lnbits_admin_users)
try:
settings.fiat_providers_admin_only = True
settings.stripe_enabled = True
user = await get_user(to_user.id)
assert user
assert user.fiat_providers == []
settings.lnbits_admin_users.append(to_user.id)
user = await get_user(to_user.id)
assert user
assert user.fiat_providers == ["stripe"]
finally:
settings.lnbits_admin_users = original_admin_users
@pytest.mark.anyio
async def test_create_wallet_fiat_invoice_admin_only_rejects_non_admin(
to_wallet: Wallet, settings: Settings
):
settings.fiat_providers_admin_only = True
settings.stripe_enabled = True
invoice_data = CreateInvoice(
unit="USD", amount=1.0, memo="Test", fiat_provider="stripe"
)
with pytest.raises(ValueError, match="available to admins only"):
await payments.create_fiat_invoice(to_wallet.id, invoice_data)
@pytest.mark.anyio
async def test_create_wallet_fiat_invoice_fiat_limits_fail(
to_wallet: Wallet, settings: Settings, mocker: MockerFixture