mirror of
https://github.com/lnbits/lnbits.git
synced 2025-09-20 04:21:20 +02:00
refactor: breaking bad
This commit is contained in:
@@ -1,6 +1,10 @@
|
|||||||
FLASK_APP=lnbits
|
FLASK_APP=lnbits
|
||||||
FLASK_ENV=development
|
FLASK_ENV=development
|
||||||
|
|
||||||
|
LNBITS_WITH_ONION=0
|
||||||
|
LNBITS_DEFAULT_WALLET_NAME="LNbits wallet"
|
||||||
|
LNBITS_FEE_RESERVE=0
|
||||||
|
|
||||||
LND_API_ENDPOINT=https://mylnd.io/rest/
|
LND_API_ENDPOINT=https://mylnd.io/rest/
|
||||||
LND_ADMIN_MACAROON=LND_ADMIN_MACAROON
|
LND_ADMIN_MACAROON=LND_ADMIN_MACAROON
|
||||||
LND_INVOICE_MACAROON=LND_INVOICE_MACAROON
|
LND_INVOICE_MACAROON=LND_INVOICE_MACAROON
|
||||||
@@ -15,9 +19,7 @@ OPENNODE_ADMIN_KEY=OPENNODE_ADMIN_KEY
|
|||||||
OPENNODE_INVOICE_KEY=OPENNODE_INVOICE_KEY
|
OPENNODE_INVOICE_KEY=OPENNODE_INVOICE_KEY
|
||||||
|
|
||||||
LNPAY_API_ENDPOINT=https://lnpay.co/v1/
|
LNPAY_API_ENDPOINT=https://lnpay.co/v1/
|
||||||
|
LNPAY_API_KEY=LNPAY_API_KEY
|
||||||
LNPAY_ADMIN_KEY=LNPAY_ADMIN_KEY
|
LNPAY_ADMIN_KEY=LNPAY_ADMIN_KEY
|
||||||
LNPAY_INVOICE_KEY=LNPAY_INVOICE_KEY
|
LNPAY_INVOICE_KEY=LNPAY_INVOICE_KEY
|
||||||
LNPAY_READ_KEY=LNPAY_READ_KEY
|
LNPAY_READ_KEY=LNPAY_READ_KEY
|
||||||
LNPAY_API_KEY=LNPAY_API_KEY
|
|
||||||
|
|
||||||
FEE_RESERVE=0
|
|
||||||
|
2
Pipfile
2
Pipfile
@@ -12,6 +12,8 @@ lnurl = "*"
|
|||||||
flask = "*"
|
flask = "*"
|
||||||
flask-assets = "*"
|
flask-assets = "*"
|
||||||
flask-compress = "*"
|
flask-compress = "*"
|
||||||
|
flask-limiter = "*"
|
||||||
|
flask-seasurf = "*"
|
||||||
flask-talisman = "*"
|
flask-talisman = "*"
|
||||||
gevent = "*"
|
gevent = "*"
|
||||||
greenlet = "*"
|
greenlet = "*"
|
||||||
|
@@ -1,18 +1,14 @@
|
|||||||
import importlib
|
import importlib
|
||||||
import json
|
|
||||||
import requests
|
|
||||||
import uuid
|
|
||||||
|
|
||||||
from flask import Flask, redirect, render_template, request, url_for
|
from flask import Flask
|
||||||
from flask_assets import Environment, Bundle
|
from flask_assets import Environment, Bundle
|
||||||
from flask_compress import Compress
|
from flask_compress import Compress
|
||||||
from flask_talisman import Talisman
|
from flask_talisman import Talisman
|
||||||
from lnurl import Lnurl, LnurlWithdrawResponse
|
from os import getenv
|
||||||
|
|
||||||
from .core import core_app
|
from .core import core_app
|
||||||
from .db import init_databases, open_db
|
from .db import init_databases
|
||||||
from .helpers import ExtensionManager, megajson
|
from .helpers import ExtensionManager, megajson
|
||||||
from .settings import WALLET, DEFAULT_USER_WALLET_NAME
|
|
||||||
|
|
||||||
|
|
||||||
app = Flask(__name__)
|
app = Flask(__name__)
|
||||||
@@ -25,6 +21,7 @@ valid_extensions = [ext for ext in ExtensionManager().extensions if ext.is_valid
|
|||||||
Compress(app)
|
Compress(app)
|
||||||
Talisman(
|
Talisman(
|
||||||
app,
|
app,
|
||||||
|
force_https=getenv("LNBITS_WITH_ONION", 0) == 0,
|
||||||
content_security_policy={
|
content_security_policy={
|
||||||
"default-src": [
|
"default-src": [
|
||||||
"'self'",
|
"'self'",
|
||||||
@@ -81,69 +78,5 @@ def init():
|
|||||||
init_databases()
|
init_databases()
|
||||||
|
|
||||||
|
|
||||||
# vvvvvvvvvvvvvvvvvvvvvvvvvvv
|
|
||||||
# move the rest to `core_app`
|
|
||||||
# vvvvvvvvvvvvvvvvvvvvvvvvvvv
|
|
||||||
# vvvvvvvvvvvvvvvvvvvvvvvvvvv
|
|
||||||
|
|
||||||
|
|
||||||
@app.route("/lnurl")
|
|
||||||
def lnurl():
|
|
||||||
lnurl = request.args.get("lightning")
|
|
||||||
return render_template("lnurl.html", lnurl=lnurl)
|
|
||||||
|
|
||||||
|
|
||||||
@app.route("/lnurlwallet")
|
|
||||||
def lnurlwallet():
|
|
||||||
lnurl = Lnurl(request.args.get("lightning"))
|
|
||||||
r = requests.get(lnurl.url)
|
|
||||||
if not r.ok:
|
|
||||||
return redirect(url_for("home"))
|
|
||||||
|
|
||||||
data = json.loads(r.text)
|
|
||||||
if data.get("status") == "ERROR":
|
|
||||||
return redirect(url_for("home"))
|
|
||||||
|
|
||||||
withdraw_res = LnurlWithdrawResponse(**data)
|
|
||||||
|
|
||||||
_, pay_hash, pay_req = WALLET.create_invoice(withdraw_res.max_sats, "LNbits lnurl funding")
|
|
||||||
|
|
||||||
r = requests.get(
|
|
||||||
withdraw_res.callback.base,
|
|
||||||
params={**withdraw_res.callback.query_params, **{"k1": withdraw_res.k1, "pr": pay_req}},
|
|
||||||
)
|
|
||||||
|
|
||||||
if not r.ok:
|
|
||||||
return redirect(url_for("home"))
|
|
||||||
data = json.loads(r.text)
|
|
||||||
|
|
||||||
for i in range(10):
|
|
||||||
r = WALLET.get_invoice_status(pay_hash).raw_response
|
|
||||||
if not r.ok:
|
|
||||||
continue
|
|
||||||
|
|
||||||
data = r.json()
|
|
||||||
break
|
|
||||||
|
|
||||||
with open_db() as db:
|
|
||||||
wallet_id = uuid.uuid4().hex
|
|
||||||
user_id = uuid.uuid4().hex
|
|
||||||
wallet_name = DEFAULT_USER_WALLET_NAME
|
|
||||||
adminkey = uuid.uuid4().hex
|
|
||||||
inkey = uuid.uuid4().hex
|
|
||||||
|
|
||||||
db.execute("INSERT INTO accounts (id) VALUES (?)", (user_id,))
|
|
||||||
db.execute(
|
|
||||||
"INSERT INTO wallets (id, name, user, adminkey, inkey) VALUES (?, ?, ?, ?, ?)",
|
|
||||||
(wallet_id, wallet_name, user_id, adminkey, inkey),
|
|
||||||
)
|
|
||||||
db.execute(
|
|
||||||
"INSERT INTO apipayments (payhash, amount, wallet, pending, memo) VALUES (?, ?, ?, 0, ?)",
|
|
||||||
(pay_hash, withdraw_res.max_sats * 1000, wallet_id, "LNbits lnurl funding",),
|
|
||||||
)
|
|
||||||
|
|
||||||
return redirect(url_for("wallet", usr=user_id, wal=wallet_id))
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
app.run()
|
app.run()
|
||||||
|
@@ -4,5 +4,6 @@ from flask import Blueprint
|
|||||||
core_app = Blueprint("core", __name__, template_folder="templates", static_folder="static")
|
core_app = Blueprint("core", __name__, template_folder="templates", static_folder="static")
|
||||||
|
|
||||||
|
|
||||||
from .views_api import * # noqa
|
from .views.api import * # noqa
|
||||||
from .views import * # noqa
|
from .views.generic import * # noqa
|
||||||
|
from .views.lnurl import * # noqa
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
from uuid import uuid4
|
from uuid import uuid4
|
||||||
|
|
||||||
from lnbits.db import open_db
|
from lnbits.db import open_db
|
||||||
from lnbits.settings import DEFAULT_USER_WALLET_NAME, FEE_RESERVE
|
from lnbits.settings import DEFAULT_WALLET_NAME, FEE_RESERVE
|
||||||
from typing import List, Optional
|
from typing import List, Optional
|
||||||
|
|
||||||
from .models import User, Wallet, Payment
|
from .models import User, Wallet, Payment
|
||||||
@@ -71,7 +71,7 @@ def create_wallet(*, user_id: str, wallet_name: Optional[str]) -> Wallet:
|
|||||||
INSERT INTO wallets (id, name, user, adminkey, inkey)
|
INSERT INTO wallets (id, name, user, adminkey, inkey)
|
||||||
VALUES (?, ?, ?, ?, ?)
|
VALUES (?, ?, ?, ?, ?)
|
||||||
""",
|
""",
|
||||||
(wallet_id, wallet_name or DEFAULT_USER_WALLET_NAME, user_id, uuid4().hex, uuid4().hex),
|
(wallet_id, wallet_name or DEFAULT_WALLET_NAME, user_id, uuid4().hex, uuid4().hex),
|
||||||
)
|
)
|
||||||
|
|
||||||
return get_wallet(wallet_id=wallet_id)
|
return get_wallet(wallet_id=wallet_id)
|
||||||
|
0
lnbits/core/migrations/0001_initial.py
Normal file
0
lnbits/core/migrations/0001_initial.py
Normal file
0
lnbits/core/migrations/__init__.py
Normal file
0
lnbits/core/migrations/__init__.py
Normal file
13
lnbits/core/static/js/lnurl.js
Normal file
13
lnbits/core/static/js/lnurl.js
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
new Vue({
|
||||||
|
el: '#vue',
|
||||||
|
mixins: [windowMixin],
|
||||||
|
methods: {
|
||||||
|
notify: function () {
|
||||||
|
this.$q.notify({
|
||||||
|
timeout: 0,
|
||||||
|
message: 'Processing...',
|
||||||
|
icon: null
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
@@ -15,20 +15,22 @@
|
|||||||
<div class="row q-col-gutter-md justify-between">
|
<div class="row q-col-gutter-md justify-between">
|
||||||
<div class="col-12 col-md-8 col-lg-7 q-gutter-y-md">
|
<div class="col-12 col-md-8 col-lg-7 q-gutter-y-md">
|
||||||
|
|
||||||
<q-card>
|
{% block call_to_action %}
|
||||||
<q-card-section>
|
<q-card>
|
||||||
<q-form class="q-gutter-md">
|
<q-card-section>
|
||||||
<q-input filled dense
|
<q-form class="q-gutter-md">
|
||||||
v-model="walletName"
|
<q-input filled dense
|
||||||
label="Name your LNbits wallet *"
|
v-model="walletName"
|
||||||
></q-input>
|
label="Name your LNbits wallet *"
|
||||||
<q-btn unelevated
|
></q-input>
|
||||||
color="deep-purple"
|
<q-btn unelevated
|
||||||
:disable="walletName == ''"
|
color="deep-purple"
|
||||||
@click="createWallet">Add a new wallet</q-btn>
|
:disable="walletName == ''"
|
||||||
</q-form>
|
@click="createWallet">Add a new wallet</q-btn>
|
||||||
</q-card-section>
|
</q-form>
|
||||||
</q-card>
|
</q-card-section>
|
||||||
|
</q-card>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
<q-card>
|
<q-card>
|
||||||
<q-card-section>
|
<q-card-section>
|
||||||
|
22
lnbits/core/templates/core/lnurl.html
Normal file
22
lnbits/core/templates/core/lnurl.html
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
{% extends "core/index.html" %}
|
||||||
|
|
||||||
|
|
||||||
|
{% block scripts %}
|
||||||
|
{% assets filters='rjsmin', output='__bundle__/core/lnurl.js',
|
||||||
|
'core/js/lnurl.js' %}
|
||||||
|
<script type="text/javascript" src="{{ ASSET_URL }}"></script>
|
||||||
|
{% endassets %}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block call_to_action %}
|
||||||
|
<q-card>
|
||||||
|
<q-card-section>
|
||||||
|
<q-btn unelevated
|
||||||
|
color="deep-purple"
|
||||||
|
@click="notify"
|
||||||
|
type="a" href="{{ url_for('core.lnurlwallet', lightning=lnurl) }}">
|
||||||
|
Press to claim bitcoin
|
||||||
|
</q-btn>
|
||||||
|
</q-card-section>
|
||||||
|
</q-card>
|
||||||
|
{% endblock %}
|
0
lnbits/core/views/__init__.py
Normal file
0
lnbits/core/views/__init__.py
Normal file
@@ -6,7 +6,7 @@ from lnbits.decorators import api_check_wallet_macaroon, api_validate_post_reque
|
|||||||
from lnbits.helpers import Status
|
from lnbits.helpers import Status
|
||||||
from lnbits.settings import FEE_RESERVE, WALLET
|
from lnbits.settings import FEE_RESERVE, WALLET
|
||||||
|
|
||||||
from .crud import create_payment
|
from ..crud import create_payment
|
||||||
|
|
||||||
|
|
||||||
@core_app.route("/api/v1/payments", methods=["GET"])
|
@core_app.route("/api/v1/payments", methods=["GET"])
|
@@ -5,7 +5,7 @@ from lnbits.core import core_app
|
|||||||
from lnbits.decorators import check_user_exists, validate_uuids
|
from lnbits.decorators import check_user_exists, validate_uuids
|
||||||
from lnbits.helpers import Status
|
from lnbits.helpers import Status
|
||||||
|
|
||||||
from .crud import (
|
from ..crud import (
|
||||||
create_account,
|
create_account,
|
||||||
get_user,
|
get_user,
|
||||||
update_user_extension,
|
update_user_extension,
|
55
lnbits/core/views/lnurl.py
Normal file
55
lnbits/core/views/lnurl.py
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
import json
|
||||||
|
import requests
|
||||||
|
|
||||||
|
from flask import redirect, render_template, request, url_for
|
||||||
|
from lnurl import LnurlWithdrawResponse, handle as handle_lnurl
|
||||||
|
from lnurl.exceptions import LnurlException
|
||||||
|
from time import sleep
|
||||||
|
|
||||||
|
from lnbits.core import core_app
|
||||||
|
from lnbits.settings import WALLET
|
||||||
|
|
||||||
|
from ..crud import create_account, get_user, create_wallet, create_payment
|
||||||
|
|
||||||
|
|
||||||
|
@core_app.route("/lnurl")
|
||||||
|
def lnurl():
|
||||||
|
lnurl = request.args.get("lightning")
|
||||||
|
return render_template("core/lnurl.html", lnurl=lnurl)
|
||||||
|
|
||||||
|
|
||||||
|
@core_app.route("/lnurlwallet")
|
||||||
|
def lnurlwallet():
|
||||||
|
try:
|
||||||
|
withdraw_res = handle_lnurl(request.args.get("lightning"), response_class=LnurlWithdrawResponse)
|
||||||
|
except LnurlException:
|
||||||
|
return redirect(url_for("core.home"))
|
||||||
|
|
||||||
|
_, payhash, payment_request = WALLET.create_invoice(withdraw_res.max_sats, "LNbits LNURL funding")
|
||||||
|
|
||||||
|
r = requests.get(
|
||||||
|
withdraw_res.callback.base,
|
||||||
|
params={**withdraw_res.callback.query_params, **{"k1": withdraw_res.k1, "pr": payment_request}},
|
||||||
|
)
|
||||||
|
|
||||||
|
if not r.ok:
|
||||||
|
return redirect(url_for("core.home")) # TODO: custom error
|
||||||
|
data = json.loads(r.text)
|
||||||
|
|
||||||
|
for i in range(10):
|
||||||
|
r = WALLET.get_invoice_status(payhash).raw_response
|
||||||
|
sleep(i)
|
||||||
|
if not r.ok:
|
||||||
|
continue
|
||||||
|
break
|
||||||
|
|
||||||
|
user = get_user(create_account().id)
|
||||||
|
wallet = create_wallet(user_id=user.id)
|
||||||
|
create_payment( # TODO: not pending?
|
||||||
|
wallet_id=wallet.id,
|
||||||
|
payhash=payhash,
|
||||||
|
amount=withdraw_res.max_sats * 1000,
|
||||||
|
memo="LNbits lnurl funding",
|
||||||
|
)
|
||||||
|
|
||||||
|
return redirect(url_for("core.wallet", usr=user.id, wal=wallet.id))
|
@@ -11,5 +11,5 @@ WALLET = OpenNodeWallet(endpoint=os.getenv("OPENNODE_API_ENDPOINT"),admin_key=os
|
|||||||
LNBITS_PATH = os.path.dirname(os.path.realpath(__file__))
|
LNBITS_PATH = os.path.dirname(os.path.realpath(__file__))
|
||||||
LNBITS_DATA_FOLDER = os.getenv("LNBITS_DATA_FOLDER", os.path.join(LNBITS_PATH, "data"))
|
LNBITS_DATA_FOLDER = os.getenv("LNBITS_DATA_FOLDER", os.path.join(LNBITS_PATH, "data"))
|
||||||
|
|
||||||
DEFAULT_USER_WALLET_NAME = os.getenv("DEFAULT_USER_WALLET_NAME", "LNbits wallet")
|
DEFAULT_WALLET_NAME = os.getenv("LNBITS_DEFAULT_WALLET_NAME", "LNbits wallet")
|
||||||
FEE_RESERVE = float(os.getenv("FEE_RESERVE", 0))
|
FEE_RESERVE = float(os.getenv("LNBITS_FEE_RESERVE", 0))
|
||||||
|
@@ -31,8 +31,10 @@
|
|||||||
</q-header>
|
</q-header>
|
||||||
|
|
||||||
<q-drawer v-model="w.visibleDrawer" side="left" :width="($q.screen.lt.md) ? 260 : 230" show-if-above :elevated="$q.screen.lt.md">
|
<q-drawer v-model="w.visibleDrawer" side="left" :width="($q.screen.lt.md) ? 260 : 230" show-if-above :elevated="$q.screen.lt.md">
|
||||||
<lnbits-wallet-list></lnbits-wallet-list>
|
{% block drawer %}
|
||||||
<lnbits-extension-list class="q-pb-xl"></lnbits-extension-list>
|
<lnbits-wallet-list></lnbits-wallet-list>
|
||||||
|
<lnbits-extension-list class="q-pb-xl"></lnbits-extension-list>
|
||||||
|
{% endblock %}
|
||||||
</q-drawer>
|
</q-drawer>
|
||||||
|
|
||||||
<q-page-container>
|
<q-page-container>
|
||||||
|
@@ -1,15 +0,0 @@
|
|||||||
<!-- @format -->
|
|
||||||
|
|
||||||
{% extends "index.html" %} {% block call_to_action %}
|
|
||||||
|
|
||||||
<button
|
|
||||||
class="btn btn-block btn-primary btn-lg"
|
|
||||||
onclick="processing()"
|
|
||||||
data-toggle="modal"
|
|
||||||
data-target=".proc"
|
|
||||||
>
|
|
||||||
Press to claim bitcoin!
|
|
||||||
</button>
|
|
||||||
<div id="processing">
|
|
||||||
</div>
|
|
||||||
{% endblock %}
|
|
@@ -5,6 +5,8 @@ chardet==3.0.4
|
|||||||
click==7.0
|
click==7.0
|
||||||
flask-assets==2.0
|
flask-assets==2.0
|
||||||
flask-compress==1.4.0
|
flask-compress==1.4.0
|
||||||
|
flask-limiter==1.2.1
|
||||||
|
flask-seasurf==0.2.2
|
||||||
flask-talisman==0.7.0
|
flask-talisman==0.7.0
|
||||||
flask==1.1.1
|
flask==1.1.1
|
||||||
gevent==1.4.0
|
gevent==1.4.0
|
||||||
@@ -13,6 +15,7 @@ gunicorn==20.0.4
|
|||||||
idna==2.9
|
idna==2.9
|
||||||
itsdangerous==1.1.0
|
itsdangerous==1.1.0
|
||||||
jinja2==2.11.1
|
jinja2==2.11.1
|
||||||
|
limits==1.5.1
|
||||||
lnurl==0.3.3
|
lnurl==0.3.3
|
||||||
markupsafe==1.1.1
|
markupsafe==1.1.1
|
||||||
pydantic==1.4
|
pydantic==1.4
|
||||||
@@ -23,4 +26,3 @@ typing-extensions==3.7.4.1 ; python_version < '3.8'
|
|||||||
urllib3==1.25.8
|
urllib3==1.25.8
|
||||||
webassets==2.0
|
webassets==2.0
|
||||||
werkzeug==1.0.0
|
werkzeug==1.0.0
|
||||||
python-dotenv==0.12.0
|
|
||||||
|
Reference in New Issue
Block a user