refactor: include admin extension into core

This commit is contained in:
Vlad Stan
2022-12-08 15:41:52 +02:00
parent 61c3476ba7
commit d15782521d
21 changed files with 349 additions and 391 deletions

View File

@@ -15,15 +15,11 @@ from fastapi.staticfiles import StaticFiles
from loguru import logger from loguru import logger
from lnbits.core.tasks import register_task_listeners from lnbits.core.tasks import register_task_listeners
from lnbits.settings import ( from lnbits.settings import get_wallet_class, set_wallet_class, settings
check_admin_settings,
get_wallet_class,
set_wallet_class,
settings,
)
from .commands import migrate_databases from .commands import migrate_databases
from .core import core_app from .core import core_app
from .core.services import check_admin_settings
from .core.views.generic import core_html_routes from .core.views.generic import core_html_routes
from .helpers import ( from .helpers import (
get_css_vendored, get_css_vendored,

View File

@@ -6,6 +6,7 @@ db = Database("database")
core_app: APIRouter = APIRouter() core_app: APIRouter = APIRouter()
from .views.admin_api import * # noqa
from .views.api import * # noqa from .views.api import * # noqa
from .views.generic import * # noqa from .views.generic import * # noqa
from .views.public_api import * # noqa from .views.public_api import * # noqa

View File

@@ -8,10 +8,18 @@ from loguru import logger
from lnbits import bolt11 from lnbits import bolt11
from lnbits.db import COCKROACH, POSTGRES, Connection from lnbits.db import COCKROACH, POSTGRES, Connection
from lnbits.settings import settings from lnbits.settings import readonly_variables, settings
from . import db from . import db
from .models import BalanceCheck, Payment, User, Wallet from .models import (
AdminSettings,
BalanceCheck,
Payment,
SuperSettings,
UpdateSettings,
User,
Wallet,
)
# accounts # accounts
# -------- # --------
@@ -564,3 +572,75 @@ async def get_balance_notify(
(wallet_id,), (wallet_id,),
) )
return row[0] if row else None 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)

View File

@@ -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
);
"""
)

View File

@@ -5,9 +5,10 @@ from sqlite3 import Row
from typing import Dict, List, NamedTuple, Optional from typing import Dict, List, NamedTuple, Optional
from ecdsa import SECP256k1, SigningKey # type: ignore from ecdsa import SECP256k1, SigningKey # type: ignore
from fastapi import Query
from lnurl import encode as lnurl_encode # type: ignore from lnurl import encode as lnurl_encode # type: ignore
from loguru import logger from loguru import logger
from pydantic import BaseModel from pydantic import BaseModel, Extra, validator
from lnbits.db import Connection from lnbits.db import Connection
from lnbits.helpers import url_for from lnbits.helpers import url_for
@@ -198,3 +199,91 @@ class BalanceCheck(BaseModel):
@classmethod @classmethod
def from_row(cls, row: Row): def from_row(cls, row: Row):
return cls(wallet=row["wallet"], service=row["service"], url=row["url"]) 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]]

View File

@@ -21,14 +21,16 @@ from lnbits.decorators import (
) )
from lnbits.helpers import url_for, urlsafe_short_hash from lnbits.helpers import url_for, urlsafe_short_hash
from lnbits.requestvars import g 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 lnbits.wallets.base import PaymentResponse, PaymentStatus
from . import db from . import db
from .crud import ( from .crud import (
check_internal, check_internal,
create_admin_settings,
create_payment, create_payment,
delete_wallet_payment, delete_wallet_payment,
get_super_settings,
get_wallet, get_wallet,
get_wallet_payment, get_wallet_payment,
update_payment_details, update_payment_details,
@@ -385,3 +387,63 @@ def fee_reserve(amount_msat: int) -> int:
reserve_min = settings.lnbits_reserve_fee_min reserve_min = settings.lnbits_reserve_fee_min
reserve_percent = settings.lnbits_reserve_fee_percent reserve_percent = settings.lnbits_reserve_fee_percent
return max(int(reserve_min), int(amount_msat * reserve_percent / 100.0)) 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()

View File

@@ -1,34 +1,31 @@
from http import HTTPStatus from http import HTTPStatus
from typing import Optional from typing import Optional
from fastapi import Body, Query from fastapi import Body
from fastapi.params import Depends from fastapi.params import Depends
from starlette.exceptions import HTTPException from starlette.exceptions import HTTPException
from lnbits.core.crud import get_wallet 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.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 lnbits.server import server_restart
from .crud import ( from .. import core_app
delete_admin_settings, from ..crud import delete_admin_settings, get_admin_settings, update_admin_settings
get_admin_settings,
update_admin_settings,
update_wallet_balance,
)
@admin_ext.get( @core_app.get(
"/api/v1/restart/", status_code=HTTPStatus.OK, dependencies=[Depends(check_admin)] "/admin/api/v1/restart/",
status_code=HTTPStatus.OK,
dependencies=[Depends(check_admin)],
) )
async def api_restart_server() -> dict[str, str]: async def api_restart_server() -> dict[str, str]:
server_restart.set() server_restart.set()
return {"status": "Success"} return {"status": "Success"}
@admin_ext.get("/api/v1/settings/") @core_app.get("/admin/api/v1/settings/")
async def api_get_settings( async def api_get_settings(
user: User = Depends(check_admin), # type: ignore user: User = Depends(check_admin), # type: ignore
) -> Optional[AdminSettings]: ) -> Optional[AdminSettings]:
@@ -36,10 +33,12 @@ async def api_get_settings(
return admin_settings return admin_settings
@admin_ext.put( @core_app.put(
"/api/v1/topup/", status_code=HTTPStatus.OK, dependencies=[Depends(check_admin)] "/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(...) id: str = Body(...), amount: int = Body(...)
) -> dict[str, str]: ) -> dict[str, str]:
try: try:
@@ -54,16 +53,20 @@ async def api_update_balance(
return {"status": "Success"} return {"status": "Success"}
@admin_ext.put( @core_app.put(
"/api/v1/settings/", status_code=HTTPStatus.OK, dependencies=[Depends(check_admin)] "/admin/api/v1/settings/",
status_code=HTTPStatus.OK,
dependencies=[Depends(check_admin)],
) )
async def api_update_settings(data: UpdateSettings): async def api_update_settings(data: UpdateSettings):
await update_admin_settings(data) await update_admin_settings(data)
return {"status": "Success"} return {"status": "Success"}
@admin_ext.delete( @core_app.delete(
"/api/v1/settings/", status_code=HTTPStatus.OK, dependencies=[Depends(check_admin)] "/admin/api/v1/settings/",
status_code=HTTPStatus.OK,
dependencies=[Depends(check_admin)],
) )
async def api_delete_settings() -> dict[str, str]: async def api_delete_settings() -> dict[str, str]:
await delete_admin_settings() await delete_admin_settings()

View File

@@ -13,9 +13,9 @@ from starlette.responses import HTMLResponse, JSONResponse
from lnbits.core import db from lnbits.core import db
from lnbits.core.models import User 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.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 ...helpers import get_valid_extensions
from ..crud import ( from ..crud import (
@@ -307,3 +307,19 @@ async def manifest(usr: str):
for wallet in user.wallets 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,
},
)

View File

@@ -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.

View File

@@ -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

View File

@@ -1,6 +0,0 @@
{
"name": "Admin",
"short_description": "Manage your LNbits install",
"icon": "build",
"contributors": ["benarc"]
}

View File

@@ -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)

View File

@@ -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
);
"""
)

View File

@@ -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]]

View File

@@ -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,
},
)

View File

@@ -9,6 +9,8 @@ import httpx
from loguru import logger from loguru import logger
from pydantic import BaseSettings, Field, validator from pydantic import BaseSettings, Field, validator
# from .core.crud import create_admin_settings, get_super_settings
def list_parse_fallback(v): def list_parse_fallback(v):
try: try:
@@ -199,54 +201,6 @@ def set_cli_settings(**kwargs):
setattr(settings, key, value) 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") wallets_module = importlib.import_module("lnbits.wallets")
FAKE_WALLET = getattr(wallets_module, "FakeWallet")() FAKE_WALLET = getattr(wallets_module, "FakeWallet")()