2020-05-22 19:24:46 +02:00
|
|
|
#!/usr/bin/python3
|
|
|
|
|
|
|
|
import sys
|
|
|
|
import locale
|
2020-05-22 20:06:59 +02:00
|
|
|
import requests
|
|
|
|
import json
|
2020-05-23 02:44:08 +02:00
|
|
|
import math
|
2020-05-22 19:24:46 +02:00
|
|
|
|
2020-05-23 13:49:13 +02:00
|
|
|
import codecs, grpc, os
|
|
|
|
from lndlibs import rpc_pb2 as ln
|
|
|
|
from lndlibs import rpc_pb2_grpc as lnrpc
|
|
|
|
|
2020-05-22 19:24:46 +02:00
|
|
|
# display config script info
|
|
|
|
if len(sys.argv) <= 1 or sys.argv[1] == "-h" or sys.argv[1] == "help":
|
2020-05-23 02:44:08 +02:00
|
|
|
print("# manage ip2tor subscriptions for raspiblitz")
|
|
|
|
print("# blitz.ip2tor.py menu")
|
2020-05-22 19:24:46 +02:00
|
|
|
sys.exit(1)
|
|
|
|
|
|
|
|
# basic settings
|
|
|
|
locale.setlocale(locale.LC_ALL, '')
|
2020-05-23 13:49:13 +02:00
|
|
|
USE_TOR=False
|
|
|
|
LND_IP="192.168.178.95"
|
|
|
|
LND_ADMIN_MACAROON_PATH=""
|
2020-05-22 19:24:46 +02:00
|
|
|
|
2020-05-23 02:44:08 +02:00
|
|
|
# TODO: check is still works when shopurl is an onion address
|
2020-05-23 13:49:13 +02:00
|
|
|
def apiGetHosts(session, shopurl):
|
2020-05-23 02:44:08 +02:00
|
|
|
|
|
|
|
print("# apiGetHosts")
|
|
|
|
hosts=[]
|
|
|
|
|
|
|
|
# make HTTP request
|
|
|
|
try:
|
2020-05-23 13:49:13 +02:00
|
|
|
response = session.get("https://{0}/api/v1/public/hosts/".format(shopurl))
|
2020-05-23 02:44:08 +02:00
|
|
|
except Exception as e:
|
|
|
|
print("error='FAILED HTTP REQUEST'")
|
|
|
|
return
|
|
|
|
if response.status_code != 200:
|
|
|
|
print("error='FAILED HTTP CODE ({0})'".format(response.status_code))
|
|
|
|
return
|
|
|
|
|
|
|
|
# parse & validate data
|
|
|
|
try:
|
|
|
|
jData = json.loads(response.content)
|
|
|
|
except Exception as e:
|
|
|
|
print("error='FAILED JSON PARSING'")
|
|
|
|
return
|
|
|
|
if not isinstance(jData, list):
|
|
|
|
print("error='NOT A JSON LIST'")
|
|
|
|
return
|
|
|
|
for idx, hostEntry in enumerate(jData):
|
|
|
|
try:
|
|
|
|
# ignore if not offering tor bridge
|
|
|
|
if not hostEntry['offers_tor_bridges']: continue
|
|
|
|
# ignore if duration is less than an hour
|
|
|
|
if hostEntry['tor_bridge_duration'] < 3600: continue
|
|
|
|
# add duration per hour value
|
|
|
|
hostEntry['tor_bridge_duration_hours'] = math.floor(hostEntry['tor_bridge_duration']/3600)
|
|
|
|
# ignore if prices are negative or below one sat (maybe msats later)
|
|
|
|
if hostEntry['tor_bridge_price_initial'] < 1000: continue
|
|
|
|
if hostEntry['tor_bridge_price_extension'] < 1000: continue
|
|
|
|
# add price in sats
|
|
|
|
hostEntry['tor_bridge_price_initial_sats'] = math.ceil(hostEntry['tor_bridge_price_initial']/1000)
|
|
|
|
hostEntry['tor_bridge_price_extension_sats'] = math.ceil(hostEntry['tor_bridge_price_extension']/1000)
|
|
|
|
# ignore name is less then 3 chars
|
|
|
|
if len(hostEntry['name']) < 3: continue
|
|
|
|
# ignore id with zero value
|
|
|
|
if len(hostEntry['id']) < 1: continue
|
|
|
|
# shorten names to 20 chars max
|
|
|
|
hostEntry['name'] = hostEntry['name'][:20]
|
|
|
|
except Exception as e:
|
|
|
|
print("error='PARSING HOST ENTRY'")
|
|
|
|
return
|
|
|
|
|
|
|
|
print("({0}) {1} ({2} hours, first: {3} sats, next: {4} sats)".format(idx, hostEntry['name'].ljust(20), hostEntry['tor_bridge_duration_hours'], hostEntry['tor_bridge_price_initial_sats'], hostEntry['tor_bridge_price_extension_sats']))
|
|
|
|
#print(hostEntry)
|
|
|
|
hosts.append(hostEntry)
|
|
|
|
|
|
|
|
print("# found {0} valid torbridge hosts".format(len(hosts)))
|
|
|
|
return hosts
|
|
|
|
|
2020-05-23 13:49:13 +02:00
|
|
|
def apiPlaceOrder(session, shopurl, hostid, toraddressWithPort):
|
2020-05-23 02:44:08 +02:00
|
|
|
|
|
|
|
print("# apiPlaceOrder")
|
|
|
|
|
|
|
|
postData={
|
|
|
|
'product': "tor_bridge",
|
|
|
|
'host_id': hostid,
|
|
|
|
'tos_accepted': True,
|
|
|
|
'comment': 'test',
|
|
|
|
'target': toraddressWithPort,
|
|
|
|
'public_key': ''
|
|
|
|
}
|
|
|
|
try:
|
2020-05-23 13:49:13 +02:00
|
|
|
response = session.post("https://{0}/api/v1/public/order/".format(shopurl), data=postData)
|
2020-05-23 02:44:08 +02:00
|
|
|
except Exception as e:
|
|
|
|
print("error='FAILED HTTP REQUEST'")
|
|
|
|
return
|
|
|
|
if response.status_code != 201:
|
2020-05-23 13:49:13 +02:00
|
|
|
print("error='FAILED HTTP CODE ({0}) != 201'".format(response.status_code))
|
2020-05-23 02:44:08 +02:00
|
|
|
return
|
|
|
|
|
|
|
|
# parse & validate data
|
|
|
|
try:
|
|
|
|
jData = json.loads(response.content)
|
2020-05-23 13:49:13 +02:00
|
|
|
if len(jData['id']) == 0:
|
|
|
|
print("error='MISSING ID'")
|
|
|
|
return
|
2020-05-23 02:44:08 +02:00
|
|
|
except Exception as e:
|
|
|
|
print("error='FAILED JSON PARSING'")
|
|
|
|
return
|
|
|
|
|
2020-05-23 13:49:13 +02:00
|
|
|
return jData['id']
|
|
|
|
|
|
|
|
|
|
|
|
def apiGetOrder(session, shopurl, orderid):
|
|
|
|
|
|
|
|
print("# apiGetOrder")
|
|
|
|
|
|
|
|
# make HTTP request
|
|
|
|
try:
|
|
|
|
response = session.get("https://{0}/api/v1/public/pos/{1}/".format(shopurl,orderid))
|
|
|
|
except Exception as e:
|
|
|
|
print("error='FAILED HTTP REQUEST'")
|
|
|
|
return
|
|
|
|
if response.status_code != 200:
|
|
|
|
print("error='FAILED HTTP CODE ({0})'".format(response.status_code))
|
|
|
|
return
|
|
|
|
|
|
|
|
# parse & validate data
|
|
|
|
try:
|
|
|
|
jData = json.loads(response.content)
|
|
|
|
if len(jData['item_details']) == 0:
|
|
|
|
print("error='MISSING ITEM'")
|
|
|
|
return
|
|
|
|
if len(jData['ln_invoices']) > 1:
|
|
|
|
print("error='MORE THEN ONE INVOICE'")
|
|
|
|
return
|
|
|
|
except Exception as e:
|
|
|
|
print("error='FAILED JSON PARSING'")
|
|
|
|
return
|
2020-05-23 02:44:08 +02:00
|
|
|
|
2020-05-23 13:49:13 +02:00
|
|
|
return jData
|
|
|
|
|
|
|
|
def lndDecodeInvoice(lnInvoiceString):
|
|
|
|
|
|
|
|
macaroon = codecs.encode(open('LND_DIR/data/chain/bitcoin/simnet/admin.macaroon', 'rb').read(), 'hex')
|
|
|
|
os.environ['GRPC_SSL_CIPHER_SUITES'] = 'HIGH+ECDSA'
|
|
|
|
cert = open('LND_DIR/tls.cert', 'rb').read()
|
|
|
|
ssl_creds = grpc.ssl_channel_credentials(cert)
|
|
|
|
channel = grpc.secure_channel('192.168.178.95:10009', ssl_creds)
|
|
|
|
stub = rpcstub.LightningStub(channel)
|
|
|
|
request = lnrpc.PayReqString(
|
|
|
|
pay_req=lnInvoiceString,
|
|
|
|
)
|
|
|
|
response = stub.DecodePayReq(request, metadata=[('macaroon', macaroon)])
|
|
|
|
print(response)
|
|
|
|
|
|
|
|
lndDecodeInvoice("lnbc300n1p0v37m5pp5xncvgrphrp9p5h52c7luqf2tkzq0v3v6ae3f9q08vrnevux9xwtsdraxgukxwpj8pjnvtfkvsun2tf5x56rgtfcxq6kgtfe89nxywpsxq6rsdfhvgazq5z08gsxxdf3xs6nvdn994jnyd33956rydfk95urjcfh943nwd338q6kydmyxgurqcqzpgxqrrsssp5ka6qqqnmuxu35783m8n8avsafmc4pasnh365pgj20vpj2r735xrq9qy9qsq956lq8l66rrt6nec2s20uwh4dcxwgt3ndqyt2pdc02axpdk3xt4k9pjpev0f9tfff0xe3g9eqp3tvl690a8n6u8dwweqm2azycj0utcpz8pkeu")
|
|
|
|
|
|
|
|
session = requests.session()
|
|
|
|
#session.proxies = {'http': 'socks5://127.0.0.1:9050', 'https': 'socks5://127.0.0.1:9050'}
|
|
|
|
#apiGetHosts(session, "shop.ip2t.org")
|
|
|
|
#orderid = apiPlaceOrder(session, "shop.ip2t.org", "fc747bae-6dbb-498d-89c2-f2445210c8f8", "facebookcorewwwi.onion:80")
|
|
|
|
#apiGetOrder(session, "shop.ip2t.org", orderid)
|
2020-05-23 02:44:08 +02:00
|
|
|
|
|
|
|
if False: '''
|
|
|
|
|
2020-05-22 19:24:46 +02:00
|
|
|
###############
|
|
|
|
# MENU
|
|
|
|
###############
|
|
|
|
|
|
|
|
if sys.argv[1] == "menu":
|
2020-05-23 02:44:08 +02:00
|
|
|
from dialog import Dialog
|
2020-05-22 19:24:46 +02:00
|
|
|
d = Dialog(dialog="dialog",autowidgetsize=True)
|
|
|
|
d.set_background_title("IP2TOR Subscription Service")
|
|
|
|
code, tag = d.menu("OK, then you have two options:",
|
2020-05-22 20:06:59 +02:00
|
|
|
choices=[("(1)", "Test HTTP REQUEST thru TOR PROXY"),
|
2020-05-22 20:28:27 +02:00
|
|
|
("(2)", "Make REST API - JSON request"),
|
|
|
|
("(3)", "TOML test"),
|
2020-05-23 02:44:08 +02:00
|
|
|
("(4)", "Working with .conf files")])
|
2020-05-22 19:24:46 +02:00
|
|
|
if code == d.OK:
|
2020-05-22 20:06:59 +02:00
|
|
|
if tag == "(1)":
|
2020-05-22 20:28:27 +02:00
|
|
|
print("Needs: pip3 install pysocks\n")
|
2020-05-22 20:06:59 +02:00
|
|
|
session = requests.session()
|
|
|
|
session.proxies = {'http': 'socks5://127.0.0.1:9050', 'https': 'socks5://127.0.0.1:9050'}
|
|
|
|
print("Call 'http://httpbin.org/ip' thru TOR proxy:\n")
|
|
|
|
print(session.get("http://httpbin.org/ip").text)
|
|
|
|
print("Call 'http://httpbin.org/ip' normal:\n")
|
|
|
|
print(requests.get("http://httpbin.org/ip").text)
|
|
|
|
print("Call 'https://shop.ip2t.org/api/v1/public/hosts/' thru TOR:\n")
|
|
|
|
print(session.get("https://shop.ip2t.org/api/v1/public/hosts/").text)
|
|
|
|
if tag == "(2)":
|
2020-05-23 02:44:08 +02:00
|
|
|
|
2020-05-22 20:28:27 +02:00
|
|
|
if tag == "(3)":
|
2020-05-22 20:32:17 +02:00
|
|
|
print ("Needs: pip3 install toml")
|
2020-05-22 20:28:27 +02:00
|
|
|
import toml
|
|
|
|
toml_string = """
|
|
|
|
"""
|
|
|
|
if tag == "(4)":
|
|
|
|
with open('/mnt/hdd/raspiblitz.conf', 'r') as myfile:
|
2020-05-22 20:29:43 +02:00
|
|
|
data=myfile.read()
|
2020-05-22 20:32:17 +02:00
|
|
|
print(data)
|
2020-05-22 20:33:04 +02:00
|
|
|
import toml
|
2020-05-22 20:32:17 +02:00
|
|
|
parsed_toml = toml.loads(data)
|
|
|
|
print(parsed_toml)
|
2020-05-22 20:28:27 +02:00
|
|
|
|
2020-05-22 19:24:46 +02:00
|
|
|
else:
|
2020-05-23 02:44:08 +02:00
|
|
|
print("Cancel")
|
|
|
|
'''
|