lnbits-legend/lnbits/settings.py

272 lines
10 KiB
Python
Raw Normal View History

import importlib
import json
import subprocess
2022-10-10 23:27:46 +02:00
import httpx
from os import path
from sqlite3 import Row
from typing import List, Optional
from loguru import logger
from pydantic import BaseSettings, Field, validator
2020-01-15 16:19:54 +01:00
2022-10-10 23:27:46 +02:00
def list_parse_fallback(v):
try:
return json.loads(v)
except Exception as e:
replaced = v.replace(" ", "")
if replaced:
return replaced.split(",")
else:
return []
2022-10-03 22:14:07 +02:00
read_only_variables = ["host", "port", "lnbits_commit", "lnbits_path"]
class Settings(BaseSettings):
lnbits_admin_ui: bool = Field(default=False)
# .env
2022-10-03 23:33:42 +02:00
debug: bool = Field(default=False)
host: str = Field(default="127.0.0.1")
port: int = Field(default=5000)
2022-10-03 22:14:07 +02:00
lnbits_path: str = Field(default=".")
lnbits_commit: str = Field(default="unknown")
2022-10-10 23:27:46 +02:00
# saas
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)
# users
lnbits_admin_users: List[str] = Field(default=[])
lnbits_allowed_users: List[str] = Field(default=[])
lnbits_admin_extensions: List[str] = Field(default=[])
lnbits_disabled_extensions: List[str] = Field(default=[])
# Change theme
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(
default=["classic", "flamingo", "mint", "salvador", "monochrome", "autumn"]
)
lnbits_custom_logo: str = Field(default=None)
2022-10-03 22:33:26 +02:00
lnbits_ad_space: List[str] = Field(default=[])
2019-12-18 14:44:58 +01:00
# ops
lnbits_data_folder: str = Field(default="./data")
lnbits_database_url: str = Field(default=None)
2022-10-03 22:14:07 +02:00
lnbits_force_https: bool = Field(default=False)
lnbits_reserve_fee_min: int = Field(default=4000)
lnbits_reserve_fee_percent: float = Field(default=1.0)
lnbits_service_fee: float = Field(default=0)
lnbits_hide_api: bool = Field(default=False)
lnbits_denomination: str = Field(default="sats")
# funding sources
lnbits_backend_wallet_class: str = Field(default="VoidWallet")
lnbits_allowed_funding_sources: List[str] = Field(
default=[
2022-10-03 22:14:07 +02:00
"VoidWallet",
"FakeWallet",
"CLightningWallet",
"LndRestWallet",
"LndWallet",
"LntxbotWallet",
"LNPayWallet",
"LnbitsWallet",
"OpenNodeWallet",
]
)
fake_wallet_secret: str = Field(default="ToTheMoon1")
lnbits_endpoint: str = Field(default="https://legend.lnbits.com")
lnbits_key: Optional[str] = Field(default=None)
cliche_endpoint: Optional[str] = Field(default=None)
corelightning_rpc: Optional[str] = Field(default=None)
eclair_url: Optional[str] = Field(default=None)
eclair_pass: Optional[str] = Field(default=None)
lnd_rest_endpoint: Optional[str] = Field(default=None)
lnd_rest_cert: Optional[str] = Field(default=None)
lnd_rest_macaroon: Optional[str] = Field(default=None)
lnd_rest_macaroon_encrypted: Optional[str] = Field(default=None)
lnd_cert: Optional[str] = Field(default=None)
lnd_admin_macaroon: Optional[str] = Field(default=None)
lnd_invoice_macaroon: Optional[str] = Field(default=None)
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)
lnd_grpc_macaroon_encrypted: Optional[str] = Field(default=None)
lnpay_api_endpoint: Optional[str] = Field(default=None)
lnpay_api_key: Optional[str] = Field(default=None)
lnpay_wallet_key: Optional[str] = Field(default=None)
lntxbot_api_endpoint: Optional[str] = Field(default=None)
lntxbot_key: Optional[str] = Field(default=None)
opennode_api_endpoint: Optional[str] = Field(default=None)
opennode_key: Optional[str] = Field(default=None)
spark_url: Optional[str] = Field(default=None)
spark_token: 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
# boltz
boltz_network: str = Field(default="main")
boltz_url: str = Field(default="https://boltz.exchange/api")
boltz_mempool_space_url: str = Field(default="https://mempool.space")
boltz_mempool_space_url_ws: str = Field(default="wss://mempool.space")
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
@validator(
"lnbits_admin_users",
"lnbits_allowed_users",
"lnbits_theme_options",
"lnbits_ad_space",
"lnbits_admin_extensions",
"lnbits_disabled_extensions",
"lnbits_allowed_funding_sources",
pre=True,
)
def validate(cls, val):
if type(val) == str:
val = val.split(",") if val else []
return val
@classmethod
def from_row(cls, row: Row) -> "Settings":
data = dict(row)
return cls(**data)
class Config:
env_file = ".env"
env_file_encoding = "utf-8"
case_sensitive = False
json_loads = list_parse_fallback
settings = Settings()
2022-10-03 22:14:07 +02:00
settings.lnbits_path = str(path.dirname(path.realpath(__file__)))
2022-10-03 23:33:42 +02:00
try:
settings.lnbits_commit = (
subprocess.check_output(
["git", "-C", settings.lnbits_path, "rev-parse", "HEAD"],
stderr=subprocess.DEVNULL,
)
.strip()
.decode("ascii")
)
2022-10-03 23:33:42 +02:00
except:
settings.lnbits_commit = "docker"
if not settings.lnbits_admin_ui:
logger.debug(f"Enviroment Settings:")
for key, value in settings.dict(exclude_none=True).items():
logger.debug(f"{key}: {value}")
2022-10-03 23:41:04 +02: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 23:41:04 +02:00
async def check_admin_settings():
if settings.lnbits_admin_ui:
try:
ext_db = importlib.import_module(f"lnbits.extensions.admin").db
except:
logger.error("could not import module lnbits.extensions.admin database")
raise
async with ext_db.connect() as db:
try:
row = await db.fetchone("SELECT * FROM admin.settings")
if not row or len(row) == 0:
logger.warning(
"admin.settings empty. inserting new settings and creating admin account"
)
from lnbits.core.crud import create_account
account = await create_account()
settings.lnbits_admin_users.insert(0, account.id)
keys = []
values = ""
for key, value in settings.dict(exclude_none=True).items():
keys.append(key)
if type(value) == list:
joined = ",".join(value)
values += f"'{joined}'"
if type(value) == int or type(value) == float:
values += str(value)
if type(value) == bool:
values += "true" if value else "false"
if type(value) == str:
value = value.replace("'", "")
values += f"'{value}'"
values += ","
q = ", ".join(keys)
v = values.rstrip(",")
sql = f"INSERT INTO admin.settings ({q}) VALUES ({v})"
await db.execute(sql)
logger.warning(
"initialized admin.settings from enviroment variables."
)
row = await db.fetchone("SELECT * FROM admin.settings")
assert row, "Newly updated settings couldn't be retrieved"
admin = Settings(**row)
for key, value in admin.dict(exclude_none=True).items():
if not key in read_only_variables:
try:
setattr(settings, key, value)
except:
logger.error(
f"error overriding setting: {key}, value: {value}"
)
2022-10-03 23:33:42 +02:00
logger.debug(f"Admin settings:")
for key, value in settings.dict(exclude_none=True).items():
logger.debug(f"{key}: {value}")
http = "https" if settings.lnbits_force_https else "http"
user = settings.lnbits_admin_users[0]
2022-10-10 23:27:46 +02:00
admin_url = f"{http}://{settings.host}:{settings.port}/wallet?usr={user}"
logger.warning(f"✔️ Access admin user account at: {admin_url}")
if settings.lnbits_saas_callback and settings.lnbits_saas_secret and settings.lnbits_saas_instance_id:
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": user
}
try:
r = client.post(settings.lnbits_saas_callback, headers=headers, json=payload)
logger.warning("sent admin user to saas application")
except:
logger.error(f"error sending admin user to saas: {settings.lnbits_saas_callback}")
except:
2022-10-10 23:27:46 +02:00
logger.error("admin.settings tables does not exist.")
raise
wallets_module = importlib.import_module("lnbits.wallets")
FAKE_WALLET = getattr(wallets_module, "FakeWallet")()
2022-10-05 09:46:59 +02:00
def get_wallet_class():
wallet_class = getattr(wallets_module, settings.lnbits_backend_wallet_class)
return wallet_class()