Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: update to 1.0.0 #37

Merged
merged 4 commits into from
Oct 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion config.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@
"short_description": "Access LNbits from BlueWallet or Zeus",
"tile": "/lndhub/static/image/lndhub.png",
"contributors": ["fiatjaf", "dni"],
"min_lnbits_version": "0.12.11"
"min_lnbits_version": "1.0.0"
}
39 changes: 15 additions & 24 deletions decorators.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
from base64 import b64decode

from fastapi import Request, status
from fastapi.param_functions import Security
from fastapi import Request, Security
from fastapi.security.api_key import APIKeyHeader
from lnbits.core.models import WalletTypeInfo
from lnbits.decorators import get_key_type
from starlette.exceptions import HTTPException
from lnbits.decorators import require_admin_key, require_invoice_key

api_key_header_auth = APIKeyHeader(
name="Authorization",
Expand All @@ -14,31 +12,24 @@
)


async def check_wallet(
r: Request, api_key: str = Security(api_key_header_auth)
) -> WalletTypeInfo:
if not api_key:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED, detail="Invalid auth key"
)
async def sanitize_token(api_key: str) -> str:
if api_key.startswith("Bearer "):
t = api_key.split(" ")[1]
_, token = b64decode(t).decode().split(":")
else:
token = api_key

return await get_key_type(r, api_key_header=token)
return token


async def require_admin_key(
r: Request, api_key_header_auth: str = Security(api_key_header_auth)
async def lndhub_require_admin_key(
request: Request, api_key_header_auth: str = Security(api_key_header_auth)
):
wallet = await check_wallet(r, api_key_header_auth)
if wallet.key_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
token = await sanitize_token(api_key_header_auth)
return await require_admin_key(request, token)


async def lndhub_require_invoice_key(
request: Request, api_key_header_auth: str = Security(api_key_header_auth)
) -> WalletTypeInfo:
token = await sanitize_token(api_key_header_auth)
return await require_invoice_key(request, token)
1,923 changes: 995 additions & 928 deletions poetry.lock

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ authors = ["Alan Bits <[email protected]>"]

[tool.poetry.dependencies]
python = "^3.10 | ^3.9"
lnbits = "*"
lnbits = {version = "*", allow-prereleases = true}

[tool.poetry.group.dev.dependencies]
black = "^24.3.0"
Expand Down
45 changes: 20 additions & 25 deletions templates/lndhub/index.html
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{% extends "base.html" %} {% from "macros.jinja" import window_vars with context
%} {% block page %} {% raw %}
%} {% block page %}
<div class="row q-col-gutter-md">
<div class="col-12 col-md-8 col-lg-7 q-gutter-y-md">
<div class="row q-col-gutter-md">
Expand All @@ -10,14 +10,13 @@
>
<q-card-section class="q-pa-none">
<div class="text-center">
<span class="text-capitalize" v-text="type"></span>
<a class="text-secondary" :href="selectedWallet[type]">
<q-responsive :ratio="1" class="q-mx-sm">
<qrcode
:value="selectedWallet[type]"
:options="{width: 800}"
class="rounded-borders"
></qrcode>
</q-responsive>
<lnbits-qrcode
:value="selectedWallet[type]"
:options="{width: 350}"
class="rounded-borders"
></lnbits-qrcode>
</a>
</div>
<div class="row q-mt-lg items-center justify-center">
Expand All @@ -26,7 +25,7 @@
color="grey"
@click="copyText(selectedWallet[type])"
class="text-center q-mb-md"
>Copy LndHub {{type}} URL</q-btn
>Copy LndHub <span v-text="type"></span> URL</q-btn
>
</div>
</q-card-section>
Expand All @@ -47,8 +46,6 @@
</q-card>
</div>

{% endraw %}

<div class="col-12 col-md-4 col-lg-5 q-gutter-y-md">
<q-card>
<q-card-section>
Expand All @@ -70,23 +67,21 @@ <h6 class="text-subtitle1 q-my-none">

{% endblock %} {% block scripts %} {{ window_vars(user) }}
<script>
Vue.component(VueQrcode.name, VueQrcode)

new Vue({
window.app = Vue.createApp({
el: '#vue',
mixins: [windowMixin],
data: function () {
var wallets = JSON.parse('{{ user.wallets | tojson }}')
.map(LNbits.map.wallet)
.map(wallet => ({
label: wallet.name,
admin: `lndhub://admin:${wallet.adminkey}@${location.protocol}//${location.host}/lndhub/ext/`,
invoice: `lndhub://invoice:${wallet.inkey}@${location.protocol}//${location.host}/lndhub/ext/`
}))

data() {
const {wallets} = JSON.parse({{ user | tojson | safe }})
const mappedWallets = wallets
.map(LNbits.map.wallet)
.map(wallet => ({
label: wallet.name,
admin: `lndhub://admin:${wallet.adminkey}@${location.protocol}//${location.host}/lndhub/ext/`,
invoice: `lndhub://invoice:${wallet.inkey}@${location.protocol}//${location.host}/lndhub/ext/`
}))
return {
wallets: wallets,
selectedWallet: wallets[0]
wallets: mappedWallets,
selectedWallet: mappedWallets[0]
}
}
})
Expand Down
2 changes: 1 addition & 1 deletion views.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,5 @@ def lndhub_renderer():
@lndhub_generic_router.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()}
"lndhub/index.html", {"request": request, "user": user.json()}
)
37 changes: 20 additions & 17 deletions views_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from lnbits.core.services import create_invoice, pay_invoice
from lnbits.settings import settings

from .decorators import check_wallet, require_admin_key
from .decorators import lndhub_require_admin_key, lndhub_require_invoice_key
from .models import LndhubAddInvoice, LndhubAuthData, LndhubCreateInvoice
from .utils import decoded_as_lndhub, to_buffer

Expand All @@ -34,10 +34,10 @@ async def lndhub_auth(data: LndhubAuthData):

@lndhub_api_router.post("/addinvoice")
async def lndhub_addinvoice(
data: LndhubAddInvoice, wallet: WalletTypeInfo = Depends(check_wallet)
data: LndhubAddInvoice, wallet: WalletTypeInfo = Depends(lndhub_require_invoice_key)
):
try:
payment_hash, pr = await create_invoice(
payment = await create_invoice(
wallet_id=wallet.wallet.id,
amount=data.amt,
memo=data.memo or settings.lnbits_site_title,
Expand All @@ -47,18 +47,18 @@ async def lndhub_addinvoice(
return {"error": f"Failed to create invoice: {exc!s}"}

return {
"pay_req": pr,
"payment_request": pr,
"pay_req": payment.bolt11,
"payment_request": payment.bolt11,
"add_index": "500",
"r_hash": to_buffer(payment_hash),
"hash": payment_hash,
"r_hash": to_buffer(payment.payment_hash),
"hash": payment.payment_hash,
}


@lndhub_api_router.post("/payinvoice")
async def lndhub_payinvoice(
r_invoice: LndhubCreateInvoice,
key_type: WalletTypeInfo = Depends(require_admin_key),
key_type: WalletTypeInfo = Depends(lndhub_require_admin_key),
):
try:
invoice = bolt11_decode(r_invoice.invoice)
Expand Down Expand Up @@ -87,14 +87,14 @@ async def lndhub_payinvoice(

@lndhub_api_router.get("/balance")
async def lndhub_balance(
key_type: WalletTypeInfo = Depends(check_wallet),
key_type: WalletTypeInfo = Depends(lndhub_require_invoice_key),
):
return {"BTC": {"AvailableBalance": key_type.wallet.balance}}


@lndhub_api_router.get("/gettxs")
async def lndhub_gettxs(
key_type: WalletTypeInfo = Depends(check_wallet),
key_type: WalletTypeInfo = Depends(lndhub_require_invoice_key),
limit: int = Query(20, ge=1, le=200),
offset: int = Query(0, ge=0),
):
Expand All @@ -108,7 +108,7 @@ async def lndhub_gettxs(
"value": int(payment.amount / 1000),
"timestamp": payment.time,
"memo": (
payment.extra.get("comment") or payment.memo
payment.extra and payment.extra.get("comment") or payment.memo
if not payment.pending
else "Payment in transition"
),
Expand All @@ -129,7 +129,7 @@ async def lndhub_gettxs(

@lndhub_api_router.get("/getuserinvoices")
async def lndhub_getuserinvoices(
key_type: WalletTypeInfo = Depends(check_wallet),
key_type: WalletTypeInfo = Depends(lndhub_require_invoice_key),
limit: int = Query(20, ge=1, le=200),
offset: int = Query(0, ge=0),
):
Expand All @@ -138,10 +138,11 @@ async def lndhub_getuserinvoices(
"r_hash": to_buffer(payment.payment_hash),
"payment_request": payment.bolt11,
"add_index": "500",
"description": payment.extra.get("comment") or payment.memo,
"description": (
payment.extra and payment.extra.get("comment") or payment.memo
),
"payment_hash": payment.payment_hash,
# todo it works for lnbits 0.12.11 but not for 0.12.10
"ispaid": payment.success, # type: ignore
"ispaid": payment.success,
"amt": int(payment.amount / 1000),
"expire_time": int(time.time() + 1800),
"timestamp": payment.time,
Expand All @@ -161,13 +162,15 @@ async def lndhub_getuserinvoices(
]


@lndhub_api_router.get("/getbtc", dependencies=[Depends(check_wallet)])
@lndhub_api_router.get("/getbtc", dependencies=[Depends(lndhub_require_invoice_key)])
async def lndhub_getbtc():
"load an address for incoming onchain btc"
return []


@lndhub_api_router.get("/getpending", dependencies=[Depends(check_wallet)])
@lndhub_api_router.get(
"/getpending", dependencies=[Depends(lndhub_require_invoice_key)]
)
async def lndhub_getpending():
"pending onchain transactions"
return []
Expand Down