[fix] settings cleanup (#3013)
This commit is contained in:
parent
a4ca88b6a4
commit
9bd037b6e7
4 changed files with 54 additions and 83 deletions
|
|
@ -24,7 +24,6 @@ from .users import (
|
||||||
check_admin_settings,
|
check_admin_settings,
|
||||||
create_user_account,
|
create_user_account,
|
||||||
create_user_account_no_ckeck,
|
create_user_account_no_ckeck,
|
||||||
init_admin_settings,
|
|
||||||
update_user_account,
|
update_user_account,
|
||||||
update_user_extensions,
|
update_user_extensions,
|
||||||
)
|
)
|
||||||
|
|
@ -58,7 +57,6 @@ __all__ = [
|
||||||
"check_admin_settings",
|
"check_admin_settings",
|
||||||
"create_user_account",
|
"create_user_account",
|
||||||
"create_user_account_no_ckeck",
|
"create_user_account_no_ckeck",
|
||||||
"init_admin_settings",
|
|
||||||
"update_user_account",
|
"update_user_account",
|
||||||
"update_user_extensions",
|
"update_user_extensions",
|
||||||
# websockets
|
# websockets
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,6 @@ from lnbits.core.models.extensions import UserExtension
|
||||||
from lnbits.settings import (
|
from lnbits.settings import (
|
||||||
EditableSettings,
|
EditableSettings,
|
||||||
SuperSettings,
|
SuperSettings,
|
||||||
send_admin_user_to_saas,
|
|
||||||
settings,
|
settings,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -154,14 +153,6 @@ async def check_admin_settings():
|
||||||
with open(Path(settings.lnbits_data_folder) / ".super_user", "w") as file:
|
with open(Path(settings.lnbits_data_folder) / ".super_user", "w") as file:
|
||||||
file.write(settings.super_user)
|
file.write(settings.super_user)
|
||||||
|
|
||||||
# callback for saas
|
|
||||||
if (
|
|
||||||
settings.lnbits_saas_callback
|
|
||||||
and settings.lnbits_saas_secret
|
|
||||||
and settings.lnbits_saas_instance_id
|
|
||||||
):
|
|
||||||
send_admin_user_to_saas()
|
|
||||||
|
|
||||||
account = await get_account(settings.super_user)
|
account = await get_account(settings.super_user)
|
||||||
if account and account.extra and account.extra.provider == "env":
|
if account and account.extra and account.extra.provider == "env":
|
||||||
settings.first_install = True
|
settings.first_install = True
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,6 @@ from urllib.parse import urlparse
|
||||||
import jinja2
|
import jinja2
|
||||||
import jwt
|
import jwt
|
||||||
import shortuuid
|
import shortuuid
|
||||||
from fastapi import Request
|
|
||||||
from fastapi.routing import APIRoute
|
from fastapi.routing import APIRoute
|
||||||
from packaging import version
|
from packaging import version
|
||||||
from pydantic.schema import field_schema
|
from pydantic.schema import field_schema
|
||||||
|
|
@ -344,7 +343,3 @@ def path_segments(path: str) -> list[str]:
|
||||||
def normalize_path(path: Optional[str]) -> str:
|
def normalize_path(path: Optional[str]) -> str:
|
||||||
path = path or ""
|
path = path or ""
|
||||||
return "/" + "/".join(path_segments(path))
|
return "/" + "/".join(path_segments(path))
|
||||||
|
|
||||||
|
|
||||||
def normalized_path(request: Request) -> str:
|
|
||||||
return "/" + "/".join(path_segments(request.url.path))
|
|
||||||
|
|
|
||||||
|
|
@ -4,16 +4,16 @@ import importlib
|
||||||
import importlib.metadata
|
import importlib.metadata
|
||||||
import inspect
|
import inspect
|
||||||
import json
|
import json
|
||||||
|
import os
|
||||||
import re
|
import re
|
||||||
from datetime import datetime, timezone
|
from datetime import datetime, timezone
|
||||||
from enum import Enum
|
from enum import Enum
|
||||||
from hashlib import sha256
|
|
||||||
from os import path
|
from os import path
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from time import gmtime, strftime, time
|
from time import gmtime, strftime, time
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
from uuid import uuid4
|
||||||
|
|
||||||
import httpx
|
|
||||||
from loguru import logger
|
from loguru import logger
|
||||||
from pydantic import BaseModel, BaseSettings, Extra, Field, validator
|
from pydantic import BaseModel, BaseSettings, Extra, Field, validator
|
||||||
|
|
||||||
|
|
@ -275,9 +275,9 @@ class OpsSettings(LNbitsSettings):
|
||||||
|
|
||||||
|
|
||||||
class FeeSettings(LNbitsSettings):
|
class FeeSettings(LNbitsSettings):
|
||||||
lnbits_reserve_fee_min: int = Field(default=2000)
|
lnbits_reserve_fee_min: int = Field(default=2000, ge=0)
|
||||||
lnbits_reserve_fee_percent: float = Field(default=1.0)
|
lnbits_reserve_fee_percent: float = Field(default=1.0, ge=0)
|
||||||
lnbits_service_fee: float = Field(default=0)
|
lnbits_service_fee: float = Field(default=0, ge=0)
|
||||||
lnbits_service_fee_ignore_internal: bool = Field(default=True)
|
lnbits_service_fee_ignore_internal: bool = Field(default=True)
|
||||||
lnbits_service_fee_max: int = Field(default=0)
|
lnbits_service_fee_max: int = Field(default=0)
|
||||||
lnbits_service_fee_wallet: str | None = Field(default=None)
|
lnbits_service_fee_wallet: str | None = Field(default=None)
|
||||||
|
|
@ -293,9 +293,9 @@ class FeeSettings(LNbitsSettings):
|
||||||
|
|
||||||
|
|
||||||
class ExchangeProvidersSettings(LNbitsSettings):
|
class ExchangeProvidersSettings(LNbitsSettings):
|
||||||
lnbits_exchange_rate_cache_seconds: int = Field(default=30)
|
lnbits_exchange_rate_cache_seconds: int = Field(default=30, ge=0)
|
||||||
lnbits_exchange_history_size: int = Field(default=60)
|
lnbits_exchange_history_size: int = Field(default=60, ge=0)
|
||||||
lnbits_exchange_history_refresh_interval_seconds: int = Field(default=300)
|
lnbits_exchange_history_refresh_interval_seconds: int = Field(default=300, ge=0)
|
||||||
|
|
||||||
lnbits_exchange_rate_providers: list[ExchangeRateProvider] = Field(
|
lnbits_exchange_rate_providers: list[ExchangeRateProvider] = Field(
|
||||||
default=[
|
default=[
|
||||||
|
|
@ -360,7 +360,7 @@ class ExchangeProvidersSettings(LNbitsSettings):
|
||||||
|
|
||||||
|
|
||||||
class SecuritySettings(LNbitsSettings):
|
class SecuritySettings(LNbitsSettings):
|
||||||
lnbits_rate_limit_no: str = Field(default="200")
|
lnbits_rate_limit_no: int = Field(default=200, ge=0)
|
||||||
lnbits_rate_limit_unit: str = Field(default="minute")
|
lnbits_rate_limit_unit: str = Field(default="minute")
|
||||||
lnbits_allowed_ips: list[str] = Field(default=[])
|
lnbits_allowed_ips: list[str] = Field(default=[])
|
||||||
lnbits_blocked_ips: list[str] = Field(default=[])
|
lnbits_blocked_ips: list[str] = Field(default=[])
|
||||||
|
|
@ -368,16 +368,16 @@ class SecuritySettings(LNbitsSettings):
|
||||||
default=["^(?!\\d+\\.\\d+\\.\\d+\\.\\d+$)(?:[a-zA-Z0-9-]+\\.)+[a-zA-Z]{2,}$"]
|
default=["^(?!\\d+\\.\\d+\\.\\d+\\.\\d+$)(?:[a-zA-Z0-9-]+\\.)+[a-zA-Z]{2,}$"]
|
||||||
)
|
)
|
||||||
|
|
||||||
lnbits_wallet_limit_max_balance: int = Field(default=0)
|
lnbits_wallet_limit_max_balance: int = Field(default=0, ge=0)
|
||||||
lnbits_wallet_limit_daily_max_withdraw: int = Field(default=0)
|
lnbits_wallet_limit_daily_max_withdraw: int = Field(default=0, ge=0)
|
||||||
lnbits_wallet_limit_secs_between_trans: int = Field(default=0)
|
lnbits_wallet_limit_secs_between_trans: int = Field(default=0, ge=0)
|
||||||
lnbits_only_allow_incoming_payments: bool = Field(default=False)
|
lnbits_only_allow_incoming_payments: bool = Field(default=False)
|
||||||
lnbits_watchdog_switch_to_voidwallet: bool = Field(default=False)
|
lnbits_watchdog_switch_to_voidwallet: bool = Field(default=False)
|
||||||
lnbits_watchdog_interval_minutes: int = Field(default=60)
|
lnbits_watchdog_interval_minutes: int = Field(default=60, gt=0)
|
||||||
lnbits_watchdog_delta: int = Field(default=1_000_000)
|
lnbits_watchdog_delta: int = Field(default=1_000_000, gt=0)
|
||||||
|
|
||||||
lnbits_max_outgoing_payment_amount_sats: int = Field(default=10_000_000)
|
lnbits_max_outgoing_payment_amount_sats: int = Field(default=10_000_000, ge=0)
|
||||||
lnbits_max_incoming_payment_amount_sats: int = Field(default=10_000_000)
|
lnbits_max_incoming_payment_amount_sats: int = Field(default=10_000_000, ge=0)
|
||||||
|
|
||||||
def is_wallet_max_balance_exceeded(self, amount):
|
def is_wallet_max_balance_exceeded(self, amount):
|
||||||
return (
|
return (
|
||||||
|
|
@ -406,9 +406,13 @@ class NotificationsSettings(LNbitsSettings):
|
||||||
notification_balance_delta_changed: bool = Field(default=True)
|
notification_balance_delta_changed: bool = Field(default=True)
|
||||||
lnbits_notification_server_start_stop: bool = Field(default=True)
|
lnbits_notification_server_start_stop: bool = Field(default=True)
|
||||||
lnbits_notification_watchdog: bool = Field(default=False)
|
lnbits_notification_watchdog: bool = Field(default=False)
|
||||||
lnbits_notification_server_status_hours: int = Field(default=24)
|
lnbits_notification_server_status_hours: int = Field(default=24, gt=0)
|
||||||
lnbits_notification_incoming_payment_amount_sats: int = Field(default=1_000_000)
|
lnbits_notification_incoming_payment_amount_sats: int = Field(
|
||||||
lnbits_notification_outgoing_payment_amount_sats: int = Field(default=1_000_000)
|
default=1_000_000, ge=0
|
||||||
|
)
|
||||||
|
lnbits_notification_outgoing_payment_amount_sats: int = Field(
|
||||||
|
default=1_000_000, ge=0
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class FakeWalletFundingSource(LNbitsSettings):
|
class FakeWalletFundingSource(LNbitsSettings):
|
||||||
|
|
@ -535,7 +539,7 @@ class BoltzFundingSource(LNbitsSettings):
|
||||||
|
|
||||||
|
|
||||||
class LightningSettings(LNbitsSettings):
|
class LightningSettings(LNbitsSettings):
|
||||||
lightning_invoice_expiry: int = Field(default=3600)
|
lightning_invoice_expiry: int = Field(default=3600, gt=0)
|
||||||
|
|
||||||
|
|
||||||
class FundingSourcesSettings(
|
class FundingSourcesSettings(
|
||||||
|
|
@ -562,7 +566,7 @@ class FundingSourcesSettings(
|
||||||
lnbits_backend_wallet_class: str = Field(default="VoidWallet")
|
lnbits_backend_wallet_class: str = Field(default="VoidWallet")
|
||||||
# How long to wait for the payment to be confirmed before returning a pending status
|
# How long to wait for the payment to be confirmed before returning a pending status
|
||||||
# It will not fail the payment, it will make it return pending after the timeout
|
# It will not fail the payment, it will make it return pending after the timeout
|
||||||
lnbits_funding_source_pay_invoice_wait_seconds: int = Field(default=5)
|
lnbits_funding_source_pay_invoice_wait_seconds: int = Field(default=5, ge=0)
|
||||||
|
|
||||||
|
|
||||||
class WebPushSettings(LNbitsSettings):
|
class WebPushSettings(LNbitsSettings):
|
||||||
|
|
@ -601,7 +605,7 @@ class AuthMethods(Enum):
|
||||||
|
|
||||||
|
|
||||||
class AuthSettings(LNbitsSettings):
|
class AuthSettings(LNbitsSettings):
|
||||||
auth_token_expire_minutes: int = Field(default=525600)
|
auth_token_expire_minutes: int = Field(default=525600, gt=0)
|
||||||
auth_all_methods = [a.value for a in AuthMethods]
|
auth_all_methods = [a.value for a in AuthMethods]
|
||||||
auth_allowed_methods: list[str] = Field(
|
auth_allowed_methods: list[str] = Field(
|
||||||
default=[
|
default=[
|
||||||
|
|
@ -611,7 +615,7 @@ class AuthSettings(LNbitsSettings):
|
||||||
)
|
)
|
||||||
# How many seconds after login the user is allowed to update its credentials.
|
# How many seconds after login the user is allowed to update its credentials.
|
||||||
# A fresh login is required afterwards.
|
# A fresh login is required afterwards.
|
||||||
auth_credetials_update_threshold: int = Field(default=120)
|
auth_credetials_update_threshold: int = Field(default=120, gt=0)
|
||||||
|
|
||||||
def is_auth_method_allowed(self, method: AuthMethods):
|
def is_auth_method_allowed(self, method: AuthMethods):
|
||||||
return method.value in self.auth_allowed_methods
|
return method.value in self.auth_allowed_methods
|
||||||
|
|
@ -643,7 +647,7 @@ class AuditSettings(LNbitsSettings):
|
||||||
lnbits_audit_enabled: bool = Field(default=True)
|
lnbits_audit_enabled: bool = Field(default=True)
|
||||||
|
|
||||||
# number of days to keep the audit entry
|
# number of days to keep the audit entry
|
||||||
lnbits_audit_retention_days: int = Field(default=7)
|
lnbits_audit_retention_days: int = Field(default=7, ge=0)
|
||||||
|
|
||||||
lnbits_audit_log_ip_address: bool = Field(default=False)
|
lnbits_audit_log_ip_address: bool = Field(default=False)
|
||||||
lnbits_audit_log_path_params: bool = Field(default=True)
|
lnbits_audit_log_path_params: bool = Field(default=True)
|
||||||
|
|
@ -780,7 +784,7 @@ class EnvSettings(LNbitsSettings):
|
||||||
debug_database: bool = Field(default=False)
|
debug_database: bool = Field(default=False)
|
||||||
bundle_assets: bool = Field(default=True)
|
bundle_assets: bool = Field(default=True)
|
||||||
host: str = Field(default="127.0.0.1")
|
host: str = Field(default="127.0.0.1")
|
||||||
port: int = Field(default=5000)
|
port: int = Field(default=5000, gt=0)
|
||||||
forwarded_allow_ips: str = Field(default="*")
|
forwarded_allow_ips: str = Field(default="*")
|
||||||
lnbits_title: str = Field(default="LNbits API")
|
lnbits_title: str = Field(default="LNbits API")
|
||||||
lnbits_path: str = Field(default=".")
|
lnbits_path: str = Field(default=".")
|
||||||
|
|
@ -792,24 +796,27 @@ class EnvSettings(LNbitsSettings):
|
||||||
enable_log_to_file: bool = Field(default=True)
|
enable_log_to_file: bool = Field(default=True)
|
||||||
log_rotation: str = Field(default="100 MB")
|
log_rotation: str = Field(default="100 MB")
|
||||||
log_retention: str = Field(default="3 months")
|
log_retention: str = Field(default="3 months")
|
||||||
server_startup_time: int = Field(default=time())
|
|
||||||
cleanup_wallets_days: int = Field(default=90)
|
cleanup_wallets_days: int = Field(default=90, ge=0)
|
||||||
funding_source_max_retries: int = Field(default=4)
|
funding_source_max_retries: int = Field(default=4, ge=0)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def has_default_extension_path(self) -> bool:
|
def has_default_extension_path(self) -> bool:
|
||||||
return self.lnbits_extensions_path == "lnbits"
|
return self.lnbits_extensions_path == "lnbits"
|
||||||
|
|
||||||
@property
|
def check_auth_secret_key(self):
|
||||||
def lnbits_server_up_time(self) -> str:
|
if self.auth_secret_key:
|
||||||
up_time = int(time() - self.server_startup_time)
|
return
|
||||||
return strftime("%H:%M:%S", gmtime(up_time))
|
if not os.path.isdir(settings.lnbits_data_folder):
|
||||||
|
os.mkdir(settings.lnbits_data_folder)
|
||||||
|
auth_key_file = Path(settings.lnbits_data_folder, ".lnbits_auth_key")
|
||||||
class SaaSSettings(LNbitsSettings):
|
if auth_key_file.is_file():
|
||||||
lnbits_saas_callback: str | None = Field(default=None)
|
with open(auth_key_file) as file:
|
||||||
lnbits_saas_secret: str | None = Field(default=None)
|
self.auth_secret_key = file.readline()
|
||||||
lnbits_saas_instance_id: str | None = Field(default=None)
|
return
|
||||||
|
self.auth_secret_key = uuid4().hex
|
||||||
|
with open(auth_key_file, "w+") as file:
|
||||||
|
file.write(self.auth_secret_key)
|
||||||
|
|
||||||
|
|
||||||
class PersistenceSettings(LNbitsSettings):
|
class PersistenceSettings(LNbitsSettings):
|
||||||
|
|
@ -861,6 +868,13 @@ class TransientSettings(InstalledExtensionsSettings, ExchangeHistorySettings):
|
||||||
|
|
||||||
lnbits_all_extensions_ids: set[str] = Field(default=[])
|
lnbits_all_extensions_ids: set[str] = Field(default=[])
|
||||||
|
|
||||||
|
server_startup_time: int = Field(default=time())
|
||||||
|
|
||||||
|
@property
|
||||||
|
def lnbits_server_up_time(self) -> str:
|
||||||
|
up_time = int(time() - self.server_startup_time)
|
||||||
|
return strftime("%H:%M:%S", gmtime(up_time))
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def readonly_fields(cls):
|
def readonly_fields(cls):
|
||||||
return [f for f in inspect.signature(cls).parameters if not f.startswith("_")]
|
return [f for f in inspect.signature(cls).parameters if not f.startswith("_")]
|
||||||
|
|
@ -869,7 +883,6 @@ class TransientSettings(InstalledExtensionsSettings, ExchangeHistorySettings):
|
||||||
class ReadOnlySettings(
|
class ReadOnlySettings(
|
||||||
EnvSettings,
|
EnvSettings,
|
||||||
ExtensionsInstallSettings,
|
ExtensionsInstallSettings,
|
||||||
SaaSSettings,
|
|
||||||
PersistenceSettings,
|
PersistenceSettings,
|
||||||
SuperUserSettings,
|
SuperUserSettings,
|
||||||
):
|
):
|
||||||
|
|
@ -948,31 +961,6 @@ def set_cli_settings(**kwargs):
|
||||||
setattr(settings, key, value)
|
setattr(settings, key, value)
|
||||||
|
|
||||||
|
|
||||||
def send_admin_user_to_saas():
|
|
||||||
if settings.lnbits_saas_callback:
|
|
||||||
with httpx.Client() as client:
|
|
||||||
headers = {
|
|
||||||
"Content-Type": "application/json; charset=utf-8",
|
|
||||||
"X-API-KEY": settings.lnbits_saas_secret,
|
|
||||||
}
|
|
||||||
payload = {
|
|
||||||
"instance_id": settings.lnbits_saas_instance_id,
|
|
||||||
"adminuser": settings.super_user,
|
|
||||||
}
|
|
||||||
try:
|
|
||||||
client.post(
|
|
||||||
settings.lnbits_saas_callback,
|
|
||||||
headers=headers,
|
|
||||||
json=payload,
|
|
||||||
)
|
|
||||||
logger.success("sent super_user to saas application")
|
|
||||||
except Exception as e:
|
|
||||||
logger.error(
|
|
||||||
"error sending super_user to saas:"
|
|
||||||
f" {settings.lnbits_saas_callback}. Error: {e!s}"
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
readonly_variables = ReadOnlySettings.readonly_fields()
|
readonly_variables = ReadOnlySettings.readonly_fields()
|
||||||
transient_variables = TransientSettings.readonly_fields()
|
transient_variables = TransientSettings.readonly_fields()
|
||||||
|
|
||||||
|
|
@ -981,9 +969,8 @@ settings = Settings()
|
||||||
settings.lnbits_path = str(path.dirname(path.realpath(__file__)))
|
settings.lnbits_path = str(path.dirname(path.realpath(__file__)))
|
||||||
|
|
||||||
settings.version = importlib.metadata.version("lnbits")
|
settings.version = importlib.metadata.version("lnbits")
|
||||||
settings.auth_secret_key = (
|
|
||||||
settings.auth_secret_key or sha256(settings.super_user.encode("utf-8")).hexdigest()
|
settings.check_auth_secret_key()
|
||||||
)
|
|
||||||
|
|
||||||
if not settings.user_agent:
|
if not settings.user_agent:
|
||||||
settings.user_agent = f"LNbits/{settings.version}"
|
settings.user_agent = f"LNbits/{settings.version}"
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue