raspiblitz/home.admin/config.scripts/blitz.subscriptions.py

347 lines
12 KiB
Python
Raw Normal View History

2020-05-26 17:24:29 +02:00
#!/usr/bin/python3
########################################################
# SSH Dialogs to manage Subscriptions on the RaspiBlitz
########################################################
import sys
import math
import time
import toml
2020-05-26 20:08:32 +02:00
import os
2020-05-26 19:58:27 +02:00
import subprocess
2020-05-26 17:24:29 +02:00
2020-05-26 17:27:47 +02:00
from dialog import Dialog
2020-05-26 17:24:29 +02:00
from blitzpy import RaspiBlitzConfig
2020-05-26 22:56:06 +02:00
# constants for standard services
LND_REST_API = "LND-REST-API"
2020-05-26 23:19:38 +02:00
LND_GRPC_API = "LND-GRPC-API"
2020-07-14 22:56:20 +02:00
LNBITS = "LNBITS"
2020-07-14 23:46:06 +02:00
BTCPAY = "BTCPAY"
2020-05-26 22:56:06 +02:00
2020-05-26 17:24:29 +02:00
# load config
cfg = RaspiBlitzConfig()
2020-05-26 17:27:47 +02:00
cfg.reload()
2020-05-26 17:24:29 +02:00
2020-05-26 19:15:03 +02:00
# basic values
SUBSCRIPTIONS_FILE="/mnt/hdd/app-data/subscriptions/subscriptions.toml"
2020-05-26 17:24:29 +02:00
####### 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")
def secondsLeft(dateObj):
return round((dateObj - datetime.datetime.utcnow()).total_seconds())
####### SSH MENU FUNCTIONS #########
def mySubscriptions():
2020-05-26 17:40:35 +02:00
# check if any subscriptions are available
countSubscriptions=0
try:
2020-06-24 21:15:06 +02:00
os.system("sudo chown admin:admin {0}".format(SUBSCRIPTIONS_FILE))
2020-05-26 17:40:35 +02:00
subs = toml.load(SUBSCRIPTIONS_FILE)
2020-07-13 13:40:42 +02:00
if 'subscriptions_ip2tor' in subs:
countSubscriptions += len(subs['subscriptions_ip2tor'])
if 'subscriptions_letsencrypt' in subs:
countSubscriptions += len(subs['subscriptions_letsencrypt'])
2020-05-26 17:40:35 +02:00
except Exception as e: pass
if countSubscriptions == 0:
Dialog(dialog="dialog",autowidgetsize=True).msgbox('''
2020-05-26 20:14:58 +02:00
You have no active or inactive subscriptions.
2020-05-26 17:40:35 +02:00
''',title="Info")
return
2020-05-26 17:43:59 +02:00
# load subscriptions and make dialog choices out of it
choices = []
lookup = {}
lookupIndex=0
subs = toml.load(SUBSCRIPTIONS_FILE)
2020-05-26 17:24:29 +02:00
2020-05-26 17:43:59 +02:00
# list ip2tor subscriptions
2020-07-13 13:40:42 +02:00
if 'subscriptions_ip2tor' in subs:
for sub in subs['subscriptions_ip2tor']:
# remember subscription under lookupindex
lookupIndex += 1
lookup[str(lookupIndex)]=sub
# add to dialog choices
if sub['active']:
activeState="active"
else:
activeState="in-active"
name="IP2TOR Bridge for {0}".format(sub['name'])
choices.append( ("{0}".format(lookupIndex), "{0} ({1})".format(name.ljust(30), activeState)) )
# list letsencrypt subscriptions
if 'subscriptions_letsencrypt' in subs:
for sub in subs['subscriptions_letsencrypt']:
# remember subscription under lookupindex
lookupIndex += 1
lookup[str(lookupIndex)]=sub
# add to dialog choices
if sub['active']:
activeState="active"
else:
activeState="in-active"
2020-07-13 16:18:22 +02:00
name="LETSENCRYPT {0}".format(sub['id'])
2020-07-13 13:40:42 +02:00
choices.append( ("{0}".format(lookupIndex), "{0} ({1})".format(name.ljust(30), activeState)) )
2020-05-26 17:24:29 +02:00
2020-05-26 17:43:59 +02:00
# show menu with options
d = Dialog(dialog="dialog",autowidgetsize=True)
d.set_background_title("RaspiBlitz Subscriptions")
code, tag = d.menu(
2020-05-26 19:43:31 +02:00
"\nYou have the following subscriptions - select for details:",
2020-05-28 15:33:16 +02:00
choices=choices, cancel_label="Back", width=65, height=15, title="My Subscriptions")
2020-05-26 17:24:29 +02:00
2020-05-26 17:43:59 +02:00
# if user chosses CANCEL
if code != d.OK: return
# get data of selected subscrption
selectedSub = lookup[str(tag)]
# show details of selected
d = Dialog(dialog="dialog",autowidgetsize=True)
d.set_background_title("My Subscriptions")
2020-07-13 13:40:42 +02:00
if selectedSub['type'] == "letsencrypt-v1":
2020-07-13 14:01:17 +02:00
if len(selectedSub['warning']) > 0:
selectedSub['warning'] = "\n{0}".format(selectedSub['warning'])
2020-07-13 13:40:42 +02:00
text='''
This is a LetsEncrypt subscription using the free DNS service
{dnsservice}
It allows using HTTPS for the domain:
{domain}
2020-07-13 15:53:12 +02:00
The domain is pointing to the IP:
2020-07-13 13:40:42 +02:00
{ip}
The state of the subscription is: {active} {warning}
2020-07-14 16:19:53 +02:00
The following additional information is available:
{description}
2020-07-13 13:40:42 +02:00
'''.format( dnsservice=selectedSub['dnsservice_type'],
domain=selectedSub['id'],
ip=selectedSub['ip'],
active= "ACTIVE" if selectedSub['active'] else "NOT ACTIVE",
2020-07-14 16:19:53 +02:00
warning=selectedSub['warning'],
description=selectedSub['description']
2020-07-13 13:40:42 +02:00
)
elif selectedSub['type'] == "ip2tor-v1":
2020-05-26 17:43:59 +02:00
if len(selectedSub['warning']) > 0:
2020-05-28 15:13:08 +02:00
selectedSub['warning'] = "\n{0}".format(selectedSub['warning'])
2020-05-26 17:43:59 +02:00
text='''
2020-05-26 17:24:29 +02:00
This is a IP2TOR subscription bought on {initdate} at
{shop}
It forwards from the public address {publicaddress} to
{toraddress}
for the RaspiBlitz service: {service}
It will renew every {renewhours} hours for {renewsats} sats.
Total payed so far: {totalsats} sats
The state of the subscription is: {active} {warning}
The following additional information is available:
{description}
2020-05-26 17:27:47 +02:00
'''.format( initdate=selectedSub['time_created'],
2020-05-26 17:24:29 +02:00
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_extension'])/1000)),
2020-05-26 20:41:01 +02:00
active= "ACTIVE" if selectedSub['active'] else "NOT ACTIVE",
2020-05-26 17:24:29 +02:00
warning=selectedSub['warning'],
description=selectedSub['description'],
2020-05-26 23:29:17 +02:00
service=selectedSub['name']
2020-05-26 17:43:59 +02:00
)
2020-05-26 17:24:29 +02:00
2020-05-26 17:43:59 +02:00
if selectedSub['active']:
2020-05-26 20:13:40 +02:00
extraLable = "CANCEL SUBSCRIPTION"
2020-05-26 17:43:59 +02:00
else:
2020-05-26 20:13:40 +02:00
extraLable = "DELETE SUBSCRIPTION"
2020-05-26 20:28:49 +02:00
code = d.msgbox(text, title="Subscription Detail", ok_label="Back", extra_button=True, extra_label=extraLable ,width=75, height=30)
2020-05-26 17:24:29 +02:00
2020-05-26 17:43:59 +02:00
# user wants to delete this subscription
2020-05-26 20:09:35 +02:00
# call the responsible sub script for deletion just in case any subscription needs to do some extra api calls when canceling
2020-05-26 17:43:59 +02:00
if code == "extra":
2020-05-26 20:10:34 +02:00
os.system("clear")
2020-07-13 13:40:42 +02:00
if selectedSub['type'] == "letsencrypt-v1":
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":
2020-05-26 20:02:37 +02:00
cmd="python /home/admin/config.scripts/blitz.subscriptions.ip2tor.py subscription-cancel {0}".format(selectedSub['id'])
2020-05-26 19:58:27 +02:00
print("# running: {0}".format(cmd))
2020-05-26 20:08:32 +02:00
os.system(cmd)
time.sleep(2)
2020-05-26 20:10:34 +02:00
else:
print("# FAIL: unknown subscription type")
time.sleep(3)
2020-05-26 20:08:32 +02:00
2020-05-26 17:43:59 +02:00
# loop until no more subscriptions or user chooses CANCEL on subscription list
mySubscriptions()
2020-05-26 17:24:29 +02:00
####### SSH MENU #########
2020-05-26 21:05:56 +02:00
choices = []
choices.append( ("LIST","My Subscriptions") )
2020-07-13 13:40:42 +02:00
choices.append( ("NEW1","+ IP2TOR Bridge (paid)") )
choices.append( ("NEW2","+ LetsEncrypt HTTPS Domain (free)") )
2020-05-26 20:41:01 +02:00
2020-05-26 21:05:56 +02:00
d = Dialog(dialog="dialog",autowidgetsize=True)
d.set_background_title("RaspiBlitz Subscriptions")
code, tag = d.menu(
2020-05-26 21:10:43 +02:00
"\nCheck existing subscriptions or create new:",
choices=choices, width=50, height=10, title="Subscription Management")
2020-05-26 20:42:07 +02:00
2020-05-26 21:05:56 +02:00
# if user chosses CANCEL
2020-05-26 21:07:28 +02:00
if code != d.OK:
sys.exit(0)
2020-05-26 20:41:01 +02:00
2020-05-26 22:56:06 +02:00
####### MANAGE SUBSCRIPTIONS #########
2020-05-26 21:05:56 +02:00
if tag == "LIST":
mySubscriptions()
sys.exit(0)
2020-05-26 20:41:01 +02:00
2020-07-13 13:40:42 +02:00
####### 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)
2020-05-26 22:56:06 +02:00
####### NEW IP2TOR BRIDGE #########
2020-05-26 21:05:56 +02:00
if tag == "NEW1":
2020-05-26 21:16:35 +02:00
# check if Blitz is running behind TOR
cfg.reload()
2020-06-01 23:52:26 +02:00
if not cfg.run_behind_tor.value:
2020-05-26 21:16:35 +02:00
Dialog(dialog="dialog",autowidgetsize=True).msgbox('''
The IP2TOR service just makes sense if you run
your RaspiBlitz behind TOR.
''',title="Info")
sys.exit(1)
2020-05-26 22:56:06 +02:00
# check for which standard services already a active bridge exists
lnd_rest_api=False
lnd_grpc_api=False
2020-07-14 22:56:20 +02:00
lnbits=False
2020-07-14 23:46:06 +02:00
btcbay=False
2020-05-26 22:56:06 +02:00
try:
if os.path.isfile(SUBSCRIPTIONS_FILE):
2020-06-24 21:15:06 +02:00
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
2020-07-14 22:56:20 +02:00
if sub['active'] and sub['name'] == LNBITS: lnbits=True
2020-07-14 23:46:06 +02:00
if sub['active'] and sub['name'] == BTCPAY: btcpay=True
2020-05-26 22:56:06 +02:00
except Exception as e:
2020-05-26 23:45:09 +02:00
print(e)
2020-05-26 22:56:06 +02:00
2020-07-14 23:46:06 +02:00
# 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()
2020-07-14 23:47:15 +02:00
if statusData.find("installed=1") > -1:
2020-07-14 23:46:06 +02:00
btcPayServer=True
2020-05-26 22:56:06 +02:00
# ask user for which RaspiBlitz service the bridge should be used
choices = []
choices.append( ("REST","LND REST API {0}".format("--> ALREADY BRIDGED" if lnd_rest_api else "")) )
2020-05-26 23:16:50 +02:00
choices.append( ("GRPC","LND gRPC API {0}".format("--> ALREADY BRIDGED" if lnd_grpc_api else "")) )
2020-07-14 22:56:20 +02:00
if cfg.lnbits:
2020-07-14 23:46:06 +02:00
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 "")) )
2020-05-26 22:56:06 +02:00
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:",
2020-05-26 23:12:55 +02:00
choices=choices, width=60, height=10, title="Select Service")
2020-05-26 22:56:06 +02:00
# if user chosses CANCEL
if code != d.OK:
2020-05-26 22:58:21 +02:00
sys.exit(0)
2020-05-26 22:56:06 +02:00
2020-05-26 23:19:38 +02:00
servicename=None
2020-05-26 22:56:06 +02:00
torAddress=None
torPort=None
if tag == "REST":
# get TOR address for REST
2020-05-26 23:19:38 +02:00
servicename=LND_REST_API
2020-05-26 23:14:35 +02:00
torAddress = subprocess.run(['sudo', 'cat', '/mnt/hdd/tor/lndrest8080/hostname'], stdout=subprocess.PIPE).stdout.decode('utf-8').strip()
2020-05-26 23:12:55 +02:00
torPort=8080
2020-05-26 22:56:06 +02:00
if tag == "GRPC":
2020-05-26 22:58:21 +02:00
# get TOR address for GRPC
2020-05-26 23:19:38 +02:00
servicename=LND_GRPC_API
2020-05-26 23:14:35 +02:00
torAddress = subprocess.run(['sudo', 'cat', '/mnt/hdd/tor/lndrpc10009/hostname'], stdout=subprocess.PIPE).stdout.decode('utf-8').strip()
2020-05-26 23:12:55 +02:00
torPort=10009
2020-07-14 22:56:20 +02:00
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
2020-07-14 23:46:06 +02:00
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
2020-05-26 22:56:06 +02:00
if tag == "SELF":
2020-05-26 23:19:38 +02:00
servicename="CUSTOM"
2020-05-26 22:56:06 +02:00
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)
sys.exit(1)
2020-05-26 21:16:35 +02:00
# run creating a new IP2TOR subscription
os.system("clear")
2020-05-26 23:19:38 +02:00
cmd="python /home/admin/config.scripts/blitz.subscriptions.ip2tor.py create-ssh-dialog {0} {1} {2}".format(servicename,torAddress,torPort)
2020-05-26 21:05:56 +02:00
print("# running: {0}".format(cmd))
2020-05-26 21:07:28 +02:00
os.system(cmd)
2020-05-26 23:12:55 +02:00
sys.exit(0)