commit dc844c79c2125d557b42c59748bae9bc998cc574
parent 4eb3da7a2241342647ef77da6d0f4dfe7b27e57c
Author: Nick <nick@nickfarrow.com>
Date: Mon, 28 Mar 2022 17:09:55 +1100
Add lightning node info page (#57)
* Add lightning node info page
* pr feedback
Diffstat:
9 files changed, 133 insertions(+), 16 deletions(-)
diff --git a/config.py b/config.py
@@ -62,6 +62,7 @@ tunnel_host = get_opt("tunnel_host", None)
tunnel_port = get_opt("tunnel_port", 22)
tor_proxy = get_opt("tor_proxy", None)
onchain_dust_limit = get_opt("onchain_dust_limit", 0.00000546)
+node_info = get_opt("node_info", None)
pollrate = get_opt("pollrate", 15)
payment_timeout = get_opt("payment_timeout", 60*60)
required_confirmations = get_opt("required_confirmations", 2)
diff --git a/config.toml b/config.toml
@@ -13,6 +13,8 @@ rpcport = "8332"
wallet = ""
## LND :: Add "lnd" to payment_methods
+# You can display your node connection so users can open channels with you by setting
+# node_info="uri" (manually) or true (fetch if macaroon has access to `getinfo`)
[lnd]
host = "127.0.0.1"
lnd_dir = "~/.lnd/"
@@ -24,6 +26,8 @@ lnd_macaroon = "invoice.macaroon"
## CLIGHTNING :: Add "clightning" to payment_methods
# If remote clightning, make sure `ssh -nNT -L {local_lightning-rpc}:{remote_lightning-rpc} {tunnel_host} -p {tunnel_port}`
# creates a lightning-rpc unix domain socket. (use full paths local: /home/install/satsale/lightning-rpc)
+# You can display your node connection so users can open channels with you by setting
+# node_info="uri" (manually) or true (fetch if macaroon has access to `getinfo`)
[clightning]
clightning_rpc_file = "/home/user/.lightning/bitcoin/lightning-rpc"
@@ -54,6 +58,10 @@ api_key_path = "SatSale_API_key"
# below this value.
onchain_dust_limit = 0.00000546
+# You can display your node uri so users can open channels with you by setting
+# node_info="uri" (manually) or true (use `admin.macaroon` to fetch `getinfo`)
+#node_info = "uri"
+
# Check for payment every xx seconds
pollrate = 1
diff --git a/node/clightning.py b/node/clightning.py
@@ -72,6 +72,14 @@ class clightning:
img.save("static/qr_codes/{}.png".format(uuid))
return
+ def get_info(self):
+ return self.clightning.getinfo()
+
+ def get_uri(self):
+ info = self.get_info()
+ address = info["address"][0]
+ return info["id"] + "@" + address["address"] + ":" + str(address["port"])
+
# Create lightning invoice
def create_clightning_invoice(self, btc_amount, label):
# Multiplying by 10^8 to convert to satoshi units
diff --git a/node/lnd.py b/node/lnd.py
@@ -48,7 +48,7 @@ class lnd:
logging.info(inv)
else:
logging.info("Getting lnd info...")
- info = self.lnd.get_info()
+ info = self.get_info()
logging.info(info)
logging.info("Successfully contacted lnd.")
@@ -149,6 +149,13 @@ class lnd:
logging.info(ret)
return
+ def get_info(self):
+ return json.loads(MessageToJson(self.lnd.get_info()))
+
+ def get_uri(self):
+ info = self.get_info()
+ return info["uris"][0]
+
# Check whether the payment has been paid
def check_payment(self, rhash):
invoice_status = json.loads(
diff --git a/satsale.py b/satsale.py
@@ -14,9 +14,11 @@ import uuid
import sqlite3
from pprint import pprint
import json
+import qrcode
import logging
import config
+
# Initialise logging before importing other modules
logging.basicConfig(
format="[%(asctime)s] [%(levelname)s] %(message)s",
@@ -61,6 +63,7 @@ database.migrate_database()
def index():
params = dict(request.args)
params["currency"] = config.base_currency
+ params["node_info"] = config.node_info
headers = {"Content-Type": "text/html"}
return make_response(render_template("donate.html", params=params), 200, headers)
@@ -71,6 +74,7 @@ def pay():
params = dict(request.args)
params["payment_methods"] = enabled_payment_methods
params["redirect"] = config.redirect
+ params["node_info"] = config.node_info
# Render payment page with the request arguments (?amount= etc.)
headers = {"Content-Type": "text/html"}
return make_response(render_template("index.html", params=params), 200, headers)
@@ -152,8 +156,12 @@ class create_payment(Resource):
if node.is_onchain and btc_value < config.onchain_dust_limit:
logging.warning(
"Requested onchain payment for {} {} below dust limit ({} < {})".format(
- base_amount, currency, btc_amount_format(btc_value),
- btc_amount_format(config.onchain_dust_limit)))
+ base_amount,
+ currency,
+ btc_amount_format(btc_value),
+ btc_amount_format(config.onchain_dust_limit),
+ )
+ )
return {"message": "Amount below dust limit."}, 406
invoice = {
@@ -163,7 +171,7 @@ class create_payment(Resource):
"method": payment_method,
"time": time.time(),
"webhook": webhook,
- "onchain_dust_limit": config.onchain_dust_limit
+ "onchain_dust_limit": config.onchain_dust_limit,
}
# Get an address / invoice, and create a QR code
@@ -354,6 +362,27 @@ for method in config.payment_methods:
logging.info("Connection to lightning node (clightning) successful.")
enabled_payment_methods.append("lightning")
+# Add node connection page
+if config.node_info is not None:
+ @app.route("/node/")
+ def node():
+ if config.node_info == True:
+ uri = lightning_node.get_uri()
+ else:
+ uri = config.node_info
+ img = qrcode.make(uri)
+ img.save("static/qr_codes/node.png")
+ headers = {"Content-Type": "text/html"}
+ return make_response(
+ render_template("node.html", params={"uri": uri}), 200, headers
+ )
+
+# Add lightning address
+if lightning_node.config['lightning_address'] is not None:
+ from gateways import lightning_address
+ lightning_address.add_ln_address_decorators(app, api, lightning_node)
+
+# Add Paynym
if config.paynym is not None:
paynym.insert_paynym_html(config.paynym)
diff --git a/static/style.css b/static/style.css
@@ -16,7 +16,7 @@ body {
/* Rounded Corners */
border-radius: 25px;
- font-size: 16px
+ font-size: 16px;
height: 275px;
width:360px;
diff --git a/templates/donate.html b/templates/donate.html
@@ -28,7 +28,6 @@
<meta property="twitter:description" content="Lightweight Bitcoin payment processor written in easily deployable Python. ">
<meta property="twitter:image" content="https://user-images.githubusercontent.com/24557779/109666538-60ee4800-7bc3-11eb-8615-2cb1b239cc11.png">
-
</head>
@@ -45,18 +44,29 @@
</div>
<div id="paymentForm">
- <center>
- <form id="pay" action='/pay' style="margin:0;padding0;">
- <h2 style="margin:0;padding0;">Amount:
+ <form id="pay" action='/pay'>
+ <div style="display:block;text-align: center;">
+ <h2 style="margin:0;">Amount:
<input id="amountenter" style="display:inline" size="4" type="float" name="amount" id="amount" placeholder="{{ params.currency }}" required>
</h2>
<br>
<input class="button button1" style="width:40%" type="submit" value="Donate">
- </form>
- </center>
+ </div>
+ </form>
+ <div id="paybutton"></div>
+ </div>
+ <br>
+ <div id="row">
+ <div id="left">
+ {% if params.node_info %}
+ <small><a id="about" href="/node/" target="_blank">Open a Lightning channel with me!</a></small>
+ </br>
+ {% endif %}
+ </div>
+ <div id="right" style="text-align:right;">
+ <small style="vertical-align:middle"><a id="about" href="https://github.com/nickfarrow/SatSale" target="_blank">SatSale</a></small>
+ </div>
</div>
-
- <div id="paybutton"></div>
</div>
</body>
</html>
diff --git a/templates/index.html b/templates/index.html
@@ -25,7 +25,7 @@
<div id="paybox">
<div id="row" height="50px">
<div id="left" style="display:inline-block;" height="75px">
- <h1>Pay Bitcoin</h>
+ <h1>Pay Bitcoin</h1>
</div>
<div id="right">
<a id="qrClick" target="_blank"><img class="logo" id="qrImage" width="100px" src="{{ url_for('static', filename='logo.svg') }}"></a>
@@ -48,7 +48,7 @@
</br>
<div id="row">
- <div id="left" style="text-align: left; padding: 0;">
+ <div id="left" style="width:40%; text-align: left; padding: 0;">
<div id="paymentMethodSwitchButton" style="display:none;">
{% if params.payment_methods|length > 1 %}
<select class="button" name="method" id="payment_method_select" onchange="replaceUrlParam(window.location, 'method', document.getElementById('payment_method_select').value);">
@@ -65,7 +65,11 @@
</div>
</div>
- <div id="right" style="text-align: right; padding: 10px 10px;">
+ <div id="right" style="width:60%; text-align: right; padding: 10px 10px;">
+ {% if params.node_info %}
+ <small><a id="about" href="/node/" target="_blank">Open a channel with me!</a></small>
+ </br>
+ {% endif %}
<small style="vertical-align:middle"><a id="about" href="https://github.com/nickfarrow/SatSale" target="_blank">SatSale</a></small>
</div>
</div>
diff --git a/templates/node.html b/templates/node.html
@@ -0,0 +1,50 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>SatSale</title>
+ <link rel="shortcut icon" href="{{ url_for('static', filename='favicon.ico') }}">
+ <meta name="viewport" content="width=device-width,initial-scale=1.0">
+
+ <script src="{{ url_for('static', filename='jquery-3.6.0.min.js') }}"></script>
+ <script src="{{ url_for('static', filename='socket.io.min.js') }}"></script>
+ <script src="{{ url_for('static', filename='satsale.js') }}"></script>
+
+ <link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
+</head>
+
+
+<body>
+ <div id="paybox">
+ <div id="row" height="50px">
+ <div id="left" style="display:inline-block;" height="75px">
+ <h1>Open a channel:</h1>
+ </div>
+ <div id="right">
+ <p><img class="qr" style="display:block; margin-left: auto; margin-right: auto;" width="100px" src="{{ url_for('static', filename='qr_codes/node.png') }}"></p>
+ </div>
+ </div>
+ <pre id="nodeInfo" style="padding:10px;background-color:black;color:white;border-radius:15px;white-space:pre-wrap;word-wrap:break-word;">
+ <span id="node_url"></span>
+ </pre>
+
+ </br>
+
+ <div id="row">
+ <div id="left" style="text-align: left; padding: 0;">
+ </div>
+
+ <div id="right" style="text-align: right; padding: 10px 10px;">
+ <small style="vertical-align:middle"><a id="about" href="https://github.com/nickfarrow/SatSale" target="_blank">SatSale</a></small>
+ </div>
+ </div>
+ </div>
+
+ <script type="text/javascript">
+ node_info = {{ params|tojson }};
+ console.log(node_info);
+ document.getElementById("node_url").innerHTML = node_info.uri;
+
+ </script>
+
+</body>
+</html>