Compare commits

...
Author SHA1 Message Date
Arc 3372f7463a defaults 2025-12-17 00:45:33 +00:00
Arc 3f4fd93858 boltz funding source seed fix
Users should be able to have a seed created or replace with their own
2025-12-17 00:42:39 +00:00
arcbtc 8325d880cb Extra precaution
Just in case someone in lnbits org creates a test release on a fork
2025-12-16 13:45:52 +00:00
dni ⚡andGitHub b090470fc1 fix: CI getting release upload url (#3667) 2025-12-16 14:12:00 +01:00
dni ⚡andGitHub c7297d2e77 feat: add the ability to print qrcodes to <lnbits-qrcode> component (#3664) 2025-12-16 12:12:11 +00:00
dni ⚡andGitHub b6e111b21c fix: dont log routes.json 404 (#3665) 2025-12-16 13:10:02 +01:00
dni ⚡andGitHub 7747d7b741 fix: path check for ext pages with arguments (#3660) 2025-12-11 13:56:49 +01:00
Tiago VasconcelosandGitHub f3a5a8e002 fix: account dropdown (#3658) 2025-12-11 13:17:17 +01:00
Tiago VasconcelosandGitHub 157a6485b4 fix: restore the blur on drawer (#3654) 2025-12-11 13:16:32 +01:00
dni ⚡andGitHub 8867b27b09 fix: LOCALE global variable still used in extension (#3659) 2025-12-11 13:03:38 +01:00
dni ⚡andGitHub 68b607ecbc fix: add spacing to the logo (#3653) 2025-12-10 08:08:00 +01:00
13 changed files with 110 additions and 22 deletions
+5 -1
View File
@@ -22,10 +22,12 @@ jobs:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
tag: ${{ github.ref_name }}
run: |
upload_url=$(gh release create "$tag" --generate-notes --draft --json upload_url -q '.upload_url')
gh release create "$tag" --generate-notes --draft
upload_url=$(gh release view "$tag" --repo "${{ github.repository }}" --json uploadUrl -q ".uploadUrl")
echo "upload_url=$upload_url" >> "$GITHUB_OUTPUT"
docker:
if: github.repository == 'lnbits/lnbits'
needs: [ release ]
uses: ./.github/workflows/docker.yml
with:
@@ -35,6 +37,7 @@ jobs:
DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }}
docker-latest:
if: github.repository == 'lnbits/lnbits'
needs: [ release ]
uses: ./.github/workflows/docker.yml
with:
@@ -44,6 +47,7 @@ jobs:
DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }}
pypi:
if: github.repository == 'lnbits/lnbits'
runs-on: ubuntu-24.04
steps:
- name: Install dependencies for building secp256k1
+3 -1
View File
@@ -138,7 +138,9 @@ def register_exception_handlers(app: FastAPI): # noqa: C901
@app.exception_handler(404)
async def error_handler_404(request: Request, exc: HTTPException):
logger.error(f"404: {request.url.path} {exc.status_code}: {exc.detail}")
if not request.url.path.endswith("routes.json"):
logger.error(f"404: {request.url.path} {exc.status_code}: {exc.detail}")
if not _is_browser_request(request):
return JSONResponse(
+19 -1
View File
@@ -6,6 +6,7 @@ import inspect
import json
import os
import re
import secrets
from datetime import datetime, timezone
from enum import Enum
from os import path
@@ -18,6 +19,21 @@ from loguru import logger
from pydantic import BaseModel, BaseSettings, Extra, Field, validator
def generate_default_boltz_mnemonic() -> str | None:
"""
Generate a BIP39 mnemonic using the bundled embit dependency.
If embit is unavailable at runtime, return None to avoid blocking startup.
"""
try:
from embit import bip39
except Exception as exc: # pragma: no cover - dependency missing at runtime
logger.warning(f"Unable to generate Boltz mnemonic (embit missing): {exc}")
return None
entropy = secrets.token_bytes(16) # 128 bits -> 12-word mnemonic
return bip39.mnemonic_from_bytes(entropy)
def list_parse_fallback(v: str):
v = v.replace(" ", "")
if len(v) > 0:
@@ -604,7 +620,9 @@ class BoltzFundingSource(LNbitsSettings):
boltz_client_wallet: str | None = Field(default="lnbits")
boltz_client_password: str = Field(default="")
boltz_client_cert: str | None = Field(default=None)
boltz_mnemonic: str | None = Field(default=None)
boltz_mnemonic: str | None = Field(
default_factory=generate_default_boltz_mnemonic
)
class StrikeFundingSource(LNbitsSettings):
File diff suppressed because one or more lines are too long
+1 -1
View File
File diff suppressed because one or more lines are too long
+1
View File
@@ -217,6 +217,7 @@ body.body--dark .q-header,
body.body--dark .q-drawer {
--q-dark: rgba(29, 29, 29, 0.3);
background-color: var(--q-dark);
backdrop-filter: blur(6px) brightness(0.8);
}
:root {
@@ -161,15 +161,21 @@ window.app.component('lnbits-admin-funding-sources', {
'Boltz',
{
boltz_client_endpoint: 'Endpoint',
boltz_client_macaroon: 'Admin Macaroon path or hex',
boltz_client_cert: 'Certificate path or hex',
boltz_client_macaroon: {
label: 'Admin Macaroon path or hex',
default: '/home/ubuntu/.boltz/macaroons/admin.macaroon'
},
boltz_client_cert: {
label: 'Certificate path or hex',
default: '/home/ben/.boltz/tls.cert'
},
boltz_client_wallet: 'Wallet Name',
boltz_client_password: 'Wallet Password (can be empty)',
boltz_mnemonic: {
label: 'Liquid mnemonic (copy into greenwallet)',
readonly: true,
copy: true,
qrcode: true
qrcode: true,
hint: 'Paste or type your liquid mnemonic'
}
}
],
@@ -13,6 +13,10 @@ window.app.component('lnbits-qrcode', {
type: Boolean,
default: false
},
print: {
type: Boolean,
default: false
},
showButtons: {
type: Boolean,
default: true
@@ -41,6 +45,41 @@ window.app.component('lnbits-qrcode', {
}
},
methods: {
printQrCode() {
const svg = this.$refs.qrCode.$el.outerHTML
const printWindow = window.open('', '_blank')
printWindow.document.write(`
<html>
<head>
<title>Print QR Code</title>
<style>
body {
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
margin: 0;
}
img {
position: absolute;
max-width: 51px;
width: 14%;
overflow: hidden;
background: #fff;
overflow: hidden;
padding: -1.2rem;
border-radius: -1.2rem;
}
</style>
</head>
<body>${svg}<img src="${this.logo}"></body>
</html>
`)
printWindow.document.close()
printWindow.focus()
printWindow.print()
printWindow.close()
},
clickQrCode(event) {
if (this.href === '') {
this.utils.copyText(this.value)
+4 -1
View File
@@ -38,7 +38,7 @@ const DynamicComponent = {
let route = RENDERED_ROUTE
// append trailing slash only on the root path `/path` -> `/path/`
if (route.split('/').length === 2) route += '/'
if (route !== this.$route.fullPath) {
if (route !== this.$route.path) {
console.log('Redirecting to non-vue route:', this.$route.fullPath)
window.location = this.$route.fullPath
return
@@ -138,6 +138,9 @@ window.router = VueRouter.createRouter({
routes
})
// BACKWARDS compatibility extensions
window.LOCALE = window.g.locale
window.i18n = new VueI18n.createI18n({
locale: window.g.locale,
fallbackLocale: 'en',
+1
View File
@@ -63,5 +63,6 @@ body.body--dark {
.q-drawer {
--q-dark: #{color.adjust(#1d1d1d, $alpha: -0.7)};
background-color: var(--q-dark);
backdrop-filter: blur(6px) brightness(0.8);
}
}
+1 -1
View File
@@ -534,7 +534,7 @@ include('components/lnbits-error.vue') %}
<q-tab name="bech32" icon="qr_code" label="bech32"></q-tab>
<q-tab name="lud17" icon="link" label="url (lud17)"></q-tab>
</q-tabs>
<lnbits-qrcode :value="lnurl" nfc="true"></lnbits-qrcode>
<lnbits-qrcode :value="lnurl" nfc="true" print="true"></lnbits-qrcode>
</div>
</template>
+15 -11
View File
@@ -22,7 +22,7 @@
@click="g.visibleDrawer = !g.visibleDrawer"
></q-btn>
<q-toolbar-title>
<q-btn flat no-caps dense size="lg" type="a" href="/">
<q-btn flat no-caps dense class="q-mr-sm" size="lg" type="a" href="/">
<q-img
v-if="customLogoUrl"
height="30px"
@@ -73,32 +73,36 @@
<lnbits-language-dropdown></lnbits-language-dropdown>
<q-btn-dropdown
v-if="g.user || g.isUserAuthorized"
flat
rounded
size="sm"
class="q-pl-sm"
>
<q-btn-dropdown v-if="g.user" flat rounded size="sm" class="q-pl-sm">
<template v-slot:label>
<q-avatar v-if="g.user?.extra?.picture !== ''" size="18px">
<q-avatar
v-if="g.user?.extra?.picture && g.user?.extra?.picture !== ''"
size="18px"
>
<q-img :src="g.user?.extra?.picture"></q-img>
</q-avatar>
<q-avatar v-else icon="account_circle" size="18px"></q-avatar>
</template>
<q-list style="max-width: 200px">
<q-item>
<q-item-section avatar v-if="g.user?.extra?.picture !== ''">
<q-item-section
avatar
v-if="
g.user &&
g.user?.extra?.picture &&
g.user?.extra?.picture !== ''
"
>
<q-avatar size="md">
<img :src="g.user?.extra?.picture" />
</q-avatar>
</q-item-section>
<q-item-section>
<q-item-label
caption
class="ellipsis"
v-text="displayName"
></q-item-label>
<q-item-label caption v-text="displayRole"></q-item-label>
</q-item-section>
</q-item>
<q-separator></q-separator>
@@ -44,6 +44,16 @@
>
<q-tooltip>Write NFC Tag</q-tooltip>
</q-btn>
<q-btn
v-if="print"
flat
dense
class="text-grey"
@click="printQrCode()"
icon="print"
>
<q-tooltip>Print</q-tooltip>
</q-btn>
<q-btn flat dense class="text-grey" icon="download" @click="downloadSVG">
<q-tooltip>Download SVG</q-tooltip>
</q-btn>