mirror of
https://github.com/raspiblitz/raspiblitz.git
synced 2025-10-02 12:12:51 +02:00
@@ -1,28 +1,32 @@
|
||||
#!/usr/bin/python3
|
||||
|
||||
import sys
|
||||
import locale
|
||||
import requests
|
||||
import codecs
|
||||
import json
|
||||
import math
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
import datetime, time
|
||||
import codecs, grpc, os
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
|
||||
import grpc
|
||||
import requests
|
||||
import toml
|
||||
from blitzpy import RaspiBlitzConfig
|
||||
|
||||
from lndlibs import rpc_pb2 as lnrpc
|
||||
from lndlibs import rpc_pb2_grpc as rpcstub
|
||||
|
||||
####### SCRIPT INFO #########
|
||||
#####################
|
||||
# SCRIPT INFO
|
||||
#####################
|
||||
|
||||
# display config script info
|
||||
if len(sys.argv) <= 1 or sys.argv[1] == "-h" or sys.argv[1] == "help":
|
||||
print("# manage ip2tor subscriptions for raspiblitz")
|
||||
print("# blitz.subscriptions.ip2tor.py create-ssh-dialog servicename toraddress torport")
|
||||
print("# blitz.subscriptions.ip2tor.py shop-list shopurl")
|
||||
print("# blitz.subscriptions.ip2tor.py shop-order shopurl servicename hostid toraddress:port duration msatsFirst msatsNext [description]")
|
||||
print("# blitz.subscriptions.ip2tor.py shop-order shopurl servicename hostid toraddress:port duration "
|
||||
"msatsFirst msatsNext [description]")
|
||||
print("# blitz.subscriptions.ip2tor.py subscriptions-list")
|
||||
print("# blitz.subscriptions.ip2tor.py subscriptions-renew secondsBeforeSuspend")
|
||||
print("# blitz.subscriptions.ip2tor.py subscription-cancel id")
|
||||
@@ -30,19 +34,25 @@ if len(sys.argv) <= 1 or sys.argv[1] == "-h" or sys.argv[1] == "help":
|
||||
print("# blitz.subscriptions.ip2tor.py ip-by-tor onionaddress")
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
|
||||
####### BASIC SETTINGS #########
|
||||
|
||||
#####################
|
||||
# BASIC SETTINGS
|
||||
#####################
|
||||
session = requests.session()
|
||||
if Path("/mnt/hdd/raspiblitz.conf").is_file():
|
||||
cfg = RaspiBlitzConfig()
|
||||
cfg.reload()
|
||||
|
||||
if cfg.chain.value == "test":
|
||||
is_testnet = True
|
||||
else:
|
||||
is_testnet = False
|
||||
|
||||
ENV = "PROD"
|
||||
# DEFAULT_SHOPURL="shopdeu2vdhazvmllyfagdcvlpflzdyt5gwftmn4hjj3zw2oyelksaid.onion"
|
||||
DEFAULT_SHOPURL = "ip2tor.fulmo.org"
|
||||
LND_IP = "127.0.0.1"
|
||||
LND_ADMIN_MACAROON_PATH="/mnt/hdd/app-data/lnd/data/chain/{0}/{1}net/admin.macaroon".format(cfg.network.value,cfg.chain.value)
|
||||
LND_ADMIN_MACAROON_PATH = "/mnt/hdd/app-data/lnd/data/chain/{0}/{1}net/admin.macaroon".format(cfg.network.value,
|
||||
cfg.chain.value)
|
||||
LND_TLS_PATH = "/mnt/hdd/app-data/lnd/tls.cert"
|
||||
# make sure to make requests thru TOR 127.0.0.1:9050
|
||||
session.proxies = {'http': 'socks5h://127.0.0.1:9050', 'https': 'socks5h://127.0.0.1:9050'}
|
||||
@@ -56,12 +66,12 @@ else:
|
||||
LND_TLS_PATH = "/Users/rotzoll/Downloads/RaspiBlitzCredentials/tls.cert"
|
||||
SUBSCRIPTIONS_FILE = "/Users/rotzoll/Downloads/RaspiBlitzCredentials/subscriptions.toml"
|
||||
|
||||
if cfg.chain.value == "test":
|
||||
is_testnet = True
|
||||
else:
|
||||
is_testnet = False
|
||||
|
||||
####### HELPER CLASSES #########
|
||||
|
||||
#####################
|
||||
# HELPER CLASSES
|
||||
#####################
|
||||
|
||||
class BlitzError(Exception):
|
||||
def __init__(self, errorShort, errorLong="", errorException=None):
|
||||
@@ -69,11 +79,15 @@ class BlitzError(Exception):
|
||||
self.errorLong = str(errorLong)
|
||||
self.errorException = errorException
|
||||
|
||||
####### HELPER FUNCTIONS #########
|
||||
|
||||
#####################
|
||||
# HELPER FUNCTIONS
|
||||
#####################
|
||||
|
||||
def eprint(*args, **kwargs):
|
||||
print(*args, file=sys.stderr, **kwargs)
|
||||
|
||||
|
||||
def handleException(e):
|
||||
if isinstance(e, BlitzError):
|
||||
eprint(e.errorLong)
|
||||
@@ -84,18 +98,21 @@ def handleException(e):
|
||||
print("error='{0}'".format(str(e)))
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def parseDate(datestr):
|
||||
return datetime.datetime.strptime(datestr,"%Y-%m-%dT%H:%M:%SZ")
|
||||
return datetime.strptime(datestr, "%Y-%m-%dT%H:%M:%SZ")
|
||||
|
||||
|
||||
def secondsLeft(dateObj):
|
||||
return round((dateObj - datetime.datetime.utcnow()).total_seconds())
|
||||
return round((dateObj - datetime.utcnow()).total_seconds())
|
||||
|
||||
|
||||
# takes a shopurl from user input and turns it into the format needed
|
||||
# also makes sure that .onion addresses run just with http not https
|
||||
def normalizeShopUrl(shopurlUserInput):
|
||||
|
||||
# basic checks and formats
|
||||
if len(shopurlUserInput) < 3: return ""
|
||||
if len(shopurlUserInput) < 3:
|
||||
return ""
|
||||
shopurlUserInput = shopurlUserInput.lower()
|
||||
shopurlUserInput = shopurlUserInput.replace(" ", "")
|
||||
shopurlUserInput = shopurlUserInput.replace("\n", "")
|
||||
@@ -110,7 +127,7 @@ def normalizeShopUrl(shopurlUserInput):
|
||||
shopurlUserInput = shopurlUserInput[:shopurlUserInput.find("/")]
|
||||
|
||||
# add correct protocol again
|
||||
if ( not shopurlUserInput.startswith("http://") and not shopurlUserInput.startswith("https://") ):
|
||||
if not shopurlUserInput.startswith("http://") and not shopurlUserInput.startswith("https://"):
|
||||
if shopurlUserInput.endswith(".onion"):
|
||||
shopurlUserInput = "http://{0}".format(shopurlUserInput)
|
||||
else:
|
||||
@@ -118,16 +135,18 @@ def normalizeShopUrl(shopurlUserInput):
|
||||
|
||||
return shopurlUserInput
|
||||
|
||||
####### IP2TOR API CALLS #########
|
||||
|
||||
#####################
|
||||
# IP2TOR API CALLS
|
||||
#####################
|
||||
|
||||
def apiGetHosts(session, shopurl):
|
||||
|
||||
print("# apiGetHosts")
|
||||
hosts = []
|
||||
|
||||
# make HTTP request
|
||||
try:
|
||||
url = "{0}/api/v1/public/hosts/?is_testnet={1}".format(shopurl, int(is_testnet))
|
||||
try:
|
||||
response = session.get(url)
|
||||
except Exception as e:
|
||||
raise BlitzError("failed HTTP request", url, e)
|
||||
@@ -144,21 +163,27 @@ def apiGetHosts(session, shopurl):
|
||||
for idx, hostEntry in enumerate(jData):
|
||||
try:
|
||||
# ignore if not offering tor bridge
|
||||
if not hostEntry['offers_tor_bridges']: continue
|
||||
if not hostEntry['offers_tor_bridges']:
|
||||
continue
|
||||
# ignore if duration is less than an hour
|
||||
if hostEntry['tor_bridge_duration'] < 3600: continue
|
||||
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
|
||||
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
|
||||
if len(hostEntry['name']) < 3:
|
||||
continue
|
||||
# ignore id with zero value
|
||||
if len(hostEntry['id']) < 1: continue
|
||||
if len(hostEntry['id']) < 1:
|
||||
continue
|
||||
# shorten names to 20 chars max
|
||||
hostEntry['name'] = hostEntry['name'][:20]
|
||||
except Exception as e:
|
||||
@@ -169,11 +194,10 @@ def apiGetHosts(session, shopurl):
|
||||
print("# found {0} valid torbridge hosts".format(len(hosts)))
|
||||
return hosts
|
||||
|
||||
def apiPlaceOrderNew(session, shopurl, hostid, toraddressWithPort):
|
||||
|
||||
def apiPlaceOrderNew(session, shopurl, hostid, toraddressWithPort):
|
||||
print("# apiPlaceOrderNew")
|
||||
|
||||
try:
|
||||
url = "{0}/api/v1/public/order/".format(shopurl)
|
||||
postData = {
|
||||
'product': "tor_bridge",
|
||||
@@ -183,6 +207,7 @@ def apiPlaceOrderNew(session, shopurl, hostid, toraddressWithPort):
|
||||
'target': toraddressWithPort,
|
||||
'public_key': ''
|
||||
}
|
||||
try:
|
||||
response = session.post(url, data=postData)
|
||||
except Exception as e:
|
||||
raise BlitzError("failed HTTP request", url, e)
|
||||
@@ -202,12 +227,12 @@ def apiPlaceOrderNew(session, shopurl, hostid, toraddressWithPort):
|
||||
|
||||
return jData['id']
|
||||
|
||||
def apiPlaceOrderExtension(session, shopurl, bridgeid):
|
||||
|
||||
def apiPlaceOrderExtension(session, shopurl, bridgeid):
|
||||
print("# apiPlaceOrderExtension")
|
||||
|
||||
try:
|
||||
url = "{0}/api/v1/public/tor_bridges/{1}/extend/".format(shopurl, bridgeid)
|
||||
try:
|
||||
response = session.post(url)
|
||||
except Exception as e:
|
||||
raise BlitzError("failed HTTP request", url, e)
|
||||
@@ -230,12 +255,11 @@ def apiPlaceOrderExtension(session, shopurl, bridgeid):
|
||||
|
||||
|
||||
def apiGetOrder(session, shopurl, orderid):
|
||||
|
||||
print("# apiGetOrder")
|
||||
|
||||
# make HTTP request
|
||||
try:
|
||||
url = "{0}/api/v1/public/pos/{1}/".format(shopurl, orderid)
|
||||
try:
|
||||
response = session.get(url)
|
||||
except Exception as e:
|
||||
raise BlitzError("failed HTTP request", url, e)
|
||||
@@ -254,13 +278,13 @@ def apiGetOrder(session, shopurl, orderid):
|
||||
|
||||
return jData
|
||||
|
||||
def apiGetBridgeStatus(session, shopurl, bridgeid):
|
||||
|
||||
def apiGetBridgeStatus(session, shopurl, bridgeid):
|
||||
print("# apiGetBridgeStatus")
|
||||
|
||||
# make HTTP request
|
||||
try:
|
||||
url = "{0}/api/v1/public/tor_bridges/{1}/".format(shopurl, bridgeid)
|
||||
try:
|
||||
response = session.get(url)
|
||||
except Exception as e:
|
||||
raise BlitzError("failed HTTP request", url, e)
|
||||
@@ -276,7 +300,10 @@ def apiGetBridgeStatus(session, shopurl, bridgeid):
|
||||
|
||||
return jData
|
||||
|
||||
####### LND API CALLS #########
|
||||
|
||||
#####################
|
||||
# LND API CALLS
|
||||
#####################
|
||||
|
||||
def lndDecodeInvoice(lnInvoiceString):
|
||||
try:
|
||||
@@ -301,6 +328,7 @@ def lndDecodeInvoice(lnInvoiceString):
|
||||
|
||||
return response
|
||||
|
||||
|
||||
def lndPayInvoice(lnInvoiceString):
|
||||
try:
|
||||
# call LND GRPC API
|
||||
@@ -324,16 +352,18 @@ def lndPayInvoice(lnInvoiceString):
|
||||
|
||||
return response
|
||||
|
||||
####### PROCESS FUNCTIONS #########
|
||||
|
||||
#####################
|
||||
# PROCESS FUNCTIONS
|
||||
#####################
|
||||
|
||||
def shopList(shopUrl):
|
||||
|
||||
print("#### Getting available options from shop ...")
|
||||
shopUrl = normalizeShopUrl(shopUrl)
|
||||
return apiGetHosts(session, shopUrl)
|
||||
|
||||
def shopOrder(shopUrl, hostid, servicename, torTarget, duration, msatsFirst, msatsNext, description=""):
|
||||
|
||||
def shopOrder(shopUrl, hostid, servicename, torTarget, duration, msatsFirst, msatsNext, description=""):
|
||||
print("#### Placeing order ...")
|
||||
shopUrl = normalizeShopUrl(shopUrl)
|
||||
orderid = apiPlaceOrderNew(session, shopUrl, hostid, torTarget)
|
||||
@@ -365,7 +395,8 @@ def shopOrder(shopUrl, hostid, servicename, torTarget, duration, msatsFirst, msa
|
||||
print("# amount as advertised: {0} milliSats".format(msatsFirst))
|
||||
print("# amount in invoice is: {0} milliSats".format(paymentRequestDecoded.num_msat))
|
||||
if int(msatsFirst) < int(paymentRequestDecoded.num_msat):
|
||||
raise BlitzError("invoice bigger amount than advertised", "advertised({0}) invoice({1})".format(msatsFirst, paymentRequestDecoded.num_msat))
|
||||
raise BlitzError("invoice bigger amount than advertised",
|
||||
"advertised({0}) invoice({1})".format(msatsFirst, paymentRequestDecoded.num_msat))
|
||||
|
||||
print("#### Paying invoice ...")
|
||||
payedInvoice = lndPayInvoice(paymentRequestStr)
|
||||
@@ -397,7 +428,7 @@ def shopOrder(shopUrl, hostid, servicename, torTarget, duration, msatsFirst, msa
|
||||
warning_text = "delivered duration shorter than advertised"
|
||||
|
||||
# create subscription data for storage
|
||||
subscription = {}
|
||||
subscription = dict()
|
||||
subscription['type'] = "ip2tor-v1"
|
||||
subscription['id'] = bridge['id']
|
||||
subscription['name'] = servicename
|
||||
@@ -409,8 +440,8 @@ def shopOrder(shopUrl, hostid, servicename, torTarget, duration, msatsFirst, msa
|
||||
subscription['price_initial'] = int(msatsFirst)
|
||||
subscription['price_extension'] = int(msatsNext)
|
||||
subscription['price_total'] = int(paymentRequestDecoded.num_msat)
|
||||
subscription['time_created'] = str(datetime.datetime.now().strftime("%Y-%m-%d %H:%M"))
|
||||
subscription['time_lastupdate'] = str(datetime.datetime.now().strftime("%Y-%m-%d %H:%M"))
|
||||
subscription['time_created'] = str(datetime.now().strftime("%Y-%m-%d %H:%M"))
|
||||
subscription['time_lastupdate'] = str(datetime.now().strftime("%Y-%m-%d %H:%M"))
|
||||
subscription['suspend_after'] = bridge['suspend_after']
|
||||
subscription['description'] = str(description)
|
||||
subscription['contract_breached'] = contract_breached
|
||||
@@ -436,13 +467,13 @@ def shopOrder(shopUrl, hostid, servicename, torTarget, duration, msatsFirst, msa
|
||||
|
||||
except Exception as e:
|
||||
eprint(e)
|
||||
raise BlitzError("fail on subscription storage",subscription, e)
|
||||
raise BlitzError("fail on subscription storage", str(subscription), e)
|
||||
|
||||
print("# OK - BRIDGE READY: {0}:{1} -> {2}".format(bridge_ip, subscription['port'], torTarget))
|
||||
return subscription
|
||||
|
||||
def subscriptionExtend(shopUrl, bridgeid, durationAdvertised, msatsNext, bridge_suspendafter):
|
||||
|
||||
def subscriptionExtend(shopUrl, bridgeid, durationAdvertised, msatsNext, bridge_suspendafter):
|
||||
warningTXT = ""
|
||||
contract_breached = False
|
||||
|
||||
@@ -462,7 +493,6 @@ def subscriptionExtend(shopUrl, bridgeid, durationAdvertised, msatsNext, bridge_
|
||||
if loopCount > 120:
|
||||
raise BlitzError("timeout on getting invoice", order)
|
||||
|
||||
|
||||
paymentRequestStr = order['ln_invoices'][0]['payment_request']
|
||||
|
||||
print("#### Decoding invoice and checking ..)")
|
||||
@@ -472,12 +502,14 @@ def subscriptionExtend(shopUrl, bridgeid, durationAdvertised, msatsNext, bridge_
|
||||
print("# amount as advertised: {0} milliSats".format(msatsNext))
|
||||
print("# amount in invoice is: {0} milliSats".format(paymentRequestDecoded.num_msat))
|
||||
if int(msatsNext) < int(paymentRequestDecoded.num_msat):
|
||||
raise BlitzError("invoice bigger amount than advertised", "advertised({0}) invoice({1})".format(msatsNext, paymentRequestDecoded.num_msat))
|
||||
raise BlitzError("invoice bigger amount than advertised",
|
||||
"advertised({0}) invoice({1})".format(msatsNext, paymentRequestDecoded.num_msat))
|
||||
|
||||
print("#### Paying invoice ...")
|
||||
payedInvoice = lndPayInvoice(paymentRequestStr)
|
||||
|
||||
print("#### Check if bridge was extended ...")
|
||||
bridge = None
|
||||
loopCount = 0
|
||||
while True:
|
||||
time.sleep(3)
|
||||
@@ -495,7 +527,7 @@ def subscriptionExtend(shopUrl, bridgeid, durationAdvertised, msatsNext, bridge_
|
||||
contract_breached = True
|
||||
break
|
||||
|
||||
if not contract_breached:
|
||||
if bridge and not contract_breached:
|
||||
print("#### Check if extension duration is as advertised ...")
|
||||
secondsLeftOld = secondsLeft(parseDate(bridge_suspendafter))
|
||||
secondsLeftNew = secondsLeft(parseDate(bridge['suspend_after']))
|
||||
@@ -513,7 +545,7 @@ def subscriptionExtend(shopUrl, bridgeid, durationAdvertised, msatsNext, bridge_
|
||||
for idx, subscription in enumerate(subscriptions['subscriptions_ip2tor']):
|
||||
if subscription['id'] == bridgeid:
|
||||
subscription['suspend_after'] = str(bridge['suspend_after'])
|
||||
subscription['time_lastupdate'] = str(datetime.datetime.now().strftime("%Y-%m-%d %H:%M"))
|
||||
subscription['time_lastupdate'] = str(datetime.now().strftime("%Y-%m-%d %H:%M"))
|
||||
subscription['price_total'] += int(paymentRequestDecoded.num_msat)
|
||||
subscription['contract_breached'] = contract_breached
|
||||
subscription['warning'] = warningTXT
|
||||
@@ -526,11 +558,14 @@ def subscriptionExtend(shopUrl, bridgeid, durationAdvertised, msatsNext, bridge_
|
||||
|
||||
except Exception as e:
|
||||
eprint(e)
|
||||
raise BlitzError("fail on subscription storage",subscription, e)
|
||||
raise BlitzError("fail on subscription storage", "", e)
|
||||
|
||||
print("# BRIDGE GOT EXTENDED: {0} -> {1}".format(bridge_suspendafter, bridge['suspend_after']))
|
||||
|
||||
|
||||
def menuMakeSubscription(blitzServiceName, torAddress, torPort):
|
||||
# late imports - so that rest of script can run also if dependency is not available
|
||||
from dialog import Dialog
|
||||
|
||||
torTarget = "{0}:{1}".format(torAddress, torPort)
|
||||
|
||||
@@ -557,7 +592,8 @@ def menuMakeSubscription(blitzServiceName, torAddress, torPort):
|
||||
title="Shop Address")
|
||||
|
||||
# if user canceled
|
||||
if code != d.OK: sys.exit(0)
|
||||
if code != d.OK:
|
||||
sys.exit(0)
|
||||
|
||||
# get host list from shop
|
||||
shopurl = text
|
||||
@@ -578,7 +614,8 @@ The shop has no available offers at the moment.
|
||||
Try again later, enter another address or cancel.
|
||||
''', title="ERROR")
|
||||
# ok we got hosts - continue
|
||||
else: break
|
||||
else:
|
||||
break
|
||||
|
||||
###############################
|
||||
# PHASE 2: SELECT SUBSCRIPTION
|
||||
@@ -587,7 +624,15 @@ Try again later, enter another address or cancel.
|
||||
host = None
|
||||
choices = []
|
||||
for idx, hostEntry in enumerate(hosts):
|
||||
choices.append( ("{0}".format(idx), "{0} ({1} hours, first: {2} sats, next: {3} sats)".format(hostEntry['name'].ljust(20), hostEntry['tor_bridge_duration_hours'], hostEntry['tor_bridge_price_initial_sats'], hostEntry['tor_bridge_price_extension_sats'])) )
|
||||
choices.append(
|
||||
("{0}".format(idx),
|
||||
"{0} ({1} hours, first: {2} sats, next: {3} sats)".format(
|
||||
hostEntry['name'].ljust(20),
|
||||
hostEntry['tor_bridge_duration_hours'],
|
||||
hostEntry['tor_bridge_price_initial_sats'],
|
||||
hostEntry['tor_bridge_price_extension_sats'])
|
||||
)
|
||||
)
|
||||
|
||||
while True:
|
||||
|
||||
@@ -643,7 +688,8 @@ More information on the service you can find under:
|
||||
blitzServiceName
|
||||
)
|
||||
|
||||
code = d.msgbox(text, title=host['name'], ok_label="Back", extra_button=True, extra_label="AGREE" ,width=75, height=30)
|
||||
code = d.msgbox(text, title=host['name'], ok_label="Back", extra_button=True, extra_label="AGREE", width=75,
|
||||
height=30)
|
||||
|
||||
# if user AGREED break loop and continue with selected host
|
||||
if code == "extra": break
|
||||
@@ -656,7 +702,8 @@ More information on the service you can find under:
|
||||
try:
|
||||
|
||||
os.system('clear')
|
||||
subscription = shopOrder(shopurl, host['id'], blitzServiceName, torTarget, host['tor_bridge_duration'], host['tor_bridge_price_initial'],host['tor_bridge_price_extension'],description)
|
||||
subscription = shopOrder(shopurl, host['id'], blitzServiceName, torTarget, host['tor_bridge_duration'],
|
||||
host['tor_bridge_price_initial'], host['tor_bridge_price_extension'], description)
|
||||
|
||||
except BlitzError as be:
|
||||
|
||||
@@ -667,7 +714,7 @@ More information on the service you can find under:
|
||||
be.errorShort == "invalid port" or
|
||||
be.errorShort == "timeout bridge not getting ready"):
|
||||
|
||||
# error happend after payment
|
||||
# error happened after payment
|
||||
exitcode = Dialog(dialog="dialog", autowidgetsize=True).msgbox('''
|
||||
You DID PAY the initial fee.
|
||||
But the service was not able to provide service.
|
||||
@@ -676,7 +723,7 @@ Error: {0}
|
||||
'''.format(be.errorShort), title="Error on Subscription", extra_button=True, extra_label="Details")
|
||||
else:
|
||||
|
||||
# error happend before payment
|
||||
# error happened before payment
|
||||
exitcode = Dialog(dialog="dialog", autowidgetsize=True).msgbox('''
|
||||
You DID NOT PAY the initial fee.
|
||||
The service was not able to provide service.
|
||||
@@ -704,7 +751,7 @@ Error: {0}
|
||||
|
||||
except Exception as e:
|
||||
|
||||
# unkown error happend
|
||||
# unknown error happened
|
||||
os.system('clear')
|
||||
print('###### EXCEPTION DETAIL FOR DEBUG #######')
|
||||
print("")
|
||||
@@ -718,7 +765,7 @@ Error: {0}
|
||||
input("Press Enter to continue ...")
|
||||
sys.exit(1)
|
||||
|
||||
# if LND REST or LND GRPS service ... add bridge IP to TLS
|
||||
# if LND REST or LND GRPC service ... add bridge IP to TLS
|
||||
if servicename == "LND-REST-API" or servicename == "LND-GRPC-API":
|
||||
os.system("sudo /home/admin/config.scripts/lnd.tlscert.sh ip-add {0}".format(subscription['ip']))
|
||||
os.system("sudo /home/admin/config.scripts/lnd.credentials.sh reset tls")
|
||||
@@ -762,7 +809,9 @@ MAIN MENU > Manage Subscriptions > My Subscriptions
|
||||
)
|
||||
|
||||
|
||||
####### COMMANDS #########
|
||||
#####################
|
||||
# COMMANDS
|
||||
#####################
|
||||
|
||||
###############
|
||||
# CREATE SSH DIALOG
|
||||
@@ -773,15 +822,15 @@ if sys.argv[1] == "create-ssh-dialog":
|
||||
|
||||
# check parameters
|
||||
try:
|
||||
if len(sys.argv) <= 4: raise BlitzError("incorrect parameters","")
|
||||
servicename = sys.argv[2]
|
||||
toraddress = sys.argv[3]
|
||||
port = sys.argv[4]
|
||||
if len(sys.argv) <= 4:
|
||||
raise BlitzError("incorrect parameters", "")
|
||||
except Exception as e:
|
||||
handleException(e)
|
||||
|
||||
# late imports - so that rest of script can run also if dependency is not available
|
||||
from dialog import Dialog
|
||||
servicename = sys.argv[2]
|
||||
toraddress = sys.argv[3]
|
||||
port = sys.argv[4]
|
||||
|
||||
menuMakeSubscription(servicename, toraddress, port)
|
||||
|
||||
sys.exit()
|
||||
@@ -795,31 +844,37 @@ if sys.argv[1] == "shop-list":
|
||||
|
||||
# check parameters
|
||||
try:
|
||||
if len(sys.argv) <= 2: raise BlitzError("incorrect parameters","")
|
||||
if len(sys.argv) <= 2:
|
||||
raise BlitzError("incorrect parameters", "")
|
||||
except Exception as e:
|
||||
handleException(e)
|
||||
|
||||
shopurl = sys.argv[2]
|
||||
except Exception as e:
|
||||
handleException(e)
|
||||
|
||||
# get data
|
||||
try:
|
||||
# get data
|
||||
hosts = shopList(shopurl)
|
||||
except Exception as e:
|
||||
handleException(e)
|
||||
|
||||
# output is json list of hosts
|
||||
print(json.dumps(hosts, indent=2))
|
||||
except Exception as e:
|
||||
handleException(e)
|
||||
|
||||
sys.exit(0)
|
||||
|
||||
###############
|
||||
##########################
|
||||
# SHOP ORDER
|
||||
# call from web interface
|
||||
###############
|
||||
##########################
|
||||
|
||||
if sys.argv[1] == "shop-order":
|
||||
|
||||
# check parameters
|
||||
try:
|
||||
if len(sys.argv) <= 8: raise BlitzError("incorrect parameters","")
|
||||
if len(sys.argv) <= 8:
|
||||
raise BlitzError("incorrect parameters", "")
|
||||
except Exception as e:
|
||||
handleException(e)
|
||||
|
||||
shopurl = sys.argv[2]
|
||||
servicename = sys.argv[3]
|
||||
hostid = sys.argv[4]
|
||||
@@ -831,22 +886,19 @@ if sys.argv[1] == "shop-order":
|
||||
description = sys.argv[9]
|
||||
else:
|
||||
description = ""
|
||||
except Exception as e:
|
||||
handleException(e)
|
||||
|
||||
# get data
|
||||
try:
|
||||
subscription = shopOrder(shopurl, hostid, servicename, toraddress, duration, msatsFirst, msatsNext, description)
|
||||
except Exception as e:
|
||||
handleException(e)
|
||||
|
||||
# output json ordered bridge
|
||||
print(json.dumps(subscription, indent=2))
|
||||
sys.exit()
|
||||
except Exception as e:
|
||||
handleException(e)
|
||||
|
||||
#######################
|
||||
# SUBSCRIPTIONS LIST
|
||||
# call in intervalls from background process
|
||||
# call in intervals from background process
|
||||
#######################
|
||||
|
||||
if sys.argv[1] == "subscriptions-list":
|
||||
@@ -869,7 +921,7 @@ if sys.argv[1] == "subscriptions-list":
|
||||
|
||||
#######################
|
||||
# SUBSCRIPTIONS RENEW
|
||||
# call in intervalls from background process
|
||||
# call in intervals from background process
|
||||
#######################
|
||||
|
||||
if sys.argv[1] == "subscriptions-renew":
|
||||
@@ -879,12 +931,13 @@ if sys.argv[1] == "subscriptions-renew":
|
||||
# check parameters
|
||||
try:
|
||||
secondsBeforeSuspend = int(sys.argv[2])
|
||||
if secondsBeforeSuspend < 0: secondsBeforeSuspend = 0
|
||||
if secondsBeforeSuspend < 0:
|
||||
secondsBeforeSuspend = 0
|
||||
except Exception as e:
|
||||
print("# running with secondsBeforeSuspend=0")
|
||||
secondsBeforeSuspend = 0
|
||||
|
||||
# check if any active subscrpitions are below the secondsBeforeSuspend - if yes extend
|
||||
# check if any active subscriptions are below the secondsBeforeSuspend - if yes extend
|
||||
|
||||
try:
|
||||
|
||||
@@ -901,7 +954,8 @@ if sys.argv[1] == "subscriptions-renew":
|
||||
if subscription['active'] and subscription['type'] == "ip2tor-v1":
|
||||
secondsToRun = secondsLeft(parseDate(subscription['suspend_after']))
|
||||
if secondsToRun < secondsBeforeSuspend:
|
||||
print("# RENEW: subscription {0} with {1} seconds to run".format(subscription['id'],secondsToRun))
|
||||
print("# RENEW: subscription {0} with {1} seconds to run".format(subscription['id'],
|
||||
secondsToRun))
|
||||
subscriptionExtend(
|
||||
subscription['shop'],
|
||||
subscription['id'],
|
||||
@@ -910,12 +964,13 @@ if sys.argv[1] == "subscriptions-renew":
|
||||
subscription['suspend_after']
|
||||
)
|
||||
else:
|
||||
print("# GOOD: subscription {0} with {1} seconds to run".format(subscription['id'],secondsToRun))
|
||||
print("# GOOD: subscription {0} with {1} "
|
||||
"seconds to run".format(subscription['id'], secondsToRun))
|
||||
|
||||
except BlitzError as be:
|
||||
# write error into subscription warning
|
||||
subs = toml.load(SUBSCRIPTIONS_FILE)
|
||||
for idx, sub in enumerate(subs['subscriptions_ip2tor']):
|
||||
for sub in subs['subscriptions_ip2tor']:
|
||||
if sub['id'] == subscription['id']:
|
||||
sub['warning'] = "Exception on Renew: {0}".format(be.errorShort)
|
||||
if be.errorShort == "invoice bigger amount than advertised":
|
||||
@@ -947,13 +1002,14 @@ if sys.argv[1] == "subscription-cancel":
|
||||
|
||||
# check parameters
|
||||
try:
|
||||
if len(sys.argv) <= 2: raise BlitzError("incorrect parameters","")
|
||||
subscriptionID = sys.argv[2]
|
||||
if len(sys.argv) <= 2:
|
||||
raise BlitzError("incorrect parameters", "")
|
||||
except Exception as e:
|
||||
handleException(e)
|
||||
|
||||
try:
|
||||
subscriptionID = sys.argv[2]
|
||||
|
||||
try:
|
||||
os.system("sudo chown admin:admin {0}".format(SUBSCRIPTIONS_FILE))
|
||||
subs = toml.load(SUBSCRIPTIONS_FILE)
|
||||
newList = []
|
||||
@@ -983,11 +1039,13 @@ if sys.argv[1] == "subscription-by-service":
|
||||
|
||||
# check parameters
|
||||
try:
|
||||
if len(sys.argv) <= 2: raise BlitzError("incorrect parameters","")
|
||||
servicename = sys.argv[2]
|
||||
if len(sys.argv) <= 2:
|
||||
raise BlitzError("incorrect parameters", "")
|
||||
except Exception as e:
|
||||
handleException(e)
|
||||
|
||||
servicename = sys.argv[2]
|
||||
|
||||
try:
|
||||
if os.path.isfile(SUBSCRIPTIONS_FILE):
|
||||
os.system("sudo chown admin:admin {0}".format(SUBSCRIPTIONS_FILE))
|
||||
@@ -1017,11 +1075,13 @@ if sys.argv[1] == "ip-by-tor":
|
||||
|
||||
# check parameters
|
||||
try:
|
||||
if len(sys.argv) <= 2: raise BlitzError("incorrect parameters","")
|
||||
onion = sys.argv[2]
|
||||
if len(sys.argv) <= 2:
|
||||
raise BlitzError("incorrect parameters", "")
|
||||
except Exception as e:
|
||||
handleException(e)
|
||||
|
||||
onion = sys.argv[2]
|
||||
|
||||
try:
|
||||
if os.path.isfile(SUBSCRIPTIONS_FILE):
|
||||
os.system("sudo chown admin:admin {0}".format(SUBSCRIPTIONS_FILE))
|
||||
@@ -1043,5 +1103,5 @@ if sys.argv[1] == "ip-by-tor":
|
||||
|
||||
sys.exit(1)
|
||||
|
||||
# unkown command
|
||||
print("# unkown command")
|
||||
# unknown command
|
||||
print("# unknown command")
|
||||
|
@@ -1,19 +1,20 @@
|
||||
#!/usr/bin/python3
|
||||
|
||||
import sys
|
||||
import locale
|
||||
import requests
|
||||
import json
|
||||
import math
|
||||
import time
|
||||
import datetime, time
|
||||
import os
|
||||
import subprocess
|
||||
import codecs, grpc, os
|
||||
import sys
|
||||
import time
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
|
||||
import requests
|
||||
import toml
|
||||
from blitzpy import RaspiBlitzConfig
|
||||
|
||||
####### SCRIPT INFO #########
|
||||
#####################
|
||||
# SCRIPT INFO
|
||||
#####################
|
||||
|
||||
# - this subscription does not require any payments
|
||||
# - the recurring part is managed by the lets encrypt ACME script
|
||||
@@ -29,7 +30,9 @@ if len(sys.argv) <= 1 or sys.argv[1] == "-h" or sys.argv[1] == "help":
|
||||
print("# blitz.subscriptions.ip2tor.py subscription-cancel <id>")
|
||||
sys.exit(1)
|
||||
|
||||
####### BASIC SETTINGS #########
|
||||
#####################
|
||||
# BASIC SETTINGS
|
||||
#####################
|
||||
|
||||
SUBSCRIPTIONS_FILE = "/mnt/hdd/app-data/subscriptions/subscriptions.toml"
|
||||
|
||||
@@ -41,7 +44,10 @@ session = requests.session()
|
||||
if cfg.run_behind_tor:
|
||||
session.proxies = {'http': 'socks5h://127.0.0.1:9050', 'https': 'socks5h://127.0.0.1:9050'}
|
||||
|
||||
####### HELPER CLASSES #########
|
||||
|
||||
#####################
|
||||
# HELPER CLASSES
|
||||
#####################
|
||||
|
||||
class BlitzError(Exception):
|
||||
def __init__(self, errorShort, errorLong="", errorException=None):
|
||||
@@ -49,11 +55,15 @@ class BlitzError(Exception):
|
||||
self.errorLong = str(errorLong)
|
||||
self.errorException = errorException
|
||||
|
||||
####### HELPER FUNCTIONS #########
|
||||
|
||||
#####################
|
||||
# HELPER FUNCTIONS
|
||||
#####################
|
||||
|
||||
def eprint(*args, **kwargs):
|
||||
print(*args, file=sys.stderr, **kwargs)
|
||||
|
||||
|
||||
def handleException(e):
|
||||
if isinstance(e, BlitzError):
|
||||
eprint(e.errorLong)
|
||||
@@ -64,30 +74,35 @@ def handleException(e):
|
||||
print("error='{0}'".format(str(e)))
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def getsubdomain(fulldomainstring):
|
||||
return fulldomainstring.split('.')[0]
|
||||
|
||||
####### API Calls to DNS Servcies #########
|
||||
|
||||
############################
|
||||
# API Calls to DNS Servcies
|
||||
############################
|
||||
|
||||
def duckDNSupdate(domain, token, ip):
|
||||
|
||||
print("# duckDNS update IP API call for {0}".format(domain))
|
||||
|
||||
# make HTTP request
|
||||
try:
|
||||
url = "https://www.duckdns.org/update?domains={0}&token={1}&ip={2}".format(getsubdomain(domain), token, ip)
|
||||
try:
|
||||
response = session.get(url)
|
||||
if response.status_code != 200:
|
||||
raise BlitzError("failed HTTP code", str(response.status_code))
|
||||
except Exception as e:
|
||||
raise BlitzError("failed HTTP request", url, e)
|
||||
if response.status_code != 200:
|
||||
raise BlitzError("failed HTTP code",response.status_code)
|
||||
|
||||
return response.content
|
||||
|
||||
####### PROCESS FUNCTIONS #########
|
||||
|
||||
#####################
|
||||
# PROCESS FUNCTIONS
|
||||
#####################
|
||||
|
||||
def subscriptionsNew(ip, dnsservice, id, token, target):
|
||||
|
||||
# id needs to the full domain name
|
||||
if id.find(".") == -1:
|
||||
raise BlitzError("not a fully qualified domainname", dnsservice_id)
|
||||
@@ -104,8 +119,9 @@ def subscriptionsNew(ip, dnsservice, id, token, target):
|
||||
if ip == "dyndns":
|
||||
updateURL = ""
|
||||
if dnsservice == "duckdns":
|
||||
updateURL=="https://www.duckdns.org/update?domains={0}&token={1}".format(getsubdomain(domain), token, ip)
|
||||
subprocess.run(['/home/admin/config.scriprs/internet.dyndomain.sh', 'on', id, updateURL], stdout=subprocess.PIPE).stdout.decode('utf-8').strip()
|
||||
updateURL = "https://www.duckdns.org/update?domains={0}&token={1}".format(getsubdomain(domain), token, ip)
|
||||
subprocess.run(['/home/admin/config.scriprs/internet.dyndomain.sh', 'on', id, updateURL],
|
||||
stdout=subprocess.PIPE).stdout.decode('utf-8').strip()
|
||||
realip = cfg.public_ip
|
||||
|
||||
# update DNS with actual IP
|
||||
@@ -114,14 +130,16 @@ def subscriptionsNew(ip, dnsservice, id, token, target):
|
||||
|
||||
# run the ACME script
|
||||
print("# Running letsencrypt ACME script ...")
|
||||
acmeResult=subprocess.Popen(["/home/admin/config.scripts/bonus.letsencrypt.sh", "issue-cert", dnsservice, id, token, target], stdout=subprocess.PIPE, stderr = subprocess.STDOUT, encoding='utf8')
|
||||
acmeResult = subprocess.Popen(
|
||||
["/home/admin/config.scripts/bonus.letsencrypt.sh", "issue-cert", dnsservice, id, token, target],
|
||||
stdout=subprocess.PIPE, stderr=subprocess.STDOUT, encoding='utf8')
|
||||
out, err = acmeResult.communicate()
|
||||
if out.find("error=") > -1:
|
||||
time.sleep(6)
|
||||
raise BlitzError("letsancrypt acme failed", out)
|
||||
|
||||
# create subscription data for storage
|
||||
subscription = {}
|
||||
subscription = dict()
|
||||
subscription['type'] = "letsencrypt-v1"
|
||||
subscription['id'] = id
|
||||
subscription['active'] = True
|
||||
@@ -131,7 +149,7 @@ def subscriptionsNew(ip, dnsservice, id, token, target):
|
||||
subscription['ip'] = ip
|
||||
subscription['target'] = target
|
||||
subscription['description'] = "For {0}".format(target)
|
||||
subscription['time_created'] = str(datetime.datetime.now().strftime("%Y-%m-%d %H:%M"))
|
||||
subscription['time_created'] = str(datetime.now().strftime("%Y-%m-%d %H:%M"))
|
||||
subscription['warning'] = ""
|
||||
|
||||
# load, add and store subscriptions
|
||||
@@ -152,17 +170,19 @@ def subscriptionsNew(ip, dnsservice, id, token, target):
|
||||
|
||||
except Exception as e:
|
||||
eprint(e)
|
||||
raise BlitzError("fail on subscription storage",subscription, e)
|
||||
raise BlitzError("fail on subscription storage", str(subscription), e)
|
||||
|
||||
print("# OK - LETSENCRYPT DOMAIN IS READY")
|
||||
return subscription
|
||||
|
||||
|
||||
def subscriptionsCancel(id):
|
||||
# ToDo(frennkie) id is not used..
|
||||
|
||||
os.system("sudo chown admin:admin {0}".format(SUBSCRIPTIONS_FILE))
|
||||
subs = toml.load(SUBSCRIPTIONS_FILE)
|
||||
newList = []
|
||||
removedCert = False
|
||||
removedCert = None
|
||||
for idx, sub in enumerate(subs['subscriptions_letsencrypt']):
|
||||
if sub['id'] != subscriptionID:
|
||||
newList.append(sub)
|
||||
@@ -172,11 +192,13 @@ def subscriptionsCancel(id):
|
||||
|
||||
# run the ACME script to remove cert
|
||||
if removedCert:
|
||||
acmeResult=subprocess.Popen(["/home/admin/config.scripts/bonus.letsencrypt.sh", "remove-cert", removedCert['id'], removedCert['target']], stdout=subprocess.PIPE, stderr = subprocess.STDOUT, encoding='utf8')
|
||||
acmeResult = subprocess.Popen(
|
||||
["/home/admin/config.scripts/bonus.letsencrypt.sh", "remove-cert", removedCert['id'],
|
||||
removedCert['target']], stdout=subprocess.PIPE, stderr=subprocess.STDOUT, encoding='utf8')
|
||||
out, err = acmeResult.communicate()
|
||||
if out.find("error=") > -1:
|
||||
time.sleep(6)
|
||||
raise BlitzError("letsancrypt acme failed", out)
|
||||
raise BlitzError("letsencrypt acme failed", out)
|
||||
|
||||
# persist change
|
||||
with open(SUBSCRIPTIONS_FILE, 'w') as writer:
|
||||
@@ -187,8 +209,8 @@ def subscriptionsCancel(id):
|
||||
|
||||
# todo: deinstall letsencrypt if this was last subscription
|
||||
|
||||
def getSubscription(subscriptionID):
|
||||
|
||||
def getSubscription(subscriptionID):
|
||||
try:
|
||||
|
||||
if Path(SUBSCRIPTIONS_FILE).is_file():
|
||||
@@ -208,7 +230,6 @@ def getSubscription(subscriptionID):
|
||||
|
||||
|
||||
def getDomainByIP(ip):
|
||||
|
||||
# does subscriptin file exists
|
||||
if Path(SUBSCRIPTIONS_FILE).is_file():
|
||||
os.system("sudo chown admin:admin {0}".format(SUBSCRIPTIONS_FILE))
|
||||
@@ -231,6 +252,8 @@ def getDomainByIP(ip):
|
||||
|
||||
|
||||
def menuMakeSubscription():
|
||||
# late imports - so that rest of script can run also if dependency is not available
|
||||
from dialog import Dialog
|
||||
|
||||
# todo ... copy parts of IP2TOR dialogs
|
||||
|
||||
@@ -314,7 +337,7 @@ This looks not like a valid token.
|
||||
# PHASE 3: Choose what kind of IP: dynDNS, IP2TOR, fixedIP
|
||||
|
||||
# ask user for which RaspiBlitz service the bridge should be used
|
||||
choices = []
|
||||
choices = list()
|
||||
choices.append(("IP2TOR", "HTTPS for a IP2TOR Bridge"))
|
||||
choices.append(("DYNDNS", "HTTPS for {0} DynamicIP DNS".format(dnsservice.upper())))
|
||||
choices.append(("STATIC", "HTTPS for a static IP"))
|
||||
@@ -332,6 +355,7 @@ This looks not like a valid token.
|
||||
|
||||
# default target are the nginx ip ports
|
||||
target = "ip"
|
||||
ip = ""
|
||||
|
||||
if tag == "IP2TOR":
|
||||
|
||||
@@ -398,7 +422,7 @@ This looks not like a valid IP.
|
||||
''', title="Unvalid Input")
|
||||
sys.exit(0)
|
||||
|
||||
# create the letsenscript subscription
|
||||
# create the letsencrypt subscription
|
||||
try:
|
||||
os.system("clear")
|
||||
subscription = subscriptionsNew(ip, dnsservice, domain, token, target)
|
||||
@@ -413,14 +437,17 @@ to reach the service you wanted.
|
||||
|
||||
except Exception as e:
|
||||
|
||||
# unkown error happend
|
||||
# unknown error happened
|
||||
Dialog(dialog="dialog", autowidgetsize=True).msgbox('''
|
||||
Unkown Error happend - please report to developers:
|
||||
Unknown Error happened - please report to developers:
|
||||
{0}
|
||||
'''.format(str(e)), title="Exception on Subscription")
|
||||
sys.exit(1)
|
||||
|
||||
####### COMMANDS #########
|
||||
|
||||
##################
|
||||
# COMMANDS
|
||||
##################
|
||||
|
||||
###############
|
||||
# CREATE SSH DIALOG
|
||||
@@ -428,24 +455,24 @@ Unkown Error happend - please report to developers:
|
||||
###############
|
||||
|
||||
if sys.argv[1] == "create-ssh-dialog":
|
||||
|
||||
# late imports - so that rest of script can run also if dependency is not available
|
||||
from dialog import Dialog
|
||||
|
||||
menuMakeSubscription()
|
||||
|
||||
sys.exit()
|
||||
|
||||
###############
|
||||
##########################
|
||||
# SUBSCRIPTIONS NEW
|
||||
# call from web interface
|
||||
###############
|
||||
##########################
|
||||
|
||||
if sys.argv[1] == "subscription-new":
|
||||
|
||||
# check parameters
|
||||
try:
|
||||
if len(sys.argv) <= 5: raise BlitzError("incorrect parameters","")
|
||||
if len(sys.argv) <= 5:
|
||||
raise BlitzError("incorrect parameters", "")
|
||||
except Exception as e:
|
||||
handleException(e)
|
||||
|
||||
ip = sys.argv[2]
|
||||
dnsservice_type = sys.argv[3]
|
||||
dnsservice_id = sys.argv[4]
|
||||
@@ -454,19 +481,18 @@ if sys.argv[1] == "subscription-new":
|
||||
target = "ip&tor"
|
||||
else:
|
||||
target = sys.argv[6]
|
||||
except Exception as e:
|
||||
handleException(e)
|
||||
|
||||
# create the subscription
|
||||
try:
|
||||
subscription = subscriptionsNew(ip, dnsservice_type, dnsservice_id, dnsservice_token, target)
|
||||
except Exception as e:
|
||||
handleException(e)
|
||||
|
||||
# output json ordered bridge
|
||||
print(json.dumps(subscription, indent=2))
|
||||
sys.exit()
|
||||
|
||||
except Exception as e:
|
||||
handleException(e)
|
||||
|
||||
#######################
|
||||
# SUBSCRIPTIONS LIST
|
||||
#######################
|
||||
@@ -496,11 +522,12 @@ if sys.argv[1] == "subscription-detail":
|
||||
|
||||
# check parameters
|
||||
try:
|
||||
if len(sys.argv) <= 2: raise BlitzError("incorrect parameters","")
|
||||
subscriptionID = sys.argv[2]
|
||||
if len(sys.argv) <= 2:
|
||||
raise BlitzError("incorrect parameters", "")
|
||||
except Exception as e:
|
||||
handleException(e)
|
||||
|
||||
subscriptionID = sys.argv[2]
|
||||
try:
|
||||
sub = getSubscription(subscriptionID)
|
||||
print(json.dumps(sub, indent=2))
|
||||
@@ -518,11 +545,13 @@ if sys.argv[1] == "domain-by-ip":
|
||||
|
||||
# check parameters
|
||||
try:
|
||||
if len(sys.argv) <= 2: raise BlitzError("incorrect parameters","")
|
||||
ip = sys.argv[2]
|
||||
if len(sys.argv) <= 2:
|
||||
raise BlitzError("incorrect parameters", "")
|
||||
|
||||
except Exception as e:
|
||||
handleException(e)
|
||||
|
||||
ip = sys.argv[2]
|
||||
try:
|
||||
|
||||
domain = getDomainByIP(ip)
|
||||
@@ -540,19 +569,18 @@ if sys.argv[1] == "subscription-cancel":
|
||||
|
||||
# check parameters
|
||||
try:
|
||||
if len(sys.argv) <= 2: raise BlitzError("incorrect parameters","")
|
||||
subscriptionID = sys.argv[2]
|
||||
if len(sys.argv) <= 2:
|
||||
raise BlitzError("incorrect parameters", "")
|
||||
except Exception as e:
|
||||
handleException(e)
|
||||
|
||||
subscriptionID = sys.argv[2]
|
||||
try:
|
||||
|
||||
subscriptionsCancel(subscriptionID)
|
||||
|
||||
except Exception as e:
|
||||
handleException(e)
|
||||
|
||||
sys.exit(0)
|
||||
|
||||
# unkown command
|
||||
print("# unkown command")
|
||||
# unknown command
|
||||
print("# unknown command")
|
||||
|
@@ -4,16 +4,15 @@
|
||||
# SSH Dialogs to manage Subscriptions on the RaspiBlitz
|
||||
########################################################
|
||||
|
||||
import sys
|
||||
import math
|
||||
import time
|
||||
import toml
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
import time
|
||||
from datetime import datetime
|
||||
|
||||
from dialog import Dialog
|
||||
|
||||
import toml
|
||||
from blitzpy import RaspiBlitzConfig
|
||||
from dialog import Dialog
|
||||
|
||||
# constants for standard services
|
||||
LND_REST_API = "LND-REST-API"
|
||||
@@ -28,21 +27,28 @@ cfg.reload()
|
||||
# basic values
|
||||
SUBSCRIPTIONS_FILE = "/mnt/hdd/app-data/subscriptions/subscriptions.toml"
|
||||
|
||||
####### HELPER FUNCTIONS #########
|
||||
|
||||
#######################
|
||||
# HELPER FUNCTIONS
|
||||
#######################
|
||||
|
||||
def eprint(*args, **kwargs):
|
||||
print(*args, file=sys.stderr, **kwargs)
|
||||
|
||||
|
||||
def parseDateIP2TORSERVER(datestr):
|
||||
return datetime.datetime.strptime(datestr,"%Y-%m-%dT%H:%M:%S.%fZ")
|
||||
return datetime.strptime(datestr, "%Y-%m-%dT%H:%M:%S.%fZ")
|
||||
|
||||
|
||||
def secondsLeft(dateObj):
|
||||
return round((dateObj - datetime.datetime.utcnow()).total_seconds())
|
||||
return round((dateObj - datetime.utcnow()).total_seconds())
|
||||
|
||||
####### SSH MENU FUNCTIONS #########
|
||||
|
||||
#######################
|
||||
# SSH MENU FUNCTIONS
|
||||
#######################
|
||||
|
||||
def mySubscriptions():
|
||||
|
||||
# check if any subscriptions are available
|
||||
countSubscriptions = 0
|
||||
try:
|
||||
@@ -52,7 +58,8 @@ def mySubscriptions():
|
||||
countSubscriptions += len(subs['subscriptions_ip2tor'])
|
||||
if 'subscriptions_letsencrypt' in subs:
|
||||
countSubscriptions += len(subs['subscriptions_letsencrypt'])
|
||||
except Exception as e: pass
|
||||
except Exception as e:
|
||||
pass
|
||||
if countSubscriptions == 0:
|
||||
Dialog(dialog="dialog", autowidgetsize=True).msgbox('''
|
||||
You have no active or inactive subscriptions.
|
||||
@@ -101,7 +108,8 @@ You have no active or inactive subscriptions.
|
||||
choices=choices, cancel_label="Back", width=65, height=15, title="My Subscriptions")
|
||||
|
||||
# if user chosses CANCEL
|
||||
if code != d.OK: return
|
||||
if code != d.OK:
|
||||
return
|
||||
|
||||
# get data of selected subscrption
|
||||
selectedSub = lookup[str(tag)]
|
||||
@@ -165,24 +173,30 @@ The following additional information is available:
|
||||
description=selectedSub['description'],
|
||||
service=selectedSub['name']
|
||||
)
|
||||
else:
|
||||
text = "no text?! FIXME"
|
||||
|
||||
if selectedSub['active']:
|
||||
extraLable = "CANCEL SUBSCRIPTION"
|
||||
else:
|
||||
extraLable = "DELETE SUBSCRIPTION"
|
||||
code = d.msgbox(text, title="Subscription Detail", ok_label="Back", extra_button=True, extra_label=extraLable ,width=75, height=30)
|
||||
code = d.msgbox(text, title="Subscription Detail", ok_label="Back", extra_button=True, extra_label=extraLable,
|
||||
width=75, height=30)
|
||||
|
||||
# user wants to delete this subscription
|
||||
# call the responsible sub script for deletion just in case any subscription needs to do some extra api calls when canceling
|
||||
# call the responsible sub script for deletion just in case any subscription needs to do some extra
|
||||
# api calls when canceling
|
||||
if code == "extra":
|
||||
os.system("clear")
|
||||
if selectedSub['type'] == "letsencrypt-v1":
|
||||
cmd="python /home/admin/config.scripts/blitz.subscriptions.letsencrypt.py subscription-cancel {0}".format(selectedSub['id'])
|
||||
cmd = "python /home/admin/config.scripts/blitz.subscriptions.letsencrypt.py subscription-cancel {0}".format(
|
||||
selectedSub['id'])
|
||||
print("# running: {0}".format(cmd))
|
||||
os.system(cmd)
|
||||
time.sleep(2)
|
||||
elif selectedSub['type'] == "ip2tor-v1":
|
||||
cmd="python /home/admin/config.scripts/blitz.subscriptions.ip2tor.py subscription-cancel {0}".format(selectedSub['id'])
|
||||
cmd = "python /home/admin/config.scripts/blitz.subscriptions.ip2tor.py subscription-cancel {0}".format(
|
||||
selectedSub['id'])
|
||||
print("# running: {0}".format(cmd))
|
||||
os.system(cmd)
|
||||
time.sleep(2)
|
||||
@@ -193,9 +207,12 @@ The following additional information is available:
|
||||
# loop until no more subscriptions or user chooses CANCEL on subscription list
|
||||
mySubscriptions()
|
||||
|
||||
####### SSH MENU #########
|
||||
|
||||
choices = []
|
||||
#######################
|
||||
# SSH MENU
|
||||
#######################
|
||||
|
||||
choices = list()
|
||||
choices.append(("LIST", "My Subscriptions"))
|
||||
choices.append(("NEW1", "+ IP2TOR Bridge (paid)"))
|
||||
choices.append(("NEW2", "+ LetsEncrypt HTTPS Domain (free)"))
|
||||
@@ -210,16 +227,19 @@ code, tag = d.menu(
|
||||
if code != d.OK:
|
||||
sys.exit(0)
|
||||
|
||||
####### MANAGE SUBSCRIPTIONS #########
|
||||
#######################
|
||||
# MANAGE SUBSCRIPTIONS
|
||||
#######################
|
||||
|
||||
if tag == "LIST":
|
||||
mySubscriptions()
|
||||
sys.exit(0)
|
||||
|
||||
####### NEW LETSENCRYPT HTTPS DOMAIN #########
|
||||
###############################
|
||||
# NEW LETSENCRYPT HTTPS DOMAIN
|
||||
###############################
|
||||
|
||||
if tag == "NEW2":
|
||||
|
||||
# run creating a new IP2TOR subscription
|
||||
os.system("clear")
|
||||
cmd = "python /home/admin/config.scripts/blitz.subscriptions.letsencrypt.py create-ssh-dialog"
|
||||
@@ -227,7 +247,10 @@ if tag == "NEW2":
|
||||
os.system(cmd)
|
||||
sys.exit(0)
|
||||
|
||||
####### NEW IP2TOR BRIDGE #########
|
||||
###############################
|
||||
# NEW IP2TOR BRIDGE
|
||||
###############################
|
||||
|
||||
|
||||
if tag == "NEW1":
|
||||
|
||||
@@ -253,22 +276,28 @@ your RaspiBlitz behind TOR.
|
||||
os.system("sudo chown admin:admin {0}".format(SUBSCRIPTIONS_FILE))
|
||||
subs = toml.load(SUBSCRIPTIONS_FILE)
|
||||
for sub in subs['subscriptions_ip2tor']:
|
||||
if not sub['active']: next
|
||||
if sub['active'] and sub['name'] == LND_REST_API: lnd_rest_api=True
|
||||
if sub['active'] and sub['name'] == LND_GRPC_API: lnd_grpc_api=True
|
||||
if sub['active'] and sub['name'] == LNBITS: lnbits=True
|
||||
if sub['active'] and sub['name'] == BTCPAY: btcpay=True
|
||||
if not sub['active']:
|
||||
continue
|
||||
if sub['active'] and sub['name'] == LND_REST_API:
|
||||
lnd_rest_api = True
|
||||
if sub['active'] and sub['name'] == LND_GRPC_API:
|
||||
lnd_grpc_api = True
|
||||
if sub['active'] and sub['name'] == LNBITS:
|
||||
lnbits = True
|
||||
if sub['active'] and sub['name'] == BTCPAY:
|
||||
btcpay = True
|
||||
except Exception as e:
|
||||
print(e)
|
||||
|
||||
# check if BTCPayserver is installed
|
||||
btcPayServer = False
|
||||
statusData= subprocess.run(['/home/admin/config.scripts/bonus.btcpayserver.sh', 'status'], stdout=subprocess.PIPE).stdout.decode('utf-8').strip()
|
||||
statusData = subprocess.run(['/home/admin/config.scripts/bonus.btcpayserver.sh', 'status'],
|
||||
stdout=subprocess.PIPE).stdout.decode('utf-8').strip()
|
||||
if statusData.find("installed=1") > -1:
|
||||
btcPayServer = True
|
||||
|
||||
# ask user for which RaspiBlitz service the bridge should be used
|
||||
choices = []
|
||||
choices = list()
|
||||
choices.append(("REST", "LND REST API {0}".format("--> ALREADY BRIDGED" if lnd_rest_api else "")))
|
||||
choices.append(("GRPC", "LND gRPC API {0}".format("--> ALREADY BRIDGED" if lnd_grpc_api else "")))
|
||||
if cfg.lnbits:
|
||||
@@ -293,22 +322,26 @@ your RaspiBlitz behind TOR.
|
||||
if tag == "REST":
|
||||
# get TOR address for REST
|
||||
servicename = LND_REST_API
|
||||
torAddress = subprocess.run(['sudo', 'cat', '/mnt/hdd/tor/lndrest8080/hostname'], stdout=subprocess.PIPE).stdout.decode('utf-8').strip()
|
||||
torAddress = subprocess.run(['sudo', 'cat', '/mnt/hdd/tor/lndrest8080/hostname'],
|
||||
stdout=subprocess.PIPE).stdout.decode('utf-8').strip()
|
||||
torPort = 8080
|
||||
if tag == "GRPC":
|
||||
# get TOR address for GRPC
|
||||
servicename = LND_GRPC_API
|
||||
torAddress = subprocess.run(['sudo', 'cat', '/mnt/hdd/tor/lndrpc10009/hostname'], stdout=subprocess.PIPE).stdout.decode('utf-8').strip()
|
||||
torAddress = subprocess.run(['sudo', 'cat', '/mnt/hdd/tor/lndrpc10009/hostname'],
|
||||
stdout=subprocess.PIPE).stdout.decode('utf-8').strip()
|
||||
torPort = 10009
|
||||
if tag == "LNBITS":
|
||||
# get TOR address for LNBits
|
||||
servicename = LNBITS
|
||||
torAddress = subprocess.run(['sudo', 'cat', '/mnt/hdd/tor/lnbits/hostname'], stdout=subprocess.PIPE).stdout.decode('utf-8').strip()
|
||||
torAddress = subprocess.run(['sudo', 'cat', '/mnt/hdd/tor/lnbits/hostname'],
|
||||
stdout=subprocess.PIPE).stdout.decode('utf-8').strip()
|
||||
torPort = 443
|
||||
if tag == "BTCPAY":
|
||||
# get TOR address for BTCPAY
|
||||
servicename = BTCPAY
|
||||
torAddress = subprocess.run(['sudo', 'cat', '/mnt/hdd/tor/btcpay/hostname'], stdout=subprocess.PIPE).stdout.decode('utf-8').strip()
|
||||
torAddress = subprocess.run(['sudo', 'cat', '/mnt/hdd/tor/btcpay/hostname'],
|
||||
stdout=subprocess.PIPE).stdout.decode('utf-8').strip()
|
||||
torPort = 443
|
||||
if tag == "SELF":
|
||||
servicename = "CUSTOM"
|
||||
@@ -320,8 +353,10 @@ your RaspiBlitz behind TOR.
|
||||
title="IP2TOR Bridge Target")
|
||||
text = text.strip()
|
||||
os.system("clear")
|
||||
if code != d.OK: sys.exit(0)
|
||||
if len(text) == 0: sys.exit(0)
|
||||
if code != d.OK:
|
||||
sys.exit(0)
|
||||
if len(text) == 0:
|
||||
sys.exit(0)
|
||||
if text.find('.onion') < 0 or text.find(' ') > 0:
|
||||
print("Not a TOR Onion Address")
|
||||
time.sleep(3)
|
||||
@@ -334,8 +369,10 @@ your RaspiBlitz behind TOR.
|
||||
title="IP2TOR Bridge Target")
|
||||
text = text.strip()
|
||||
os.system("clear")
|
||||
if code != d.OK: sys.exit(0)
|
||||
if len(text) == 0: sys.exit(0)
|
||||
if code != d.OK:
|
||||
sys.exit(0)
|
||||
if len(text) == 0:
|
||||
sys.exit(0)
|
||||
torPort = int(text)
|
||||
except Exception as e:
|
||||
print(e)
|
||||
@@ -344,7 +381,8 @@ your RaspiBlitz behind TOR.
|
||||
|
||||
# run creating a new IP2TOR subscription
|
||||
os.system("clear")
|
||||
cmd="python /home/admin/config.scripts/blitz.subscriptions.ip2tor.py create-ssh-dialog {0} {1} {2}".format(servicename,torAddress,torPort)
|
||||
cmd = "python /home/admin/config.scripts/blitz.subscriptions.ip2tor.py create-ssh-dialog {0} {1} {2}".format(
|
||||
servicename, torAddress, torPort)
|
||||
print("# running: {0}".format(cmd))
|
||||
os.system(cmd)
|
||||
sys.exit(0)
|
Reference in New Issue
Block a user