Compare commits
15
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8f10c40943 | ||
|
|
99e4f33142 | ||
|
|
f4f43ad361 | ||
|
|
f14ea6c577 | ||
|
|
07428ecf94 | ||
|
|
867e3d06f6 | ||
|
|
4b4b6d0bcd | ||
|
|
07b1521dad | ||
|
|
7a2ddd9826 | ||
|
|
0eb4b477b7 | ||
|
|
06a0ba58ce | ||
|
|
5399b36027 | ||
|
|
3f01c91e3e | ||
|
|
ba5005fc44 | ||
|
|
2329770acd |
+5
-1
@@ -7,9 +7,13 @@
|
||||
# They are NOT managed by the Admin UI and are not stored in the database.
|
||||
|
||||
# === First Install Token ===
|
||||
# if set the user is required to enter this token on the /first_install page
|
||||
# If set the user is required to enter this token on the /first_install page
|
||||
# FIRST_INSTALL_TOKEN="myaccesstoken"
|
||||
|
||||
# === Security ===
|
||||
# When enabled (recommended), auth cookies require HTTPS and SSO will reject insecure HTTP.
|
||||
AUTH_HTTPS_ONLY=true
|
||||
|
||||
# === Logging and Development ===
|
||||
|
||||
DEBUG=False
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
<a href="https://lnbits.com" target="_blank" rel="noopener noreferrer">
|
||||
<picture>
|
||||
<source media="(prefers-color-scheme: dark)" srcset="https://i.imgur.com/QE6SIrs.png">
|
||||
<img src="https://i.imgur.com/fyKPgVT.png" alt="LNbits" style="width:300px">
|
||||
<source media="(prefers-color-scheme: dark)" srcset="docs/logos/lnbits-full-inverse.svg">
|
||||
<img src="docs/logos/lnbits-full.svg" alt="LNbits" style="width:300px">
|
||||
</picture>
|
||||
</a>
|
||||
|
||||
 [![license-badge]](LICENSE) [![docs-badge]][docs]  [](https://extensions.lnbits.com/) [](https://shop.lnbits.com/) [<img src="https://img.shields.io/badge/community_chat-Telegram-24A1DE">](https://t.me/lnbits) [<img src="https://img.shields.io/badge/supported_by-%3E__OpenSats-f97316">](https://opensats.org)
|
||||
<img width="2000" height="203" alt="lnbits_head" src="https://github.com/user-attachments/assets/77669718-ac10-43c7-ae95-6ce236c77401" />
|
||||
<img alt="lnbits_head" src="docs/assets/header.jpg" />
|
||||
[](https://demo.lnbits.com/tipjar/DwaUiE4kBX6mUW6pj3X5Kg)
|
||||
|
||||
# LNbits — The most powerful Bitcoin & Lightning toolkit
|
||||
@@ -46,7 +46,7 @@ Get yourself familiar and test on our demo server [demo.lnbits.com](https://demo
|
||||
|
||||
LNbits is packaged with tools to help manage funds, such as a table of transactions, line chart of spending, export to csv. Each wallet also comes with its own API keys, to help partition the exposure of your funding source.
|
||||
|
||||
<img src="https://i.imgur.com/w8jdGpF.png" style="width:800px">
|
||||
<img alt="lnbits_wallet" src="docs/assets/wallet.jpg" />
|
||||
|
||||
## LNbits extension universe
|
||||
|
||||
@@ -54,25 +54,25 @@ Extend YOUR LNbits to meet YOUR needs.
|
||||
|
||||
All non-core features are installed as extensions, reducing your code base and making your LNbits unique to you. Extend your LNbits install in any direction, and even create and share your own extensions.
|
||||
|
||||
<img src="https://i.imgur.com/aEBpwJF.png" style="width:800px">
|
||||
<img alt="lnbits_extensions" src="docs/assets/extensions.jpg" />
|
||||
|
||||
## LNbits API
|
||||
|
||||
LNbits has a powerful API, many projects use LNbits to do the heavy lifting for their bitcoin/lightning services.
|
||||
|
||||
<img src="https://i.imgur.com/V742sb9.png" style="width:800px">
|
||||
<img alt="lnbits_api" src="docs/assets/api.jpg" />
|
||||
|
||||
## LNbits node manager
|
||||
|
||||
LNbits comes packaged with a light node management UI, to make running your node that much easier.
|
||||
|
||||
<img src="https://i.imgur.com/TYqIK60.png" style="width:800px">
|
||||
<img alt="lnbits_api" src="docs/assets/lightning_node.jpg" />
|
||||
|
||||
## LNbits across all your devices
|
||||
## LNbits merchant tools
|
||||
|
||||
As well as working great in a browser, LNbits has native IoS and Android apps as well as a chrome extension. So you can enjoy the same UI across ALL your devices.
|
||||
The LNbits stack can process both bitcoin and fiat payments, making it a turnkey, all-in-one solution for merchants. With orders and inventory shared across extensions, and built-in notifications for Nostr, Telegram, and email, LNbits keeps everything in sync, freeing merchants to focus on their business.
|
||||
|
||||
<img src="https://i.imgur.com/J96EbRf.png" style="width:800px">
|
||||
<img alt="lnbits_merchants" src="docs/assets/merchants_small.webp" />
|
||||
|
||||
## Powered by LNbits
|
||||
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 180 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 317 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 139 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 157 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 28 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 305 KiB |
+5
-4
@@ -324,7 +324,8 @@ class AssetSettings(LNbitsSettings):
|
||||
"heif",
|
||||
"heics",
|
||||
"text/plain",
|
||||
"text/json" "text/xml",
|
||||
"text/json",
|
||||
"text/xml",
|
||||
"application/json",
|
||||
"application/pdf",
|
||||
]
|
||||
@@ -588,6 +589,8 @@ class ZBDFundingSource(LNbitsSettings):
|
||||
class PhoenixdFundingSource(LNbitsSettings):
|
||||
phoenixd_api_endpoint: str | None = Field(default="http://localhost:9740/")
|
||||
phoenixd_api_password: str | None = Field(default=None)
|
||||
phoenixd_data_dir: str | None = Field(default=None)
|
||||
phoenixd_mnemonic: str | None = Field(default=None)
|
||||
|
||||
|
||||
class AlbyFundingSource(LNbitsSettings):
|
||||
@@ -1007,9 +1010,7 @@ class EnvSettings(LNbitsSettings):
|
||||
debug_database: bool = Field(default=False)
|
||||
bundle_assets: bool = Field(default=True)
|
||||
# When enabled, auth cookies require HTTPS and SSO will reject insecure HTTP.
|
||||
# Keep disabled by default so local HTTP installs continue to work unless
|
||||
# operators explicitly opt into HTTPS-only auth cookies.
|
||||
auth_https_only: bool = Field(default=False)
|
||||
auth_https_only: bool = Field(default=True)
|
||||
host: str = Field(default="127.0.0.1")
|
||||
port: int = Field(default=5000, gt=0)
|
||||
forwarded_allow_ips: str = Field(default="*")
|
||||
|
||||
+1
-1
File diff suppressed because one or more lines are too long
Vendored
+11
-11
File diff suppressed because one or more lines are too long
@@ -275,6 +275,8 @@ window.localisation.en = {
|
||||
requires_server_restart:
|
||||
'Changing these settings requires a server restart to take effect.',
|
||||
funding_source_info: 'Select the active funding wallet',
|
||||
phoenixd_warning:
|
||||
"Phoenixd mnemonic is only available if phoenixd data-dir is specified and is readable by LNbits. It's not indicative of phoenixd not running. It just means LNbits cannot access the mnemonic to display it here.",
|
||||
latest_update: 'You are on the latest version {version}.',
|
||||
notifications: 'Notifications',
|
||||
notifications_configure: 'Configure Notifications',
|
||||
|
||||
@@ -202,7 +202,18 @@ window.app.component('lnbits-admin-funding-sources', {
|
||||
'Phoenixd',
|
||||
{
|
||||
phoenixd_api_endpoint: 'Endpoint',
|
||||
phoenixd_api_password: 'Key'
|
||||
phoenixd_api_password: 'Key',
|
||||
phoenixd_data_dir: {
|
||||
label: 'Data Directory',
|
||||
hint: 'Directory where phoenixd stores its data, including the seed phrase.'
|
||||
},
|
||||
phoenixd_mnemonic: {
|
||||
label: 'Phoenixd Seed Phrase',
|
||||
hint: 'Only available if phoenixd data-dir is specified',
|
||||
readonly: true,
|
||||
copy: true,
|
||||
qrcode: true
|
||||
}
|
||||
}
|
||||
],
|
||||
[
|
||||
|
||||
@@ -41,5 +41,37 @@ window.app.component('lnbits-admin-site-customisation', {
|
||||
]
|
||||
}
|
||||
},
|
||||
methods: {}
|
||||
methods: {
|
||||
onBackgroundImageInput(e) {
|
||||
const file = e.target.files[0]
|
||||
if (file) {
|
||||
this.uploadBackgroundImage(file)
|
||||
}
|
||||
e.target.value = null
|
||||
},
|
||||
async uploadBackgroundImage(file) {
|
||||
const formData = new FormData()
|
||||
formData.append('file', file)
|
||||
try {
|
||||
const {data} = await LNbits.api.request(
|
||||
'POST',
|
||||
'/api/v1/assets?public_asset=true',
|
||||
null,
|
||||
formData,
|
||||
{
|
||||
headers: {'Content-Type': 'multipart/form-data'}
|
||||
}
|
||||
)
|
||||
const assetUrl = `${window.location.origin}/api/v1/assets/${data.id}/thumbnail`
|
||||
this.formData.lnbits_default_bgimage = assetUrl
|
||||
Quasar.Notify.create({
|
||||
type: 'positive',
|
||||
message: 'Background image uploaded.',
|
||||
icon: null
|
||||
})
|
||||
} catch (e) {
|
||||
LNbits.utils.notifyApiError(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
@@ -545,31 +545,56 @@ window.PageAccount = {
|
||||
if (file) {
|
||||
this.uploadAsset(file)
|
||||
}
|
||||
e.target.value = null
|
||||
},
|
||||
async uploadAsset(file) {
|
||||
onBackgroundImageInput(e) {
|
||||
const file = e.target.files[0]
|
||||
if (file) {
|
||||
this.uploadBackgroundImage(file)
|
||||
}
|
||||
e.target.value = null
|
||||
},
|
||||
async uploadAsset(
|
||||
file,
|
||||
{isPublic = this.assetsUploadToPublic, notifySuccess = true} = {}
|
||||
) {
|
||||
const formData = new FormData()
|
||||
formData.append('file', file)
|
||||
try {
|
||||
await LNbits.api.request(
|
||||
const {data} = await LNbits.api.request(
|
||||
'POST',
|
||||
`/api/v1/assets?public_asset=${this.assetsUploadToPublic}`,
|
||||
`/api/v1/assets?public_asset=${isPublic}`,
|
||||
null,
|
||||
formData,
|
||||
{
|
||||
headers: {'Content-Type': 'multipart/form-data'}
|
||||
}
|
||||
)
|
||||
this.$q.notify({
|
||||
type: 'positive',
|
||||
message: 'Upload successful!',
|
||||
icon: null
|
||||
})
|
||||
if (notifySuccess) {
|
||||
this.$q.notify({
|
||||
type: 'positive',
|
||||
message: 'Upload successful!',
|
||||
icon: null
|
||||
})
|
||||
}
|
||||
await this.getUserAssets()
|
||||
return data
|
||||
} catch (e) {
|
||||
console.warn(e)
|
||||
LNbits.utils.notifyApiError(e)
|
||||
}
|
||||
},
|
||||
async uploadBackgroundImage(file) {
|
||||
const asset = await this.uploadAsset(file, {
|
||||
isPublic: false,
|
||||
notifySuccess: false
|
||||
})
|
||||
if (!asset) {
|
||||
return
|
||||
}
|
||||
const assetUrl = `${window.location.origin}/api/v1/assets/${asset.id}/thumbnail`
|
||||
await this.siteCustomisationChanged({bgimageChoice: assetUrl})
|
||||
},
|
||||
async deleteAsset(asset) {
|
||||
LNbits.utils
|
||||
.confirmDialog('Are you sure you want to delete this asset?')
|
||||
|
||||
Vendored
+294
-153
File diff suppressed because it is too large
Load Diff
@@ -52,6 +52,7 @@
|
||||
:label="prop.label"
|
||||
:hint="prop.hint"
|
||||
:value="prop.value"
|
||||
:readonly="prop.readonly || false"
|
||||
>
|
||||
<q-btn
|
||||
v-if="prop.copy"
|
||||
@@ -73,6 +74,15 @@
|
||||
></q-btn>
|
||||
</q-input>
|
||||
</div>
|
||||
<p
|
||||
v-if="fund === 'PhoenixdWallet' && key === 'phoenixd_mnemonic'"
|
||||
class="col-12 q-my-md"
|
||||
>
|
||||
<span>
|
||||
<q-icon name="warning" color="orange" size="xs"></q-icon>
|
||||
<span v-text="$t('phoenixd_warning')"></span>
|
||||
</span>
|
||||
</p>
|
||||
</div>
|
||||
<q-expansion-item
|
||||
v-if="
|
||||
|
||||
@@ -251,10 +251,27 @@
|
||||
type="text"
|
||||
v-model="formData.lnbits_default_bgimage"
|
||||
label="Background Image"
|
||||
@update:model-value="applyGlobalBgimage"
|
||||
hint="This must be a trusted source. It can change the content and it can log your IP address."
|
||||
>
|
||||
<template v-slot:append>
|
||||
<q-btn
|
||||
dense
|
||||
flat
|
||||
round
|
||||
icon="upload"
|
||||
@click="$refs.adminBackgroundImageInput.click()"
|
||||
>
|
||||
<q-tooltip>Upload background image</q-tooltip>
|
||||
</q-btn>
|
||||
</template>
|
||||
</q-input>
|
||||
<input
|
||||
type="file"
|
||||
ref="adminBackgroundImageInput"
|
||||
accept="image/*"
|
||||
style="display: none"
|
||||
@change="onBackgroundImageInput"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row q-col-gutter-md q-mb-md">
|
||||
|
||||
@@ -492,10 +492,28 @@
|
||||
siteCustomisationChanged({bgimageChoice: $event})
|
||||
"
|
||||
>
|
||||
<template v-slot:append>
|
||||
<q-btn
|
||||
dense
|
||||
flat
|
||||
round
|
||||
icon="upload"
|
||||
@click="$refs.backgroundImageInput.click()"
|
||||
>
|
||||
<q-tooltip>Upload background image</q-tooltip>
|
||||
</q-btn>
|
||||
</template>
|
||||
<q-tooltip
|
||||
><span v-text="$t('background_image')"></span
|
||||
></q-tooltip>
|
||||
</q-input>
|
||||
<input
|
||||
type="file"
|
||||
ref="backgroundImageInput"
|
||||
accept="image/*"
|
||||
style="display: none"
|
||||
@change="onBackgroundImageInput"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row q-mb-md">
|
||||
@@ -1108,82 +1126,130 @@
|
||||
<q-separator></q-separator>
|
||||
|
||||
<q-card-section>
|
||||
<q-btn-dropdown
|
||||
color="grey"
|
||||
dense
|
||||
outline
|
||||
no-caps
|
||||
:label="props.row.name"
|
||||
:icon="props.row.is_public ? 'public' : ''"
|
||||
<div
|
||||
class="row items-center no-wrap q-col-gutter-sm"
|
||||
>
|
||||
<q-list>
|
||||
<q-item
|
||||
clickable
|
||||
v-close-popup
|
||||
@click="copyAssetLinkToClipboard(props.row)"
|
||||
<div class="col">
|
||||
<q-btn-dropdown
|
||||
color="grey"
|
||||
dense
|
||||
outline
|
||||
no-caps
|
||||
class="full-width"
|
||||
:label="props.row.name"
|
||||
:icon="props.row.is_public ? 'public' : ''"
|
||||
>
|
||||
<q-item-section avatar>
|
||||
<q-avatar icon="content_copy" />
|
||||
</q-item-section>
|
||||
<q-item-section>
|
||||
<q-item-label>Copy Link</q-item-label>
|
||||
<q-item-label caption
|
||||
>Copy asset link to
|
||||
clipboard</q-item-label
|
||||
>
|
||||
</q-item-section>
|
||||
</q-item>
|
||||
|
||||
<q-item
|
||||
clickable
|
||||
v-close-popup
|
||||
@click="toggleAssetPublicAccess(props.row)"
|
||||
>
|
||||
<q-item-section avatar>
|
||||
<q-avatar
|
||||
:icon="
|
||||
props.row.is_public
|
||||
? 'public_off'
|
||||
: 'public'
|
||||
<q-list>
|
||||
<q-item
|
||||
clickable
|
||||
v-close-popup
|
||||
@click="
|
||||
copyAssetLinkToClipboard(props.row)
|
||||
"
|
||||
text-color="primary"
|
||||
/>
|
||||
</q-item-section>
|
||||
<q-item-section v-if="props.row.is_public">
|
||||
<q-item-label>Unpublish</q-item-label>
|
||||
<q-item-label caption
|
||||
>Make this asset private</q-item-label
|
||||
>
|
||||
</q-item-section>
|
||||
<q-item-section v-else>
|
||||
<q-item-label>Publish</q-item-label>
|
||||
<q-item-label caption
|
||||
>Make this asset public</q-item-label
|
||||
>
|
||||
</q-item-section>
|
||||
</q-item>
|
||||
<q-item-section avatar>
|
||||
<q-avatar icon="content_copy" />
|
||||
</q-item-section>
|
||||
<q-item-section>
|
||||
<q-item-label>Copy Link</q-item-label>
|
||||
<q-item-label caption
|
||||
>Copy asset link to
|
||||
clipboard</q-item-label
|
||||
>
|
||||
</q-item-section>
|
||||
</q-item>
|
||||
|
||||
<q-item
|
||||
clickable
|
||||
v-close-popup
|
||||
@click="deleteAsset(props.row)"
|
||||
>
|
||||
<q-item-section avatar>
|
||||
<q-avatar
|
||||
icon="delete"
|
||||
text-color="negative"
|
||||
/>
|
||||
</q-item-section>
|
||||
<q-item-section>
|
||||
<q-item-label>Delete</q-item-label>
|
||||
<q-item-label caption
|
||||
>Permanently delete this
|
||||
asset</q-item-label
|
||||
<q-item
|
||||
clickable
|
||||
v-close-popup
|
||||
@click="
|
||||
toggleAssetPublicAccess(props.row)
|
||||
"
|
||||
>
|
||||
</q-item-section>
|
||||
</q-item>
|
||||
</q-list>
|
||||
</q-btn-dropdown>
|
||||
<q-item-section avatar>
|
||||
<q-avatar
|
||||
:icon="
|
||||
props.row.is_public
|
||||
? 'public_off'
|
||||
: 'public'
|
||||
"
|
||||
text-color="primary"
|
||||
/>
|
||||
</q-item-section>
|
||||
<q-item-section
|
||||
v-if="props.row.is_public"
|
||||
>
|
||||
<q-item-label>Unpublish</q-item-label>
|
||||
<q-item-label caption
|
||||
>Make this asset
|
||||
private</q-item-label
|
||||
>
|
||||
</q-item-section>
|
||||
<q-item-section v-else>
|
||||
<q-item-label>Publish</q-item-label>
|
||||
<q-item-label caption
|
||||
>Make this asset
|
||||
public</q-item-label
|
||||
>
|
||||
</q-item-section>
|
||||
</q-item>
|
||||
|
||||
<q-item
|
||||
clickable
|
||||
v-close-popup
|
||||
@click="deleteAsset(props.row)"
|
||||
>
|
||||
<q-item-section avatar>
|
||||
<q-avatar
|
||||
icon="delete"
|
||||
text-color="negative"
|
||||
/>
|
||||
</q-item-section>
|
||||
<q-item-section>
|
||||
<q-item-label>Delete</q-item-label>
|
||||
<q-item-label caption
|
||||
>Permanently delete this
|
||||
asset</q-item-label
|
||||
>
|
||||
</q-item-section>
|
||||
</q-item>
|
||||
</q-list>
|
||||
</q-btn-dropdown>
|
||||
</div>
|
||||
<div class="col-auto">
|
||||
<q-btn
|
||||
type="a"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
color="primary"
|
||||
dense
|
||||
flat
|
||||
round
|
||||
icon="image"
|
||||
:href="`/api/v1/assets/${props.row.id}/data`"
|
||||
>
|
||||
<q-tooltip>Full image</q-tooltip>
|
||||
</q-btn>
|
||||
</div>
|
||||
<div
|
||||
class="col-auto"
|
||||
v-if="props.row.thumbnail_base64"
|
||||
>
|
||||
<q-btn
|
||||
type="a"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
color="secondary"
|
||||
dense
|
||||
flat
|
||||
round
|
||||
icon="photo_size_select_small"
|
||||
:href="`/api/v1/assets/${props.row.id}/thumbnail`"
|
||||
>
|
||||
<q-tooltip>Thumbnail</q-tooltip>
|
||||
</q-btn>
|
||||
</div>
|
||||
</div>
|
||||
</q-card-section>
|
||||
</q-card>
|
||||
</div>
|
||||
|
||||
@@ -4,9 +4,11 @@ import hashlib
|
||||
import json
|
||||
import urllib.parse
|
||||
from collections.abc import AsyncGenerator
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
import httpx
|
||||
from embit.bip39 import mnemonic_is_valid
|
||||
from httpx import RequestError, TimeoutException
|
||||
from loguru import logger
|
||||
from websockets import connect
|
||||
@@ -61,6 +63,8 @@ class PhoenixdWallet(Wallet):
|
||||
}
|
||||
|
||||
self.client = httpx.AsyncClient(base_url=self.endpoint, headers=self.headers)
|
||||
self._seed_mnemonic_to_persist: str | None = None
|
||||
self._load_mnemonic_from_seed_file()
|
||||
|
||||
async def cleanup(self):
|
||||
try:
|
||||
@@ -69,6 +73,7 @@ class PhoenixdWallet(Wallet):
|
||||
logger.warning(f"Error closing wallet connection: {e}")
|
||||
|
||||
async def status(self) -> StatusResponse:
|
||||
await self._persist_loaded_mnemonic()
|
||||
try:
|
||||
r = await self.client.get("/getinfo", timeout=10)
|
||||
r.raise_for_status()
|
||||
@@ -101,7 +106,6 @@ class PhoenixdWallet(Wallet):
|
||||
unhashed_description: bytes | None = None,
|
||||
**kwargs,
|
||||
) -> InvoiceResponse:
|
||||
|
||||
try:
|
||||
msats_amount = amount
|
||||
data: dict[str, Any] = {
|
||||
@@ -309,7 +313,7 @@ class PhoenixdWallet(Wallet):
|
||||
and message_json.get("type") == "payment_received"
|
||||
):
|
||||
logger.info(
|
||||
f'payment-received: {message_json["paymentHash"]}'
|
||||
f"payment-received: {message_json['paymentHash']}"
|
||||
)
|
||||
yield message_json["paymentHash"]
|
||||
|
||||
@@ -319,3 +323,49 @@ class PhoenixdWallet(Wallet):
|
||||
"retrying in 5 seconds"
|
||||
)
|
||||
await asyncio.sleep(5)
|
||||
|
||||
def _load_mnemonic_from_seed_file(self):
|
||||
data_dir = settings.phoenixd_data_dir
|
||||
if not data_dir:
|
||||
return
|
||||
|
||||
seed_path = Path(data_dir).expanduser() / "seed.dat"
|
||||
if not seed_path.is_file():
|
||||
return
|
||||
|
||||
try:
|
||||
mnemonic = seed_path.read_text(encoding="utf-8").strip()
|
||||
if mnemonic == settings.phoenixd_mnemonic:
|
||||
return
|
||||
except OSError as exc:
|
||||
logger.warning(f"Failed to read Phoenixd seed file '{seed_path}': {exc}")
|
||||
return
|
||||
|
||||
if not mnemonic:
|
||||
logger.warning(f"Phoenixd seed file '{seed_path}' is empty.")
|
||||
return
|
||||
|
||||
if not mnemonic_is_valid(mnemonic):
|
||||
logger.warning(
|
||||
f"Phoenixd seed file '{seed_path}' does not contain a valid "
|
||||
"BIP39 mnemonic."
|
||||
)
|
||||
return
|
||||
|
||||
settings.phoenixd_mnemonic = mnemonic
|
||||
self._seed_mnemonic_to_persist = mnemonic
|
||||
|
||||
async def _persist_loaded_mnemonic(self):
|
||||
if not self._seed_mnemonic_to_persist:
|
||||
return
|
||||
|
||||
logger.info("Updating 'PHOENIXD_MNEMONIC' mnemonic settings.")
|
||||
try:
|
||||
from lnbits.core.crud.settings import set_settings_field
|
||||
|
||||
await set_settings_field(
|
||||
"phoenixd_mnemonic", self._seed_mnemonic_to_persist
|
||||
)
|
||||
self._seed_mnemonic_to_persist = None
|
||||
except Exception as exc:
|
||||
logger.warning(f"Failed to persist Phoenixd mnemonic: {exc}")
|
||||
|
||||
Generated
+12
-8
@@ -6,7 +6,7 @@
|
||||
"": {
|
||||
"name": "lnbits",
|
||||
"dependencies": {
|
||||
"axios": "^1.13.5",
|
||||
"axios": "^1.15.0",
|
||||
"chart.js": "^4.5.1",
|
||||
"moment": "^2.30.1",
|
||||
"nostr-tools": "^2.18.2",
|
||||
@@ -734,14 +734,14 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/axios": {
|
||||
"version": "1.13.5",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-1.13.5.tgz",
|
||||
"integrity": "sha512-cz4ur7Vb0xS4/KUN0tPWe44eqxrIu31me+fbang3ijiNscE129POzipJJA6zniq2C/Z6sJCjMimjS8Lc/GAs8Q==",
|
||||
"version": "1.15.0",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-1.15.0.tgz",
|
||||
"integrity": "sha512-wWyJDlAatxk30ZJer+GeCWS209sA42X+N5jU2jy6oHTp7ufw8uzUTVFBX9+wTfAlhiJXGS0Bq7X6efruWjuK9Q==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"follow-redirects": "^1.15.11",
|
||||
"form-data": "^4.0.5",
|
||||
"proxy-from-env": "^1.1.0"
|
||||
"proxy-from-env": "^2.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/balanced-match": {
|
||||
@@ -1555,9 +1555,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/proxy-from-env": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
|
||||
"integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg=="
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-2.1.0.tgz",
|
||||
"integrity": "sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/pyright": {
|
||||
"version": "1.1.289",
|
||||
|
||||
+1
-1
@@ -21,7 +21,7 @@
|
||||
"terser": "^5.44.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"axios": "^1.13.5",
|
||||
"axios": "^1.15.0",
|
||||
"chart.js": "^4.5.1",
|
||||
"moment": "^2.30.1",
|
||||
"nostr-tools": "^2.18.2",
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
[project]
|
||||
name = "lnbits"
|
||||
version = "1.5.3"
|
||||
version = "1.5.4"
|
||||
requires-python = ">=3.10,<3.13"
|
||||
description = "LNbits, free and open-source Lightning wallet and accounts system."
|
||||
authors = [{ name = "Alan Bits", email = "alan@lnbits.com" }]
|
||||
|
||||
@@ -1263,7 +1263,7 @@ wheels = [
|
||||
|
||||
[[package]]
|
||||
name = "lnbits"
|
||||
version = "1.5.3"
|
||||
version = "1.5.4"
|
||||
source = { editable = "." }
|
||||
dependencies = [
|
||||
{ name = "aiosqlite" },
|
||||
@@ -2114,7 +2114,7 @@ wheels = [
|
||||
|
||||
[[package]]
|
||||
name = "pytest"
|
||||
version = "9.0.2"
|
||||
version = "9.0.3"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "colorama", marker = "sys_platform == 'win32'" },
|
||||
@@ -2125,9 +2125,9 @@ dependencies = [
|
||||
{ name = "pygments" },
|
||||
{ name = "tomli", marker = "python_full_version < '3.11'" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/d1/db/7ef3487e0fb0049ddb5ce41d3a49c235bf9ad299b6a25d5780a89f19230f/pytest-9.0.2.tar.gz", hash = "sha256:75186651a92bd89611d1d9fc20f0b4345fd827c41ccd5c299a868a05d70edf11", size = 1568901, upload-time = "2025-12-06T21:30:51.014Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/7d/0d/549bd94f1a0a402dc8cf64563a117c0f3765662e2e668477624baeec44d5/pytest-9.0.3.tar.gz", hash = "sha256:b86ada508af81d19edeb213c681b1d48246c1a91d304c6c81a427674c17eb91c", size = 1572165, upload-time = "2026-04-07T17:16:18.027Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/3b/ab/b3226f0bd7cdcf710fbede2b3548584366da3b19b5021e74f5bde2a8fa3f/pytest-9.0.2-py3-none-any.whl", hash = "sha256:711ffd45bf766d5264d487b917733b453d917afd2b0ad65223959f59089f875b", size = 374801, upload-time = "2025-12-06T21:30:49.154Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/d4/24/a372aaf5c9b7208e7112038812994107bc65a84cd00e0354a88c2c77a617/pytest-9.0.3-py3-none-any.whl", hash = "sha256:2c5efc453d45394fdd706ade797c0a81091eccd1d6e4bccfcd476e2b8e0ab5d9", size = 375249, upload-time = "2026-04-07T17:16:16.13Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2213,11 +2213,11 @@ wheels = [
|
||||
|
||||
[[package]]
|
||||
name = "python-multipart"
|
||||
version = "0.0.22"
|
||||
version = "0.0.26"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/94/01/979e98d542a70714b0cb2b6728ed0b7c46792b695e3eaec3e20711271ca3/python_multipart-0.0.22.tar.gz", hash = "sha256:7340bef99a7e0032613f56dc36027b959fd3b30a787ed62d310e951f7c3a3a58", size = 37612, upload-time = "2026-01-25T10:15:56.219Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/88/71/b145a380824a960ebd60e1014256dbb7d2253f2316ff2d73dfd8928ec2c3/python_multipart-0.0.26.tar.gz", hash = "sha256:08fadc45918cd615e26846437f50c5d6d23304da32c341f289a617127b081f17", size = 43501, upload-time = "2026-04-10T14:09:59.473Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/1b/d0/397f9626e711ff749a95d96b7af99b9c566a9bb5129b8e4c10fc4d100304/python_multipart-0.0.22-py3-none-any.whl", hash = "sha256:2b2cd894c83d21bf49d702499531c7bafd057d730c201782048f7945d82de155", size = 24579, upload-time = "2026-01-25T10:15:54.811Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/9a/22/f1925cdda983ab66fc8ec6ec8014b959262747e58bdca26a4e3d1da29d56/python_multipart-0.0.26-py3-none-any.whl", hash = "sha256:c0b169f8c4484c13b0dcf2ef0ec3a4adb255c4b7d18d8e420477d2b1dd03f185", size = 28847, upload-time = "2026-04-10T14:09:58.131Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
||||
Reference in New Issue
Block a user