2023-09-25 15:04:44 +02:00
|
|
|
from __future__ import annotations
|
|
|
|
|
2020-03-31 19:05:25 +02:00
|
|
|
import importlib
|
2023-03-30 14:19:45 +02:00
|
|
|
import importlib.metadata
|
2022-12-09 12:14:22 +01:00
|
|
|
import inspect
|
2022-10-03 16:46:46 +02:00
|
|
|
import json
|
2023-12-12 11:38:19 +01:00
|
|
|
from enum import Enum
|
|
|
|
from hashlib import sha256
|
2020-09-05 08:00:44 +02:00
|
|
|
from os import path
|
2022-10-03 16:46:46 +02:00
|
|
|
from sqlite3 import Row
|
2023-10-27 13:50:49 +02:00
|
|
|
from time import time
|
2023-02-22 10:12:16 +01:00
|
|
|
from typing import Any, List, Optional
|
2020-09-05 08:00:44 +02:00
|
|
|
|
2022-10-12 13:08:59 +02:00
|
|
|
import httpx
|
2022-10-03 16:46:46 +02:00
|
|
|
from loguru import logger
|
2023-09-12 11:59:32 +02:00
|
|
|
from pydantic import BaseModel, BaseSettings, Extra, Field, validator
|
2020-09-05 08:00:44 +02:00
|
|
|
|
2020-01-15 16:19:54 +01:00
|
|
|
|
2023-08-24 12:50:38 +02:00
|
|
|
def list_parse_fallback(v: str):
|
|
|
|
v = v.replace(" ", "")
|
|
|
|
if len(v) > 0:
|
|
|
|
if v.startswith("[") or v.startswith("{"):
|
|
|
|
return json.loads(v)
|
2022-10-03 16:46:46 +02:00
|
|
|
else:
|
2023-08-24 12:50:38 +02:00
|
|
|
return v.split(",")
|
|
|
|
else:
|
|
|
|
return []
|
2020-09-05 08:00:44 +02:00
|
|
|
|
2022-07-07 14:30:16 +02:00
|
|
|
|
2023-09-12 11:59:32 +02:00
|
|
|
class LNbitsSettings(BaseModel):
|
2023-02-02 13:58:23 +01:00
|
|
|
@classmethod
|
2023-09-12 11:59:32 +02:00
|
|
|
def validate_list(cls, val):
|
2023-08-16 12:22:14 +02:00
|
|
|
if isinstance(val, str):
|
2022-12-09 09:57:53 +01:00
|
|
|
val = val.split(",") if val else []
|
|
|
|
return val
|
2022-12-09 10:06:43 +01:00
|
|
|
|
2022-12-09 09:57:53 +01:00
|
|
|
|
2022-12-19 09:10:41 +01:00
|
|
|
class UsersSettings(LNbitsSettings):
|
2022-10-03 16:46:46 +02:00
|
|
|
lnbits_admin_users: List[str] = Field(default=[])
|
|
|
|
lnbits_allowed_users: List[str] = Field(default=[])
|
2023-10-11 13:46:27 +02:00
|
|
|
lnbits_allow_new_accounts: bool = Field(default=True)
|
|
|
|
|
|
|
|
@property
|
|
|
|
def new_accounts_allowed(self) -> bool:
|
|
|
|
return self.lnbits_allow_new_accounts and len(self.lnbits_allowed_users) == 0
|
2023-01-18 10:49:23 +01:00
|
|
|
|
|
|
|
|
|
|
|
class ExtensionsSettings(LNbitsSettings):
|
2022-10-03 16:46:46 +02:00
|
|
|
lnbits_admin_extensions: List[str] = Field(default=[])
|
2024-03-26 11:44:33 +01:00
|
|
|
lnbits_extensions_deactivate_all: bool = Field(default=False)
|
2023-01-23 13:58:32 +01:00
|
|
|
lnbits_extensions_manifests: List[str] = Field(
|
|
|
|
default=[
|
|
|
|
"https://raw.githubusercontent.com/lnbits/lnbits-extensions/main/extensions.json"
|
|
|
|
]
|
|
|
|
)
|
2023-05-11 02:14:07 +02:00
|
|
|
|
|
|
|
|
|
|
|
class ExtensionsInstallSettings(LNbitsSettings):
|
2023-02-16 09:48:12 +01:00
|
|
|
lnbits_extensions_default_install: List[str] = Field(default=[])
|
2023-01-20 08:39:27 +01:00
|
|
|
# required due to GitHUb rate-limit
|
|
|
|
lnbits_ext_github_token: str = Field(default="")
|
|
|
|
|
|
|
|
|
|
|
|
class InstalledExtensionsSettings(LNbitsSettings):
|
|
|
|
# installed extensions that have been deactivated
|
|
|
|
lnbits_deactivated_extensions: List[str] = Field(default=[])
|
|
|
|
# upgraded extensions that require API redirects
|
2022-12-22 16:03:26 +01:00
|
|
|
lnbits_upgraded_extensions: List[str] = Field(default=[])
|
2023-02-22 10:12:16 +01:00
|
|
|
# list of redirects that extensions want to perform
|
|
|
|
lnbits_extensions_redirects: List[Any] = Field(default=[])
|
2022-12-09 10:35:46 +01:00
|
|
|
|
2024-02-21 11:08:37 +01:00
|
|
|
def extension_upgrade_path(self, ext_id: str) -> Optional[str]:
|
|
|
|
return next(
|
|
|
|
(e for e in self.lnbits_upgraded_extensions if e.endswith(f"/{ext_id}")),
|
|
|
|
None,
|
|
|
|
)
|
|
|
|
|
|
|
|
def extension_upgrade_hash(self, ext_id: str) -> Optional[str]:
|
|
|
|
path = settings.extension_upgrade_path(ext_id)
|
|
|
|
return path.split("/")[0] if path else None
|
|
|
|
|
2022-12-22 16:07:27 +01:00
|
|
|
|
2022-12-19 09:10:41 +01:00
|
|
|
class ThemesSettings(LNbitsSettings):
|
2022-10-03 16:46:46 +02:00
|
|
|
lnbits_site_title: str = Field(default="LNbits")
|
|
|
|
lnbits_site_tagline: str = Field(default="free and open-source lightning wallet")
|
|
|
|
lnbits_site_description: str = Field(default=None)
|
|
|
|
lnbits_default_wallet_name: str = Field(default="LNbits wallet")
|
|
|
|
lnbits_theme_options: List[str] = Field(
|
2023-02-20 23:45:52 +01:00
|
|
|
default=[
|
|
|
|
"classic",
|
|
|
|
"freedom",
|
|
|
|
"mint",
|
|
|
|
"salvador",
|
|
|
|
"monochrome",
|
|
|
|
"autumn",
|
|
|
|
"cyber",
|
|
|
|
]
|
2022-09-23 10:01:14 +02:00
|
|
|
)
|
2022-10-03 16:46:46 +02:00
|
|
|
lnbits_custom_logo: str = Field(default=None)
|
2022-12-06 10:58:59 +01:00
|
|
|
lnbits_ad_space_title: str = Field(default="Supported by")
|
2022-12-02 15:38:21 +01:00
|
|
|
lnbits_ad_space: str = Field(
|
2022-12-02 15:59:02 +01:00
|
|
|
default="https://shop.lnbits.com/;/static/images/lnbits-shop-light.png;/static/images/lnbits-shop-dark.png"
|
2022-12-02 15:38:21 +01:00
|
|
|
) # sneaky sneaky
|
2022-12-02 15:36:09 +01:00
|
|
|
lnbits_ad_space_enabled: bool = Field(default=False)
|
2023-06-19 12:24:19 +02:00
|
|
|
lnbits_allowed_currencies: List[str] = Field(default=[])
|
2023-08-28 12:00:59 +02:00
|
|
|
lnbits_default_accounting_currency: Optional[str] = Field(default=None)
|
2023-10-12 12:59:02 +02:00
|
|
|
lnbits_qr_logo: str = Field(default="/static/images/logos/lnbits.png")
|
2019-12-18 14:44:58 +01:00
|
|
|
|
2022-12-09 10:35:46 +01:00
|
|
|
|
2022-12-19 09:10:41 +01:00
|
|
|
class OpsSettings(LNbitsSettings):
|
2023-03-01 09:55:29 +01:00
|
|
|
lnbits_baseurl: str = Field(default="http://127.0.0.1:5000/")
|
2022-12-07 15:57:22 +01:00
|
|
|
lnbits_reserve_fee_min: int = Field(default=2000)
|
2022-10-03 16:46:46 +02:00
|
|
|
lnbits_reserve_fee_percent: float = Field(default=1.0)
|
|
|
|
lnbits_service_fee: float = Field(default=0)
|
2023-11-21 12:11:21 +01:00
|
|
|
lnbits_service_fee_ignore_internal: bool = Field(default=True)
|
|
|
|
lnbits_service_fee_max: int = Field(default=0)
|
|
|
|
lnbits_service_fee_wallet: str = Field(default=None)
|
2022-10-03 16:46:46 +02:00
|
|
|
lnbits_hide_api: bool = Field(default=False)
|
|
|
|
lnbits_denomination: str = Field(default="sats")
|
|
|
|
|
2022-12-09 10:35:46 +01:00
|
|
|
|
2023-06-20 11:26:33 +02:00
|
|
|
class SecuritySettings(LNbitsSettings):
|
|
|
|
lnbits_rate_limit_no: str = Field(default="200")
|
|
|
|
lnbits_rate_limit_unit: str = Field(default="minute")
|
|
|
|
lnbits_allowed_ips: List[str] = Field(default=[])
|
|
|
|
lnbits_blocked_ips: List[str] = Field(default=[])
|
|
|
|
lnbits_notifications: bool = Field(default=False)
|
|
|
|
lnbits_killswitch: bool = Field(default=False)
|
|
|
|
lnbits_killswitch_interval: int = Field(default=60)
|
2024-02-09 16:25:53 +01:00
|
|
|
lnbits_wallet_limit_max_balance: int = Field(default=0)
|
|
|
|
lnbits_wallet_limit_daily_max_withdraw: int = Field(default=0)
|
|
|
|
lnbits_wallet_limit_secs_between_trans: int = Field(default=0)
|
2023-06-20 11:26:33 +02:00
|
|
|
lnbits_watchdog: bool = Field(default=False)
|
|
|
|
lnbits_watchdog_interval: int = Field(default=60)
|
|
|
|
lnbits_watchdog_delta: int = Field(default=1_000_000)
|
|
|
|
lnbits_status_manifest: str = Field(
|
2023-08-24 11:26:09 +02:00
|
|
|
default=(
|
|
|
|
"https://raw.githubusercontent.com/lnbits/lnbits-status/main/manifest.json"
|
|
|
|
)
|
2023-06-20 11:26:33 +02:00
|
|
|
)
|
|
|
|
|
2024-02-09 16:25:53 +01:00
|
|
|
def is_wallet_max_balance_exceeded(self, amount):
|
|
|
|
return (
|
|
|
|
self.lnbits_wallet_limit_max_balance
|
|
|
|
and self.lnbits_wallet_limit_max_balance > 0
|
|
|
|
and amount > self.lnbits_wallet_limit_max_balance
|
|
|
|
)
|
|
|
|
|
2023-06-20 11:26:33 +02:00
|
|
|
|
2022-12-19 09:10:41 +01:00
|
|
|
class FakeWalletFundingSource(LNbitsSettings):
|
2022-10-03 16:46:46 +02:00
|
|
|
fake_wallet_secret: str = Field(default="ToTheMoon1")
|
2022-12-09 10:35:46 +01:00
|
|
|
|
|
|
|
|
2022-12-19 09:10:41 +01:00
|
|
|
class LNbitsFundingSource(LNbitsSettings):
|
2022-10-03 16:46:46 +02:00
|
|
|
lnbits_endpoint: str = Field(default="https://legend.lnbits.com")
|
|
|
|
lnbits_key: Optional[str] = Field(default=None)
|
2023-02-02 13:58:23 +01:00
|
|
|
lnbits_admin_key: Optional[str] = Field(default=None)
|
|
|
|
lnbits_invoice_key: Optional[str] = Field(default=None)
|
2022-12-09 10:35:46 +01:00
|
|
|
|
|
|
|
|
2022-12-19 09:10:41 +01:00
|
|
|
class ClicheFundingSource(LNbitsSettings):
|
2022-10-03 16:46:46 +02:00
|
|
|
cliche_endpoint: Optional[str] = Field(default=None)
|
2022-12-09 10:35:46 +01:00
|
|
|
|
|
|
|
|
2022-12-19 09:10:41 +01:00
|
|
|
class CoreLightningFundingSource(LNbitsSettings):
|
2022-10-03 16:46:46 +02:00
|
|
|
corelightning_rpc: Optional[str] = Field(default=None)
|
2022-12-19 15:54:31 +01:00
|
|
|
clightning_rpc: Optional[str] = Field(default=None)
|
2022-12-09 10:35:46 +01:00
|
|
|
|
|
|
|
|
2023-08-23 08:59:39 +02:00
|
|
|
class CoreLightningRestFundingSource(LNbitsSettings):
|
|
|
|
corelightning_rest_url: Optional[str] = Field(default=None)
|
|
|
|
corelightning_rest_macaroon: Optional[str] = Field(default=None)
|
|
|
|
corelightning_rest_cert: Optional[str] = Field(default=None)
|
|
|
|
|
|
|
|
|
2022-12-19 09:10:41 +01:00
|
|
|
class EclairFundingSource(LNbitsSettings):
|
2022-10-03 16:46:46 +02:00
|
|
|
eclair_url: Optional[str] = Field(default=None)
|
|
|
|
eclair_pass: Optional[str] = Field(default=None)
|
2022-12-09 10:35:46 +01:00
|
|
|
|
|
|
|
|
2022-12-19 09:10:41 +01:00
|
|
|
class LndRestFundingSource(LNbitsSettings):
|
2022-10-03 16:46:46 +02:00
|
|
|
lnd_rest_endpoint: Optional[str] = Field(default=None)
|
|
|
|
lnd_rest_cert: Optional[str] = Field(default=None)
|
|
|
|
lnd_rest_macaroon: Optional[str] = Field(default=None)
|
2022-10-05 13:12:16 +02:00
|
|
|
lnd_rest_macaroon_encrypted: Optional[str] = Field(default=None)
|
2024-03-22 12:45:39 +01:00
|
|
|
lnd_rest_route_hints: bool = Field(default=True)
|
2022-10-06 10:13:45 +02:00
|
|
|
lnd_cert: Optional[str] = Field(default=None)
|
|
|
|
lnd_admin_macaroon: Optional[str] = Field(default=None)
|
|
|
|
lnd_invoice_macaroon: Optional[str] = Field(default=None)
|
2023-01-10 17:25:12 +01:00
|
|
|
lnd_rest_admin_macaroon: Optional[str] = Field(default=None)
|
|
|
|
lnd_rest_invoice_macaroon: Optional[str] = Field(default=None)
|
2022-12-09 10:35:46 +01:00
|
|
|
|
|
|
|
|
2022-12-19 09:10:41 +01:00
|
|
|
class LndGrpcFundingSource(LNbitsSettings):
|
2022-10-06 10:13:45 +02:00
|
|
|
lnd_grpc_endpoint: Optional[str] = Field(default=None)
|
|
|
|
lnd_grpc_cert: Optional[str] = Field(default=None)
|
|
|
|
lnd_grpc_port: Optional[int] = Field(default=None)
|
|
|
|
lnd_grpc_admin_macaroon: Optional[str] = Field(default=None)
|
|
|
|
lnd_grpc_invoice_macaroon: Optional[str] = Field(default=None)
|
2022-11-24 15:43:15 +01:00
|
|
|
lnd_grpc_macaroon: Optional[str] = Field(default=None)
|
2022-10-06 10:13:45 +02:00
|
|
|
lnd_grpc_macaroon_encrypted: Optional[str] = Field(default=None)
|
2022-12-09 10:35:46 +01:00
|
|
|
|
|
|
|
|
2022-12-19 09:10:41 +01:00
|
|
|
class LnPayFundingSource(LNbitsSettings):
|
2022-10-03 16:46:46 +02:00
|
|
|
lnpay_api_endpoint: Optional[str] = Field(default=None)
|
|
|
|
lnpay_api_key: Optional[str] = Field(default=None)
|
|
|
|
lnpay_wallet_key: Optional[str] = Field(default=None)
|
2023-02-02 13:58:23 +01:00
|
|
|
lnpay_admin_key: Optional[str] = Field(default=None)
|
2022-12-09 10:35:46 +01:00
|
|
|
|
|
|
|
|
2024-02-02 01:10:15 +01:00
|
|
|
class ZBDFundingSource(LNbitsSettings):
|
|
|
|
zbd_api_endpoint: Optional[str] = Field(default="https://api.zebedee.io/v0/")
|
|
|
|
zbd_api_key: Optional[str] = Field(default=None)
|
|
|
|
|
2024-02-02 03:36:17 +01:00
|
|
|
|
2023-11-14 20:28:25 +01:00
|
|
|
class AlbyFundingSource(LNbitsSettings):
|
|
|
|
alby_api_endpoint: Optional[str] = Field(default="https://api.getalby.com/")
|
|
|
|
alby_access_token: Optional[str] = Field(default=None)
|
|
|
|
|
|
|
|
|
2022-12-19 09:10:41 +01:00
|
|
|
class OpenNodeFundingSource(LNbitsSettings):
|
2022-10-03 16:46:46 +02:00
|
|
|
opennode_api_endpoint: Optional[str] = Field(default=None)
|
|
|
|
opennode_key: Optional[str] = Field(default=None)
|
2023-02-02 13:58:23 +01:00
|
|
|
opennode_admin_key: Optional[str] = Field(default=None)
|
|
|
|
opennode_invoice_key: Optional[str] = Field(default=None)
|
2022-12-09 10:35:46 +01:00
|
|
|
|
|
|
|
|
2022-12-19 09:10:41 +01:00
|
|
|
class SparkFundingSource(LNbitsSettings):
|
2022-10-03 16:46:46 +02:00
|
|
|
spark_url: Optional[str] = Field(default=None)
|
|
|
|
spark_token: Optional[str] = Field(default=None)
|
2022-12-09 10:35:46 +01:00
|
|
|
|
|
|
|
|
2022-12-19 09:10:41 +01:00
|
|
|
class LnTipsFundingSource(LNbitsSettings):
|
2022-11-30 16:53:46 +01:00
|
|
|
lntips_api_endpoint: Optional[str] = Field(default=None)
|
|
|
|
lntips_api_key: Optional[str] = Field(default=None)
|
|
|
|
lntips_admin_key: Optional[str] = Field(default=None)
|
|
|
|
lntips_invoice_key: Optional[str] = Field(default=None)
|
Boltz.exchange Extension (#922)
* initial commit and still draft, ready for review
* forgot to uncomment this line
* fee estimation and blockheight
* resolve conversation with michael, to use mempool websockets instead of boltz status event
* Update lnbits/extensions/boltz/boltz.py
Co-authored-by: michael1011 <me@michael1011.at>
* add status to swaps, add sorting and data into listing
* add swap status checks, change urls to docker test setup, dynamic minimum and maximum limits
* fix docker hosts for development
* add api endpoints to _api_docs
* add wallet name and id, to list and status information
* fix status_update for reverse_swaps
* chore: format with black
* more blackformatting and refactoring create_swap()
* fix variable bug
* check if swap is already refunded
* use create_task instead of ensure_future
* add mempool and boltz urls depending on DEBUG .env
* raise exception in mempool fails
* fix onchain txs, sending funds to wrong address and add a refund address for normal swaps beforehand
* add status to swaps, add sorting and data into listing
* add swap status checks, change urls to docker test setup, dynamic minimum and maximum limits
* add wallet name and id, to list and status information
* fix status_update for reverse_swaps
* chore: format with black
* use create_task instead of ensure_future
* add mempool and boltz urls depending on DEBUG .env
* fix onchain txs, sending funds to wrong address and add a refund address for normal swaps beforehand
* black formatting
* add some logging with loguru, and remove function duplication
* cleanup readme
* updates/suggestions from calle
Co-authored-by: calle <93376500+callebtc@users.noreply.github.com>
* remove unused comments
* Update API Endpoints
Co-authored-by: calle <93376500+callebtc@users.noreply.github.com>
* un-factor get_boltz_pairs
* added a explaination for the onchain tx
* remove unused template file
* rename api endpoints
* fix isort and prettier
* more verbose logging!!
* add boltz to mock_data.zip
* new mockdata
* remove comment
* better readme
* fix mempool urls
* change /refund /check /status to post requests
* first step in tests2
* add first tests
* change refund,check,status to post requests
* next try on tests
* overall code improvements
* just testing tests
* throw http exceptions in views_api
* require admincheck for refund,check,status and added fastapi documentation for those
* added more tests
* black
* many code improvements
* adding tests
* temp fix test
* fix race condition when pay_invoice fails
* test are working
* add boltz env variables
* add startup check, bugfixes, improvements
* improve on status checking
* remove check_invoice_status
* more fixes and tests
* testing testing testing
* make tests run again inside regtest
* fix bad error :O
* fix postgres boolean bug and add swap test
* Update README.md
Update README.md
Update README.md
Update README.md
* some mypy
* blacked
* the missing commit?
* fix api_docs readme link
* better refunding error catching
fix
* check swaps now also shows pending reverse swap, ui improvements, tooltips
* add backend check for boltz limits
fixup
* many improvements, startup check for swaps working, reverse needs more testing
* little last fixes
* remove unused logic
* fastapi documentation
fixup
* formatting and remove unused tests
* fix test
* fix swapstatus model
* Update lnbits/extensions/boltz/tasks.py
Co-authored-by: calle <93376500+callebtc@users.noreply.github.com>
* Update lnbits/extensions/boltz/views_api.py
Co-authored-by: calle <93376500+callebtc@users.noreply.github.com>
* balance check msg, format
* fix mypy data override
* fix swapstatus, remove can refund column
* Update lnbits/extensions/boltz/README.md
Co-authored-by: michael1011 <me@michael1011.at>
* empty lines
* fix error message when swap is not found
* remove preimage_hash from database
* fix api_docs html
fix api_docs html
* catch boltz network exceptions better
* formatting
* check for timeout on swap at get request
Co-authored-by: michael1011 <me@michael1011.at>
Co-authored-by: fusion44 <some.fusion@gmail.com>
Co-authored-by: calle <93376500+callebtc@users.noreply.github.com>
2022-08-30 12:51:17 +02:00
|
|
|
|
2022-12-09 10:35:46 +01:00
|
|
|
|
2023-01-26 11:08:40 +01:00
|
|
|
class LightningSettings(LNbitsSettings):
|
2023-07-19 13:13:46 +02:00
|
|
|
lightning_invoice_expiry: int = Field(default=3600)
|
2023-01-26 11:08:40 +01:00
|
|
|
|
|
|
|
|
2022-12-19 09:10:41 +01:00
|
|
|
class FundingSourcesSettings(
|
2022-12-09 10:35:46 +01:00
|
|
|
FakeWalletFundingSource,
|
|
|
|
LNbitsFundingSource,
|
|
|
|
ClicheFundingSource,
|
|
|
|
CoreLightningFundingSource,
|
2023-08-23 08:59:39 +02:00
|
|
|
CoreLightningRestFundingSource,
|
2022-12-09 10:35:46 +01:00
|
|
|
EclairFundingSource,
|
|
|
|
LndRestFundingSource,
|
|
|
|
LndGrpcFundingSource,
|
|
|
|
LnPayFundingSource,
|
2023-11-14 20:28:25 +01:00
|
|
|
AlbyFundingSource,
|
2024-02-02 03:36:17 +01:00
|
|
|
ZBDFundingSource,
|
2022-12-09 10:35:46 +01:00
|
|
|
OpenNodeFundingSource,
|
|
|
|
SparkFundingSource,
|
|
|
|
LnTipsFundingSource,
|
|
|
|
):
|
|
|
|
lnbits_backend_wallet_class: str = Field(default="VoidWallet")
|
|
|
|
|
|
|
|
|
2023-09-11 15:48:49 +02:00
|
|
|
class WebPushSettings(LNbitsSettings):
|
|
|
|
lnbits_webpush_pubkey: str = Field(default=None)
|
|
|
|
lnbits_webpush_privkey: str = Field(default=None)
|
|
|
|
|
|
|
|
|
2023-09-25 15:04:44 +02:00
|
|
|
class NodeUISettings(LNbitsSettings):
|
|
|
|
# on-off switch for node ui
|
|
|
|
lnbits_node_ui: bool = Field(default=False)
|
|
|
|
# whether to display the public node ui (only if lnbits_node_ui is True)
|
|
|
|
lnbits_public_node_ui: bool = Field(default=False)
|
|
|
|
# can be used to disable the transactions tab in the node ui
|
|
|
|
# (recommended for large cln nodes)
|
|
|
|
lnbits_node_ui_transactions: bool = Field(default=False)
|
|
|
|
|
|
|
|
|
2023-12-14 11:34:23 +01:00
|
|
|
class AuthMethods(Enum):
|
|
|
|
user_id_only = "user-id-only"
|
|
|
|
username_and_password = "username-password"
|
|
|
|
google_auth = "google-auth"
|
|
|
|
github_auth = "github-auth"
|
2024-02-14 09:23:37 +01:00
|
|
|
keycloak_auth = "keycloak-auth"
|
2023-12-14 11:34:23 +01:00
|
|
|
|
|
|
|
|
|
|
|
class AuthSettings(LNbitsSettings):
|
|
|
|
auth_token_expire_minutes: int = Field(default=525600)
|
|
|
|
auth_all_methods = [a.value for a in AuthMethods]
|
|
|
|
auth_allowed_methods: List[str] = Field(
|
|
|
|
default=[
|
|
|
|
AuthMethods.user_id_only.value,
|
|
|
|
AuthMethods.username_and_password.value,
|
|
|
|
]
|
|
|
|
)
|
|
|
|
|
|
|
|
def is_auth_method_allowed(self, method: AuthMethods):
|
|
|
|
return method.value in self.auth_allowed_methods
|
|
|
|
|
|
|
|
|
|
|
|
class GoogleAuthSettings(LNbitsSettings):
|
|
|
|
google_client_id: str = Field(default="")
|
|
|
|
google_client_secret: str = Field(default="")
|
|
|
|
|
|
|
|
|
|
|
|
class GitHubAuthSettings(LNbitsSettings):
|
|
|
|
github_client_id: str = Field(default="")
|
|
|
|
github_client_secret: str = Field(default="")
|
|
|
|
|
|
|
|
|
2024-02-14 09:23:37 +01:00
|
|
|
class KeycloakAuthSettings(LNbitsSettings):
|
|
|
|
keycloak_discovery_url: str = Field(default="")
|
|
|
|
keycloak_client_id: str = Field(default="")
|
|
|
|
keycloak_client_secret: str = Field(default="")
|
|
|
|
|
|
|
|
|
2022-12-19 09:10:41 +01:00
|
|
|
class EditableSettings(
|
|
|
|
UsersSettings,
|
2023-01-18 10:49:23 +01:00
|
|
|
ExtensionsSettings,
|
2022-12-19 09:10:41 +01:00
|
|
|
ThemesSettings,
|
|
|
|
OpsSettings,
|
2023-06-20 11:26:33 +02:00
|
|
|
SecuritySettings,
|
2022-12-19 09:10:41 +01:00
|
|
|
FundingSourcesSettings,
|
2023-01-26 11:08:40 +01:00
|
|
|
LightningSettings,
|
2023-09-11 15:48:49 +02:00
|
|
|
WebPushSettings,
|
2023-09-25 15:04:44 +02:00
|
|
|
NodeUISettings,
|
2023-12-14 11:34:23 +01:00
|
|
|
AuthSettings,
|
|
|
|
GoogleAuthSettings,
|
|
|
|
GitHubAuthSettings,
|
2024-02-14 09:23:37 +01:00
|
|
|
KeycloakAuthSettings,
|
2022-12-09 10:35:46 +01:00
|
|
|
):
|
2022-12-09 09:57:53 +01:00
|
|
|
@validator(
|
|
|
|
"lnbits_admin_users",
|
|
|
|
"lnbits_allowed_users",
|
|
|
|
"lnbits_theme_options",
|
|
|
|
"lnbits_admin_extensions",
|
|
|
|
pre=True,
|
|
|
|
)
|
2023-02-02 13:58:23 +01:00
|
|
|
@classmethod
|
2022-12-09 09:57:53 +01:00
|
|
|
def validate_editable_settings(cls, val):
|
2023-09-12 11:59:32 +02:00
|
|
|
return super().validate_list(val)
|
2022-12-09 09:57:53 +01:00
|
|
|
|
2022-12-09 12:14:22 +01:00
|
|
|
@classmethod
|
|
|
|
def from_dict(cls, d: dict):
|
|
|
|
return cls(
|
|
|
|
**{k: v for k, v in d.items() if k in inspect.signature(cls).parameters}
|
|
|
|
)
|
|
|
|
|
2023-07-19 13:28:27 +02:00
|
|
|
# fixes openapi.json validation, remove field env_names
|
|
|
|
class Config:
|
|
|
|
@staticmethod
|
|
|
|
def schema_extra(schema: dict[str, Any]) -> None:
|
|
|
|
for prop in schema.get("properties", {}).values():
|
|
|
|
prop.pop("env_names", None)
|
|
|
|
|
2022-12-09 08:46:30 +01:00
|
|
|
|
2023-09-12 11:59:32 +02:00
|
|
|
class UpdateSettings(EditableSettings):
|
|
|
|
class Config:
|
|
|
|
extra = Extra.forbid
|
|
|
|
|
|
|
|
|
2022-12-19 09:10:41 +01:00
|
|
|
class EnvSettings(LNbitsSettings):
|
2022-12-09 08:46:30 +01:00
|
|
|
debug: bool = Field(default=False)
|
2024-03-21 09:59:17 +01:00
|
|
|
debug_database: bool = Field(default=False)
|
2023-04-27 16:05:49 +02:00
|
|
|
bundle_assets: bool = Field(default=True)
|
2022-12-09 08:46:30 +01:00
|
|
|
host: str = Field(default="127.0.0.1")
|
|
|
|
port: int = Field(default=5000)
|
|
|
|
forwarded_allow_ips: str = Field(default="*")
|
2023-08-24 11:52:12 +02:00
|
|
|
lnbits_title: str = Field(default="LNbits API")
|
2022-12-09 08:46:30 +01:00
|
|
|
lnbits_path: str = Field(default=".")
|
2023-09-25 12:44:29 +02:00
|
|
|
lnbits_extensions_path: str = Field(default="lnbits")
|
2022-12-09 09:57:53 +01:00
|
|
|
super_user: str = Field(default="")
|
2023-12-14 11:34:23 +01:00
|
|
|
auth_secret_key: str = Field(default="")
|
2023-03-30 14:19:45 +02:00
|
|
|
version: str = Field(default="0.0.0")
|
2023-11-30 13:54:07 +01:00
|
|
|
user_agent: str = Field(default="")
|
2023-10-12 11:24:05 +02:00
|
|
|
enable_log_to_file: bool = Field(default=True)
|
|
|
|
log_rotation: str = Field(default="100 MB")
|
|
|
|
log_retention: str = Field(default="3 months")
|
2023-10-27 13:50:49 +02:00
|
|
|
server_startup_time: int = Field(default=time())
|
2024-01-30 07:47:15 +01:00
|
|
|
cleanup_wallets_days: int = Field(default=90)
|
2024-04-11 18:29:25 +02:00
|
|
|
funding_source_max_retries: int = Field(default=4)
|
2022-12-09 08:46:30 +01:00
|
|
|
|
2023-09-25 12:44:29 +02:00
|
|
|
@property
|
|
|
|
def has_default_extension_path(self) -> bool:
|
|
|
|
return self.lnbits_extensions_path == "lnbits"
|
|
|
|
|
2022-12-09 14:13:58 +01:00
|
|
|
|
2022-12-19 09:10:41 +01:00
|
|
|
class SaaSSettings(LNbitsSettings):
|
2022-12-09 08:46:30 +01:00
|
|
|
lnbits_saas_callback: Optional[str] = Field(default=None)
|
|
|
|
lnbits_saas_secret: Optional[str] = Field(default=None)
|
|
|
|
lnbits_saas_instance_id: Optional[str] = Field(default=None)
|
|
|
|
|
2022-12-09 14:13:58 +01:00
|
|
|
|
2022-12-19 09:10:41 +01:00
|
|
|
class PersistenceSettings(LNbitsSettings):
|
2022-12-09 08:46:30 +01:00
|
|
|
lnbits_data_folder: str = Field(default="./data")
|
|
|
|
lnbits_database_url: str = Field(default=None)
|
|
|
|
|
2022-12-09 14:13:58 +01:00
|
|
|
|
2022-12-19 09:10:41 +01:00
|
|
|
class SuperUserSettings(LNbitsSettings):
|
2022-12-09 08:46:30 +01:00
|
|
|
lnbits_allowed_funding_sources: List[str] = Field(
|
|
|
|
default=[
|
|
|
|
"VoidWallet",
|
|
|
|
"FakeWallet",
|
2023-01-26 11:08:40 +01:00
|
|
|
"CoreLightningWallet",
|
2023-08-23 08:59:39 +02:00
|
|
|
"CoreLightningRestWallet",
|
2022-12-09 08:46:30 +01:00
|
|
|
"LndRestWallet",
|
2023-01-26 11:08:40 +01:00
|
|
|
"EclairWallet",
|
2022-12-09 08:46:30 +01:00
|
|
|
"LndWallet",
|
2023-01-26 11:08:40 +01:00
|
|
|
"LnTipsWallet",
|
2022-12-09 08:46:30 +01:00
|
|
|
"LNPayWallet",
|
2023-11-14 20:28:25 +01:00
|
|
|
"AlbyWallet",
|
2024-02-02 03:36:17 +01:00
|
|
|
"ZBDWallet",
|
2022-12-09 08:46:30 +01:00
|
|
|
"LNbitsWallet",
|
|
|
|
"OpenNodeWallet",
|
|
|
|
]
|
|
|
|
)
|
2022-12-09 10:06:43 +01:00
|
|
|
|
2022-12-09 14:13:58 +01:00
|
|
|
|
2023-01-20 17:10:29 +01:00
|
|
|
class TransientSettings(InstalledExtensionsSettings):
|
|
|
|
# Transient Settings:
|
|
|
|
# - are initialized, updated and used at runtime
|
2023-02-22 10:12:16 +01:00
|
|
|
# - are not read from a file or from the `settings` table
|
2023-01-20 17:26:58 +01:00
|
|
|
# - are not persisted in the `settings` table when the settings are updated
|
|
|
|
# - are cleared on server restart
|
2024-01-25 14:33:40 +01:00
|
|
|
first_install: bool = Field(default=False)
|
2023-01-20 17:10:29 +01:00
|
|
|
|
|
|
|
@classmethod
|
|
|
|
def readonly_fields(cls):
|
|
|
|
return [f for f in inspect.signature(cls).parameters if not f.startswith("_")]
|
|
|
|
|
|
|
|
|
2022-12-09 14:13:58 +01:00
|
|
|
class ReadOnlySettings(
|
2023-01-26 11:08:40 +01:00
|
|
|
EnvSettings,
|
2023-05-11 02:14:07 +02:00
|
|
|
ExtensionsInstallSettings,
|
2023-01-26 11:08:40 +01:00
|
|
|
SaaSSettings,
|
|
|
|
PersistenceSettings,
|
|
|
|
SuperUserSettings,
|
2022-12-09 14:13:58 +01:00
|
|
|
):
|
|
|
|
lnbits_admin_ui: bool = Field(default=False)
|
|
|
|
|
2022-12-09 10:06:43 +01:00
|
|
|
@validator(
|
|
|
|
"lnbits_allowed_funding_sources",
|
|
|
|
pre=True,
|
|
|
|
)
|
2023-02-02 13:58:23 +01:00
|
|
|
@classmethod
|
2022-12-09 10:06:43 +01:00
|
|
|
def validate_readonly_settings(cls, val):
|
2023-09-12 11:59:32 +02:00
|
|
|
return super().validate_list(val)
|
2022-12-09 09:57:53 +01:00
|
|
|
|
2022-12-09 12:37:36 +01:00
|
|
|
@classmethod
|
|
|
|
def readonly_fields(cls):
|
|
|
|
return [f for f in inspect.signature(cls).parameters if not f.startswith("_")]
|
|
|
|
|
2022-12-09 09:57:53 +01:00
|
|
|
|
2023-09-12 11:59:32 +02:00
|
|
|
class Settings(EditableSettings, ReadOnlySettings, TransientSettings, BaseSettings):
|
2022-12-09 09:57:53 +01:00
|
|
|
@classmethod
|
|
|
|
def from_row(cls, row: Row) -> "Settings":
|
|
|
|
data = dict(row)
|
|
|
|
return cls(**data)
|
|
|
|
|
2023-09-12 11:59:32 +02:00
|
|
|
class Config:
|
|
|
|
env_file = ".env"
|
|
|
|
env_file_encoding = "utf-8"
|
|
|
|
case_sensitive = False
|
|
|
|
json_loads = list_parse_fallback
|
|
|
|
|
2023-12-12 11:38:19 +01:00
|
|
|
def is_user_allowed(self, user_id: str):
|
|
|
|
return (
|
|
|
|
len(self.lnbits_allowed_users) == 0
|
|
|
|
or user_id in self.lnbits_allowed_users
|
|
|
|
or user_id in self.lnbits_admin_users
|
|
|
|
or user_id == self.super_user
|
|
|
|
)
|
|
|
|
|
2022-12-09 09:57:53 +01:00
|
|
|
|
2022-12-19 09:10:41 +01:00
|
|
|
class SuperSettings(EditableSettings):
|
2022-12-09 09:57:53 +01:00
|
|
|
super_user: str
|
|
|
|
|
|
|
|
|
2022-12-19 09:10:41 +01:00
|
|
|
class AdminSettings(EditableSettings):
|
2023-05-09 10:20:51 +02:00
|
|
|
is_super_user: bool
|
2022-12-09 09:57:53 +01:00
|
|
|
lnbits_allowed_funding_sources: Optional[List[str]]
|
|
|
|
|
2022-12-09 08:46:30 +01:00
|
|
|
|
2022-10-03 23:33:42 +02:00
|
|
|
def set_cli_settings(**kwargs):
|
|
|
|
for key, value in kwargs.items():
|
|
|
|
setattr(settings, key, value)
|
2022-10-03 16:46:46 +02:00
|
|
|
|
2022-10-03 23:41:04 +02:00
|
|
|
|
2022-12-05 20:41:23 +01:00
|
|
|
def send_admin_user_to_saas():
|
2022-12-05 16:10:35 +01:00
|
|
|
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,
|
2022-12-05 20:41:23 +01:00
|
|
|
"adminuser": settings.super_user,
|
2022-12-05 16:10:35 +01:00
|
|
|
}
|
|
|
|
try:
|
|
|
|
client.post(
|
|
|
|
settings.lnbits_saas_callback,
|
|
|
|
headers=headers,
|
|
|
|
json=payload,
|
|
|
|
)
|
2022-12-12 12:27:52 +01:00
|
|
|
logger.success("sent super_user to saas application")
|
2022-12-12 09:20:27 +01:00
|
|
|
except Exception as e:
|
2022-12-05 16:10:35 +01:00
|
|
|
logger.error(
|
2023-08-24 11:26:09 +02:00
|
|
|
"error sending super_user to saas:"
|
|
|
|
f" {settings.lnbits_saas_callback}. Error: {str(e)}"
|
2022-12-05 16:10:35 +01:00
|
|
|
)
|
2022-12-09 12:40:22 +01:00
|
|
|
|
|
|
|
|
|
|
|
readonly_variables = ReadOnlySettings.readonly_fields()
|
2023-01-20 17:10:29 +01:00
|
|
|
transient_variables = TransientSettings.readonly_fields()
|
2022-12-09 12:40:22 +01:00
|
|
|
|
|
|
|
settings = Settings()
|
|
|
|
|
|
|
|
settings.lnbits_path = str(path.dirname(path.realpath(__file__)))
|
|
|
|
|
2023-03-30 14:19:45 +02:00
|
|
|
settings.version = importlib.metadata.version("lnbits")
|
2023-12-12 11:38:19 +01:00
|
|
|
settings.auth_secret_key = (
|
|
|
|
settings.auth_secret_key or sha256(settings.super_user.encode("utf-8")).hexdigest()
|
|
|
|
)
|
2022-12-09 12:40:22 +01:00
|
|
|
|
2023-11-30 13:54:07 +01:00
|
|
|
if not settings.user_agent:
|
|
|
|
settings.user_agent = f"LNbits/{settings.version}"
|
|
|
|
|
2023-09-25 15:04:44 +02:00
|
|
|
# printing environment variable for debugging
|
|
|
|
if not settings.lnbits_admin_ui:
|
|
|
|
logger.debug("Environment Settings:")
|
|
|
|
for key, value in settings.dict(exclude_none=True).items():
|
|
|
|
logger.debug(f"{key}: {value}")
|
|
|
|
|
2022-12-09 12:40:22 +01:00
|
|
|
|
2024-04-15 09:02:21 +02:00
|
|
|
def get_funding_source():
|
2023-06-27 16:11:00 +02:00
|
|
|
"""
|
|
|
|
Backwards compatibility
|
|
|
|
"""
|
2024-04-15 09:02:21 +02:00
|
|
|
from lnbits.wallets import get_funding_source
|
2023-06-27 16:11:00 +02:00
|
|
|
|
2024-04-15 09:02:21 +02:00
|
|
|
return get_funding_source()
|