diff --git a/home.admin/BlitzPy/CHANGELOG.md b/home.admin/BlitzPy/CHANGELOG.md index be32c0ce9..c3c2b0029 100644 --- a/home.admin/BlitzPy/CHANGELOG.md +++ b/home.admin/BlitzPy/CHANGELOG.md @@ -5,6 +5,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [0.3.0] - 2020-07-19 +### Added +- add BlitzError Class + ## [0.2.0] - 2020-05-23 ### Added - add write() to BlitzPy config Classes diff --git a/home.admin/BlitzPy/blitzpy/__init__.py b/home.admin/BlitzPy/blitzpy/__init__.py index c217ead14..2d6c6ba7a 100644 --- a/home.admin/BlitzPy/blitzpy/__init__.py +++ b/home.admin/BlitzPy/blitzpy/__init__.py @@ -1,8 +1,10 @@ -# -*- coding: utf-8 -*- - -from .config import RaspiBlitzConfig, RaspiBlitzInfo - -__all__ = [ - 'RaspiBlitzConfig', - 'RaspiBlitzInfo', -] +# -*- coding: utf-8 -*- + +from .config import RaspiBlitzConfig, RaspiBlitzInfo +from .exceptions import BlitzError + +__all__ = [ + 'RaspiBlitzConfig', + 'RaspiBlitzInfo', + 'BlitzError' +] diff --git a/home.admin/BlitzPy/blitzpy/exceptions.py b/home.admin/BlitzPy/blitzpy/exceptions.py new file mode 100644 index 000000000..2289dc04f --- /dev/null +++ b/home.admin/BlitzPy/blitzpy/exceptions.py @@ -0,0 +1,16 @@ +from datetime import datetime + +TS_FORMAT = "%Y-%m-%dT%H:%M:%SZ" + + +class BlitzError(Exception): + def __init__(self, short: str, details: dict = None, org: Exception = None): + self.short: str = str(short) + if details: + self.details: dict = details + self.details.update({'timestamp': datetime.utcnow().strftime(TS_FORMAT)}) + else: + self.details = dict() + self.details['timestamp'] = datetime.utcnow().strftime(TS_FORMAT) + + self.org: Exception = org diff --git a/home.admin/BlitzPy/blitzpy/version.py b/home.admin/BlitzPy/blitzpy/version.py index f2d8494e5..bb6b41a2d 100644 --- a/home.admin/BlitzPy/blitzpy/version.py +++ b/home.admin/BlitzPy/blitzpy/version.py @@ -4,5 +4,5 @@ # 3) we can import it into your module module """ -__version_info__ = ('0', '2', '0') +__version_info__ = ('0', '3', '0') __version__ = '.'.join(__version_info__) diff --git a/home.admin/BlitzPy/dist/BlitzPy-0.3.0-py2.py3-none-any.whl b/home.admin/BlitzPy/dist/BlitzPy-0.3.0-py2.py3-none-any.whl new file mode 100644 index 000000000..504e533a3 Binary files /dev/null and b/home.admin/BlitzPy/dist/BlitzPy-0.3.0-py2.py3-none-any.whl differ diff --git a/home.admin/BlitzPy/dist/BlitzPy-0.3.0.tar.gz b/home.admin/BlitzPy/dist/BlitzPy-0.3.0.tar.gz new file mode 100644 index 000000000..a8955b48d Binary files /dev/null and b/home.admin/BlitzPy/dist/BlitzPy-0.3.0.tar.gz differ diff --git a/home.admin/config.scripts/blitz.subscriptions.ip2tor.py b/home.admin/config.scripts/blitz.subscriptions.ip2tor.py index 8cbd64543..1fa76ed4f 100644 --- a/home.admin/config.scripts/blitz.subscriptions.ip2tor.py +++ b/home.admin/config.scripts/blitz.subscriptions.ip2tor.py @@ -1,6 +1,5 @@ #!/usr/bin/python3 -import ast import codecs import json import math @@ -13,7 +12,7 @@ from pathlib import Path import grpc import requests import toml -from blitzpy import RaspiBlitzConfig +from blitzpy import RaspiBlitzConfig, BlitzError from lndlibs import rpc_pb2 as lnrpc from lndlibs import rpc_pb2_grpc as rpcstub @@ -35,6 +34,12 @@ 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) +# constants for standard services +SERVICE_LND_REST_API = "LND-REST-API" +SERVICE_LND_GRPC_API = "LND-GRPC-API" +SERVICE_LNBITS = "LNBITS" +SERVICE_BTCPAY = "BTCPAY" + ##################### # BASIC SETTINGS ##################### @@ -70,17 +75,6 @@ else: is_testnet = False -##################### -# HELPER CLASSES -##################### - -class BlitzError(Exception): - def __init__(self, errorShort, errorLong="", errorException=None): - self.errorShort = str(errorShort) - self.errorLong = str(errorLong) - self.errorException = errorException - - ##################### # HELPER FUNCTIONS ##################### @@ -91,9 +85,9 @@ def eprint(*args, **kwargs): def handleException(e): if isinstance(e, BlitzError): - eprint(e.errorLong) - eprint(e.errorException) - print("error='{0}'".format(e.errorShort)) + eprint(e.details) + eprint(e.org) + print("error='{0}'".format(e.short)) else: eprint(e) print("error='{0}'".format(str(e))) @@ -150,17 +144,17 @@ def apiGetHosts(session, shopurl): try: response = session.get(url) except Exception as e: - raise BlitzError("failed HTTP request", url, e) + raise BlitzError("failed HTTP request", {'url': url}, e) if response.status_code != 200: - raise BlitzError("failed HTTP code", response.status_code, ) + raise BlitzError("failed HTTP code", {'status_code': response.status_code}) # parse & validate data try: jData = json.loads(response.content) except Exception as e: - raise BlitzError("failed JSON parsing", response.content, e) + raise BlitzError("failed JSON parsing", {'content': response.content}, e) if not isinstance(jData, list): - raise BlitzError("hosts not list", response.content) + raise BlitzError("hosts not list", {'content': response.content}) for idx, hostEntry in enumerate(jData): try: # ignore if not offering tor bridge @@ -188,7 +182,7 @@ def apiGetHosts(session, shopurl): # shorten names to 20 chars max hostEntry['name'] = hostEntry['name'][:20] except Exception as e: - raise BlitzError("failed host entry pasring", str(hostEntry), e) + raise BlitzError("failed host entry pasring", hostEntry, e) hosts.append(hostEntry) @@ -211,11 +205,11 @@ def apiPlaceOrderNew(session, shopurl, hostid, toraddressWithPort): try: response = session.post(url, data=postData) except Exception as e: - raise BlitzError("failed HTTP request", url, e) + raise BlitzError("failed HTTP request", {'url': url}, e) if response.status_code == 420: - raise BlitzError("forwarding this address was rejected", response.status_code) + raise BlitzError("forwarding this address was rejected", {'status_code': response.status_code}) if response.status_code != 201: - raise BlitzError("failed HTTP code", response.status_code) + raise BlitzError("failed HTTP code", {'status_code': response.status_code}) # parse & validate data try: @@ -224,7 +218,7 @@ def apiPlaceOrderNew(session, shopurl, hostid, toraddressWithPort): print("error='MISSING ID'") return except Exception as e: - raise BlitzError("failed JSON parsing", response.status_code, e) + raise BlitzError("failed JSON parsing", {'status_code': response.status_code}, e) return jData['id'] @@ -236,11 +230,11 @@ def apiPlaceOrderExtension(session, shopurl, bridgeid): try: response = session.post(url) except Exception as e: - raise BlitzError("failed HTTP request", url, e) + raise BlitzError("failed HTTP request", {'url': url}, e) if response.status_code == 420: - raise BlitzError("forwarding this address was rejected", response.status_code) + raise BlitzError("forwarding this address was rejected", {'status_code': response.status_code}) if response.status_code != 200 and response.status_code != 201: - raise BlitzError("failed HTTP code", response.status_code) + raise BlitzError("failed HTTP code", {'status_code': response.status_code}) # parse & validate data print("# parse") @@ -250,12 +244,12 @@ def apiPlaceOrderExtension(session, shopurl, bridgeid): print("error='MISSING ID'") return except Exception as e: - raise BlitzError("failed JSON parsing", response.content, e) + raise BlitzError("failed JSON parsing", {'content': response.content}, e) return jData['po_id'] -def apiGetOrder(session, shopurl, orderid): +def apiGetOrder(session, shopurl, orderid) -> dict: print("# apiGetOrder") # make HTTP request @@ -263,19 +257,19 @@ def apiGetOrder(session, shopurl, orderid): try: response = session.get(url) except Exception as e: - raise BlitzError("failed HTTP request", url, e) + raise BlitzError("failed HTTP request", {'url': url}, e) if response.status_code != 200: - raise BlitzError("failed HTTP code", response.status_code) + raise BlitzError("failed HTTP code", {'status_code': response.status_code}) # parse & validate data try: jData = json.loads(response.content) if len(jData['item_details']) == 0: - raise BlitzError("missing item", response.content) + raise BlitzError("missing item", {'content': response.content}) if len(jData['ln_invoices']) > 1: - raise BlitzError("more than one invoice", response.content) + raise BlitzError("more than one invoice", {'content': response.content}) except Exception as e: - raise BlitzError("failed JSON parsing", response.content, e) + raise BlitzError("failed JSON parsing", {'content': response.content}, e) return jData @@ -288,16 +282,16 @@ def apiGetBridgeStatus(session, shopurl, bridgeid): try: response = session.get(url) except Exception as e: - raise BlitzError("failed HTTP request", url, e) + raise BlitzError("failed HTTP request", {'url': url}, e) if response.status_code != 200: - raise BlitzError("failed HTTP code", response.status_code) + raise BlitzError("failed HTTP code", {'status_code': response.status_code}) # parse & validate data try: jData = json.loads(response.content) if len(jData['id']) == 0: - raise BlitzError("missing id", response.content) + raise BlitzError("missing id", {'content': response.content}) except Exception as e: - raise BlitzError("failed JSON parsing", response.content, e) + raise BlitzError("failed JSON parsing", {'content': response.content}, e) return jData @@ -322,10 +316,10 @@ def lndDecodeInvoice(lnInvoiceString): # validate results if response.num_msat <= 0: - raise BlitzError("zero invoice not allowed", lnInvoiceString) + raise BlitzError("zero invoice not allowed", {'invoice': lnInvoiceString}) except Exception as e: - raise BlitzError("failed LND invoice decoding", lnInvoiceString, e) + raise BlitzError("failed LND invoice decoding", {'invoice': lnInvoiceString}, e) return response @@ -346,10 +340,10 @@ def lndPayInvoice(lnInvoiceString): # validate results if len(response.payment_error) > 0: - raise BlitzError(response.payment_error, lnInvoiceString) + raise BlitzError(response.payment_error, {'invoice': lnInvoiceString}) except Exception as e: - raise BlitzError("payment failed", lnInvoiceString, e) + raise BlitzError("payment failed", {'invoice': lnInvoiceString}, e) return response @@ -480,7 +474,7 @@ def shopOrder(shopUrl, hostid, servicename, torTarget, duration, msatsFirst, msa except Exception as e: eprint(e) - raise BlitzError("fail on subscription storage", str(subscription), e) + raise BlitzError("fail on subscription storage", subscription, e) print("# OK - BRIDGE READY: {0}:{1} -> {2}".format(bridge_ip, bridge_port, torTarget)) return subscription @@ -578,7 +572,7 @@ def subscriptionExtend(shopUrl, bridgeid, durationAdvertised, msatsNext, bridge_ except Exception as e: eprint(e) - raise BlitzError("fail on subscription storage", "", e) + raise BlitzError("fail on subscription storage", org=e) print("# BRIDGE GOT EXTENDED: {0} -> {1}".format(bridge_suspendafter, bridge['suspend_after'])) @@ -664,7 +658,8 @@ Try again later, enter another address or cancel. choices=choices, title="Available Subscriptions") # if user cancels - if code != d.OK: sys.exit(0) + if code != d.OK: + sys.exit(0) # get data of selected seletedIndex = int(tag) @@ -712,7 +707,8 @@ More information on the service you can find under: height=30) # if user AGREED break loop and continue with selected host - if code == "extra": break + if code == "extra": + break ############################ # PHASE 3: Make Subscription @@ -729,16 +725,15 @@ More information on the service you can find under: exitcode = 0 - order = ast.literal_eval(be.errorLong) - try : - message = order['message'] - except Exception as e: - message = "n/a" + try: + message = be.details['message'] + except KeyError: + message = "" - if (be.errorShort == "timeout on waiting for extending bridge" or - be.errorShort == "fail on subscription storage" or - be.errorShort == "invalid port" or - be.errorShort == "timeout bridge not getting ready"): + if (be.short == "timeout on waiting for extending bridge" or + be.short == "fail on subscription storage" or + be.short == "invalid port" or + be.short == "timeout bridge not getting ready"): # error happened after payment exitcode = Dialog(dialog="dialog", autowidgetsize=True).msgbox(''' @@ -748,7 +743,7 @@ Subscription will be ignored. Error: {0} Message: {1} - '''.format(be.errorShort, message), title="Error on Subscription", extra_button=True, extra_label="Details") + '''.format(be.short, message), title="Error on Subscription", extra_button=True, extra_label="Details") else: # error happened before payment @@ -759,7 +754,7 @@ Subscription will be ignored. Error: {0} Message: {1} - '''.format(be.errorShort, message), title="Error on Subscription", extra_button=True, extra_label="Details") + '''.format(be.short, message), title="Error on Subscription", extra_button=True, extra_label="Details") # show more details (when user used extra button) if exitcode == Dialog.EXTRA: @@ -767,13 +762,13 @@ Message: {1} print('###### ERROR DETAIL FOR DEBUG #######') print("") print("Error Short:") - print(be.errorShort) + print(be.short) print('Shop:') print(shopurl) print('Bridge:') print(str(host)) print("Error Detail:") - print(be.errorLong) + print(be.details) print("") input("Press Enter to continue ...") @@ -796,7 +791,7 @@ Message: {1} sys.exit(1) # if LND REST or LND GRPC service ... add bridge IP to TLS - if servicename == "LND-REST-API" or servicename == "LND-GRPC-API": + if blitzServiceName == SERVICE_LND_REST_API or blitzServiceName == SERVICE_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") os.system("sudo /home/admin/config.scripts/lnd.credentials.sh sync") @@ -811,7 +806,7 @@ You may want to consider to cancel the subscription later. # decide if https:// address protocol = "" - if blitzServiceName == "LNBITS": + if blitzServiceName == SERVICE_LNBITS: protocol = "https://" # Give final result feedback to user @@ -847,13 +842,11 @@ MAIN MENU > Manage Subscriptions > My Subscriptions # CREATE SSH DIALOG # use for ssh shell menu ############### - -if sys.argv[1] == "create-ssh-dialog": - +def create_ssh_dialog(): # check parameters try: if len(sys.argv) <= 4: - raise BlitzError("incorrect parameters", "") + raise BlitzError("incorrect parameters") except Exception as e: handleException(e) @@ -865,17 +858,16 @@ if sys.argv[1] == "create-ssh-dialog": sys.exit() + ############### # SHOP LIST # call from web interface ############### - -if sys.argv[1] == "shop-list": - +def shop_list(): # check parameters try: if len(sys.argv) <= 2: - raise BlitzError("incorrect parameters", "") + raise BlitzError("incorrect parameters") except Exception as e: handleException(e) @@ -891,17 +883,16 @@ if sys.argv[1] == "shop-list": sys.exit(0) + ########################## # SHOP ORDER # call from web interface ########################## - -if sys.argv[1] == "shop-order": - +def shop_order(): # check parameters try: if len(sys.argv) <= 8: - raise BlitzError("incorrect parameters", "") + raise BlitzError("incorrect parameters") except Exception as e: handleException(e) @@ -926,13 +917,12 @@ if sys.argv[1] == "shop-order": except Exception as e: handleException(e) + ####################### # SUBSCRIPTIONS LIST # call in intervals from background process ####################### - -if sys.argv[1] == "subscriptions-list": - +def subscriptions_list(): try: if Path(SUBSCRIPTIONS_FILE).is_file(): @@ -947,15 +937,12 @@ if sys.argv[1] == "subscriptions-list": except Exception as e: handleException(e) - sys.exit(0) ####################### # SUBSCRIPTIONS RENEW # call in intervals from background process ####################### - -if sys.argv[1] == "subscriptions-renew": - +def subscriptions_renew(): print("# RUNNING subscriptions-renew") # check parameters @@ -1002,16 +989,16 @@ if sys.argv[1] == "subscriptions-renew": subs = toml.load(SUBSCRIPTIONS_FILE) 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": + sub['warning'] = "Exception on Renew: {0}".format(be.short) + if be.short == "invoice bigger amount than advertised": sub['contract_breached'] = True sub['active'] = False with open(SUBSCRIPTIONS_FILE, 'w') as writer: writer.write(toml.dumps(subs)) writer.close() break - print("# BLITZERROR on subscriptions-renew of subscription index {0}: {1}".format(idx, be.errorShort)) - print("# {0}".format(be.errorShort)) + print("# BLITZERROR on subscriptions-renew of subscription index {0}: {1}".format(idx, be.short)) + print("# {0}".format(be.short)) except Exception as e: print("# EXCEPTION on subscriptions-renew of subscription index {0}".format(idx)) @@ -1022,18 +1009,17 @@ if sys.argv[1] == "subscriptions-renew": # output - not needed only for debug logs print("# DONE subscriptions-renew") - sys.exit(1) + ####################### # SUBSCRIPTION CANCEL -# call in intervalls from background process +# call in intervals from background process ####################### -if sys.argv[1] == "subscription-cancel": - +def subscription_cancel(): # check parameters try: if len(sys.argv) <= 2: - raise BlitzError("incorrect parameters", "") + raise BlitzError("incorrect parameters") except Exception as e: handleException(e) @@ -1058,30 +1044,28 @@ if sys.argv[1] == "subscription-cancel": except Exception as e: handleException(e) - sys.exit(0) ####################### -# GET ADDRESS BY SERVICENAME +# GET ADDRESS BY SERVICE NAME # gets called by other scripts to check if service has a ip2tor bridge address # output is bash key/value style so that it can be imported with source ####################### -if sys.argv[1] == "subscription-by-service": - +def subscription_by_service(): # check parameters try: if len(sys.argv) <= 2: - raise BlitzError("incorrect parameters", "") + raise BlitzError("incorrect parameters") except Exception as e: handleException(e) - servicename = sys.argv[2] + service_name = sys.argv[2] try: if os.path.isfile(SUBSCRIPTIONS_FILE): os.system("sudo chown admin:admin {0}".format(SUBSCRIPTIONS_FILE)) subs = toml.load(SUBSCRIPTIONS_FILE) for idx, sub in enumerate(subs['subscriptions_ip2tor']): - if sub['active'] and sub['name'] == servicename: + if sub['active'] and sub['name'] == service_name: print("type='{0}'".format(sub['type'])) print("ip='{0}'".format(sub['ip'])) print("port='{0}'".format(sub['port'])) @@ -1089,24 +1073,22 @@ if sys.argv[1] == "subscription-by-service": sys.exit(0) print("error='not found'") - sys.exit(0) except Exception as e: handleException(e) + sys.exit(1) - sys.exit(1) ####################### -# GET IP BY ONIONADDRESS +# GET IP BY ONION ADDRESS # gets called by other scripts to check if a onion address as a IP2TOR bridge # output is bash key/value style so that it can be imported with source ####################### -if sys.argv[1] == "ip-by-tor": - +def ip_by_tor(): # check parameters try: if len(sys.argv) <= 2: - raise BlitzError("incorrect parameters", "") + raise BlitzError("incorrect parameters") except Exception as e: handleException(e) @@ -1126,12 +1108,41 @@ if sys.argv[1] == "ip-by-tor": sys.exit(0) print("error='not found'") - sys.exit(0) except Exception as e: handleException(e) + sys.exit(1) - sys.exit(1) -# unknown command -print("# unknown command") +def main(): + if sys.argv[1] == "create-ssh-dialog": + create_ssh_dialog() + + elif sys.argv[1] == "shop-list": + shop_list() + + elif sys.argv[1] == "shop-order": + shop_order() + + elif sys.argv[1] == "subscriptions-list": + subscriptions_list() + + elif sys.argv[1] == "subscriptions-renew": + subscriptions_renew() + + elif sys.argv[1] == "subscription-cancel": + subscription_cancel() + + elif sys.argv[1] == "subscription-by-service": + subscription_by_service() + + elif sys.argv[1] == "ip-by-tor": + ip_by_tor() + + else: + # unknown command + print("# unknown command") + + +if __name__ == '__main__': + main() diff --git a/home.admin/config.scripts/blitz.subscriptions.letsencrypt.py b/home.admin/config.scripts/blitz.subscriptions.letsencrypt.py index ea8657d5a..80d49b50c 100644 --- a/home.admin/config.scripts/blitz.subscriptions.letsencrypt.py +++ b/home.admin/config.scripts/blitz.subscriptions.letsencrypt.py @@ -10,7 +10,7 @@ from pathlib import Path import requests import toml -from blitzpy import RaspiBlitzConfig +from blitzpy import RaspiBlitzConfig,BlitzError ##################### # SCRIPT INFO @@ -30,6 +30,12 @@ if len(sys.argv) <= 1 or sys.argv[1] == "-h" or sys.argv[1] == "help": print("# blitz.subscriptions.ip2tor.py subscription-cancel ") sys.exit(1) +# constants for standard services +SERVICE_LND_REST_API = "LND-REST-API" +SERVICE_LND_GRPC_API = "LND-GRPC-API" +SERVICE_LNBITS = "LNBITS" +SERVICE_BTCPAY = "BTCPAY" + ##################### # BASIC SETTINGS ##################### @@ -49,6 +55,7 @@ if cfg.run_behind_tor: # HELPER CLASSES ##################### +# ToDo(frennkie) replace this with updated BlitzError from blitzpy class BlitzError(Exception): def __init__(self, errorShort, errorLong="", errorException=None): self.errorShort = str(errorShort) @@ -75,19 +82,19 @@ def handleException(e): sys.exit(1) -def getsubdomain(fulldomainstring): - return fulldomainstring.split('.')[0] +def get_subdomain(fulldomain_str): + return fulldomain_str.split('.')[0] ############################ -# API Calls to DNS Servcies +# API Calls to DNS Services ############################ -def duckDNSupdate(domain, token, ip): +def duckdns_update(domain, token, ip): print("# duckDNS update IP API call for {0}".format(domain)) # make HTTP request - url = "https://www.duckdns.org/update?domains={0}&token={1}&ip={2}".format(getsubdomain(domain), token, ip) + url = "https://www.duckdns.org/update?domains={0}&token={1}&ip={2}".format(get_subdomain(domain), token, ip) try: response = session.get(url) if response.status_code != 200: @@ -102,31 +109,33 @@ def duckDNSupdate(domain, token, ip): # PROCESS FUNCTIONS ##################### -def subscriptionsNew(ip, dnsservice, id, token, target): - # id needs to the full domain name +def subscriptions_new(ip, dnsservice, id, token, target): + # id needs to be the full domain name if id.find(".") == -1: - raise BlitzError("not a fully qualified domainname", dnsservice_id) + # ToDo(frennkie) dnsservice_id doesn't exit + raise BlitzError("not a fully qualified domain name", dnsservice_id) # check if id already exists - if len(getSubscription(id)) > 0: + if len(get_subscription(id)) > 0: raise BlitzError("id already exists", id) # make sure lets encrypt client is installed os.system("/home/admin/config.scripts/bonus.letsencrypt.sh on") # dyndns - realip = ip + real_ip = ip if ip == "dyndns": - updateURL = "" + update_url = "" 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], + # ToDo(frennkie) domain doesn't exit + update_url = "https://www.duckdns.org/update?domains={0}&token={1}".format(get_subdomain(domain), token, ip) + subprocess.run(['/home/admin/config.scriprs/internet.dyndomain.sh', 'on', id, update_url], stdout=subprocess.PIPE).stdout.decode('utf-8').strip() - realip = cfg.public_ip + real_ip = cfg.public_ip # update DNS with actual IP if dnsservice == "duckdns": - duckDNSupdate(getsubdomain(id), token, realip) + duckdns_update(get_subdomain(id), token, real_ip) # create subscription data for storage subscription = dict() @@ -164,10 +173,10 @@ def subscriptionsNew(ip, dnsservice, id, token, target): # run the ACME script print("# Running letsencrypt ACME script ...") - acmeResult = subprocess.Popen( + acme_result = 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() + out, err = acme_result.communicate() eprint(str(out)) eprint(str(err)) if out.find("error=") > -1: @@ -178,26 +187,24 @@ def subscriptionsNew(ip, dnsservice, id, token, target): return subscription -def subscriptionsCancel(id): - # ToDo(frennkie) id is not used.. - +def subscriptions_cancel(s_id): os.system("sudo chown admin:admin {0}".format(SUBSCRIPTIONS_FILE)) subs = toml.load(SUBSCRIPTIONS_FILE) - newList = [] - removedCert = None + new_list = [] + removed_cert = None for idx, sub in enumerate(subs['subscriptions_letsencrypt']): - if sub['id'] != subscriptionID: - newList.append(sub) + if sub['id'] != s_id: + new_list.append(sub) else: - removedCert = sub - subs['subscriptions_letsencrypt'] = newList + removed_cert = sub + subs['subscriptions_letsencrypt'] = new_list # 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') - out, err = acmeResult.communicate() + if removed_cert: + acme_result = subprocess.Popen( + ["/home/admin/config.scripts/bonus.letsencrypt.sh", "remove-cert", removed_cert['id'], + removed_cert['target']], stdout=subprocess.PIPE, stderr=subprocess.STDOUT, encoding='utf8') + out, err = acme_result.communicate() if out.find("error=") > -1: time.sleep(6) raise BlitzError("letsencrypt acme failed", out) @@ -212,7 +219,7 @@ def subscriptionsCancel(id): # todo: deinstall letsencrypt if this was last subscription -def getSubscription(subscriptionID): +def get_subscription(subscription_id): try: if Path(SUBSCRIPTIONS_FILE).is_file(): @@ -223,7 +230,7 @@ def getSubscription(subscriptionID): if "subscriptions_letsencrypt" not in subs: return [] for idx, sub in enumerate(subs['subscriptions_letsencrypt']): - if sub['id'] == subscriptionID: + if sub['id'] == subscription_id: return sub return [] @@ -231,7 +238,7 @@ def getSubscription(subscriptionID): return [] -def getDomainByIP(ip): +def get_domain_by_ip(ip): # does subscriptin file exists if Path(SUBSCRIPTIONS_FILE).is_file(): os.system("sudo chown admin:admin {0}".format(SUBSCRIPTIONS_FILE)) @@ -253,7 +260,7 @@ def getDomainByIP(ip): raise BlitzError("no match") -def menuMakeSubscription(): +def menu_make_subscription(): # late imports - so that rest of script can run also if dependency is not available from dialog import Dialog @@ -299,7 +306,7 @@ If you havent already go to https://duckdns.org title="DuckDNS Domain") subdomain = text.strip() subdomain = subdomain.split(' ')[0] - subdomain = getsubdomain(subdomain) + subdomain = get_subdomain(subdomain) domain = "{0}.duckdns.org".format(subdomain) os.system("clear") @@ -326,7 +333,7 @@ This looks not like a valid subdomain. if len(token) < 20: Dialog(dialog="dialog", autowidgetsize=True).msgbox(''' This looks not like a valid token. - ''', title="Unvalid Input") + ''', title="Invalid Input") sys.exit(0) else: @@ -350,7 +357,7 @@ This looks not like a valid token. "\nChoose the kind of IP you want to use:", choices=choices, width=60, height=10, title="Select Service") - # if user chosses CANCEL + # if user chooses CANCEL os.system("clear") if code != d.OK: sys.exit(0) @@ -362,16 +369,16 @@ This looks not like a valid token. if tag == "IP2TOR": # get all active IP2TOR subscriptions (just in case) - ip2torSubs = [] + ip2tor_subs = [] if Path(SUBSCRIPTIONS_FILE).is_file(): os.system("sudo chown admin:admin {0}".format(SUBSCRIPTIONS_FILE)) subs = toml.load(SUBSCRIPTIONS_FILE) for idx, sub in enumerate(subs['subscriptions_ip2tor']): if sub['active']: - ip2torSubs.append(sub) + ip2tor_subs.append(sub) # when user has no IP2TOR subs yet - if len(ip2torSubs) == 0: + if len(ip2tor_subs) == 0: Dialog(dialog="dialog", autowidgetsize=True).msgbox(''' You have no active IP2TOR subscriptions. Create one first and try again. @@ -380,7 +387,7 @@ Create one first and try again. # let user select a IP2TOR subscription choices = [] - for idx, sub in enumerate(ip2torSubs): + for idx, sub in enumerate(ip2tor_subs): choices.append(("{0}".format(idx), "IP2TOR {0} {1}:{2}".format(sub['name'], sub['ip'], sub['port']))) d = Dialog(dialog="dialog", autowidgetsize=True) @@ -394,8 +401,8 @@ Create one first and try again. sys.exit(0) # get the slected IP2TOR bridge - ip2torSelect = ip2torSubs[int(tag)] - ip = ip2torSelect["ip"] + ip2tor_select = ip2tor_subs[int(tag)] + ip = ip2tor_select["ip"] target = "tor" elif tag == "DYNDNS": @@ -421,13 +428,13 @@ Create one first and try again. if len(ip) == 0: Dialog(dialog="dialog", autowidgetsize=True).msgbox(''' This looks not like a valid IP. - ''', title="Unvalid Input") + ''', title="Invalid Input") sys.exit(0) # create the letsencrypt subscription try: os.system("clear") - subscription = subscriptionsNew(ip, dnsservice, domain, token, target) + subscription = subscriptions_new(ip, dnsservice, domain, token, target) # success dialog Dialog(dialog="dialog", autowidgetsize=True).msgbox(''' @@ -455,19 +462,15 @@ Unknown Error happened - please report to developers: # CREATE SSH DIALOG # use for ssh shell menu ############### +def create_ssh_dialog(): + menu_make_subscription() -if sys.argv[1] == "create-ssh-dialog": - menuMakeSubscription() - - sys.exit() ########################## # SUBSCRIPTIONS NEW # call from web interface ########################## - -if sys.argv[1] == "subscription-new": - +def subscription_new(): # check parameters try: if len(sys.argv) <= 5: @@ -486,7 +489,7 @@ if sys.argv[1] == "subscription-new": # create the subscription try: - subscription = subscriptionsNew(ip, dnsservice_type, dnsservice_id, dnsservice_token, target) + subscription = subscriptions_new(ip, dnsservice_type, dnsservice_id, dnsservice_token, target) # output json ordered bridge print(json.dumps(subscription, indent=2)) @@ -495,12 +498,11 @@ if sys.argv[1] == "subscription-new": except Exception as e: handleException(e) + ####################### # SUBSCRIPTIONS LIST ####################### - -if sys.argv[1] == "subscriptions-list": - +def subscriptions_list(): try: if Path(SUBSCRIPTIONS_FILE).is_file(): @@ -515,13 +517,11 @@ if sys.argv[1] == "subscriptions-list": except Exception as e: handleException(e) - sys.exit(0) ####################### # SUBSCRIPTION DETAIL ####################### -if sys.argv[1] == "subscription-detail": - +def subscription_detail(): # check parameters try: if len(sys.argv) <= 2: @@ -529,22 +529,20 @@ if sys.argv[1] == "subscription-detail": except Exception as e: handleException(e) - subscriptionID = sys.argv[2] + subscription_id = sys.argv[2] try: - sub = getSubscription(subscriptionID) + sub = get_subscription(subscription_id) print(json.dumps(sub, indent=2)) except Exception as e: handleException(e) - sys.exit(0) ####################### # DOMAIN BY IP # to check if an ip has a domain mapping ####################### -if sys.argv[1] == "domain-by-ip": - +def domain_by_ip(): # check parameters try: if len(sys.argv) <= 2: @@ -556,19 +554,17 @@ if sys.argv[1] == "domain-by-ip": ip = sys.argv[2] try: - domain = getDomainByIP(ip) + domain = get_domain_by_ip(ip) print("domain='{0}'".format(domain)) except Exception as e: handleException(e) - sys.exit(0) ####################### # SUBSCRIPTION CANCEL ####################### -if sys.argv[1] == "subscription-cancel": - +def subscription_cancel(): # check parameters try: if len(sys.argv) <= 2: @@ -576,13 +572,36 @@ if sys.argv[1] == "subscription-cancel": except Exception as e: handleException(e) - subscriptionID = sys.argv[2] + subscription_id = sys.argv[2] try: - subscriptionsCancel(subscriptionID) + subscriptions_cancel(subscription_id) except Exception as e: handleException(e) - sys.exit(0) -# unknown command -print("# unknown command") +def main(): + if sys.argv[1] == "create-ssh-dialog": + create_ssh_dialog() + + elif sys.argv[1] == "domain-by-ip": + domain_by_ip() + + elif sys.argv[1] == "subscriptions-list": + subscriptions_list() + + elif sys.argv[1] == "subscription-cancel": + subscription_cancel() + + elif sys.argv[1] == "subscription-detail": + subscription_detail() + + elif sys.argv[1] == "subscription-new": + subscription_new() + + else: + # unknown command + print("# unknown command") + + +if __name__ == '__main__': + main() diff --git a/home.admin/config.scripts/blitz.subscriptions.py b/home.admin/config.scripts/blitz.subscriptions.py index 2b6b18576..993ca28b6 100644 --- a/home.admin/config.scripts/blitz.subscriptions.py +++ b/home.admin/config.scripts/blitz.subscriptions.py @@ -15,10 +15,10 @@ from blitzpy import RaspiBlitzConfig from dialog import Dialog # constants for standard services -LND_REST_API = "LND-REST-API" -LND_GRPC_API = "LND-GRPC-API" -LNBITS = "LNBITS" -BTCPAY = "BTCPAY" +SERVICE_LND_REST_API = "LND-REST-API" +SERVICE_LND_GRPC_API = "LND-GRPC-API" +SERVICE_LNBITS = "LNBITS" +SERVICE_BTCPAY = "BTCPAY" # load config cfg = RaspiBlitzConfig() @@ -32,35 +32,38 @@ SUBSCRIPTIONS_FILE = "/mnt/hdd/app-data/subscriptions/subscriptions.toml" # HELPER FUNCTIONS ####################### +# ToDo(frennkie) these are not being used! + def eprint(*args, **kwargs): print(*args, file=sys.stderr, **kwargs) -def parseDateIP2TORSERVER(datestr): - return datetime.strptime(datestr, "%Y-%m-%dT%H:%M:%S.%fZ") +def parse_date_ip2tor(date_str): + return datetime.strptime(date_str, "%Y-%m-%dT%H:%M:%S.%fZ") -def secondsLeft(dateObj): - return round((dateObj - datetime.utcnow()).total_seconds()) +def seconds_left(date_obj): + return round((date_obj - datetime.utcnow()).total_seconds()) ####################### # SSH MENU FUNCTIONS ####################### -def mySubscriptions(): +def my_subscriptions(): # check if any subscriptions are available - countSubscriptions = 0 + count_subscriptions = 0 try: os.system("sudo chown admin:admin {0}".format(SUBSCRIPTIONS_FILE)) subs = toml.load(SUBSCRIPTIONS_FILE) if 'subscriptions_ip2tor' in subs: - countSubscriptions += len(subs['subscriptions_ip2tor']) + count_subscriptions += len(subs['subscriptions_ip2tor']) if 'subscriptions_letsencrypt' in subs: - countSubscriptions += len(subs['subscriptions_letsencrypt']) + count_subscriptions += len(subs['subscriptions_letsencrypt']) except Exception as e: - pass - if countSubscriptions == 0: + print(f"warning: {e}") + + if count_subscriptions == 0: Dialog(dialog="dialog", autowidgetsize=True).msgbox(''' You have no active or inactive subscriptions. ''', title="Info") @@ -69,36 +72,36 @@ You have no active or inactive subscriptions. # load subscriptions and make dialog choices out of it choices = [] lookup = {} - lookupIndex = 0 + lookup_index = 0 subs = toml.load(SUBSCRIPTIONS_FILE) # list ip2tor subscriptions if 'subscriptions_ip2tor' in subs: for sub in subs['subscriptions_ip2tor']: # remember subscription under lookupindex - lookupIndex += 1 - lookup[str(lookupIndex)] = sub + lookup_index += 1 + lookup[str(lookup_index)] = sub # add to dialog choices if sub['active']: - activeState = "active" + active_state = "active" else: - activeState = "in-active" + active_state = "in-active" name = "IP2TOR Bridge (P:{1}) for {0}".format(sub['name'], sub['port']) - choices.append(("{0}".format(lookupIndex), "{0} ({1})".format(name.ljust(30), activeState))) + choices.append(("{0}".format(lookup_index), "{0} ({1})".format(name.ljust(30), active_state))) # list letsencrypt subscriptions if 'subscriptions_letsencrypt' in subs: for sub in subs['subscriptions_letsencrypt']: # remember subscription under lookupindex - lookupIndex += 1 - lookup[str(lookupIndex)] = sub + lookup_index += 1 + lookup[str(lookup_index)] = sub # add to dialog choices if sub['active']: - activeState = "active" + active_state = "active" else: - activeState = "in-active" + active_state = "in-active" name = "LETSENCRYPT {0}".format(sub['id']) - choices.append(("{0}".format(lookupIndex), "{0} ({1})".format(name.ljust(30), activeState))) + choices.append(("{0}".format(lookup_index), "{0} ({1})".format(name.ljust(30), active_state))) # show menu with options d = Dialog(dialog="dialog", autowidgetsize=True) @@ -111,15 +114,15 @@ You have no active or inactive subscriptions. if code != d.OK: return - # get data of selected subscrption - selectedSub = lookup[str(tag)] + # get data of selected subscription + selected_sub = lookup[str(tag)] # show details of selected d = Dialog(dialog="dialog", autowidgetsize=True) d.set_background_title("My Subscriptions") - if selectedSub['type'] == "letsencrypt-v1": - if len(selectedSub['warning']) > 0: - selectedSub['warning'] = "\n{0}".format(selectedSub['warning']) + if selected_sub['type'] == "letsencrypt-v1": + if len(selected_sub['warning']) > 0: + selected_sub['warning'] = "\n{0}".format(selected_sub['warning']) text = ''' This is a LetsEncrypt subscription using the free DNS service {dnsservice} @@ -135,17 +138,17 @@ The state of the subscription is: {active} {warning} The following additional information is available: {description} -'''.format(dnsservice=selectedSub['dnsservice_type'], - domain=selectedSub['id'], - ip=selectedSub['ip'], - active="ACTIVE" if selectedSub['active'] else "NOT ACTIVE", - warning=selectedSub['warning'], - description=selectedSub['description'] +'''.format(dnsservice=selected_sub['dnsservice_type'], + domain=selected_sub['id'], + ip=selected_sub['ip'], + active="ACTIVE" if selected_sub['active'] else "NOT ACTIVE", + warning=selected_sub['warning'], + description=selected_sub['description'] ) - elif selectedSub['type'] == "ip2tor-v1": - if len(selectedSub['warning']) > 0: - selectedSub['warning'] = "\n{0}".format(selectedSub['warning']) + elif selected_sub['type'] == "ip2tor-v1": + if len(selected_sub['warning']) > 0: + selected_sub['warning'] = "\n{0}".format(selected_sub['warning']) text = ''' This is a IP2TOR subscription bought on {initdate} at {shop} @@ -161,26 +164,26 @@ The state of the subscription is: {active} {warning} The following additional information is available: {description} -'''.format(initdate=selectedSub['time_created'], - shop=selectedSub['shop'], - publicaddress="{0}:{1}".format(selectedSub['ip'], selectedSub['port']), - toraddress=selectedSub['tor'], - renewhours=(round(int(selectedSub['duration']) / 3600)), - renewsats=(round(int(selectedSub['price_extension']) / 1000)), - totalsats=(round(int(selectedSub['price_total']) / 1000)), - active="ACTIVE" if selectedSub['active'] else "NOT ACTIVE", - warning=selectedSub['warning'], - description=selectedSub['description'], - service=selectedSub['name'] +'''.format(initdate=selected_sub['time_created'], + shop=selected_sub['shop'], + publicaddress="{0}:{1}".format(selected_sub['ip'], selected_sub['port']), + toraddress=selected_sub['tor'], + renewhours=(round(int(selected_sub['duration']) / 3600)), + renewsats=(round(int(selected_sub['price_extension']) / 1000)), + totalsats=(round(int(selected_sub['price_total']) / 1000)), + active="ACTIVE" if selected_sub['active'] else "NOT ACTIVE", + warning=selected_sub['warning'], + description=selected_sub['description'], + service=selected_sub['name'] ) else: text = "no text?! FIXME" - if selectedSub['active']: - extraLable = "CANCEL SUBSCRIPTION" + if selected_sub['active']: + extra_label = "CANCEL SUBSCRIPTION" else: - extraLable = "DELETE SUBSCRIPTION" - code = d.msgbox(text, title="Subscription Detail", ok_label="Back", extra_button=True, extra_label=extraLable, + extra_label = "DELETE SUBSCRIPTION" + code = d.msgbox(text, title="Subscription Detail", ok_label="Back", extra_button=True, extra_label=extra_label, width=75, height=30) # user wants to delete this subscription @@ -188,15 +191,15 @@ The following additional information is available: # api calls when canceling if code == "extra": os.system("clear") - if selectedSub['type'] == "letsencrypt-v1": + if selected_sub['type'] == "letsencrypt-v1": cmd = "python /home/admin/config.scripts/blitz.subscriptions.letsencrypt.py subscription-cancel {0}".format( - selectedSub['id']) + selected_sub['id']) print("# running: {0}".format(cmd)) os.system(cmd) time.sleep(2) - elif selectedSub['type'] == "ip2tor-v1": + elif selected_sub['type'] == "ip2tor-v1": cmd = "python /home/admin/config.scripts/blitz.subscriptions.ip2tor.py subscription-cancel {0}".format( - selectedSub['id']) + selected_sub['id']) print("# running: {0}".format(cmd)) os.system(cmd) time.sleep(2) @@ -205,183 +208,188 @@ The following additional information is available: time.sleep(3) # loop until no more subscriptions or user chooses CANCEL on subscription list - mySubscriptions() + my_subscriptions() -####################### -# SSH MENU -####################### +def main(): + ####################### + # SSH MENU + ####################### -choices = list() -choices.append(("LIST", "My Subscriptions")) -choices.append(("NEW1", "+ IP2TOR Bridge (paid)")) -choices.append(("NEW2", "+ LetsEncrypt HTTPS Domain (free)")) - -d = Dialog(dialog="dialog", autowidgetsize=True) -d.set_background_title("RaspiBlitz Subscriptions") -code, tag = d.menu( - "\nCheck existing subscriptions or create new:", - choices=choices, width=50, height=10, title="Subscription Management") - -# if user chosses CANCEL -if code != d.OK: - sys.exit(0) - -####################### -# MANAGE SUBSCRIPTIONS -####################### - -if tag == "LIST": - mySubscriptions() - sys.exit(0) - -############################### -# 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" - print("# running: {0}".format(cmd)) - os.system(cmd) - sys.exit(0) - -############################### -# NEW IP2TOR BRIDGE -############################### - -if tag == "NEW1": - - # check if Blitz is running behind TOR - cfg.reload() - if not cfg.run_behind_tor.value: - Dialog(dialog="dialog", autowidgetsize=True).msgbox(''' -The IP2TOR service just makes sense if you run -your RaspiBlitz behind TOR. - ''', title="Info") - sys.exit(1) - - os.system("clear") - print("please wait ..") - - # check for which standard services already a active bridge exists - lnd_rest_api = False - lnd_grpc_api = False - lnbits = False - btcpay = False - try: - if os.path.isfile(SUBSCRIPTIONS_FILE): - 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']: - 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() - if statusData.find("installed=1") > -1: - btcPayServer = True - - # ask user for which RaspiBlitz service the bridge should be used 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: - choices.append(("LNBITS", "LNbits Webinterface {0}".format("--> ALREADY BRIDGED" if lnd_grpc_api else ""))) - if btcPayServer: - choices.append(("BTCPAY", "BTCPay Server Webinterface {0}".format("--> ALREADY BRIDGED" if btcpay else ""))) - choices.append(("SELF", "Create a custom IP2TOR Bridge")) + choices.append(("LIST", "My Subscriptions")) + choices.append(("NEW1", "+ IP2TOR Bridge (paid)")) + choices.append(("NEW2", "+ LetsEncrypt HTTPS Domain (free)")) d = Dialog(dialog="dialog", autowidgetsize=True) d.set_background_title("RaspiBlitz Subscriptions") code, tag = d.menu( - "\nChoose RaspiBlitz Service to create Bridge for:", - choices=choices, width=60, height=10, title="Select Service") + "\nCheck existing subscriptions or create new:", + choices=choices, width=50, height=10, title="Subscription Management") # if user chosses CANCEL if code != d.OK: sys.exit(0) - servicename = None - torAddress = None - torPort = None - 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() - 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() - 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() - 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() - torPort = 443 - if tag == "SELF": - servicename = "CUSTOM" - try: - # get custom TOR address - code, text = d.inputbox( - "Enter TOR Onion-Address:", - height=10, width=60, init="", - 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 text.find('.onion') < 0 or text.find(' ') > 0: - print("Not a TOR Onion Address") - time.sleep(3) - sys.exit(0) - torAddress = text - # get custom TOR port - code, text = d.inputbox( - "Enter TOR Port Number:", - height=10, width=40, init="80", - title="IP2TOR Bridge Target") - text = text.strip() - os.system("clear") - if code != d.OK: - sys.exit(0) - if len(text) == 0: - sys.exit(0) - torPort = int(text) - except Exception as e: - print(e) - time.sleep(3) + ####################### + # MANAGE SUBSCRIPTIONS + ####################### + + if tag == "LIST": + my_subscriptions() + sys.exit(0) + + ############################### + # 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" + print("# running: {0}".format(cmd)) + os.system(cmd) + sys.exit(0) + + ############################### + # NEW IP2TOR BRIDGE + ############################### + + if tag == "NEW1": + + # check if Blitz is running behind TOR + cfg.reload() + if not cfg.run_behind_tor.value: + Dialog(dialog="dialog", autowidgetsize=True).msgbox(''' + The IP2TOR service just makes sense if you run + your RaspiBlitz behind TOR. + ''', title="Info") sys.exit(1) - # 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) - print("# running: {0}".format(cmd)) - os.system(cmd) - sys.exit(0) + os.system("clear") + print("please wait ..") + + # check for which standard services already a active bridge exists + lnd_rest_api = False + lnd_grpc_api = False + lnbits = False + btcpay = False + try: + if os.path.isfile(SUBSCRIPTIONS_FILE): + 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']: + continue + if sub['active'] and sub['name'] == SERVICE_LND_REST_API: + lnd_rest_api = True + if sub['active'] and sub['name'] == SERVICE_LND_GRPC_API: + lnd_grpc_api = True + if sub['active'] and sub['name'] == SERVICE_LNBITS: + lnbits = True + if sub['active'] and sub['name'] == SERVICE_BTCPAY: + btcpay = True + except Exception as e: + print(e) + + # check if BTCPayServer is installed + btc_pay_server = False + status_data = subprocess.run(['/home/admin/config.scripts/bonus.btcpayserver.sh', 'status'], + stdout=subprocess.PIPE).stdout.decode('utf-8').strip() + if status_data.find("installed=1") > -1: + btc_pay_server = True + + # ask user for which RaspiBlitz service the bridge should be used + 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: + choices.append(("LNBITS", "LNbits Webinterface {0}".format("--> ALREADY BRIDGED" if lnbits else ""))) + if btc_pay_server: + choices.append(("BTCPAY", "BTCPay Server Webinterface {0}".format("--> ALREADY BRIDGED" if btcpay else ""))) + choices.append(("SELF", "Create a custom IP2TOR Bridge")) + + d = Dialog(dialog="dialog", autowidgetsize=True) + d.set_background_title("RaspiBlitz Subscriptions") + code, tag = d.menu( + "\nChoose RaspiBlitz Service to create Bridge for:", + choices=choices, width=60, height=10, title="Select Service") + + # if user chosses CANCEL + if code != d.OK: + sys.exit(0) + + service_name = None + tor_address = None + tor_port = None + if tag == "REST": + # get TOR address for REST + service_name = SERVICE_LND_REST_API + tor_address = subprocess.run(['sudo', 'cat', '/mnt/hdd/tor/lndrest8080/hostname'], + stdout=subprocess.PIPE).stdout.decode('utf-8').strip() + tor_port = 8080 + if tag == "GRPC": + # get TOR address for GRPC + service_name = SERVICE_LND_GRPC_API + tor_address = subprocess.run(['sudo', 'cat', '/mnt/hdd/tor/lndrpc10009/hostname'], + stdout=subprocess.PIPE).stdout.decode('utf-8').strip() + tor_port = 10009 + if tag == "LNBITS": + # get TOR address for LNBits + service_name = SERVICE_LNBITS + tor_address = subprocess.run(['sudo', 'cat', '/mnt/hdd/tor/lnbits/hostname'], + stdout=subprocess.PIPE).stdout.decode('utf-8').strip() + tor_port = 443 + if tag == "BTCPAY": + # get TOR address for BTCPAY + service_name = SERVICE_BTCPAY + tor_address = subprocess.run(['sudo', 'cat', '/mnt/hdd/tor/btcpay/hostname'], + stdout=subprocess.PIPE).stdout.decode('utf-8').strip() + tor_port = 443 + if tag == "SELF": + service_name = "CUSTOM" + try: + # get custom TOR address + code, text = d.inputbox( + "Enter TOR Onion-Address:", + height=10, width=60, init="", + 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 text.find('.onion') < 0 or text.find(' ') > 0: + print("Not a TOR Onion Address") + time.sleep(3) + sys.exit(0) + tor_address = text + # get custom TOR port + code, text = d.inputbox( + "Enter TOR Port Number:", + height=10, width=40, init="80", + title="IP2TOR Bridge Target") + text = text.strip() + os.system("clear") + if code != d.OK: + sys.exit(0) + if len(text) == 0: + sys.exit(0) + tor_port = int(text) + except Exception as e: + print(e) + time.sleep(3) + sys.exit(1) + + # 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( + service_name, tor_address, tor_port) + print("# running: {0}".format(cmd)) + os.system(cmd) + sys.exit(0) + + +if __name__ == '__main__': + main()