diff --git a/lnbits/extensions/lndhub/README.md b/lnbits/extensions/lndhub/README.md deleted file mode 100644 index ddd2020a..00000000 --- a/lnbits/extensions/lndhub/README.md +++ /dev/null @@ -1,6 +0,0 @@ -

lndhub Extension

-

*connect to your lnbits wallet from BlueWallet or Zeus*

- -Lndhub has nothing to do with lnd, it is just the name of the HTTP/JSON protocol https://bluewallet.io/ uses to talk to their Lightning custodian server at https://lndhub.io/. - -Despite not having been planned to this, Lndhub because somewhat a standard for custodian wallet communication when https://t.me/lntxbot and https://zeusln.app/ implemented the same interface. And with this extension LNbits joins the same club. diff --git a/lnbits/extensions/lndhub/__init__.py b/lnbits/extensions/lndhub/__init__.py deleted file mode 100644 index 344e91c6..00000000 --- a/lnbits/extensions/lndhub/__init__.py +++ /dev/null @@ -1,27 +0,0 @@ -from fastapi import APIRouter -from starlette.staticfiles import StaticFiles - -from lnbits.db import Database -from lnbits.helpers import template_renderer - -db = Database("ext_lndhub") - -lndhub_ext: APIRouter = APIRouter(prefix="/lndhub", tags=["lndhub"]) - -lndhub_static_files = [ - { - "path": "/lndhub/static", - "app": StaticFiles(directory="lnbits/extensions/lndhub/static"), - "name": "lndhub_static", - } -] - - -def lndhub_renderer(): - return template_renderer(["lnbits/extensions/lndhub/templates"]) - - -from .decorators import * # noqa: F401,F403 -from .utils import * # noqa: F401,F403 -from .views import * # noqa: F401,F403 -from .views_api import * # noqa: F401,F403 diff --git a/lnbits/extensions/lndhub/config.json b/lnbits/extensions/lndhub/config.json deleted file mode 100644 index 30a2ce59..00000000 --- a/lnbits/extensions/lndhub/config.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "name": "LndHub", - "short_description": "Access lnbits from BlueWallet or Zeus", - "tile": "/lndhub/static/image/lndhub.png", - "contributors": ["fiatjaf"] -} diff --git a/lnbits/extensions/lndhub/decorators.py b/lnbits/extensions/lndhub/decorators.py deleted file mode 100644 index 48118087..00000000 --- a/lnbits/extensions/lndhub/decorators.py +++ /dev/null @@ -1,42 +0,0 @@ -from base64 import b64decode - -from fastapi import Request, status -from fastapi.param_functions import Security -from fastapi.security.api_key import APIKeyHeader -from starlette.exceptions import HTTPException - -from lnbits.decorators import WalletTypeInfo, get_key_type - -api_key_header_auth = APIKeyHeader( - name="AUTHORIZATION", - auto_error=False, - description="Admin or Invoice key for LNDHub API's", -) - - -async def check_wallet( - r: Request, api_key_header_auth: str = Security(api_key_header_auth) -) -> WalletTypeInfo: - if not api_key_header_auth: - raise HTTPException( - status_code=status.HTTP_401_UNAUTHORIZED, detail="Invalid auth key" - ) - - t = api_key_header_auth.split(" ")[1] - _, token = b64decode(t).decode().split(":") - - return await get_key_type(r, api_key_header=token) - - -async def require_admin_key( - r: Request, api_key_header_auth: str = Security(api_key_header_auth) -): - wallet = await check_wallet(r, api_key_header_auth) - if wallet.wallet_type != 0: - # If wallet type is not admin then return the unauthorized status - # This also covers when the user passes an invalid key type - raise HTTPException( - status_code=status.HTTP_401_UNAUTHORIZED, detail="Admin key required." - ) - else: - return wallet diff --git a/lnbits/extensions/lndhub/migrations.py b/lnbits/extensions/lndhub/migrations.py deleted file mode 100644 index d6ea5fde..00000000 --- a/lnbits/extensions/lndhub/migrations.py +++ /dev/null @@ -1,2 +0,0 @@ -async def migrate(): - pass diff --git a/lnbits/extensions/lndhub/static/image/lndhub.png b/lnbits/extensions/lndhub/static/image/lndhub.png deleted file mode 100644 index f5e95a6e..00000000 Binary files a/lnbits/extensions/lndhub/static/image/lndhub.png and /dev/null differ diff --git a/lnbits/extensions/lndhub/templates/lndhub/_instructions.html b/lnbits/extensions/lndhub/templates/lndhub/_instructions.html deleted file mode 100644 index a5eba8a2..00000000 --- a/lnbits/extensions/lndhub/templates/lndhub/_instructions.html +++ /dev/null @@ -1,38 +0,0 @@ - - - - To access an LNbits wallet from a mobile phone, -
    -
  1. - Install either - Zeus or - BlueWallet; -
  2. -
  3. - Go to Add a wallet / Import wallet on BlueWallet or - Settings / Add a new node on Zeus. -
  4. -
  5. Select the desired wallet on this page;
  6. -
  7. Scan one of the two QR codes from the mobile wallet.
  8. -
-
    -
  • - Invoice URLs mean the mobile wallet will only have the - authorization to read your payments and invoices and generate new - invoices. -
  • -
  • - Admin URLs mean the mobile wallet will be able to pay - invoices.. -
  • -
-
- -
-
diff --git a/lnbits/extensions/lndhub/templates/lndhub/_lndhub.html b/lnbits/extensions/lndhub/templates/lndhub/_lndhub.html deleted file mode 100644 index 73097dbf..00000000 --- a/lnbits/extensions/lndhub/templates/lndhub/_lndhub.html +++ /dev/null @@ -1,20 +0,0 @@ - - - -

- LndHub is a protocol invented by - BlueWallet - that allows mobile wallets to query payments and balances, generate - invoices and make payments from accounts that exist on a server. The - protocol is a collection of HTTP endpoints exposed through the internet. -

-

- For a wallet that supports it, reading a QR code that contains the URL - along with secret access credentials should enable access. Currently it - is supported by - Zeus and - BlueWallet. -

-
-
-
diff --git a/lnbits/extensions/lndhub/templates/lndhub/index.html b/lnbits/extensions/lndhub/templates/lndhub/index.html deleted file mode 100644 index fc666da9..00000000 --- a/lnbits/extensions/lndhub/templates/lndhub/index.html +++ /dev/null @@ -1,94 +0,0 @@ -{% extends "base.html" %} {% from "macros.jinja" import window_vars with context -%} {% block page %} {% raw %} -
-
-
- - - -
- Copy LndHub {{type}} URL -
-
-
-
- - - - - - - -
- - {% endraw %} - -
- - -
- {{SITE_TITLE}} LndHub extension -
-
- - - - {% include "lndhub/_instructions.html" %} - - {% include "lndhub/_lndhub.html" %} - - -
-
-
- -{% endblock %} {% block scripts %} {{ window_vars(user) }} - -{% endblock %} diff --git a/lnbits/extensions/lndhub/utils.py b/lnbits/extensions/lndhub/utils.py deleted file mode 100644 index 00865080..00000000 --- a/lnbits/extensions/lndhub/utils.py +++ /dev/null @@ -1,19 +0,0 @@ -from lnbits.bolt11 import Invoice - - -def to_buffer(payment_hash: str): - return {"type": "Buffer", "data": [b for b in bytes.fromhex(payment_hash)]} - - -def decoded_as_lndhub(invoice: Invoice): - return { - "destination": invoice.payee, - "payment_hash": invoice.payment_hash, - "num_satoshis": invoice.amount_msat / 1000, - "timestamp": str(invoice.date), - "expiry": str(invoice.expiry), - "description": invoice.description, - "fallback_addr": "", - "cltv_expiry": invoice.min_final_cltv_expiry, - "route_hints": "", - } diff --git a/lnbits/extensions/lndhub/views.py b/lnbits/extensions/lndhub/views.py deleted file mode 100644 index b216f8b1..00000000 --- a/lnbits/extensions/lndhub/views.py +++ /dev/null @@ -1,13 +0,0 @@ -from fastapi import Depends, Request - -from lnbits.core.models import User -from lnbits.decorators import check_user_exists - -from . import lndhub_ext, lndhub_renderer - - -@lndhub_ext.get("/") -async def lndhub_index(request: Request, user: User = Depends(check_user_exists)): - return lndhub_renderer().TemplateResponse( - "lndhub/index.html", {"request": request, "user": user.dict()} - ) diff --git a/lnbits/extensions/lndhub/views_api.py b/lnbits/extensions/lndhub/views_api.py deleted file mode 100644 index 059604f2..00000000 --- a/lnbits/extensions/lndhub/views_api.py +++ /dev/null @@ -1,230 +0,0 @@ -import time -from base64 import urlsafe_b64encode -from http import HTTPStatus - -from fastapi import Depends, Query -from pydantic import BaseModel -from starlette.exceptions import HTTPException - -from lnbits import bolt11 -from lnbits.core.crud import get_payments -from lnbits.core.services import create_invoice, pay_invoice -from lnbits.decorators import WalletTypeInfo -from lnbits.settings import get_wallet_class, settings - -from . import lndhub_ext -from .decorators import check_wallet, require_admin_key -from .utils import decoded_as_lndhub, to_buffer - - -@lndhub_ext.get("/ext/getinfo") -async def lndhub_getinfo(): - return {"alias": settings.lnbits_site_title} - - -class AuthData(BaseModel): - login: str = Query(None) - password: str = Query(None) - refresh_token: str = Query(None) - - -@lndhub_ext.post("/ext/auth") -async def lndhub_auth(data: AuthData): - token = ( - data.refresh_token - if data.refresh_token - else urlsafe_b64encode((data.login + ":" + data.password).encode()).decode( - "ascii" - ) - ) - return {"refresh_token": token, "access_token": token} - - -class AddInvoice(BaseModel): - amt: str = Query(...) - memo: str = Query(...) - preimage: str = Query(None) - - -@lndhub_ext.post("/ext/addinvoice") -async def lndhub_addinvoice( - data: AddInvoice, wallet: WalletTypeInfo = Depends(check_wallet) -): - try: - _, pr = await create_invoice( - wallet_id=wallet.wallet.id, - amount=int(data.amt), - memo=data.memo or settings.lnbits_site_title, - extra={"tag": "lndhub"}, - ) - except: - raise HTTPException( - status_code=HTTPStatus.NOT_FOUND, detail="Failed to create invoice" - ) - invoice = bolt11.decode(pr) - return { - "pay_req": pr, - "payment_request": pr, - "add_index": "500", - "r_hash": to_buffer(invoice.payment_hash), - "hash": invoice.payment_hash, - } - - -class CreateInvoice(BaseModel): - invoice: str = Query(...) - - -@lndhub_ext.post("/ext/payinvoice") -async def lndhub_payinvoice( - r_invoice: CreateInvoice, wallet: WalletTypeInfo = Depends(require_admin_key) -): - try: - await pay_invoice( - wallet_id=wallet.wallet.id, - payment_request=r_invoice.invoice, - extra={"tag": "lndhub"}, - ) - except: - raise HTTPException(status_code=HTTPStatus.NOT_FOUND, detail="Payment failed") - - invoice: bolt11.Invoice = bolt11.decode(r_invoice.invoice) - - return { - "payment_error": "", - "payment_preimage": "0" * 64, - "route": {}, - "payment_hash": invoice.payment_hash, - "decoded": decoded_as_lndhub(invoice), - "fee_msat": 0, - "type": "paid_invoice", - "fee": 0, - "value": invoice.amount_msat / 1000, - "timestamp": int(time.time()), - "memo": invoice.description, - } - - -@lndhub_ext.get("/ext/balance") -async def lndhub_balance( - wallet: WalletTypeInfo = Depends(check_wallet), -): - return {"BTC": {"AvailableBalance": wallet.wallet.balance}} - - -@lndhub_ext.get("/ext/gettxs") -async def lndhub_gettxs( - wallet: WalletTypeInfo = Depends(check_wallet), - limit: int = Query(20, ge=1, le=20), - offset: int = Query(0, ge=0), -): - for payment in await get_payments( - wallet_id=wallet.wallet.id, - complete=False, - pending=True, - outgoing=True, - incoming=False, - limit=limit, - offset=offset, - exclude_uncheckable=True, - ): - await payment.check_status() - - return [ - { - "payment_preimage": payment.preimage, - "payment_hash": payment.payment_hash, - "fee_msat": payment.fee * 1000, - "type": "paid_invoice", - "fee": payment.fee, - "value": int(payment.amount / 1000), - "timestamp": payment.time, - "memo": payment.memo if not payment.pending else "Payment in transition", - } - for payment in reversed( - ( - await get_payments( - wallet_id=wallet.wallet.id, - pending=True, - complete=True, - outgoing=True, - incoming=False, - limit=limit, - offset=offset, - ) - ) - ) - ] - - -@lndhub_ext.get("/ext/getuserinvoices") -async def lndhub_getuserinvoices( - wallet: WalletTypeInfo = Depends(check_wallet), - limit: int = Query(20, ge=1, le=20), - offset: int = Query(0, ge=0), -): - WALLET = get_wallet_class() - for invoice in await get_payments( - wallet_id=wallet.wallet.id, - complete=False, - pending=True, - outgoing=False, - incoming=True, - limit=limit, - offset=offset, - exclude_uncheckable=True, - ): - await invoice.set_pending( - (await WALLET.get_invoice_status(invoice.checking_id)).pending - ) - - return [ - { - "r_hash": to_buffer(invoice.payment_hash), - "payment_request": invoice.bolt11, - "add_index": "500", - "description": invoice.memo, - "payment_hash": invoice.payment_hash, - "ispaid": not invoice.pending, - "amt": int(invoice.amount / 1000), - "expire_time": int(time.time() + 1800), - "timestamp": invoice.time, - "type": "user_invoice", - } - for invoice in reversed( - ( - await get_payments( - wallet_id=wallet.wallet.id, - pending=True, - complete=True, - incoming=True, - outgoing=False, - limit=limit, - offset=offset, - ) - ) - ) - ] - - -@lndhub_ext.get("/ext/getbtc") -async def lndhub_getbtc(wallet: WalletTypeInfo = Depends(check_wallet)): - "load an address for incoming onchain btc" - return [] - - -@lndhub_ext.get("/ext/getpending") -async def lndhub_getpending(wallet: WalletTypeInfo = Depends(check_wallet)): - "pending onchain transactions" - return [] - - -@lndhub_ext.get("/ext/decodeinvoice") -async def lndhub_decodeinvoice(invoice: str = Query(None)): - inv = bolt11.decode(invoice) - return decoded_as_lndhub(inv) - - -@lndhub_ext.get("/ext/checkrouteinvoice") -async def lndhub_checkrouteinvoice(): - "not implemented on canonical lndhub"