From 552e4a90411bd122ff97bba38fb68f8070aea539 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?dni=20=E2=9A=A1?= Date: Wed, 7 Dec 2022 13:57:08 +0100 Subject: [PATCH 1/6] remove unused env in tests --- .github/workflows/tests.yml | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 5d368fbb..487411ed 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -16,7 +16,7 @@ jobs: with: python-version: ${{ matrix.python-version }} - name: Install dependencies - env: + env: VIRTUAL_ENV: ./venv PATH: ${{ env.VIRTUAL_ENV }}/bin:${{ env.PATH }} run: | @@ -43,9 +43,6 @@ jobs: with: poetry-version: ${{ matrix.poetry-version }} - name: Install dependencies - env: - VIRTUAL_ENV: ./venv - PATH: ${{ env.VIRTUAL_ENV }}/bin:${{ env.PATH }} run: | poetry install - name: Run tests From 931ecefe150d133653e10f450604a71b12faecaf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?dni=20=E2=9A=A1?= Date: Sat, 17 Dec 2022 12:51:02 +0100 Subject: [PATCH 2/6] add admin_ui docs --- docs/guide/admin_ui.md | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 docs/guide/admin_ui.md diff --git a/docs/guide/admin_ui.md b/docs/guide/admin_ui.md new file mode 100644 index 00000000..29c7591f --- /dev/null +++ b/docs/guide/admin_ui.md @@ -0,0 +1,42 @@ +--- +layout: default +title: Admin UI +nav_order: 4 +--- + + +Admin UI +======== +The LNbits Admin UI lets you change LNbits settings via the LNbits backend. +It is disabled by default and the first time you set the enviroment variable LNBITS_ADMIN_UI=true +the settings are initialized and saved to the database and will be used from there as long the UI is enabled. +From there on the settings from the database are used. + + +Super User +========== +With the Admin UI we introduced the super user, it is created with the initialisation of the Admin UI and will be shown with a success message in the server logs. +The super user has access to the server and can change settings that may crash the server and make it unresponsive via the backend and api, like changing funding sources. + +Also only the super user can brrrr satoshis to different wallets. + +The super user is only stored inside the settings table of the database and after the settings are "reset to defaults" and a restart happened, +a new super user is created. + +The super user is never sent over the api and the backend only receives a bool if you are super user or not. + +We also added a decorator for the API routes to check for super user. + +There is also the possibility of posting the super user via webhook to another service when it is created. you can look it up here https://github.com/lnbits/lnbits/blob/main/lnbits/settings.py `class SaaSSettings` + + +Admin Users +=========== +enviroment variable: LNBITS_ADMIN_USERS, comma-seperated list of user ids +Admin Users can change settings in the admin ui aswell, with the exception of funding source settings, because they require e server restart and could potentially make the server inaccessable. Also they have access to all the extension defined in LNBITS_ADMIN_EXTENSIONS. + + +Allowed Users +============= +enviroment variable: LNBITS_ALLOWED_USERS, comma-seperated list of user ids +By defining this users, LNbits will no longer be useable by the public, only defined users and admins can then access the LNbits backend. From c24c75ce347aaaf50bbbea19c67765edb30f8d29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?dni=20=E2=9A=A1?= Date: Sat, 17 Dec 2022 14:45:00 +0100 Subject: [PATCH 3/6] change backend to frontend --- docs/guide/admin_ui.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/guide/admin_ui.md b/docs/guide/admin_ui.md index 29c7591f..1248d3f3 100644 --- a/docs/guide/admin_ui.md +++ b/docs/guide/admin_ui.md @@ -7,7 +7,7 @@ nav_order: 4 Admin UI ======== -The LNbits Admin UI lets you change LNbits settings via the LNbits backend. +The LNbits Admin UI lets you change LNbits settings via the LNbits frontend. It is disabled by default and the first time you set the enviroment variable LNBITS_ADMIN_UI=true the settings are initialized and saved to the database and will be used from there as long the UI is enabled. From there on the settings from the database are used. @@ -16,14 +16,14 @@ From there on the settings from the database are used. Super User ========== With the Admin UI we introduced the super user, it is created with the initialisation of the Admin UI and will be shown with a success message in the server logs. -The super user has access to the server and can change settings that may crash the server and make it unresponsive via the backend and api, like changing funding sources. +The super user has access to the server and can change settings that may crash the server and make it unresponsive via the frontend and api, like changing funding sources. Also only the super user can brrrr satoshis to different wallets. The super user is only stored inside the settings table of the database and after the settings are "reset to defaults" and a restart happened, a new super user is created. -The super user is never sent over the api and the backend only receives a bool if you are super user or not. +The super user is never sent over the api and the frontend only receives a bool if you are super user or not. We also added a decorator for the API routes to check for super user. @@ -39,4 +39,4 @@ Admin Users can change settings in the admin ui aswell, with the exception of fu Allowed Users ============= enviroment variable: LNBITS_ALLOWED_USERS, comma-seperated list of user ids -By defining this users, LNbits will no longer be useable by the public, only defined users and admins can then access the LNbits backend. +By defining this users, LNbits will no longer be useable by the public, only defined users and admins can then access the LNbits frontend. From 99410913f124d4452a16c1042e0068e955f14b9a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?dni=20=E2=9A=A1?= Date: Sat, 17 Dec 2022 14:55:22 +0100 Subject: [PATCH 4/6] change documentation theme to darkmode --- docs/_config.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/_config.yml b/docs/_config.yml index 74e65187..6c3d6512 100644 --- a/docs/_config.yml +++ b/docs/_config.yml @@ -1,7 +1,7 @@ title: "LNbits docs" - remote_theme: pmarsceill/just-the-docs -logo: "/logos/lnbits-full.png" +color_scheme: dark +logo: "/logos/lnbits-full--inverse.png" search_enabled: true url: https://legend.lnbits.org aux_links: From 1f3dff16fb2ea9adb2b431dfecf8072328be95cd Mon Sep 17 00:00:00 2001 From: Vlad Stan Date: Mon, 19 Dec 2022 10:39:42 +0200 Subject: [PATCH 5/6] fix: wrong permission required --- lnbits/extensions/satspay/views.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lnbits/extensions/satspay/views.py b/lnbits/extensions/satspay/views.py index b0f89025..90f8a6b9 100644 --- a/lnbits/extensions/satspay/views.py +++ b/lnbits/extensions/satspay/views.py @@ -8,7 +8,7 @@ from starlette.requests import Request from starlette.responses import HTMLResponse from lnbits.core.models import User -from lnbits.decorators import check_admin +from lnbits.decorators import check_user_exists from lnbits.extensions.satspay.helpers import public_charge from . import satspay_ext, satspay_renderer @@ -18,7 +18,7 @@ templates = Jinja2Templates(directory="templates") @satspay_ext.get("/", response_class=HTMLResponse) -async def index(request: Request, user: User = Depends(check_admin)): +async def index(request: Request, user: User = Depends(check_user_exists)): return satspay_renderer().TemplateResponse( "satspay/index.html", {"request": request, "user": user.dict(), "admin": user.admin}, From 1d509fb9d2383038dbebfa9ceccf628a73f96372 Mon Sep 17 00:00:00 2001 From: Vlad Stan Date: Mon, 19 Dec 2022 10:10:41 +0200 Subject: [PATCH 6/6] fix: typo `Setings` -> `Settings` --- lnbits/core/crud.py | 4 +-- lnbits/core/services.py | 4 +-- lnbits/core/views/admin_api.py | 4 +-- lnbits/settings.py | 60 +++++++++++++++++----------------- 4 files changed, 36 insertions(+), 36 deletions(-) diff --git a/lnbits/core/crud.py b/lnbits/core/crud.py index f2c7da61..1c8c71ad 100644 --- a/lnbits/core/crud.py +++ b/lnbits/core/crud.py @@ -6,7 +6,7 @@ from uuid import uuid4 from lnbits import bolt11 from lnbits.db import COCKROACH, POSTGRES, Connection -from lnbits.settings import AdminSettings, EditableSetings, SuperSettings, settings +from lnbits.settings import AdminSettings, EditableSettings, SuperSettings, settings from . import db from .models import BalanceCheck, Payment, User, Wallet @@ -579,7 +579,7 @@ async def delete_admin_settings(): await db.execute("DELETE FROM settings") -async def update_admin_settings(data: EditableSetings): +async def update_admin_settings(data: EditableSettings): await db.execute(f"UPDATE settings SET editable_settings = ?", (json.dumps(data),)) diff --git a/lnbits/core/services.py b/lnbits/core/services.py index 90910524..336d2665 100644 --- a/lnbits/core/services.py +++ b/lnbits/core/services.py @@ -23,7 +23,7 @@ from lnbits.helpers import url_for, urlsafe_short_hash from lnbits.requestvars import g from lnbits.settings import ( FAKE_WALLET, - EditableSetings, + EditableSettings, get_wallet_class, readonly_variables, send_admin_user_to_saas, @@ -474,7 +474,7 @@ async def init_admin_settings(super_user: str = None): if not account.wallets or len(account.wallets) == 0: await create_wallet(user_id=account.id) - editable_settings = EditableSetings.from_dict(settings.dict()) + editable_settings = EditableSettings.from_dict(settings.dict()) return await create_admin_settings(account.id, editable_settings.dict()) diff --git a/lnbits/core/views/admin_api.py b/lnbits/core/views/admin_api.py index 7c057adc..20eaeea3 100644 --- a/lnbits/core/views/admin_api.py +++ b/lnbits/core/views/admin_api.py @@ -9,7 +9,7 @@ from lnbits.core.models import User from lnbits.core.services import update_cached_settings, update_wallet_balance from lnbits.decorators import check_admin, check_super_user from lnbits.server import server_restart -from lnbits.settings import AdminSettings, EditableSetings +from lnbits.settings import AdminSettings, EditableSettings from .. import core_app from ..crud import delete_admin_settings, get_admin_settings, update_admin_settings @@ -28,7 +28,7 @@ async def api_get_settings( status_code=HTTPStatus.OK, dependencies=[Depends(check_admin)], ) -async def api_update_settings(data: EditableSetings): +async def api_update_settings(data: EditableSettings): await update_admin_settings(data) update_cached_settings(dict(data)) return {"status": "Success"} diff --git a/lnbits/settings.py b/lnbits/settings.py index d46a061d..e75f5b62 100644 --- a/lnbits/settings.py +++ b/lnbits/settings.py @@ -22,7 +22,7 @@ def list_parse_fallback(v): return [] -class LNbitsSetings(BaseSettings): +class LNbitsSettings(BaseSettings): def validate(cls, val): if type(val) == str: val = val.split(",") if val else [] @@ -35,14 +35,14 @@ class LNbitsSetings(BaseSettings): json_loads = list_parse_fallback -class UsersSetings(LNbitsSetings): +class UsersSettings(LNbitsSettings): 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=[]) -class ThemesSetings(LNbitsSetings): +class ThemesSettings(LNbitsSettings): 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) @@ -58,7 +58,7 @@ class ThemesSetings(LNbitsSetings): lnbits_ad_space_enabled: bool = Field(default=False) -class OpsSetings(LNbitsSetings): +class OpsSettings(LNbitsSettings): lnbits_force_https: bool = Field(default=False) lnbits_reserve_fee_min: int = Field(default=2000) lnbits_reserve_fee_percent: float = Field(default=1.0) @@ -67,29 +67,29 @@ class OpsSetings(LNbitsSetings): lnbits_denomination: str = Field(default="sats") -class FakeWalletFundingSource(LNbitsSetings): +class FakeWalletFundingSource(LNbitsSettings): fake_wallet_secret: str = Field(default="ToTheMoon1") -class LNbitsFundingSource(LNbitsSetings): +class LNbitsFundingSource(LNbitsSettings): lnbits_endpoint: str = Field(default="https://legend.lnbits.com") lnbits_key: Optional[str] = Field(default=None) -class ClicheFundingSource(LNbitsSetings): +class ClicheFundingSource(LNbitsSettings): cliche_endpoint: Optional[str] = Field(default=None) -class CoreLightningFundingSource(LNbitsSetings): +class CoreLightningFundingSource(LNbitsSettings): corelightning_rpc: Optional[str] = Field(default=None) -class EclairFundingSource(LNbitsSetings): +class EclairFundingSource(LNbitsSettings): eclair_url: Optional[str] = Field(default=None) eclair_pass: Optional[str] = Field(default=None) -class LndRestFundingSource(LNbitsSetings): +class LndRestFundingSource(LNbitsSettings): lnd_rest_endpoint: Optional[str] = Field(default=None) lnd_rest_cert: Optional[str] = Field(default=None) lnd_rest_macaroon: Optional[str] = Field(default=None) @@ -99,7 +99,7 @@ class LndRestFundingSource(LNbitsSetings): lnd_invoice_macaroon: Optional[str] = Field(default=None) -class LndGrpcFundingSource(LNbitsSetings): +class LndGrpcFundingSource(LNbitsSettings): lnd_grpc_endpoint: Optional[str] = Field(default=None) lnd_grpc_cert: Optional[str] = Field(default=None) lnd_grpc_port: Optional[int] = Field(default=None) @@ -109,28 +109,28 @@ class LndGrpcFundingSource(LNbitsSetings): lnd_grpc_macaroon_encrypted: Optional[str] = Field(default=None) -class LnPayFundingSource(LNbitsSetings): +class LnPayFundingSource(LNbitsSettings): lnpay_api_endpoint: Optional[str] = Field(default=None) lnpay_api_key: Optional[str] = Field(default=None) lnpay_wallet_key: Optional[str] = Field(default=None) -class LnTxtBotFundingSource(LNbitsSetings): +class LnTxtBotFundingSource(LNbitsSettings): lntxbot_api_endpoint: Optional[str] = Field(default=None) lntxbot_key: Optional[str] = Field(default=None) -class OpenNodeFundingSource(LNbitsSetings): +class OpenNodeFundingSource(LNbitsSettings): opennode_api_endpoint: Optional[str] = Field(default=None) opennode_key: Optional[str] = Field(default=None) -class SparkFundingSource(LNbitsSetings): +class SparkFundingSource(LNbitsSettings): spark_url: Optional[str] = Field(default=None) spark_token: Optional[str] = Field(default=None) -class LnTipsFundingSource(LNbitsSetings): +class LnTipsFundingSource(LNbitsSettings): lntips_api_endpoint: Optional[str] = Field(default=None) lntips_api_key: Optional[str] = Field(default=None) lntips_admin_key: Optional[str] = Field(default=None) @@ -138,14 +138,14 @@ class LnTipsFundingSource(LNbitsSetings): # todo: must be extracted -class BoltzExtensionSettings(LNbitsSetings): +class BoltzExtensionSettings(LNbitsSettings): 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") -class FundingSourcesSetings( +class FundingSourcesSettings( FakeWalletFundingSource, LNbitsFundingSource, ClicheFundingSource, @@ -162,11 +162,11 @@ class FundingSourcesSetings( lnbits_backend_wallet_class: str = Field(default="VoidWallet") -class EditableSetings( - UsersSetings, - ThemesSetings, - OpsSetings, - FundingSourcesSetings, +class EditableSettings( + UsersSettings, + ThemesSettings, + OpsSettings, + FundingSourcesSettings, BoltzExtensionSettings, ): @validator( @@ -187,7 +187,7 @@ class EditableSetings( ) -class EnvSettings(LNbitsSetings): +class EnvSettings(LNbitsSettings): debug: bool = Field(default=False) host: str = Field(default="127.0.0.1") port: int = Field(default=5000) @@ -197,18 +197,18 @@ class EnvSettings(LNbitsSetings): super_user: str = Field(default="") -class SaaSSettings(LNbitsSetings): +class SaaSSettings(LNbitsSettings): 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) -class PersistenceSettings(LNbitsSetings): +class PersistenceSettings(LNbitsSettings): lnbits_data_folder: str = Field(default="./data") lnbits_database_url: str = Field(default=None) -class SuperUserSettings(LNbitsSetings): +class SuperUserSettings(LNbitsSettings): lnbits_allowed_funding_sources: List[str] = Field( default=[ "VoidWallet", @@ -242,18 +242,18 @@ class ReadOnlySettings( return [f for f in inspect.signature(cls).parameters if not f.startswith("_")] -class Settings(EditableSetings, ReadOnlySettings): +class Settings(EditableSettings, ReadOnlySettings): @classmethod def from_row(cls, row: Row) -> "Settings": data = dict(row) return cls(**data) -class SuperSettings(EditableSetings): +class SuperSettings(EditableSettings): super_user: str -class AdminSettings(EditableSetings): +class AdminSettings(EditableSettings): super_user: bool lnbits_allowed_funding_sources: Optional[List[str]]