diff --git a/lnbits/app.py b/lnbits/app.py index 0e13a67d..b4a7e032 100644 --- a/lnbits/app.py +++ b/lnbits/app.py @@ -15,15 +15,11 @@ from fastapi.staticfiles import StaticFiles from loguru import logger from lnbits.core.tasks import register_task_listeners -from lnbits.settings import ( - check_admin_settings, - get_wallet_class, - set_wallet_class, - settings, -) +from lnbits.settings import get_wallet_class, set_wallet_class, settings from .commands import migrate_databases from .core import core_app +from .core.services import check_admin_settings from .core.views.generic import core_html_routes from .helpers import ( get_css_vendored, diff --git a/lnbits/core/__init__.py b/lnbits/core/__init__.py index 85e72d50..dec15d78 100644 --- a/lnbits/core/__init__.py +++ b/lnbits/core/__init__.py @@ -6,6 +6,7 @@ db = Database("database") core_app: APIRouter = APIRouter() +from .views.admin_api import * # noqa from .views.api import * # noqa from .views.generic import * # noqa from .views.public_api import * # noqa diff --git a/lnbits/core/crud.py b/lnbits/core/crud.py index 14082999..9e1e8fd6 100644 --- a/lnbits/core/crud.py +++ b/lnbits/core/crud.py @@ -8,10 +8,18 @@ from loguru import logger from lnbits import bolt11 from lnbits.db import COCKROACH, POSTGRES, Connection -from lnbits.settings import settings +from lnbits.settings import readonly_variables, settings from . import db -from .models import BalanceCheck, Payment, User, Wallet +from .models import ( + AdminSettings, + BalanceCheck, + Payment, + SuperSettings, + UpdateSettings, + User, + Wallet, +) # accounts # -------- @@ -564,3 +572,75 @@ async def get_balance_notify( (wallet_id,), ) return row[0] if row else None + + +# admin +# -------- + + +async def get_super_settings() -> Optional[SuperSettings]: + row = await db.fetchone("SELECT * FROM settings") + if not row: + return None + return SuperSettings(**row) + + +async def get_admin_settings(is_super_user: bool = False) -> Optional[AdminSettings]: + sets = await get_super_settings() + if not sets: + return None + row_dict = dict(sets) + row_dict.pop("super_user") + admin_settings = AdminSettings( + super_user=is_super_user, + lnbits_allowed_funding_sources=settings.lnbits_allowed_funding_sources, + **row_dict, + ) + return admin_settings + + +async def delete_admin_settings(): + await db.execute("DELETE FROM settings") + + +async def update_admin_settings(data: UpdateSettings): + q, values = get_q_and_values(data) + await db.execute(f"UPDATE settings SET {q}", (values,)) # type: ignore + + +def get_q_and_values(data): + keys = [] + values = [] + for key, value in data.items(): + setattr(settings, key, value) + keys.append(f"{key} = ?") + if type(value) == list: + value = ",".join(value) + values.append(value) + return ", ".join(keys), values + + +async def create_admin_settings(): + account = await create_account() + settings.super_user = account.id + keys = [] + values = "" + for key, value in settings.dict(exclude_none=True).items(): + if not key in readonly_variables: + 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 settings ({q}) VALUES ({v})" + await db.execute(sql) diff --git a/lnbits/core/migrations.py b/lnbits/core/migrations.py index d92f384a..463871dc 100644 --- a/lnbits/core/migrations.py +++ b/lnbits/core/migrations.py @@ -188,3 +188,71 @@ async def m005_balance_check_balance_notify(db): ); """ ) + + +async def m006_create_admin_settings_table(db): + await db.execute( + """ + CREATE TABLE IF NOT EXISTS settings ( + super_user TEXT, + lnbits_admin_extensions TEXT, + lnbits_admin_users TEXT, + lnbits_allowed_users TEXT, + lnbits_disabled_extensions TEXT, + lnbits_site_title TEXT, + lnbits_site_tagline TEXT, + lnbits_site_description TEXT, + lnbits_default_wallet_name TEXT, + lnbits_theme_options TEXT, + lnbits_custom_logo TEXT, + lnbits_ad_space TEXT, + lnbits_ad_space_title TEXT, + lnbits_ad_space_enabled BOOLEAN, + lnbits_force_https TEXT, + lnbits_reserve_fee_min TEXT, + lnbits_reserve_fee_percent TEXT, + lnbits_service_fee TEXT, + lnbits_hide_api TEXT, + lnbits_denomination TEXT, + lnbits_backend_wallet_class TEXT, + lnbits_endpoint TEXT, + lnbits_key TEXT, + fake_wallet_secret TEXT, + cliche_endpoint TEXT, + corelightning_rpc TEXT, + eclair_url TEXT, + eclair_pass TEXT, + lnd_cert TEXT, + lnd_admin_macaroon TEXT, + lnd_invoice_macaroon TEXT, + lnd_rest_endpoint TEXT, + lnd_rest_cert TEXT, + lnd_rest_macaroon TEXT, + lnd_rest_macaroon_encrypted TEXT, + lnd_grpc_endpoint TEXT, + lnd_grpc_cert TEXT, + lnd_grpc_port INTEGER, + lnd_grpc_admin_macaroon TEXT, + lnd_grpc_invoice_macaroon TEXT, + lnd_grpc_macaroon TEXT, + lnd_grpc_macaroon_encrypted TEXT, + lnpay_api_endpoint TEXT, + lnpay_api_key TEXT, + lnpay_wallet_key TEXT, + lntxbot_api_endpoint TEXT, + lntxbot_key TEXT, + opennode_api_endpoint TEXT, + opennode_key TEXT, + spark_url TEXT, + spark_token TEXT, + boltz_network TEXT, + boltz_url TEXT, + boltz_mempool_space_url TEXT, + boltz_mempool_space_url_ws TEXT, + lntips_api_endpoint TEXT, + lntips_api_key TEXT, + lntips_admin_key TEXT, + lntips_invoice_key TEXT + ); + """ + ) diff --git a/lnbits/core/models.py b/lnbits/core/models.py index 691995de..5ec78ca4 100644 --- a/lnbits/core/models.py +++ b/lnbits/core/models.py @@ -5,9 +5,10 @@ from sqlite3 import Row from typing import Dict, List, NamedTuple, Optional from ecdsa import SECP256k1, SigningKey # type: ignore +from fastapi import Query from lnurl import encode as lnurl_encode # type: ignore from loguru import logger -from pydantic import BaseModel +from pydantic import BaseModel, Extra, validator from lnbits.db import Connection from lnbits.helpers import url_for @@ -198,3 +199,91 @@ class BalanceCheck(BaseModel): @classmethod def from_row(cls, row: Row): return cls(wallet=row["wallet"], service=row["service"], url=row["url"]) + + +# admin +# -------- +class UpdateSettings(BaseModel, extra=Extra.forbid): + @validator( + "lnbits_admin_users", + "lnbits_allowed_users", + "lnbits_theme_options", + "lnbits_disabled_extensions", + "lnbits_admin_extensions", + pre=True, + ) + def validate(cls, val): + if type(val) == str: + val = val.split(",") if val else [] + return val + + lnbits_backend_wallet_class: str = Query(None) + lnbits_admin_users: List[str] = Query(None) + lnbits_allowed_users: List[str] = Query(None) + lnbits_admin_extensions: List[str] = Query(None) + lnbits_disabled_extensions: List[str] = Query(None) + lnbits_theme_options: List[str] = Query(None) + lnbits_force_https: bool = Query(None) + lnbits_reserve_fee_min: int = Query(None, ge=0) + lnbits_reserve_fee_percent: float = Query(None, ge=0) + lnbits_service_fee: float = Query(None, ge=0) + lnbits_hide_api: bool = Query(None) + lnbits_site_title: str = Query(None) + lnbits_site_tagline: str = Query(None) + lnbits_site_description: str = Query(None) + lnbits_default_wallet_name: str = Query(None) + lnbits_denomination: str = Query(None) + lnbits_custom_logo: str = Query(None) + lnbits_ad_space: str = Query(None) + lnbits_ad_space_title: str = Query(None) + lnbits_ad_space_enabled: bool = Query(None) + + # funding sources + fake_wallet_secret: str = Query(None) + lnbits_endpoint: str = Query(None) + lnbits_key: str = Query(None) + cliche_endpoint: str = Query(None) + corelightning_rpc: str = Query(None) + eclair_url: str = Query(None) + eclair_pass: str = Query(None) + lnd_rest_endpoint: str = Query(None) + lnd_rest_cert: str = Query(None) + lnd_rest_macaroon: str = Query(None) + lnd_rest_macaroon_encrypted: str = Query(None) + lnd_cert: str = Query(None) + lnd_admin_macaroon: str = Query(None) + lnd_invoice_macaroon: str = Query(None) + lnd_grpc_endpoint: str = Query(None) + lnd_grpc_cert: str = Query(None) + lnd_grpc_port: int = Query(None, ge=0) + lnd_grpc_admin_macaroon: str = Query(None) + lnd_grpc_invoice_macaroon: str = Query(None) + lnd_grpc_macaroon: str = Query(None) + lnd_grpc_macaroon_encrypted: str = Query(None) + lnpay_api_endpoint: str = Query(None) + lnpay_api_key: str = Query(None) + lnpay_wallet_key: str = Query(None) + lntxbot_api_endpoint: str = Query(None) + lntxbot_key: str = Query(None) + opennode_api_endpoint: str = Query(None) + opennode_key: str = Query(None) + spark_url: str = Query(None) + spark_token: str = Query(None) + lntips_api_endpoint: str = Query(None) + lntips_api_key: str = Query(None) + lntips_admin_key: str = Query(None) + lntips_invoice_key: str = Query(None) + + boltz_mempool_space_url: str = Query(None) + boltz_mempool_space_url_ws: str = Query(None) + boltz_network: str = Query(None) + boltz_url: str = Query(None) + + +class SuperSettings(UpdateSettings): + super_user: str + + +class AdminSettings(UpdateSettings): + super_user: bool + lnbits_allowed_funding_sources: Optional[List[str]] diff --git a/lnbits/core/services.py b/lnbits/core/services.py index eeadcfcc..f47e6359 100644 --- a/lnbits/core/services.py +++ b/lnbits/core/services.py @@ -21,14 +21,16 @@ from lnbits.decorators import ( ) from lnbits.helpers import url_for, urlsafe_short_hash from lnbits.requestvars import g -from lnbits.settings import FAKE_WALLET, get_wallet_class, settings +from lnbits.settings import FAKE_WALLET, get_wallet_class, readonly_variables, settings from lnbits.wallets.base import PaymentResponse, PaymentStatus from . import db from .crud import ( check_internal, + create_admin_settings, create_payment, delete_wallet_payment, + get_super_settings, get_wallet, get_wallet_payment, update_payment_details, @@ -385,3 +387,63 @@ def fee_reserve(amount_msat: int) -> int: reserve_min = settings.lnbits_reserve_fee_min reserve_percent = settings.lnbits_reserve_fee_percent return max(int(reserve_min), int(amount_msat * reserve_percent / 100.0)) + + +async def update_wallet_balance(wallet_id: str, amount: int): + internal_id = f"internal_{urlsafe_short_hash()}" + payment = await create_payment( + wallet_id=wallet_id, + checking_id=internal_id, + payment_request="admin_internal", + payment_hash="admin_internal", + amount=amount * 1000, + memo="Admin top up", + pending=False, + ) + # manually send this for now + from lnbits.tasks import internal_invoice_queue + + await internal_invoice_queue.put(internal_id) + return payment + + +async def check_admin_settings(): + + if settings.lnbits_admin_ui: + + sets = await get_super_settings() + if not sets: + # create new settings if table is empty + logger.warning( + "settings empty. inserting new settings and creating admin account" + ) + await create_admin_settings() + logger.warning("initialized settings from enviroment variables.") + sets = await get_super_settings() + + if sets: + for key, value in sets.dict().items(): + if not key in readonly_variables: + try: + setattr(settings, key, value) + except: + logger.error(f"error overriding setting: {key}, value: {value}") + + # printing settings for debugging + 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" + admin_url = ( + f"{http}://{settings.host}:{settings.port}/wallet?usr={settings.super_user}" + ) + logger.success(f"✔️ Access admin user account at: {admin_url}") + + # callback for saas + if ( + settings.lnbits_saas_callback + and settings.lnbits_saas_secret + and settings.lnbits_saas_instance_id + ): + settings.send_admin_user_to_saas() diff --git a/lnbits/extensions/admin/templates/admin/_tab_funding.html b/lnbits/core/templates/admin/_tab_funding.html similarity index 100% rename from lnbits/extensions/admin/templates/admin/_tab_funding.html rename to lnbits/core/templates/admin/_tab_funding.html diff --git a/lnbits/extensions/admin/templates/admin/_tab_server.html b/lnbits/core/templates/admin/_tab_server.html similarity index 100% rename from lnbits/extensions/admin/templates/admin/_tab_server.html rename to lnbits/core/templates/admin/_tab_server.html diff --git a/lnbits/extensions/admin/templates/admin/_tab_theme.html b/lnbits/core/templates/admin/_tab_theme.html similarity index 100% rename from lnbits/extensions/admin/templates/admin/_tab_theme.html rename to lnbits/core/templates/admin/_tab_theme.html diff --git a/lnbits/extensions/admin/templates/admin/_tab_users.html b/lnbits/core/templates/admin/_tab_users.html similarity index 100% rename from lnbits/extensions/admin/templates/admin/_tab_users.html rename to lnbits/core/templates/admin/_tab_users.html diff --git a/lnbits/extensions/admin/templates/admin/index.html b/lnbits/core/templates/admin/index.html similarity index 100% rename from lnbits/extensions/admin/templates/admin/index.html rename to lnbits/core/templates/admin/index.html diff --git a/lnbits/extensions/admin/views_api.py b/lnbits/core/views/admin_api.py similarity index 59% rename from lnbits/extensions/admin/views_api.py rename to lnbits/core/views/admin_api.py index c8bfba60..cb65be40 100644 --- a/lnbits/extensions/admin/views_api.py +++ b/lnbits/core/views/admin_api.py @@ -1,34 +1,31 @@ from http import HTTPStatus from typing import Optional -from fastapi import Body, Query +from fastapi import Body from fastapi.params import Depends from starlette.exceptions import HTTPException from lnbits.core.crud import get_wallet -from lnbits.core.models import User +from lnbits.core.models import AdminSettings, UpdateSettings, User +from lnbits.core.services import update_wallet_balance from lnbits.decorators import check_admin -from lnbits.extensions.admin import admin_ext -from lnbits.extensions.admin.models import AdminSettings, UpdateSettings from lnbits.server import server_restart -from .crud import ( - delete_admin_settings, - get_admin_settings, - update_admin_settings, - update_wallet_balance, -) +from .. import core_app +from ..crud import delete_admin_settings, get_admin_settings, update_admin_settings -@admin_ext.get( - "/api/v1/restart/", status_code=HTTPStatus.OK, dependencies=[Depends(check_admin)] +@core_app.get( + "/admin/api/v1/restart/", + status_code=HTTPStatus.OK, + dependencies=[Depends(check_admin)], ) async def api_restart_server() -> dict[str, str]: server_restart.set() return {"status": "Success"} -@admin_ext.get("/api/v1/settings/") +@core_app.get("/admin/api/v1/settings/") async def api_get_settings( user: User = Depends(check_admin), # type: ignore ) -> Optional[AdminSettings]: @@ -36,10 +33,12 @@ async def api_get_settings( return admin_settings -@admin_ext.put( - "/api/v1/topup/", status_code=HTTPStatus.OK, dependencies=[Depends(check_admin)] +@core_app.put( + "/admin/api/v1/topup/", + status_code=HTTPStatus.OK, + dependencies=[Depends(check_admin)], ) -async def api_update_balance( +async def api_topup_balance( id: str = Body(...), amount: int = Body(...) ) -> dict[str, str]: try: @@ -54,16 +53,20 @@ async def api_update_balance( return {"status": "Success"} -@admin_ext.put( - "/api/v1/settings/", status_code=HTTPStatus.OK, dependencies=[Depends(check_admin)] +@core_app.put( + "/admin/api/v1/settings/", + status_code=HTTPStatus.OK, + dependencies=[Depends(check_admin)], ) async def api_update_settings(data: UpdateSettings): await update_admin_settings(data) return {"status": "Success"} -@admin_ext.delete( - "/api/v1/settings/", status_code=HTTPStatus.OK, dependencies=[Depends(check_admin)] +@core_app.delete( + "/admin/api/v1/settings/", + status_code=HTTPStatus.OK, + dependencies=[Depends(check_admin)], ) async def api_delete_settings() -> dict[str, str]: await delete_admin_settings() diff --git a/lnbits/core/views/generic.py b/lnbits/core/views/generic.py index 028682fe..9df133b2 100644 --- a/lnbits/core/views/generic.py +++ b/lnbits/core/views/generic.py @@ -13,9 +13,9 @@ from starlette.responses import HTMLResponse, JSONResponse from lnbits.core import db from lnbits.core.models import User -from lnbits.decorators import check_user_exists +from lnbits.decorators import check_admin, check_user_exists from lnbits.helpers import template_renderer, url_for -from lnbits.settings import settings +from lnbits.settings import get_wallet_class, settings from ...helpers import get_valid_extensions from ..crud import ( @@ -307,3 +307,19 @@ async def manifest(usr: str): for wallet in user.wallets ], } + + +@core_html_routes.get("/admin", response_class=HTMLResponse) +async def index(request: Request, user: User = Depends(check_admin)): # type: ignore + WALLET = get_wallet_class() + _, balance = await WALLET.status() + + return template_renderer().TemplateResponse( + "admin/index.html", + { + "request": request, + "user": user.dict(), + "settings": settings.dict(), + "balance": balance, + }, + ) diff --git a/lnbits/extensions/admin/README.md b/lnbits/extensions/admin/README.md deleted file mode 100644 index 6cf073a1..00000000 --- a/lnbits/extensions/admin/README.md +++ /dev/null @@ -1,12 +0,0 @@ -# Admin Extension - -## Dashboard to manage LNbits from the UI - -With AdminUI you can manage your LNbits from the UI - -![AdminUI](https://i.imgur.com/BIyLkyG.png) - -## Before you start - -**This extension doesn't discard the need for the `.env` file!** -In the .env file, set the `LNBITS_ADMIN_USERS` variable to include at least your user id. diff --git a/lnbits/extensions/admin/__init__.py b/lnbits/extensions/admin/__init__.py deleted file mode 100644 index 24b91fe2..00000000 --- a/lnbits/extensions/admin/__init__.py +++ /dev/null @@ -1,16 +0,0 @@ -from fastapi import APIRouter - -from lnbits.db import Database -from lnbits.helpers import template_renderer - -db = Database("ext_admin") - -admin_ext: APIRouter = APIRouter(prefix="/admin", tags=["admin"]) - - -def admin_renderer(): - return template_renderer(["lnbits/extensions/admin/templates"]) - - -from .views import * # noqa -from .views_api import * # noqa diff --git a/lnbits/extensions/admin/config.json b/lnbits/extensions/admin/config.json deleted file mode 100644 index 69661733..00000000 --- a/lnbits/extensions/admin/config.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "name": "Admin", - "short_description": "Manage your LNbits install", - "icon": "build", - "contributors": ["benarc"] -} diff --git a/lnbits/extensions/admin/crud.py b/lnbits/extensions/admin/crud.py deleted file mode 100644 index 090b2c0f..00000000 --- a/lnbits/extensions/admin/crud.py +++ /dev/null @@ -1,93 +0,0 @@ -from typing import Optional - -from lnbits.core.crud import create_account, create_payment -from lnbits.helpers import urlsafe_short_hash -from lnbits.settings import readonly_variables, settings -from lnbits.tasks import internal_invoice_queue - -from . import db -from .models import AdminSettings, SuperSettings, UpdateSettings - - -async def update_wallet_balance(wallet_id: str, amount: int): - internal_id = f"internal_{urlsafe_short_hash()}" - payment = await create_payment( - wallet_id=wallet_id, - checking_id=internal_id, - payment_request="admin_internal", - payment_hash="admin_internal", - amount=amount * 1000, - memo="Admin top up", - pending=False, - ) - # manually send this for now - await internal_invoice_queue.put(internal_id) - return payment - - -async def get_super_settings() -> Optional[SuperSettings]: - row = await db.fetchone("SELECT * FROM admin.settings") - if not row: - return None - return SuperSettings(**row) - - -async def get_admin_settings(is_super_user: bool = False) -> Optional[AdminSettings]: - sets = await get_super_settings() - if not sets: - return None - row_dict = dict(sets) - row_dict.pop("super_user") - admin_settings = AdminSettings( - super_user=is_super_user, - lnbits_allowed_funding_sources=settings.lnbits_allowed_funding_sources, - **row_dict, - ) - return admin_settings - - -async def delete_admin_settings(): - await db.execute("DELETE FROM admin.settings") - - -async def update_admin_settings(data: UpdateSettings): - q, values = get_q_and_values(data) - await db.execute(f"UPDATE admin.settings SET {q}", (values,)) # type: ignore - - -def get_q_and_values(data): - keys = [] - values = [] - for key, value in data.items(): - setattr(settings, key, value) - keys.append(f"{key} = ?") - if type(value) == list: - value = ",".join(value) - values.append(value) - return ", ".join(keys), values - - -async def create_admin_settings(): - account = await create_account() - settings.super_user = account.id - keys = [] - values = "" - for key, value in settings.dict(exclude_none=True).items(): - if not key in readonly_variables: - 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) diff --git a/lnbits/extensions/admin/migrations.py b/lnbits/extensions/admin/migrations.py deleted file mode 100644 index b5ec1730..00000000 --- a/lnbits/extensions/admin/migrations.py +++ /dev/null @@ -1,66 +0,0 @@ -async def m001_create_admin_settings_table(db): - await db.execute( - """ - CREATE TABLE IF NOT EXISTS admin.settings ( - super_user TEXT, - lnbits_admin_extensions TEXT, - lnbits_admin_users TEXT, - lnbits_allowed_users TEXT, - lnbits_disabled_extensions TEXT, - lnbits_site_title TEXT, - lnbits_site_tagline TEXT, - lnbits_site_description TEXT, - lnbits_default_wallet_name TEXT, - lnbits_theme_options TEXT, - lnbits_custom_logo TEXT, - lnbits_ad_space TEXT, - lnbits_ad_space_title TEXT, - lnbits_ad_space_enabled BOOLEAN, - lnbits_force_https TEXT, - lnbits_reserve_fee_min TEXT, - lnbits_reserve_fee_percent TEXT, - lnbits_service_fee TEXT, - lnbits_hide_api TEXT, - lnbits_denomination TEXT, - lnbits_backend_wallet_class TEXT, - lnbits_endpoint TEXT, - lnbits_key TEXT, - fake_wallet_secret TEXT, - cliche_endpoint TEXT, - corelightning_rpc TEXT, - eclair_url TEXT, - eclair_pass TEXT, - lnd_cert TEXT, - lnd_admin_macaroon TEXT, - lnd_invoice_macaroon TEXT, - lnd_rest_endpoint TEXT, - lnd_rest_cert TEXT, - lnd_rest_macaroon TEXT, - lnd_rest_macaroon_encrypted TEXT, - lnd_grpc_endpoint TEXT, - lnd_grpc_cert TEXT, - lnd_grpc_port INTEGER, - lnd_grpc_admin_macaroon TEXT, - lnd_grpc_invoice_macaroon TEXT, - lnd_grpc_macaroon TEXT, - lnd_grpc_macaroon_encrypted TEXT, - lnpay_api_endpoint TEXT, - lnpay_api_key TEXT, - lnpay_wallet_key TEXT, - lntxbot_api_endpoint TEXT, - lntxbot_key TEXT, - opennode_api_endpoint TEXT, - opennode_key TEXT, - spark_url TEXT, - spark_token TEXT, - boltz_network TEXT, - boltz_url TEXT, - boltz_mempool_space_url TEXT, - boltz_mempool_space_url_ws TEXT, - lntips_api_endpoint TEXT, - lntips_api_key TEXT, - lntips_admin_key TEXT, - lntips_invoice_key TEXT - ); - """ - ) diff --git a/lnbits/extensions/admin/models.py b/lnbits/extensions/admin/models.py deleted file mode 100644 index 965a28dc..00000000 --- a/lnbits/extensions/admin/models.py +++ /dev/null @@ -1,90 +0,0 @@ -from typing import List, Optional - -from fastapi import Query -from pydantic import BaseModel, Extra, validator - - -class UpdateSettings(BaseModel, extra=Extra.forbid): - @validator( - "lnbits_admin_users", - "lnbits_allowed_users", - "lnbits_theme_options", - "lnbits_disabled_extensions", - "lnbits_admin_extensions", - pre=True, - ) - def validate(cls, val): - if type(val) == str: - val = val.split(",") if val else [] - return val - - lnbits_backend_wallet_class: str = Query(None) - lnbits_admin_users: List[str] = Query(None) - lnbits_allowed_users: List[str] = Query(None) - lnbits_admin_extensions: List[str] = Query(None) - lnbits_disabled_extensions: List[str] = Query(None) - lnbits_theme_options: List[str] = Query(None) - lnbits_force_https: bool = Query(None) - lnbits_reserve_fee_min: int = Query(None, ge=0) - lnbits_reserve_fee_percent: float = Query(None, ge=0) - lnbits_service_fee: float = Query(None, ge=0) - lnbits_hide_api: bool = Query(None) - lnbits_site_title: str = Query(None) - lnbits_site_tagline: str = Query(None) - lnbits_site_description: str = Query(None) - lnbits_default_wallet_name: str = Query(None) - lnbits_denomination: str = Query(None) - lnbits_custom_logo: str = Query(None) - lnbits_ad_space: str = Query(None) - lnbits_ad_space_title: str = Query(None) - lnbits_ad_space_enabled: bool = Query(None) - - # funding sources - fake_wallet_secret: str = Query(None) - lnbits_endpoint: str = Query(None) - lnbits_key: str = Query(None) - cliche_endpoint: str = Query(None) - corelightning_rpc: str = Query(None) - eclair_url: str = Query(None) - eclair_pass: str = Query(None) - lnd_rest_endpoint: str = Query(None) - lnd_rest_cert: str = Query(None) - lnd_rest_macaroon: str = Query(None) - lnd_rest_macaroon_encrypted: str = Query(None) - lnd_cert: str = Query(None) - lnd_admin_macaroon: str = Query(None) - lnd_invoice_macaroon: str = Query(None) - lnd_grpc_endpoint: str = Query(None) - lnd_grpc_cert: str = Query(None) - lnd_grpc_port: int = Query(None, ge=0) - lnd_grpc_admin_macaroon: str = Query(None) - lnd_grpc_invoice_macaroon: str = Query(None) - lnd_grpc_macaroon: str = Query(None) - lnd_grpc_macaroon_encrypted: str = Query(None) - lnpay_api_endpoint: str = Query(None) - lnpay_api_key: str = Query(None) - lnpay_wallet_key: str = Query(None) - lntxbot_api_endpoint: str = Query(None) - lntxbot_key: str = Query(None) - opennode_api_endpoint: str = Query(None) - opennode_key: str = Query(None) - spark_url: str = Query(None) - spark_token: str = Query(None) - lntips_api_endpoint: str = Query(None) - lntips_api_key: str = Query(None) - lntips_admin_key: str = Query(None) - lntips_invoice_key: str = Query(None) - - boltz_mempool_space_url: str = Query(None) - boltz_mempool_space_url_ws: str = Query(None) - boltz_network: str = Query(None) - boltz_url: str = Query(None) - - -class SuperSettings(UpdateSettings): - super_user: str - - -class AdminSettings(UpdateSettings): - super_user: bool - lnbits_allowed_funding_sources: Optional[List[str]] diff --git a/lnbits/extensions/admin/views.py b/lnbits/extensions/admin/views.py deleted file mode 100644 index 72f47b63..00000000 --- a/lnbits/extensions/admin/views.py +++ /dev/null @@ -1,28 +0,0 @@ -from fastapi import Request -from fastapi.params import Depends -from fastapi.templating import Jinja2Templates -from starlette.responses import HTMLResponse - -from lnbits.core.models import User -from lnbits.decorators import check_admin -from lnbits.settings import get_wallet_class, settings - -from . import admin_ext, admin_renderer - -templates = Jinja2Templates(directory="templates") - - -@admin_ext.get("/", response_class=HTMLResponse) -async def index(request: Request, user: User = Depends(check_admin)): # type: ignore - WALLET = get_wallet_class() - _, balance = await WALLET.status() - - return admin_renderer().TemplateResponse( - "admin/index.html", - { - "request": request, - "user": user.dict(), - "settings": settings.dict(), - "balance": balance, - }, - ) diff --git a/lnbits/settings.py b/lnbits/settings.py index 507e9bf7..ff4b5a64 100644 --- a/lnbits/settings.py +++ b/lnbits/settings.py @@ -9,6 +9,8 @@ import httpx from loguru import logger from pydantic import BaseSettings, Field, validator +# from .core.crud import create_admin_settings, get_super_settings + def list_parse_fallback(v): try: @@ -199,54 +201,6 @@ def set_cli_settings(**kwargs): setattr(settings, key, value) -async def check_admin_settings(): - - if settings.lnbits_admin_ui: - - # if not imported here, circular import error - from lnbits.extensions.admin.crud import ( - create_admin_settings, - get_super_settings, - ) - - sets = await get_super_settings() - if not sets: - # create new settings if table is empty - logger.warning( - "admin.settings empty. inserting new settings and creating admin account" - ) - await create_admin_settings() - logger.warning("initialized admin.settings from enviroment variables.") - sets = await get_super_settings() - - if sets: - for key, value in sets.dict().items(): - if not key in readonly_variables: - try: - setattr(settings, key, value) - except: - logger.error(f"error overriding setting: {key}, value: {value}") - - # printing settings for debugging - 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" - admin_url = ( - f"{http}://{settings.host}:{settings.port}/wallet?usr={settings.super_user}" - ) - logger.success(f"✔️ Access admin user account at: {admin_url}") - - # callback for saas - if ( - settings.lnbits_saas_callback - and settings.lnbits_saas_secret - and settings.lnbits_saas_instance_id - ): - send_admin_user_to_saas() - - wallets_module = importlib.import_module("lnbits.wallets") FAKE_WALLET = getattr(wallets_module, "FakeWallet")()