mirror of https://github.com/lukechilds/lnbits.git
Browse Source
Original server code has been moved to __init__ file, so we can work on `lnbits` as a package.fee_issues
Eneko Illarramendi
5 years ago
13 changed files with 731 additions and 514 deletions
@ -0,0 +1,14 @@ |
|||
root = true |
|||
|
|||
[*] |
|||
charset = utf-8 |
|||
end_of_line = lf |
|||
insert_final_newline = true |
|||
trim_trailing_whitespace = true |
|||
|
|||
[*.md] |
|||
trim_trailing_whitespace = false |
|||
|
|||
[*.py] |
|||
indent_size = 4 |
|||
indent_style = space |
@ -0,0 +1,2 @@ |
|||
FLASK_APP=lnbits |
|||
FLASK_ENV=development |
@ -0,0 +1,15 @@ |
|||
.DS_Store |
|||
._* |
|||
|
|||
__pycache__ |
|||
*.py[cod] |
|||
*$py.class |
|||
.mypy_cache |
|||
.vscode |
|||
|
|||
*.egg |
|||
*.egg-info |
|||
.coverage |
|||
.pytest_cache |
|||
htmlcov |
|||
Pipfile.lock |
@ -0,0 +1,29 @@ |
|||
For developers |
|||
============== |
|||
|
|||
LNbits uses [Flask](http://flask.pocoo.org/). |
|||
Feel free to contribute to the project. |
|||
|
|||
Application dependencies |
|||
------------------------ |
|||
The application uses [Pipenv][pipenv] to manage Python packages. |
|||
While in development, you will need to install all dependencies: |
|||
|
|||
$ pipenv shell |
|||
$ pipenv install --dev |
|||
|
|||
Running the server |
|||
------------------ |
|||
|
|||
$ flask run |
|||
|
|||
There is an environment variable called `FLASK_ENV` that has to be set to `development` |
|||
if you want to run Flask in debug mode with autoreload |
|||
|
|||
Style guide |
|||
----------- |
|||
Tab size is 4 spaces. Maximum line length is 120. You should run `black` before commiting any change. |
|||
|
|||
$ black lnbits |
|||
|
|||
[pipenv]: https://docs.pipenv.org/#install-pipenv-today |
@ -0,0 +1,636 @@ |
|||
from flask import Flask, render_template |
|||
from flask import Flask, redirect |
|||
from flask import request |
|||
from flask import jsonify |
|||
from flask import Flask, g |
|||
from random import seed |
|||
from random import random |
|||
from flask import json |
|||
import re |
|||
import os |
|||
import sqlite3 |
|||
import base64 |
|||
import lnurl |
|||
import requests |
|||
import hashlib |
|||
import time |
|||
import json |
|||
import bech32 |
|||
|
|||
# DATABASE = 'database.db' |
|||
|
|||
INVOICE_KEY = "YOUR-LNTXBOT-INVOICE-KEY" # In the lntxbot bot on telegram type "/api" |
|||
ADMIN_KEY = "YOUR-LNTXBOT-ADMIN-KEY" |
|||
API_ENDPOINT = "YOUR-LNTXBOT-API-BASE-URL" |
|||
|
|||
app = Flask(__name__) |
|||
|
|||
|
|||
DEFAULT_PATH = "database.sqlite3" |
|||
|
|||
|
|||
def db_connect(db_path=DEFAULT_PATH): |
|||
con = sqlite3.connect(db_path) |
|||
return con |
|||
|
|||
|
|||
def encrypt_string(hash_string): |
|||
sha_signature = hashlib.sha256(hash_string.encode()).hexdigest() |
|||
return sha_signature |
|||
|
|||
|
|||
@app.route("/") |
|||
def home(): |
|||
|
|||
return render_template("index.html") |
|||
|
|||
|
|||
@app.route("/deletewallet") |
|||
def deletewallet(): |
|||
|
|||
thewal = request.args.get("wal") |
|||
|
|||
con = db_connect() |
|||
cur = con.cursor() |
|||
print(thewal) |
|||
cur.execute("select * from wallets WHERE hash = '" + str(thewal) + "'") |
|||
rowss = cur.fetchall() |
|||
|
|||
if len(rowss) > 0: |
|||
|
|||
cur.close() |
|||
print(rowss) |
|||
|
|||
con = db_connect() |
|||
cur = con.cursor() |
|||
|
|||
cur.execute("UPDATE wallets SET user = '" + "del" + rowss[0][4] + "' WHERE hash = '" + rowss[0][0] + "'") |
|||
|
|||
con.commit() |
|||
cur.close() |
|||
|
|||
con = db_connect() |
|||
cur = con.cursor() |
|||
|
|||
cur.execute("UPDATE wallets SET adminkey = '" + "del" + rowss[0][5] + "' WHERE hash = '" + rowss[0][0] + "'") |
|||
|
|||
con.commit() |
|||
cur.close() |
|||
|
|||
con = db_connect() |
|||
cur = con.cursor() |
|||
|
|||
cur.execute("UPDATE wallets SET inkey = '" + "del" + rowss[0][6] + "' WHERE hash = '" + rowss[0][0] + "'") |
|||
|
|||
con.commit() |
|||
cur.close() |
|||
|
|||
con = db_connect() |
|||
cur = con.cursor() |
|||
print(thewal) |
|||
cur.execute("select * from wallets WHERE user = '" + rowss[0][4] + "'") |
|||
rowsss = cur.fetchall() |
|||
|
|||
if len(rowsss) > 0: |
|||
cur.close() |
|||
return render_template("deletewallet.html", theid=rowsss[0][4], thewal=rowsss[0][0]) |
|||
else: |
|||
return render_template("index.html") |
|||
|
|||
else: |
|||
return render_template("index.html") |
|||
|
|||
|
|||
@app.route("/lnurlwallet") |
|||
def lnurlwallet(): |
|||
|
|||
# put in a function |
|||
thestr = request.args.get("lightning") |
|||
lnurll = lnurl.decode(thestr) |
|||
r = requests.get(url=lnurll) |
|||
|
|||
data = r.json() |
|||
|
|||
callback = data["callback"] |
|||
maxwithdraw = data["maxWithdrawable"] |
|||
withdraw = int(maxwithdraw / 1000) |
|||
k1 = data["k1"] |
|||
|
|||
# get invoice |
|||
dataj = {"amt": str(withdraw)} |
|||
headers = {"Authorization": "Basic %s" % INVOICE_KEY} |
|||
rr = requests.post(url=API_ENDPOINT + "/addinvoice", json=dataj, headers=headers) |
|||
|
|||
dataa = rr.json() |
|||
|
|||
# get callback |
|||
|
|||
pay_req = dataa["pay_req"] |
|||
payment_hash = dataa["payment_hash"] |
|||
|
|||
invurl = callback + "&k1=" + k1 + "&pr=" + pay_req |
|||
|
|||
rrr = requests.get(url=invurl) |
|||
dataaa = rrr.json() |
|||
|
|||
print(dataaa) |
|||
print("poo") |
|||
|
|||
if dataaa["status"] == "OK": |
|||
|
|||
data = "" |
|||
while data == "": |
|||
r = requests.post(url=API_ENDPOINT + "/invoicestatus/" + str(payment_hash), headers=headers) |
|||
data = r.json() |
|||
print(r.json()) |
|||
|
|||
adminkey = encrypt_string(payment_hash)[0:20] |
|||
inkey = encrypt_string(adminkey)[0:20] |
|||
thewal = encrypt_string(inkey)[0:20] |
|||
theid = encrypt_string(thewal)[0:20] |
|||
thenme = "Bitcoin LN Wallet" |
|||
|
|||
con = db_connect() |
|||
cur = con.cursor() |
|||
|
|||
cur.execute("INSERT INTO accounts (userhash) VALUES ('" + theid + "')") |
|||
con.commit() |
|||
cur.close() |
|||
|
|||
con = db_connect() |
|||
cur = con.cursor() |
|||
|
|||
adminkey = encrypt_string(theid) |
|||
inkey = encrypt_string(adminkey) |
|||
|
|||
cur.execute( |
|||
"INSERT INTO wallets (hash, balance, transactions, name, user, adminkey, inkey) VALUES ('" |
|||
+ thewal |
|||
+ "',',0," |
|||
+ str(withdraw) |
|||
+ "','0','" |
|||
+ thenme |
|||
+ "','" |
|||
+ theid |
|||
+ "','" |
|||
+ adminkey |
|||
+ "','" |
|||
+ inkey |
|||
+ "')" |
|||
) |
|||
con.commit() |
|||
cur.close() |
|||
|
|||
con = db_connect() |
|||
cur = con.cursor() |
|||
print(thewal) |
|||
cur.execute("select * from wallets WHERE user = '" + str(theid) + "'") |
|||
rows = cur.fetchall() |
|||
con.commit() |
|||
cur.close() |
|||
return render_template( |
|||
"lnurlwallet.html", |
|||
len=len("1"), |
|||
walnme=thenme, |
|||
walbal=str(withdraw), |
|||
theid=theid, |
|||
thewal=thewal, |
|||
adminkey=adminkey, |
|||
inkey=inkey, |
|||
) |
|||
else: |
|||
return render_template("index.html") |
|||
|
|||
|
|||
@app.route("/wallet") |
|||
def wallet(): |
|||
|
|||
theid = request.args.get("usr") |
|||
thewal = request.args.get("wal") |
|||
theamt = request.args.get("amt") |
|||
thenme = request.args.get("nme") |
|||
|
|||
if not thewal: |
|||
return render_template("index.html") |
|||
else: |
|||
# Checks if the user exists in "accounts" |
|||
con = db_connect() |
|||
cur = con.cursor() |
|||
print(thewal) |
|||
cur.execute("select * from accounts WHERE userhash = '" + str(theid) + "'") |
|||
rows = cur.fetchall() |
|||
|
|||
if len(rows) > 0: |
|||
cur.close() |
|||
|
|||
# Yes, check the user has a wallet |
|||
con = db_connect() |
|||
cur = con.cursor() |
|||
print(thewal) |
|||
cur.execute("select * from wallets WHERE user = '" + str(theid) + "'") |
|||
rowss = cur.fetchall() |
|||
|
|||
if len(rowss) > 0: |
|||
cur.close() |
|||
|
|||
# Checks if the current wallet exists |
|||
con = db_connect() |
|||
cur = con.cursor() |
|||
print(thewal) |
|||
cur.execute("select * from wallets WHERE hash = '" + str(thewal) + "'") |
|||
rowsss = cur.fetchall() |
|||
|
|||
if len(rowsss) > 0: |
|||
cur.close() |
|||
walb = rowsss[0][1].split(",")[-1] |
|||
return render_template( |
|||
"wallet.html", |
|||
thearr=rowss, |
|||
len=len(rowss), |
|||
walnme=rowsss[0][3], |
|||
user=theid, |
|||
walbal=walb, |
|||
theid=theid, |
|||
thewal=thewal, |
|||
transactions=rowsss[0][2], |
|||
adminkey=rowsss[0][5], |
|||
inkey=rowsss[0][6], |
|||
) |
|||
else: |
|||
cur.close() |
|||
|
|||
con = db_connect() |
|||
cur = con.cursor() |
|||
|
|||
adminkey = encrypt_string(thewal) |
|||
inkey = encrypt_string(adminkey) |
|||
|
|||
cur.execute( |
|||
"INSERT INTO wallets (hash, balance, transactions, name, user, adminkey, inkey) VALUES ('" |
|||
+ thewal |
|||
+ "',',0','0','" |
|||
+ thenme |
|||
+ "','" |
|||
+ theid |
|||
+ "','" |
|||
+ adminkey |
|||
+ "','" |
|||
+ inkey |
|||
+ "')" |
|||
) |
|||
con.commit() |
|||
cur.close() |
|||
|
|||
con = db_connect() |
|||
cur = con.cursor() |
|||
print(thewal) |
|||
cur.execute("select * from wallets WHERE user = '" + str(theid) + "'") |
|||
rowss = cur.fetchall() |
|||
cur.close() |
|||
|
|||
return render_template( |
|||
"wallet.html", |
|||
thearr=rowss, |
|||
len=len(rowss), |
|||
walnme=thenme, |
|||
walbal="0", |
|||
theid=theid, |
|||
thewal=thewal, |
|||
adminkey=adminkey, |
|||
inkey=inkey, |
|||
) |
|||
else: |
|||
cur.close() |
|||
|
|||
con = db_connect() |
|||
cur = con.cursor() |
|||
|
|||
adminkey = encrypt_string(theid) |
|||
inkey = encrypt_string(adminkey) |
|||
|
|||
cur.execute( |
|||
"INSERT INTO wallets (hash, balance, transactions, name, user, adminkey, inkey) VALUES ('" |
|||
+ thewal |
|||
+ "',',0','0','" |
|||
+ thenme |
|||
+ "','" |
|||
+ theid |
|||
+ "','" |
|||
+ adminkey |
|||
+ "','" |
|||
+ inkey |
|||
+ "')" |
|||
) |
|||
con.commit() |
|||
cur.close() |
|||
|
|||
return render_template( |
|||
"wallet.html", |
|||
len=len("1"), |
|||
walnme=thenme, |
|||
walbal="0", |
|||
theid=theid, |
|||
thewal=thewal, |
|||
adminkey=adminkey, |
|||
inkey=inkey, |
|||
) |
|||
|
|||
else: |
|||
cur.close() |
|||
con = db_connect() |
|||
cur = con.cursor() |
|||
|
|||
cur.execute("INSERT INTO accounts (userhash) VALUES ('" + theid + "')") |
|||
con.commit() |
|||
cur.close() |
|||
|
|||
con = db_connect() |
|||
cur = con.cursor() |
|||
|
|||
adminkey = encrypt_string(theid) |
|||
inkey = encrypt_string(adminkey) |
|||
|
|||
cur.execute( |
|||
"INSERT INTO wallets (hash, balance, transactions, name, user, adminkey, inkey) VALUES ('" |
|||
+ thewal |
|||
+ "',',0','0','" |
|||
+ thenme |
|||
+ "','" |
|||
+ theid |
|||
+ "','" |
|||
+ adminkey |
|||
+ "','" |
|||
+ inkey |
|||
+ "')" |
|||
) |
|||
con.commit() |
|||
cur.close() |
|||
|
|||
con = db_connect() |
|||
cur = con.cursor() |
|||
print(thewal) |
|||
cur.execute("select * from wallets WHERE user = '" + str(theid) + "'") |
|||
rows = cur.fetchall() |
|||
con.commit() |
|||
cur.close() |
|||
|
|||
return render_template( |
|||
"wallet.html", |
|||
len=len("1"), |
|||
walnme=thenme, |
|||
walbal="0", |
|||
theid=theid, |
|||
thewal=thewal, |
|||
adminkey=adminkey, |
|||
inkey=inkey, |
|||
) |
|||
|
|||
|
|||
# API requests |
|||
@app.route("/v1/invoices", methods=["GET", "POST"]) |
|||
def api_invoices(): |
|||
if request.headers["Content-Type"] == "application/json": |
|||
|
|||
postedjson = request.json |
|||
print(postedjson) |
|||
|
|||
if "value" in postedjson: |
|||
if postedjson["value"].isdigit() == True: |
|||
if "memo" in postedjson: |
|||
con = db_connect() |
|||
cur = con.cursor() |
|||
|
|||
cur.execute( |
|||
"select * from wallets WHERE inkey = '" + request.headers["Grpc-Metadata-macaroon"] + "'" |
|||
) |
|||
rows = cur.fetchall() |
|||
|
|||
if len(rows) > 0: |
|||
cur.close() |
|||
|
|||
dataj = {"amt": postedjson["value"], "memo": postedjson["memo"]} |
|||
headers = {"Authorization": "Basic %s" % INVOICE_KEY} |
|||
r = requests.post(url=API_ENDPOINT + "/addinvoice", json=dataj, headers=headers) |
|||
|
|||
data = r.json() |
|||
|
|||
pay_req = data["pay_req"] |
|||
payment_hash = data["payment_hash"] |
|||
|
|||
con = db_connect() |
|||
cur = con.cursor() |
|||
|
|||
cur.execute( |
|||
"INSERT INTO apipayments (payhash, amount, wallet, paid, inkey, memo) VALUES ('" |
|||
+ payment_hash |
|||
+ "','" |
|||
+ postedjson["value"] |
|||
+ "','" |
|||
+ rows[0][0] |
|||
+ "','0','" |
|||
+ request.headers["Grpc-Metadata-macaroon"] |
|||
+ "','" |
|||
+ postedjson["memo"] |
|||
+ "')" |
|||
) |
|||
con.commit() |
|||
cur.close() |
|||
|
|||
return jsonify({"pay_req": pay_req, "payment_hash": payment_hash}), 200 |
|||
|
|||
else: |
|||
return jsonify({"ERROR": "NO KEY"}), 200 |
|||
else: |
|||
return jsonify({"ERROR": "NO MEMO"}), 200 |
|||
else: |
|||
return jsonify({"ERROR": "VALUE MUST BE A NUMMBER"}), 200 |
|||
else: |
|||
return jsonify({"ERROR": "NO VALUE"}), 200 |
|||
else: |
|||
return jsonify({"ERROR": "MUST BE JSON"}), 200 |
|||
|
|||
|
|||
# API requests |
|||
@app.route("/v1/channels/transactions", methods=["GET", "POST"]) |
|||
def api_transactions(): |
|||
if request.headers["Content-Type"] == "application/json": |
|||
postedjson = request.json |
|||
print(postedjson) |
|||
print(postedjson["payment_request"]) |
|||
|
|||
if "payment_request" in postedjson: |
|||
con = db_connect() |
|||
cur = con.cursor() |
|||
print(request.headers["Grpc-Metadata-macaroon"]) |
|||
print() |
|||
cur.execute("select * from wallets WHERE adminkey = '" + request.headers["Grpc-Metadata-macaroon"] + "'") |
|||
rows = cur.fetchall() |
|||
if len(rows) > 0: |
|||
cur.close() |
|||
|
|||
s = postedjson["payment_request"] |
|||
result = re.search("lnbc(.*)1p", s) |
|||
tempp = result.group(1) |
|||
|
|||
alpha = "" |
|||
num = "" |
|||
|
|||
for i in range(len(tempp)): |
|||
if tempp[i].isdigit(): |
|||
num = num + tempp[i] |
|||
else: |
|||
alpha += tempp[i] |
|||
sats = "" |
|||
if alpha == "n": |
|||
sats = int(num) / 10 |
|||
elif alpha == "u": |
|||
sats = int(num) * 100 |
|||
elif alpha == "m": |
|||
sats = int(num) * 100000 |
|||
|
|||
print(sats) |
|||
print(alpha) |
|||
print(num) |
|||
|
|||
dataj = {"invoice": postedjson["payment_request"]} |
|||
headers = {"Authorization": "Basic %s" % ADMIN_KEY} |
|||
r = requests.post(url=API_ENDPOINT + "/payinvoice", json=dataj, headers=headers) |
|||
data = r.json() |
|||
print(data) |
|||
|
|||
con = db_connect() |
|||
cur = con.cursor() |
|||
|
|||
cur.execute( |
|||
"INSERT INTO apipayments (payhash, amount, wallet, paid, adminkey, memo) VALUES ('" |
|||
+ data["decoded"]["payment_hash"] |
|||
+ "','" |
|||
+ str(-int(data["decoded"]["num_satoshis"])) |
|||
+ "','" |
|||
+ rows[0][0] |
|||
+ "','1','" |
|||
+ request.headers["Grpc-Metadata-macaroon"] |
|||
+ "','" |
|||
+ data["decoded"]["description"] |
|||
+ "')" |
|||
) |
|||
con.commit() |
|||
cur.close() |
|||
|
|||
con = db_connect() |
|||
cur = con.cursor() |
|||
cur.execute("select * from apipayments WHERE payhash = '" + data["decoded"]["payment_hash"] + "'") |
|||
rowss = cur.fetchall() |
|||
cur.close() |
|||
|
|||
data["decoded"]["num_satoshis"] |
|||
|
|||
lastamt = rows[0][1].split(",") |
|||
newamt = int(lastamt[-1]) - int(data["decoded"]["num_satoshis"]) |
|||
updamt = rows[0][1] + "," + str(newamt) |
|||
thetime = time.time() |
|||
transactions = ( |
|||
rows[0][2] + "!" + rowss[0][5] + "," + str(thetime) + "," + str(rowss[0][1]) + "," + str(newamt) |
|||
) |
|||
|
|||
con = db_connect() |
|||
cur = con.cursor() |
|||
|
|||
cur.execute( |
|||
"UPDATE wallets SET balance = '" |
|||
+ updamt |
|||
+ "', transactions = '" |
|||
+ transactions |
|||
+ "' WHERE hash = '" |
|||
+ rows[0][0] |
|||
+ "'" |
|||
) |
|||
con.commit() |
|||
cur.close() |
|||
|
|||
return jsonify({"PAID": "TRUE"}), 200 |
|||
else: |
|||
return jsonify({"ERROR": "BAD AUTH"}), 200 |
|||
return jsonify({"ERROR": "NO PAY REQ"}), 200 |
|||
|
|||
return jsonify({"ERROR": "MUST BE JSON"}), 200 |
|||
|
|||
|
|||
@app.route("/v1/invoice/<payhash>", methods=["GET"]) |
|||
def api_checkinvoice(payhash): |
|||
|
|||
if request.headers["Content-Type"] == "application/json": |
|||
|
|||
print(request.headers["Grpc-Metadata-macaroon"]) |
|||
con = db_connect() |
|||
cur = con.cursor() |
|||
cur.execute("select * from apipayments WHERE payhash = '" + payhash + "'") |
|||
rows = cur.fetchall() |
|||
cur.close() |
|||
print(payhash) |
|||
if request.headers["Grpc-Metadata-macaroon"] == rows[0][4]: |
|||
|
|||
if rows[0][3] == "0": |
|||
print(rows[0][3]) |
|||
print("did it work?") |
|||
headers = {"Authorization": "Basic %s" % INVOICE_KEY} |
|||
r = requests.post(url=API_ENDPOINT + "/invoicestatus/" + payhash, headers=headers) |
|||
data = r.json() |
|||
print(r.json()) |
|||
print("no") |
|||
if data == "": |
|||
return jsonify({"PAID": "FALSE"}), 400 |
|||
else: |
|||
con = db_connect() |
|||
cur = con.cursor() |
|||
|
|||
cur.execute("select * from wallets WHERE hash = '" + rows[0][2] + "'") |
|||
|
|||
rowsss = cur.fetchall() |
|||
con.commit() |
|||
cur.close() |
|||
|
|||
lastamt = rowsss[0][1].split(",") |
|||
newamt = int(lastamt[-1]) + int(rows[0][1]) |
|||
updamt = rowsss[0][1] + "," + str(newamt) |
|||
|
|||
thetime = time.time() |
|||
transactions = ( |
|||
rowsss[0][2] + "!" + rows[0][5] + "," + str(thetime) + "," + str(rows[0][1]) + "," + str(newamt) |
|||
) |
|||
|
|||
con = db_connect() |
|||
cur = con.cursor() |
|||
|
|||
cur.execute( |
|||
"UPDATE wallets SET balance = '" |
|||
+ updamt |
|||
+ "', transactions = '" |
|||
+ transactions |
|||
+ "' WHERE hash = '" |
|||
+ rows[0][2] |
|||
+ "'" |
|||
) |
|||
|
|||
con.commit() |
|||
cur.close() |
|||
|
|||
con = db_connect() |
|||
cur = con.cursor() |
|||
|
|||
cur.execute("UPDATE apipayments SET paid = '1' WHERE payhash = '" + payhash + "'") |
|||
|
|||
con.commit() |
|||
cur.close() |
|||
return jsonify({"PAID": "TRUE"}), 200 |
|||
else: |
|||
return jsonify({"PAID": "TRUE"}), 200 |
|||
else: |
|||
return jsonify({"ERROR": "WRONG KEY"}), 400 |
|||
|
|||
else: |
|||
return jsonify({"ERROR": "NEEDS TO BE JSON"}), 400 |
|||
|
|||
|
|||
if __name__ == "__main__": |
|||
app.run(debug=True, host="0.0.0.0") |
Binary file not shown.
@ -1,3 +0,0 @@ |
|||
lnurl==0.1.0 |
|||
Flask==1.1.1 |
|||
requests==2.21.0 |
@ -1,511 +0,0 @@ |
|||
from flask import Flask, render_template |
|||
from flask import Flask, redirect |
|||
from flask import request |
|||
from flask import jsonify |
|||
from flask import Flask, g |
|||
from random import seed |
|||
from random import random |
|||
from flask import json |
|||
import re |
|||
import os |
|||
import sqlite3 |
|||
import base64 |
|||
import lnurl |
|||
import requests |
|||
import hashlib |
|||
import time |
|||
import json |
|||
import bech32 |
|||
|
|||
#DATABASE = 'database.db' |
|||
|
|||
INVOICE_KEY = "YOUR-LNTXBOT-INVOICE-KEY" #In the lntxbot bot on telegram type "/api" |
|||
ADMIN_KEY = "YOUR-LNTXBOT-ADMIN-KEY" |
|||
API_ENDPOINT = "YOUR-LNTXBOT-API-BASE-URL" |
|||
|
|||
app = Flask(__name__) |
|||
|
|||
|
|||
DEFAULT_PATH = "database.sqlite3" |
|||
|
|||
|
|||
def db_connect(db_path=DEFAULT_PATH): |
|||
con = sqlite3.connect(db_path) |
|||
return con |
|||
|
|||
def encrypt_string(hash_string): |
|||
sha_signature = \ |
|||
hashlib.sha256(hash_string.encode()).hexdigest() |
|||
return sha_signature |
|||
|
|||
|
|||
@app.route('/') |
|||
def home(): |
|||
|
|||
return render_template('index.html') |
|||
|
|||
@app.route('/deletewallet') |
|||
def deletewallet(): |
|||
|
|||
thewal = request.args.get('wal'); |
|||
|
|||
con = db_connect() |
|||
cur = con.cursor() |
|||
print(thewal) |
|||
cur.execute("select * from wallets WHERE hash = '" + str(thewal) + "'") |
|||
rowss = cur.fetchall() |
|||
|
|||
if len(rowss) > 0: |
|||
|
|||
cur.close() |
|||
print(rowss) |
|||
|
|||
con = db_connect() |
|||
cur = con.cursor() |
|||
|
|||
cur.execute("UPDATE wallets SET user = '" + "del" + rowss[0][4] + "' WHERE hash = '" + rowss[0][0] + "'") |
|||
|
|||
con.commit() |
|||
cur.close() |
|||
|
|||
con = db_connect() |
|||
cur = con.cursor() |
|||
|
|||
cur.execute("UPDATE wallets SET adminkey = '" + "del" + rowss[0][5] + "' WHERE hash = '" + rowss[0][0] + "'") |
|||
|
|||
con.commit() |
|||
cur.close() |
|||
|
|||
|
|||
con = db_connect() |
|||
cur = con.cursor() |
|||
|
|||
cur.execute("UPDATE wallets SET inkey = '" + "del" + rowss[0][6] + "' WHERE hash = '" + rowss[0][0] + "'") |
|||
|
|||
con.commit() |
|||
cur.close() |
|||
|
|||
con = db_connect() |
|||
cur = con.cursor() |
|||
print(thewal) |
|||
cur.execute("select * from wallets WHERE user = '" + rowss[0][4] + "'") |
|||
rowsss = cur.fetchall() |
|||
|
|||
if len(rowsss) > 0: |
|||
cur.close() |
|||
return render_template('deletewallet.html', theid = rowsss[0][4], thewal = rowsss[0][0]) |
|||
else: |
|||
return render_template('index.html') |
|||
|
|||
else: |
|||
return render_template('index.html') |
|||
|
|||
|
|||
|
|||
@app.route('/lnurlwallet') |
|||
def lnurlwallet(): |
|||
|
|||
#put in a function |
|||
thestr = request.args.get('lightning'); |
|||
lnurll = lnurl.decode(thestr) |
|||
r = requests.get(url = lnurll) |
|||
|
|||
data = r.json() |
|||
|
|||
|
|||
callback = data['callback'] |
|||
maxwithdraw = data['maxWithdrawable'] |
|||
withdraw = int(maxwithdraw/1000) |
|||
k1 = data['k1'] |
|||
|
|||
|
|||
#get invoice |
|||
dataj = {'amt': str(withdraw)} |
|||
headers = {'Authorization': 'Basic %s' % INVOICE_KEY} |
|||
rr = requests.post(url = API_ENDPOINT + "/addinvoice", json = dataj, headers = headers) |
|||
|
|||
dataa = rr.json() |
|||
|
|||
#get callback |
|||
|
|||
pay_req = dataa['pay_req'] |
|||
payment_hash = dataa['payment_hash'] |
|||
|
|||
invurl = callback + '&k1=' + k1 + '&pr=' + pay_req |
|||
|
|||
rrr = requests.get(url = invurl) |
|||
dataaa = rrr.json() |
|||
|
|||
print(dataaa) |
|||
print("poo") |
|||
|
|||
if dataaa['status'] == "OK": |
|||
|
|||
data = "" |
|||
while data == "": |
|||
r = requests.post(url = API_ENDPOINT + "/invoicestatus/" + str(payment_hash), headers = headers) |
|||
data = r.json() |
|||
print(r.json()) |
|||
|
|||
adminkey = encrypt_string(payment_hash)[0:20] |
|||
inkey = encrypt_string(adminkey)[0:20] |
|||
thewal = encrypt_string(inkey)[0:20] |
|||
theid = encrypt_string(thewal)[0:20] |
|||
thenme = "Bitcoin LN Wallet" |
|||
|
|||
|
|||
con = db_connect() |
|||
cur = con.cursor() |
|||
|
|||
cur.execute("INSERT INTO accounts (userhash) VALUES ('" + theid + "')") |
|||
con.commit() |
|||
cur.close() |
|||
|
|||
con = db_connect() |
|||
cur = con.cursor() |
|||
|
|||
adminkey = encrypt_string(theid) |
|||
inkey = encrypt_string(adminkey) |
|||
|
|||
cur.execute("INSERT INTO wallets (hash, balance, transactions, name, user, adminkey, inkey) VALUES ('" + thewal + "',',0," + str(withdraw) + "','0','" + thenme + "','" + theid + "','" + adminkey + "','" + inkey + "')") |
|||
con.commit() |
|||
cur.close() |
|||
|
|||
con = db_connect() |
|||
cur = con.cursor() |
|||
print(thewal) |
|||
cur.execute("select * from wallets WHERE user = '" + str(theid) + "'") |
|||
rows = cur.fetchall() |
|||
con.commit() |
|||
cur.close() |
|||
return render_template('lnurlwallet.html', len = len("1"), walnme = thenme, walbal = str(withdraw), theid = theid, thewal = thewal, adminkey = adminkey, inkey = inkey) |
|||
else: |
|||
return render_template('index.html') |
|||
|
|||
|
|||
@app.route('/wallet') |
|||
def wallet(): |
|||
|
|||
theid = request.args.get('usr'); |
|||
thewal = request.args.get('wal'); |
|||
theamt = request.args.get('amt'); |
|||
thenme = request.args.get('nme'); |
|||
|
|||
if not thewal: |
|||
return render_template('index.html') |
|||
else: |
|||
#Checks if the user exists in "accounts" |
|||
con = db_connect() |
|||
cur = con.cursor() |
|||
print(thewal) |
|||
cur.execute("select * from accounts WHERE userhash = '" + str(theid) + "'") |
|||
rows = cur.fetchall() |
|||
|
|||
if len(rows) > 0: |
|||
cur.close() |
|||
|
|||
#Yes, check the user has a wallet |
|||
con = db_connect() |
|||
cur = con.cursor() |
|||
print(thewal) |
|||
cur.execute("select * from wallets WHERE user = '" + str(theid) + "'") |
|||
rowss = cur.fetchall() |
|||
|
|||
if len(rowss) > 0: |
|||
cur.close() |
|||
|
|||
#Checks if the current wallet exists |
|||
con = db_connect() |
|||
cur = con.cursor() |
|||
print(thewal) |
|||
cur.execute("select * from wallets WHERE hash = '" + str(thewal) + "'") |
|||
rowsss = cur.fetchall() |
|||
|
|||
if len(rowsss) > 0: |
|||
cur.close() |
|||
walb = rowsss[0][1].split(",")[-1] |
|||
return render_template('wallet.html', thearr = rowss, len = len(rowss), walnme = rowsss[0][3], user = theid, walbal = walb, theid = theid, thewal = thewal, transactions = rowsss[0][2], adminkey = rowsss[0][5], inkey = rowsss[0][6]) |
|||
else: |
|||
cur.close() |
|||
|
|||
con = db_connect() |
|||
cur = con.cursor() |
|||
|
|||
adminkey = encrypt_string(thewal) |
|||
inkey = encrypt_string(adminkey) |
|||
|
|||
cur.execute("INSERT INTO wallets (hash, balance, transactions, name, user, adminkey, inkey) VALUES ('" + thewal + "',',0','0','" + thenme + "','" + theid + "','" + adminkey + "','" + inkey + "')") |
|||
con.commit() |
|||
cur.close() |
|||
|
|||
|
|||
con = db_connect() |
|||
cur = con.cursor() |
|||
print(thewal) |
|||
cur.execute("select * from wallets WHERE user = '" + str(theid) + "'") |
|||
rowss = cur.fetchall() |
|||
cur.close() |
|||
|
|||
return render_template('wallet.html', thearr = rowss, len = len(rowss), walnme = thenme, walbal = '0', theid = theid, thewal = thewal, adminkey = adminkey, inkey = inkey) |
|||
else: |
|||
cur.close() |
|||
|
|||
con = db_connect() |
|||
cur = con.cursor() |
|||
|
|||
adminkey = encrypt_string(theid) |
|||
inkey = encrypt_string(adminkey) |
|||
|
|||
cur.execute("INSERT INTO wallets (hash, balance, transactions, name, user, adminkey, inkey) VALUES ('" + thewal + "',',0','0','" + thenme + "','" + theid + "','" + adminkey + "','" + inkey + "')") |
|||
con.commit() |
|||
cur.close() |
|||
|
|||
return render_template('wallet.html', len = len("1"), walnme = thenme, walbal = '0', theid = theid, thewal = thewal, adminkey = adminkey, inkey = inkey) |
|||
|
|||
else: |
|||
cur.close() |
|||
con = db_connect() |
|||
cur = con.cursor() |
|||
|
|||
cur.execute("INSERT INTO accounts (userhash) VALUES ('" + theid + "')") |
|||
con.commit() |
|||
cur.close() |
|||
|
|||
con = db_connect() |
|||
cur = con.cursor() |
|||
|
|||
adminkey = encrypt_string(theid) |
|||
inkey = encrypt_string(adminkey) |
|||
|
|||
cur.execute("INSERT INTO wallets (hash, balance, transactions, name, user, adminkey, inkey) VALUES ('" + thewal + "',',0','0','" + thenme + "','" + theid + "','" + adminkey + "','" + inkey + "')") |
|||
con.commit() |
|||
cur.close() |
|||
|
|||
con = db_connect() |
|||
cur = con.cursor() |
|||
print(thewal) |
|||
cur.execute("select * from wallets WHERE user = '" + str(theid) + "'") |
|||
rows = cur.fetchall() |
|||
con.commit() |
|||
cur.close() |
|||
|
|||
return render_template('wallet.html', len = len("1"), walnme = thenme, walbal = '0', theid = theid, thewal = thewal, adminkey = adminkey, inkey = inkey) |
|||
|
|||
|
|||
|
|||
#API requests |
|||
@app.route('/v1/invoices', methods=['GET', 'POST']) |
|||
def api_invoices(): |
|||
if request.headers['Content-Type'] == 'application/json': |
|||
|
|||
postedjson = request.json |
|||
print(postedjson) |
|||
|
|||
if "value" in postedjson: |
|||
if postedjson["value"].isdigit() == True: |
|||
if "memo" in postedjson: |
|||
con = db_connect() |
|||
cur = con.cursor() |
|||
|
|||
cur.execute("select * from wallets WHERE inkey = '" + request.headers['Grpc-Metadata-macaroon']+ "'") |
|||
rows = cur.fetchall() |
|||
|
|||
if len(rows) > 0: |
|||
cur.close() |
|||
|
|||
dataj = {'amt': postedjson["value"], 'memo': postedjson["memo"]} |
|||
headers = {'Authorization': 'Basic %s' % INVOICE_KEY} |
|||
r = requests.post(url = API_ENDPOINT + "/addinvoice", json = dataj, headers = headers) |
|||
|
|||
data = r.json() |
|||
|
|||
pay_req = data['pay_req'] |
|||
payment_hash = data['payment_hash'] |
|||
|
|||
con = db_connect() |
|||
cur = con.cursor() |
|||
|
|||
cur.execute("INSERT INTO apipayments (payhash, amount, wallet, paid, inkey, memo) VALUES ('" + payment_hash + "','" + postedjson["value"] + "','" + rows[0][0] + "','0','" + request.headers['Grpc-Metadata-macaroon'] + "','" + postedjson["memo"] + "')") |
|||
con.commit() |
|||
cur.close() |
|||
|
|||
return jsonify({"pay_req": pay_req, "payment_hash": payment_hash}), 200 |
|||
|
|||
else: |
|||
return jsonify({"ERROR": "NO KEY"}), 200 |
|||
else: |
|||
return jsonify({"ERROR": "NO MEMO"}), 200 |
|||
else: |
|||
return jsonify({"ERROR": "VALUE MUST BE A NUMMBER"}), 200 |
|||
else: |
|||
return jsonify({"ERROR": "NO VALUE"}), 200 |
|||
else: |
|||
return jsonify({"ERROR": "MUST BE JSON"}), 200 |
|||
|
|||
|
|||
#API requests |
|||
@app.route('/v1/channels/transactions', methods=['GET', 'POST']) |
|||
def api_transactions(): |
|||
if request.headers['Content-Type'] == 'application/json': |
|||
postedjson = request.json |
|||
print(postedjson) |
|||
print(postedjson["payment_request"]) |
|||
|
|||
if "payment_request" in postedjson: |
|||
con = db_connect() |
|||
cur = con.cursor() |
|||
print(request.headers['Grpc-Metadata-macaroon']) |
|||
print() |
|||
cur.execute("select * from wallets WHERE adminkey = '" + request.headers['Grpc-Metadata-macaroon']+ "'") |
|||
rows = cur.fetchall() |
|||
if len(rows) > 0: |
|||
cur.close() |
|||
|
|||
|
|||
|
|||
s = postedjson["payment_request"] |
|||
result = re.search('lnbc(.*)1p', s) |
|||
tempp = result.group(1) |
|||
|
|||
alpha = "" |
|||
num = "" |
|||
|
|||
for i in range(len(tempp)): |
|||
if (tempp[i].isdigit()): |
|||
num = num+ tempp[i] |
|||
else: |
|||
alpha += tempp[i] |
|||
sats = "" |
|||
if alpha == "n": |
|||
sats = int(num)/10 |
|||
elif alpha == "u": |
|||
sats = int(num)*100 |
|||
elif alpha == "m": |
|||
sats = int(num)*100000 |
|||
|
|||
print(sats) |
|||
print(alpha) |
|||
print(num) |
|||
|
|||
dataj = {'invoice': postedjson["payment_request"]} |
|||
headers = {'Authorization': 'Basic %s' % ADMIN_KEY} |
|||
r = requests.post(url = API_ENDPOINT + "/payinvoice", json = dataj, headers = headers) |
|||
data = r.json() |
|||
print(data); |
|||
|
|||
|
|||
con = db_connect() |
|||
cur = con.cursor() |
|||
|
|||
cur.execute("INSERT INTO apipayments (payhash, amount, wallet, paid, adminkey, memo) VALUES ('" + data["decoded"]["payment_hash"] + "','" + str(-int(data["decoded"]["num_satoshis"])) + "','" + rows[0][0] + "','1','" + request.headers['Grpc-Metadata-macaroon'] + "','" + data["decoded"]["description"] + "')") |
|||
con.commit() |
|||
cur.close() |
|||
|
|||
|
|||
con = db_connect() |
|||
cur = con.cursor() |
|||
cur.execute("select * from apipayments WHERE payhash = '" + data["decoded"]["payment_hash"] + "'") |
|||
rowss = cur.fetchall() |
|||
cur.close() |
|||
|
|||
|
|||
|
|||
data["decoded"]["num_satoshis"] |
|||
|
|||
|
|||
lastamt = rows[0][1].split(",") |
|||
newamt = int(lastamt[-1]) - int(data["decoded"]["num_satoshis"]) |
|||
updamt = rows[0][1] + "," + str(newamt) |
|||
thetime = time.time() |
|||
transactions = rows[0][2] + "!" + rowss[0][5] + "," + str(thetime) + "," + str(rowss[0][1]) + "," + str(newamt) |
|||
|
|||
con = db_connect() |
|||
cur = con.cursor() |
|||
|
|||
|
|||
cur.execute("UPDATE wallets SET balance = '" + updamt + "', transactions = '" + transactions + "' WHERE hash = '" + rows[0][0] + "'") |
|||
con.commit() |
|||
cur.close() |
|||
|
|||
|
|||
|
|||
return jsonify({"PAID": "TRUE"}), 200 |
|||
else: |
|||
return jsonify({"ERROR": "BAD AUTH"}), 200 |
|||
return jsonify({"ERROR": "NO PAY REQ"}), 200 |
|||
|
|||
return jsonify({"ERROR": "MUST BE JSON"}), 200 |
|||
|
|||
|
|||
|
|||
@app.route('/v1/invoice/<payhash>', methods=['GET']) |
|||
def api_checkinvoice(payhash): |
|||
|
|||
if request.headers['Content-Type'] == 'application/json': |
|||
|
|||
print(request.headers["Grpc-Metadata-macaroon"]) |
|||
con = db_connect() |
|||
cur = con.cursor() |
|||
cur.execute("select * from apipayments WHERE payhash = '" + payhash + "'") |
|||
rows = cur.fetchall() |
|||
cur.close() |
|||
print(payhash) |
|||
if request.headers["Grpc-Metadata-macaroon"] == rows[0][4]: |
|||
|
|||
if rows[0][3] == "0": |
|||
print(rows[0][3]) |
|||
print("did it work?") |
|||
headers = {'Authorization': 'Basic %s' % INVOICE_KEY} |
|||
r = requests.post(url = API_ENDPOINT + "/invoicestatus/" + payhash, headers = headers) |
|||
data = r.json() |
|||
print(r.json()) |
|||
print("no") |
|||
if data == "": |
|||
return jsonify({"PAID": "FALSE"}), 400 |
|||
else: |
|||
con = db_connect() |
|||
cur = con.cursor() |
|||
|
|||
cur.execute("select * from wallets WHERE hash = '" + rows[0][2] + "'") |
|||
|
|||
rowsss = cur.fetchall() |
|||
con.commit() |
|||
cur.close() |
|||
|
|||
lastamt = rowsss[0][1].split(",") |
|||
newamt = int(lastamt[-1]) + int(rows[0][1]) |
|||
updamt = rowsss[0][1] + "," + str(newamt) |
|||
|
|||
thetime = time.time() |
|||
transactions = rowsss[0][2] + "!" + rows[0][5] + "," + str(thetime) + "," + str(rows[0][1]) + "," + str(newamt) |
|||
|
|||
con = db_connect() |
|||
cur = con.cursor() |
|||
|
|||
cur.execute("UPDATE wallets SET balance = '" + updamt + "', transactions = '" + transactions + "' WHERE hash = '" + rows[0][2] + "'") |
|||
|
|||
con.commit() |
|||
cur.close() |
|||
|
|||
con = db_connect() |
|||
cur = con.cursor() |
|||
|
|||
cur.execute("UPDATE apipayments SET paid = '1' WHERE payhash = '" + payhash + "'") |
|||
|
|||
con.commit() |
|||
cur.close() |
|||
return jsonify({"PAID": "TRUE"}), 200 |
|||
else: |
|||
return jsonify({"PAID": "TRUE"}), 200 |
|||
else: |
|||
return jsonify({"ERROR": "WRONG KEY"}), 400 |
|||
|
|||
else: |
|||
return jsonify({"ERROR": "NEEDS TO BE JSON"}), 400 |
|||
|
|||
|
|||
|
|||
|
|||
|
|||
if __name__ == '__main__': |
|||
app.run(debug=True, host= '0.0.0.0') |
@ -0,0 +1,20 @@ |
|||
[[source]] |
|||
name = "pypi" |
|||
url = "https://pypi.org/simple" |
|||
verify_ssl = true |
|||
|
|||
[requires] |
|||
python_version = "3.7" |
|||
|
|||
[packages] |
|||
lnurl = "*" |
|||
flask = "*" |
|||
requests = "*" |
|||
|
|||
[dev-packages] |
|||
black = "==19.10b0" |
|||
flake8 = "*" |
|||
flake8-mypy = "*" |
|||
pytest = "*" |
|||
pytest-cov = "*" |
|||
pytest-sugar = "*" |
@ -0,0 +1,2 @@ |
|||
[tool.black] |
|||
line-length = 120 |
@ -0,0 +1,13 @@ |
|||
bech32==1.1.0 |
|||
certifi==2019.11.28 |
|||
chardet==3.0.4 |
|||
click==7.0 |
|||
flask==1.1.1 |
|||
idna==2.8 |
|||
itsdangerous==1.1.0 |
|||
jinja2==2.10.3 |
|||
lnurl==0.1.1 |
|||
markupsafe==1.1.1 |
|||
requests==2.22.0 |
|||
urllib3==1.25.7 |
|||
werkzeug==0.16.0 |
Loading…
Reference in new issue