2019-06-15 23:02:44 +00:00
|
|
|
from config import *
|
2019-11-04 04:50:47 +00:00
|
|
|
from threading import Timer
|
2020-05-13 01:54:17 +00:00
|
|
|
from werkzeug.routing import RequestRedirect
|
2021-04-25 19:25:49 +00:00
|
|
|
from flask import flash, redirect
|
2021-03-13 21:57:23 +00:00
|
|
|
from utilities import *
|
2020-10-08 02:59:44 +00:00
|
|
|
from enable_disable_functions import *
|
|
|
|
from systemctl_info import *
|
2019-11-14 02:32:37 +00:00
|
|
|
import time
|
2020-07-19 03:16:51 +00:00
|
|
|
import json
|
2019-06-15 23:02:44 +00:00
|
|
|
import os
|
|
|
|
import subprocess
|
2020-08-01 03:51:59 +00:00
|
|
|
import random
|
|
|
|
import string
|
2021-10-10 00:27:50 +00:00
|
|
|
import re
|
2019-06-15 23:02:44 +00:00
|
|
|
|
2021-05-01 04:37:59 +00:00
|
|
|
try:
|
|
|
|
import qrcode
|
|
|
|
except:
|
|
|
|
pass
|
2021-04-11 00:51:26 +00:00
|
|
|
try:
|
|
|
|
import subprocess32
|
|
|
|
except:
|
|
|
|
pass
|
|
|
|
|
2019-08-27 01:36:15 +00:00
|
|
|
# Globals
|
|
|
|
local_ip = "unknown"
|
2020-06-06 01:46:39 +00:00
|
|
|
cached_data = {}
|
2020-09-11 03:21:24 +00:00
|
|
|
warning_data = {}
|
2021-12-03 17:05:50 +00:00
|
|
|
ui_settings = None
|
2019-08-27 01:36:15 +00:00
|
|
|
|
2020-01-11 02:04:31 +00:00
|
|
|
#==================================
|
|
|
|
# Manage Device
|
|
|
|
#==================================
|
|
|
|
def reboot_device():
|
|
|
|
os.system("sync")
|
|
|
|
os.system("/usr/bin/mynode_stop_critical_services.sh")
|
|
|
|
os.system("reboot")
|
|
|
|
|
|
|
|
def shutdown_device():
|
|
|
|
os.system("sync")
|
|
|
|
os.system("/usr/bin/mynode_stop_critical_services.sh")
|
|
|
|
os.system("shutdown -h now")
|
|
|
|
|
2021-01-07 18:49:29 +00:00
|
|
|
def is_shutting_down():
|
|
|
|
return os.path.isfile("/tmp/shutting_down")
|
|
|
|
|
2020-01-11 02:04:31 +00:00
|
|
|
def factory_reset():
|
2021-01-11 23:36:06 +00:00
|
|
|
# Try and make sure drive is r/w
|
|
|
|
os.system("mount -o remount,rw /mnt/hdd")
|
2021-01-23 04:55:44 +00:00
|
|
|
|
2020-01-11 02:04:31 +00:00
|
|
|
# Reset subsystems that have local data
|
|
|
|
delete_quicksync_data()
|
|
|
|
|
|
|
|
# Delete LND data
|
|
|
|
delete_lnd_data()
|
|
|
|
|
|
|
|
# Delete Tor data
|
|
|
|
reset_tor()
|
|
|
|
|
|
|
|
# Disable services
|
|
|
|
os.system("systemctl disable electrs --no-pager")
|
|
|
|
os.system("systemctl disable lndhub --no-pager")
|
2021-04-11 00:51:26 +00:00
|
|
|
os.system("systemctl disable btcrpcexplorer --no-pager")
|
2020-01-11 02:04:31 +00:00
|
|
|
os.system("systemctl disable vpn --no-pager")
|
|
|
|
|
|
|
|
# Trigger drive to be reformatted on reboot
|
|
|
|
os.system("rm -f /mnt/hdd/.mynode")
|
|
|
|
|
|
|
|
# Reset password
|
|
|
|
os.system("/usr/bin/mynode_chpasswd.sh bolt")
|
|
|
|
|
|
|
|
# Reboot
|
|
|
|
reboot_device()
|
|
|
|
|
2020-05-13 01:54:17 +00:00
|
|
|
def check_and_mark_reboot_action(tmp_marker):
|
|
|
|
if os.path.isfile("/tmp/{}".format(tmp_marker)):
|
|
|
|
flash(u'Refresh prevented - action already triggered', category="error")
|
|
|
|
raise RequestRedirect("/")
|
2022-01-30 07:13:36 +00:00
|
|
|
touch("/tmp/{}".format(tmp_marker))
|
2020-05-13 01:54:17 +00:00
|
|
|
|
2020-09-10 03:10:14 +00:00
|
|
|
def reload_throttled_data():
|
|
|
|
global cached_data
|
|
|
|
if os.path.isfile("/tmp/get_throttled_data"):
|
|
|
|
cached_data["get_throttled_data"] = get_file_contents("/tmp/get_throttled_data")
|
|
|
|
|
|
|
|
def get_throttled_data():
|
|
|
|
global cached_data
|
|
|
|
if "get_throttled_data" in cached_data:
|
|
|
|
data = cached_data["get_throttled_data"]
|
|
|
|
hex_data = int(data, 16)
|
|
|
|
r = {}
|
|
|
|
r["RAW_DATA"] = data
|
|
|
|
r["UNDERVOLTED"] = 1 if hex_data & 0x1 else 0
|
|
|
|
r["CAPPED"] = 1 if hex_data & 0x2 else 0
|
|
|
|
r["THROTTLED"] = 1 if hex_data & 0x4 else 0
|
|
|
|
r["SOFT_TEMPLIMIT"] = 1 if hex_data & 0x8 else 0
|
|
|
|
r["HAS_UNDERVOLTED"] = 1 if hex_data & 0x10000 else 0
|
|
|
|
r["HAS_CAPPED"] = 1 if hex_data & 0x20000 else 0
|
|
|
|
r["HAS_THROTTLED"] = 1 if hex_data & 0x40000 else 0
|
|
|
|
r["HAS_SOFT_TEMPLIMIT"] = 1 if hex_data & 0x80000 else 0
|
|
|
|
return r
|
|
|
|
else:
|
|
|
|
r = {}
|
|
|
|
r["RAW_DATA"] = "MISSING"
|
|
|
|
return r
|
|
|
|
|
2020-01-11 02:04:31 +00:00
|
|
|
#==================================
|
|
|
|
# Manage Versions and Upgrades
|
|
|
|
#==================================
|
2019-06-15 23:02:44 +00:00
|
|
|
def get_current_version():
|
|
|
|
current_version = "0.0"
|
|
|
|
try:
|
|
|
|
with open("/usr/share/mynode/version", "r") as f:
|
|
|
|
current_version = f.read().strip()
|
|
|
|
except:
|
|
|
|
current_version = "error"
|
|
|
|
return current_version
|
|
|
|
|
2020-02-24 01:39:40 +00:00
|
|
|
def get_current_beta_version():
|
|
|
|
current_beta_version = "0.0"
|
|
|
|
try:
|
|
|
|
with open("/usr/share/mynode/beta_version", "r") as f:
|
|
|
|
current_beta_version = f.read().strip()
|
|
|
|
except:
|
2020-02-24 02:35:08 +00:00
|
|
|
current_beta_version = "beta_not_installed"
|
2020-02-24 01:39:40 +00:00
|
|
|
return current_beta_version
|
2019-06-15 23:02:44 +00:00
|
|
|
|
|
|
|
def update_latest_version():
|
2020-07-24 18:02:15 +00:00
|
|
|
os.system("/usr/bin/mynode_get_latest_version.sh")
|
2019-06-15 23:02:44 +00:00
|
|
|
return True
|
|
|
|
|
|
|
|
def get_latest_version():
|
|
|
|
latest_version = "0.0"
|
|
|
|
try:
|
|
|
|
with open("/usr/share/mynode/latest_version", "r") as f:
|
|
|
|
latest_version = f.read().strip()
|
2019-11-02 04:04:37 +00:00
|
|
|
if latest_version == "":
|
|
|
|
latest_version = get_current_version()
|
2019-06-15 23:02:44 +00:00
|
|
|
except:
|
|
|
|
latest_version = get_current_version()
|
|
|
|
return latest_version
|
|
|
|
|
2020-02-24 01:39:40 +00:00
|
|
|
def get_latest_beta_version():
|
|
|
|
beta_version = ""
|
|
|
|
try:
|
|
|
|
with open("/usr/share/mynode/latest_beta_version", "r") as f:
|
|
|
|
beta_version = f.read().strip()
|
|
|
|
except:
|
|
|
|
beta_version = ""
|
|
|
|
return beta_version
|
|
|
|
|
2020-04-18 04:00:48 +00:00
|
|
|
def mark_upgrade_started():
|
2022-01-30 07:05:57 +00:00
|
|
|
touch("/tmp/upgrade_started")
|
2020-01-26 03:39:55 +00:00
|
|
|
|
2020-04-18 04:00:48 +00:00
|
|
|
def is_upgrade_running():
|
|
|
|
return os.path.isfile("/tmp/upgrade_started")
|
|
|
|
|
2020-01-11 02:04:31 +00:00
|
|
|
def upgrade_device():
|
2020-04-18 04:00:48 +00:00
|
|
|
if not is_upgrade_running():
|
|
|
|
mark_upgrade_started()
|
2019-06-15 23:02:44 +00:00
|
|
|
|
2020-04-18 04:00:48 +00:00
|
|
|
# Upgrade
|
|
|
|
os.system("mkdir -p /home/admin/upgrade_logs")
|
2021-11-04 03:39:54 +00:00
|
|
|
os.system("cp -f /usr/bin/mynode_upgrade.sh /usr/bin/mynode_upgrade_running.sh")
|
2021-01-07 20:52:41 +00:00
|
|
|
file1 = "/home/admin/upgrade_logs/upgrade_log_from_{}_upgrade.txt".format(get_current_version())
|
|
|
|
file2 = "/home/admin/upgrade_logs/upgrade_log_latest.txt"
|
2021-11-04 03:39:54 +00:00
|
|
|
cmd = "/usr/bin/mynode_upgrade_running.sh 2>&1 | tee {} {}".format(file1, file2)
|
2021-04-30 01:56:17 +00:00
|
|
|
ret = subprocess.call(cmd, shell=True)
|
|
|
|
if ret != 0:
|
|
|
|
# Try one more time....
|
|
|
|
subprocess.call(cmd, shell=True)
|
2020-04-18 04:00:48 +00:00
|
|
|
|
|
|
|
# Sync
|
|
|
|
os.system("sync")
|
|
|
|
time.sleep(1)
|
2020-01-10 05:41:12 +00:00
|
|
|
|
2020-04-18 04:00:48 +00:00
|
|
|
# Reboot
|
|
|
|
reboot_device()
|
2020-02-24 01:39:40 +00:00
|
|
|
|
2020-04-18 04:00:48 +00:00
|
|
|
def upgrade_device_beta():
|
|
|
|
if not is_upgrade_running():
|
|
|
|
mark_upgrade_started()
|
|
|
|
|
|
|
|
# Upgrade
|
|
|
|
os.system("mkdir -p /home/admin/upgrade_logs")
|
2021-11-04 03:39:54 +00:00
|
|
|
os.system("cp -f /usr/bin/mynode_upgrade.sh /usr/bin/mynode_upgrade_running.sh")
|
2021-01-07 20:52:41 +00:00
|
|
|
file1 = "/home/admin/upgrade_logs/upgrade_log_from_{}_upgrade.txt".format(get_current_version())
|
|
|
|
file2 = "/home/admin/upgrade_logs/upgrade_log_latest.txt"
|
2021-11-04 03:39:54 +00:00
|
|
|
cmd = "/usr/bin/mynode_upgrade_running.sh beta 2>&1 | tee {} {}".format(file1, file2)
|
2021-04-30 01:56:17 +00:00
|
|
|
ret = subprocess.call(cmd, shell=True)
|
|
|
|
if ret != 0:
|
|
|
|
# Try one more time....
|
|
|
|
subprocess.call(cmd, shell=True)
|
2020-04-18 04:00:48 +00:00
|
|
|
|
|
|
|
# Sync
|
|
|
|
os.system("sync")
|
|
|
|
time.sleep(1)
|
|
|
|
|
|
|
|
# Reboot
|
|
|
|
reboot_device()
|
2020-02-24 01:39:40 +00:00
|
|
|
|
2019-11-16 20:46:00 +00:00
|
|
|
def did_upgrade_fail():
|
|
|
|
return os.path.isfile("/mnt/hdd/mynode/settings/upgrade_error")
|
|
|
|
|
2021-10-10 00:27:50 +00:00
|
|
|
def cleanup_log(log):
|
|
|
|
log = re.sub("(product_key|PRODUCT_KEY)=[0-9A-Z]+", "product_key=************", log)
|
|
|
|
return log
|
|
|
|
|
|
|
|
def get_recent_upgrade_log():
|
|
|
|
log = get_file_contents("/home/admin/upgrade_logs/upgrade_log_latest.txt").decode("utf8")
|
|
|
|
return cleanup_log(log)
|
|
|
|
|
|
|
|
def get_all_upgrade_logs():
|
|
|
|
log_list = []
|
|
|
|
folder = "/home/admin/upgrade_logs/"
|
|
|
|
log_id = 0
|
|
|
|
|
2021-10-28 01:42:12 +00:00
|
|
|
try:
|
|
|
|
# Add latest upgrade log
|
|
|
|
if os.path.isfile( os.path.join(folder, "upgrade_log_latest.txt") ):
|
2021-10-10 00:27:50 +00:00
|
|
|
log = {}
|
|
|
|
log["id"] = log_id
|
2021-10-28 01:42:12 +00:00
|
|
|
log["name"] = "Latest Upgrade"
|
|
|
|
modTimeSeconds = os.path.getmtime( os.path.join(folder, "upgrade_log_latest.txt") )
|
2021-10-10 00:27:50 +00:00
|
|
|
log["date"] = time.strftime('%Y-%m-%d', time.localtime(modTimeSeconds))
|
2021-10-28 01:42:12 +00:00
|
|
|
log["log"] = get_recent_upgrade_log()
|
2021-10-10 00:27:50 +00:00
|
|
|
log_list.append( log )
|
|
|
|
log_id += 1
|
2021-10-28 01:42:12 +00:00
|
|
|
|
|
|
|
# Add file logs
|
|
|
|
if os.path.isdir(folder):
|
|
|
|
for f in os.listdir(folder):
|
|
|
|
fullpath = os.path.join(folder, f)
|
|
|
|
if os.path.isfile( fullpath ):
|
|
|
|
log = {}
|
|
|
|
log["id"] = log_id
|
|
|
|
log["name"] = f
|
|
|
|
modTimeSeconds = os.path.getmtime(fullpath)
|
|
|
|
log["date"] = time.strftime('%Y-%m-%d', time.localtime(modTimeSeconds))
|
|
|
|
log["log"] = cleanup_log( get_file_contents(fullpath).decode("utf8") )
|
|
|
|
log_list.append( log )
|
|
|
|
log_id += 1
|
|
|
|
except Exception as e:
|
|
|
|
pass
|
|
|
|
|
2021-10-10 00:27:50 +00:00
|
|
|
return log_list
|
2020-01-24 18:07:03 +00:00
|
|
|
|
2020-07-23 02:28:07 +00:00
|
|
|
def has_checkin_error():
|
|
|
|
return os.path.isfile("/tmp/check_in_error")
|
|
|
|
|
2020-09-04 01:37:51 +00:00
|
|
|
|
2020-05-01 01:37:17 +00:00
|
|
|
#==================================
|
|
|
|
# Reseller Info
|
|
|
|
#==================================
|
|
|
|
def is_device_from_reseller():
|
|
|
|
return os.path.isfile("/opt/mynode/custom/reseller")
|
|
|
|
|
2019-11-16 20:46:00 +00:00
|
|
|
|
2020-01-11 02:04:31 +00:00
|
|
|
#==================================
|
|
|
|
# Device Info
|
|
|
|
#==================================
|
2019-06-29 15:53:49 +00:00
|
|
|
def get_system_uptime():
|
2022-01-30 19:58:00 +00:00
|
|
|
uptime = to_string(subprocess.check_output('awk \'{print int($1/86400)" days "int($1%86400/3600)" hour(s) "int(($1%3600)/60)" minute(s) "int($1%60)" seconds(s)"}\' /proc/uptime', shell=True))
|
|
|
|
uptime = uptime.strip()
|
2019-06-29 15:53:49 +00:00
|
|
|
return uptime
|
|
|
|
|
2020-04-05 02:25:52 +00:00
|
|
|
def get_system_uptime_in_seconds():
|
2022-01-30 19:58:00 +00:00
|
|
|
uptime = to_string(subprocess.check_output('awk \'{print $1}\' /proc/uptime', shell=True))
|
2020-04-05 02:25:52 +00:00
|
|
|
uptime = int(float(uptime.strip()))
|
|
|
|
return uptime
|
|
|
|
|
2020-09-11 02:03:11 +00:00
|
|
|
def get_system_time_in_ms():
|
|
|
|
return int(round(time.time() * 1000))
|
|
|
|
|
2020-02-05 02:12:52 +00:00
|
|
|
def get_system_date():
|
2022-01-30 19:58:00 +00:00
|
|
|
date = to_string(subprocess.check_output('date', shell=True))
|
|
|
|
date = date.strip()
|
2020-02-05 02:12:52 +00:00
|
|
|
return date
|
|
|
|
|
2019-06-15 23:02:44 +00:00
|
|
|
def get_device_serial():
|
2020-06-06 01:46:39 +00:00
|
|
|
global cached_data
|
|
|
|
if "serial" in cached_data:
|
|
|
|
return cached_data["serial"]
|
|
|
|
|
2022-01-30 19:58:00 +00:00
|
|
|
serial = to_string(subprocess.check_output("mynode-get-device-serial", shell=True))
|
|
|
|
serial = serial.strip()
|
2020-06-06 01:46:39 +00:00
|
|
|
|
|
|
|
cached_data["serial"] = serial
|
2019-06-15 23:02:44 +00:00
|
|
|
return serial
|
|
|
|
|
2019-07-16 03:30:08 +00:00
|
|
|
def get_device_type():
|
2020-06-06 01:46:39 +00:00
|
|
|
global cached_data
|
|
|
|
if "device_type" in cached_data:
|
|
|
|
return cached_data["device_type"]
|
|
|
|
|
2022-01-30 07:05:57 +00:00
|
|
|
device = to_string(subprocess.check_output("mynode-get-device-type", shell=True).strip())
|
|
|
|
cached_data["device_type"] = device
|
2019-10-30 02:22:11 +00:00
|
|
|
return device
|
2019-07-16 03:30:08 +00:00
|
|
|
|
2021-06-15 03:20:59 +00:00
|
|
|
def get_device_arch():
|
|
|
|
global cached_data
|
|
|
|
if "device_arch" in cached_data:
|
|
|
|
return cached_data["device_arch"]
|
|
|
|
|
2022-01-30 07:05:57 +00:00
|
|
|
arch = to_string(subprocess.check_output("uname -m", shell=True).decode("utf-8").strip())
|
|
|
|
cached_data["device_arch"] = arch
|
2021-06-15 03:20:59 +00:00
|
|
|
return arch
|
|
|
|
|
2020-04-17 02:19:11 +00:00
|
|
|
def get_device_ram():
|
2020-06-06 01:46:39 +00:00
|
|
|
global cached_data
|
|
|
|
if "ram" in cached_data:
|
|
|
|
return cached_data["ram"]
|
|
|
|
|
2022-01-30 07:05:57 +00:00
|
|
|
ram = to_string(subprocess.check_output("free --giga | grep Mem | awk '{print $2}'", shell=True).strip())
|
|
|
|
cached_data["ram"] = ram
|
2020-04-17 02:19:11 +00:00
|
|
|
return ram
|
|
|
|
|
2020-01-11 02:04:31 +00:00
|
|
|
def get_local_ip():
|
|
|
|
local_ip = "unknown"
|
|
|
|
try:
|
2022-01-30 19:58:00 +00:00
|
|
|
local_ip = to_string(subprocess.check_output('/usr/bin/get_local_ip.py', shell=True).strip())
|
2020-01-11 02:04:31 +00:00
|
|
|
except:
|
|
|
|
local_ip = "error"
|
|
|
|
|
2022-01-30 19:58:00 +00:00
|
|
|
return local_ip
|
2020-01-11 02:04:31 +00:00
|
|
|
|
|
|
|
def get_device_changelog():
|
|
|
|
changelog = ""
|
|
|
|
try:
|
2022-01-30 19:58:00 +00:00
|
|
|
changelog = to_string(subprocess.check_output(["cat", "/usr/share/mynode/changelog"]))
|
2020-01-11 02:04:31 +00:00
|
|
|
except:
|
|
|
|
changelog = "ERROR"
|
2022-01-30 19:58:00 +00:00
|
|
|
return changelog
|
2020-01-11 02:04:31 +00:00
|
|
|
|
|
|
|
def has_changed_password():
|
2020-03-25 01:07:25 +00:00
|
|
|
try:
|
|
|
|
with open("/home/bitcoin/.mynode/.hashedpw", "r") as f:
|
|
|
|
hashedpw = f.read().strip()
|
|
|
|
if hashedpw != "d0b3cba71f725563d316ea3516099328042095d10f4571be25c07f9ce31985a5":
|
|
|
|
return True
|
|
|
|
except:
|
|
|
|
return False
|
|
|
|
return False
|
2020-01-11 02:04:31 +00:00
|
|
|
|
2021-12-05 00:26:42 +00:00
|
|
|
def hide_password_warning():
|
|
|
|
if os.path.isfile("/mnt/hdd/mynode/settings/hide_password_warning"):
|
|
|
|
return True
|
|
|
|
return False
|
|
|
|
|
2020-04-23 03:47:50 +00:00
|
|
|
def is_mount_read_only(mnt):
|
|
|
|
with open('/proc/mounts') as f:
|
|
|
|
for line in f:
|
|
|
|
device, mount_point, filesystem, flags, __, __ = line.split()
|
|
|
|
flags = flags.split(',')
|
|
|
|
if mount_point == mnt:
|
|
|
|
return 'ro' in flags
|
|
|
|
return False
|
|
|
|
|
2020-05-23 03:18:50 +00:00
|
|
|
def set_swap_size(size):
|
|
|
|
size_mb = int(size) * 1024
|
|
|
|
os.system("sed -i 's|CONF_SWAPSIZE=.*|CONF_SWAPSIZE={}|' /etc/dphys-swapfile".format(size_mb))
|
|
|
|
return set_file_contents("/mnt/hdd/mynode/settings/swap_size", size)
|
|
|
|
|
|
|
|
def get_swap_size():
|
|
|
|
return get_file_contents("/mnt/hdd/mynode/settings/swap_size")
|
2019-07-16 03:30:08 +00:00
|
|
|
|
2020-01-11 02:04:31 +00:00
|
|
|
#==================================
|
2020-10-08 02:59:44 +00:00
|
|
|
# myNode Status
|
2020-01-11 02:04:31 +00:00
|
|
|
#==================================
|
2020-10-08 02:59:44 +00:00
|
|
|
STATE_DRIVE_MISSING = "drive_missing"
|
|
|
|
STATE_DRIVE_CONFIRM_FORMAT = "drive_format_confirm"
|
|
|
|
STATE_DRIVE_FORMATTING = "drive_formatting"
|
|
|
|
STATE_DRIVE_MOUNTED = "drive_mounted"
|
2021-02-04 01:11:19 +00:00
|
|
|
STATE_DRIVE_CLONE = "drive_clone"
|
2021-01-28 04:01:34 +00:00
|
|
|
STATE_DRIVE_FULL = "drive_full"
|
2021-11-24 02:52:59 +00:00
|
|
|
STATE_DOCKER_RESET = "docker_reset"
|
2020-10-08 02:59:44 +00:00
|
|
|
STATE_GEN_DHPARAM = "gen_dhparam"
|
|
|
|
STATE_QUICKSYNC_DOWNLOAD = "quicksync_download"
|
|
|
|
STATE_QUICKSYNC_COPY = "quicksync_copy"
|
|
|
|
STATE_QUICKSYNC_RESET = "quicksync_reset"
|
|
|
|
STATE_STABLE = "stable"
|
|
|
|
STATE_ROOTFS_READ_ONLY = "rootfs_read_only"
|
|
|
|
STATE_HDD_READ_ONLY = "hdd_read_only"
|
2021-01-07 18:49:29 +00:00
|
|
|
STATE_SHUTTING_DOWN = "shutting_down"
|
|
|
|
STATE_UPGRADING = "upgrading"
|
2020-10-08 02:59:44 +00:00
|
|
|
STATE_UNKNOWN = "unknown"
|
|
|
|
|
|
|
|
def get_mynode_status():
|
2020-01-11 02:04:31 +00:00
|
|
|
try:
|
2020-10-08 02:59:44 +00:00
|
|
|
status_file = "/tmp/.mynode_status"
|
|
|
|
status = STATE_UNKNOWN
|
|
|
|
|
2021-02-04 01:11:19 +00:00
|
|
|
# Get status
|
2020-10-08 02:59:44 +00:00
|
|
|
if (os.path.isfile(status_file)):
|
|
|
|
try:
|
|
|
|
with open(status_file, "r") as f:
|
|
|
|
status = f.read().strip()
|
|
|
|
except:
|
|
|
|
status = STATE_DRIVE_MISSING
|
|
|
|
else:
|
|
|
|
status = STATE_DRIVE_MISSING
|
2021-02-04 01:11:19 +00:00
|
|
|
|
|
|
|
# If its been a while, check for error conditions
|
|
|
|
uptime_in_sec = get_system_uptime_in_seconds()
|
|
|
|
if uptime_in_sec > 120:
|
|
|
|
# Check for read-only sd card
|
|
|
|
if is_mount_read_only("/"):
|
|
|
|
return STATE_ROOTFS_READ_ONLY
|
|
|
|
# Check for read-only drive (unless cloning - it purposefully mounts read only)
|
|
|
|
if is_mount_read_only("/mnt/hdd") and status != STATE_DRIVE_CLONE:
|
|
|
|
return STATE_HDD_READ_ONLY
|
2020-01-11 02:04:31 +00:00
|
|
|
except:
|
2020-10-08 02:59:44 +00:00
|
|
|
status = STATE_UNKNOWN
|
|
|
|
return status
|
2020-01-11 02:04:31 +00:00
|
|
|
|
2021-02-04 01:11:19 +00:00
|
|
|
#==================================
|
|
|
|
# myNode Clone Tool
|
|
|
|
#==================================
|
|
|
|
CLONE_STATE_DETECTING = "detecting"
|
|
|
|
CLONE_STATE_ERROR = "error"
|
|
|
|
CLONE_STATE_NEED_CONFIRM = "need_confirm"
|
|
|
|
CLONE_STATE_IN_PROGRESS = "in_progress"
|
|
|
|
CLONE_STATE_COMPLETE = "complete"
|
|
|
|
|
|
|
|
def get_clone_state():
|
|
|
|
return get_file_contents("/tmp/.clone_state")
|
|
|
|
|
|
|
|
def get_clone_error():
|
|
|
|
return get_file_contents("/tmp/.clone_error")
|
|
|
|
|
|
|
|
def get_clone_progress():
|
|
|
|
return get_file_contents("/tmp/.clone_progress")
|
|
|
|
|
|
|
|
def get_clone_source_drive():
|
|
|
|
return get_file_contents("/tmp/.clone_source")
|
|
|
|
|
|
|
|
def get_clone_target_drive():
|
|
|
|
return get_file_contents("/tmp/.clone_target")
|
|
|
|
|
|
|
|
def get_clone_target_drive_has_mynode():
|
|
|
|
return os.path.isfile("/tmp/.clone_target_drive_has_mynode")
|
|
|
|
|
|
|
|
def get_drive_info(drive):
|
|
|
|
data = {}
|
|
|
|
data["name"] = "NOT_FOUND"
|
|
|
|
try:
|
2022-01-30 19:58:00 +00:00
|
|
|
lsblk_output = to_string(subprocess.check_output("lsblk -io KNAME,TYPE,SIZE,MODEL,VENDOR /dev/{} | grep disk".format(drive), shell=True).decode("utf-8"))
|
2021-02-04 01:11:19 +00:00
|
|
|
parts = lsblk_output.split()
|
|
|
|
data["name"] = parts[0]
|
|
|
|
data["size"] = parts[2]
|
|
|
|
data["model"] = parts[3]
|
|
|
|
data["vendor"] = parts[4]
|
|
|
|
except:
|
|
|
|
pass
|
|
|
|
return data
|
|
|
|
|
2020-11-17 00:55:30 +00:00
|
|
|
|
2020-10-03 04:43:30 +00:00
|
|
|
#==================================
|
|
|
|
# UI Functions
|
|
|
|
#==================================
|
2021-12-03 17:05:50 +00:00
|
|
|
def init_ui_setting_defaults(ui_settings):
|
|
|
|
if "darkmode" not in ui_settings:
|
|
|
|
ui_settings["darkmode"] = False
|
|
|
|
if "price_ticker" not in ui_settings:
|
|
|
|
ui_settings["price_ticker"] = False
|
|
|
|
if "pinned_lightning_details" not in ui_settings:
|
|
|
|
ui_settings["pinned_lightning_details"] = False
|
|
|
|
if "background" not in ui_settings:
|
|
|
|
ui_settings["background"] = "none"
|
|
|
|
return ui_settings
|
|
|
|
|
2020-07-19 03:16:51 +00:00
|
|
|
def read_ui_settings():
|
2021-12-03 17:05:50 +00:00
|
|
|
global ui_settings
|
|
|
|
if ui_settings != None:
|
|
|
|
return ui_settings
|
|
|
|
|
2020-07-19 03:16:51 +00:00
|
|
|
ui_hdd_file = '/mnt/hdd/mynode/settings/ui.json'
|
|
|
|
ui_mynode_file = '/home/bitcoin/.mynode/ui.json'
|
|
|
|
|
|
|
|
# read ui.json from HDD
|
2021-12-04 04:07:07 +00:00
|
|
|
try:
|
|
|
|
if os.path.isfile(ui_hdd_file):
|
|
|
|
with open(ui_hdd_file, 'r') as fp:
|
|
|
|
ui_settings = json.load(fp)
|
|
|
|
# read ui.json from mynode
|
|
|
|
elif os.path.isfile(ui_mynode_file):
|
|
|
|
with open(ui_mynode_file, 'r') as fp:
|
|
|
|
ui_settings = json.load(fp)
|
|
|
|
except Exception as e:
|
|
|
|
# Error reading ui settings
|
|
|
|
pass
|
2020-07-19 03:16:51 +00:00
|
|
|
|
2021-12-04 02:50:33 +00:00
|
|
|
# If no files were read, init variable and mark we need to write files
|
|
|
|
need_file_write = False
|
|
|
|
if ui_settings == None:
|
|
|
|
ui_settings = {}
|
|
|
|
need_file_write = True
|
|
|
|
|
2020-07-19 03:16:51 +00:00
|
|
|
# Set reseller
|
|
|
|
ui_settings["reseller"] = is_device_from_reseller()
|
|
|
|
|
2021-12-04 02:50:33 +00:00
|
|
|
# Load defaults
|
2021-12-03 17:05:50 +00:00
|
|
|
ui_settings = init_ui_setting_defaults(ui_settings)
|
|
|
|
|
2021-12-04 02:50:33 +00:00
|
|
|
if need_file_write:
|
|
|
|
write_ui_settings(ui_settings)
|
|
|
|
|
2020-07-19 03:16:51 +00:00
|
|
|
return ui_settings
|
|
|
|
|
2021-12-03 17:05:50 +00:00
|
|
|
def write_ui_settings(ui_settings_new):
|
|
|
|
global ui_settings
|
|
|
|
ui_settings = ui_settings_new
|
|
|
|
|
2020-07-19 03:16:51 +00:00
|
|
|
ui_hdd_file = '/mnt/hdd/mynode/settings/ui.json'
|
|
|
|
ui_mynode_file = '/home/bitcoin/.mynode/ui.json'
|
|
|
|
try:
|
|
|
|
with open(ui_hdd_file, 'w') as fp:
|
|
|
|
json.dump(ui_settings, fp)
|
2021-12-04 04:07:07 +00:00
|
|
|
|
|
|
|
with open(ui_mynode_file, 'w') as fp:
|
|
|
|
json.dump(ui_settings, fp)
|
2020-07-19 03:16:51 +00:00
|
|
|
except:
|
|
|
|
pass
|
|
|
|
|
2021-12-03 17:05:50 +00:00
|
|
|
def get_ui_setting(name):
|
2020-07-19 03:16:51 +00:00
|
|
|
ui_settings = read_ui_settings()
|
2021-12-03 17:05:50 +00:00
|
|
|
return ui_settings[name]
|
2020-07-19 03:16:51 +00:00
|
|
|
|
2021-12-03 17:05:50 +00:00
|
|
|
def set_ui_setting(name, value):
|
2020-07-19 03:16:51 +00:00
|
|
|
ui_settings = read_ui_settings()
|
2021-12-03 17:05:50 +00:00
|
|
|
ui_settings[name] = value
|
2020-07-19 03:16:51 +00:00
|
|
|
write_ui_settings(ui_settings)
|
|
|
|
|
2021-12-03 17:05:50 +00:00
|
|
|
def toggle_ui_setting(name):
|
|
|
|
set_ui_setting(name, not get_ui_setting(name))
|
2020-01-11 02:04:31 +00:00
|
|
|
|
2021-04-16 05:24:56 +00:00
|
|
|
|
|
|
|
# def get_background_choices():
|
|
|
|
# choices = []
|
|
|
|
# choices.append("none")
|
|
|
|
# for filename in os.listdir("/var/www/mynode/static/images/backgrounds/"):
|
|
|
|
# if filename.endswith(".png") or filename.endswith(".jpg"):
|
|
|
|
# name = filename.replace(".png","").replace(".jpg","")
|
|
|
|
# choices.append(name)
|
|
|
|
# return choices
|
|
|
|
|
2020-07-22 01:54:30 +00:00
|
|
|
def is_https_forced():
|
2020-07-24 18:48:41 +00:00
|
|
|
return os.path.isfile('/home/bitcoin/.mynode/https_forced')
|
|
|
|
|
|
|
|
def force_https(force):
|
|
|
|
if force:
|
2022-01-30 07:05:57 +00:00
|
|
|
touch("/home/bitcoin/.mynode/https_forced")
|
2020-07-24 18:48:41 +00:00
|
|
|
else:
|
2022-01-30 07:05:57 +00:00
|
|
|
delete_file("/home/bitcoin/.mynode/https_forced")
|
2020-07-22 01:54:30 +00:00
|
|
|
|
2021-05-05 03:51:50 +00:00
|
|
|
# Regen cert
|
|
|
|
def regen_https_cert():
|
|
|
|
os.system("rm -rf /home/bitcoin/.mynode/https")
|
|
|
|
os.system("rm -rf /mnt/hdd/mynode/settings/https")
|
|
|
|
os.system("/usr/bin/mynode_gen_cert.sh https 825")
|
|
|
|
os.system("sync")
|
|
|
|
os.system("systemctl restart nginx")
|
|
|
|
|
2020-08-01 03:51:59 +00:00
|
|
|
def get_flask_secret_key():
|
|
|
|
if os.path.isfile("/home/bitcoin/.mynode/flask_secret_key"):
|
|
|
|
key = get_file_contents("/home/bitcoin/.mynode/flask_secret_key")
|
|
|
|
else:
|
|
|
|
letters = string.ascii_letters
|
|
|
|
key = ''.join(random.choice(letters) for i in range(32))
|
|
|
|
set_file_contents("/home/bitcoin/.mynode/flask_secret_key", key)
|
|
|
|
return key
|
|
|
|
|
2021-03-27 22:46:56 +00:00
|
|
|
def get_flask_session_timeout():
|
|
|
|
try:
|
|
|
|
if os.path.isfile("/home/bitcoin/.mynode/flask_session_timeout"):
|
|
|
|
timeout = get_file_contents("/home/bitcoin/.mynode/flask_session_timeout")
|
|
|
|
parts = timeout.split(",")
|
|
|
|
d = parts[0]
|
|
|
|
h = parts[1]
|
2021-03-28 00:11:10 +00:00
|
|
|
return int(d),int(h)
|
2021-03-27 22:46:56 +00:00
|
|
|
else:
|
2021-03-28 16:21:45 +00:00
|
|
|
set_file_contents("/home/bitcoin/.mynode/flask_session_timeout", "7,0")
|
|
|
|
return 7,0
|
2021-03-27 22:46:56 +00:00
|
|
|
except:
|
2021-03-28 16:21:45 +00:00
|
|
|
return 7,0
|
2021-03-28 00:11:10 +00:00
|
|
|
|
|
|
|
def set_flask_session_timeout(days, hours):
|
|
|
|
set_file_contents("/home/bitcoin/.mynode/flask_session_timeout", "{},{}".format(days, hours))
|
|
|
|
os.system("sync")
|
|
|
|
|
2022-01-07 03:57:00 +00:00
|
|
|
def get_randomize_balances():
|
|
|
|
return os.path.isfile('/home/bitcoin/.mynode/randomize_balances')
|
|
|
|
|
|
|
|
def set_randomize_balances(randomize):
|
|
|
|
if randomize:
|
2022-01-30 07:13:36 +00:00
|
|
|
touch("/home/bitcoin/.mynode/randomize_balances")
|
2022-01-30 07:05:57 +00:00
|
|
|
else:
|
|
|
|
delete_file("rm -f /home/bitcoin/.mynode/randomize_balances")
|
|
|
|
|
|
|
|
def is_www_python3():
|
|
|
|
return os.path.isfile('/home/bitcoin/.mynode/.www_use_python3')
|
|
|
|
|
|
|
|
def set_www_python3(use_python3):
|
|
|
|
if use_python3:
|
|
|
|
touch("/home/bitcoin/.mynode/.www_use_python3")
|
2022-01-07 03:57:00 +00:00
|
|
|
else:
|
2022-01-30 07:05:57 +00:00
|
|
|
delete_file("/home/bitcoin/.mynode/.www_use_python3")
|
2021-03-28 00:11:10 +00:00
|
|
|
|
|
|
|
#==================================
|
2021-12-18 05:18:25 +00:00
|
|
|
# Web Server Functions
|
2021-03-28 00:11:10 +00:00
|
|
|
#==================================
|
|
|
|
def restart_flask():
|
|
|
|
os.system("systemctl restart www")
|
2021-03-27 22:46:56 +00:00
|
|
|
|
2020-08-01 03:51:59 +00:00
|
|
|
|
2020-01-11 02:04:31 +00:00
|
|
|
#==================================
|
|
|
|
# Uploader Functions
|
|
|
|
#==================================
|
2019-07-25 02:51:12 +00:00
|
|
|
def is_uploader():
|
2020-03-14 21:01:21 +00:00
|
|
|
return os.path.isfile("/mnt/hdd/mynode/settings/uploader")
|
2019-08-01 00:47:04 +00:00
|
|
|
def set_uploader():
|
2022-01-30 07:05:57 +00:00
|
|
|
touch("/mnt/hdd/mynode/settings/uploader")
|
2019-08-01 00:47:04 +00:00
|
|
|
def unset_uploader():
|
2022-01-30 07:05:57 +00:00
|
|
|
delete_file("/mnt/hdd/mynode/settings/uploader")
|
2019-07-25 02:51:12 +00:00
|
|
|
|
|
|
|
|
2020-01-11 02:04:31 +00:00
|
|
|
#==================================
|
|
|
|
# QuickSync Functions
|
|
|
|
#==================================
|
2019-08-01 02:46:22 +00:00
|
|
|
def is_quicksync_enabled():
|
2019-10-24 04:18:46 +00:00
|
|
|
return not os.path.isfile("/mnt/hdd/mynode/settings/quicksync_disabled")
|
2019-08-01 02:46:22 +00:00
|
|
|
def disable_quicksync():
|
2022-01-30 07:05:57 +00:00
|
|
|
touch("/mnt/hdd/mynode/settings/quicksync_disabled")
|
2019-08-01 02:46:22 +00:00
|
|
|
def enable_quicksync():
|
2022-01-30 07:05:57 +00:00
|
|
|
delete_file("/mnt/hdd/mynode/settings/quicksync_disabled")
|
2019-08-01 02:46:22 +00:00
|
|
|
|
2020-01-11 02:04:31 +00:00
|
|
|
def settings_disable_quicksync():
|
2020-10-08 02:59:44 +00:00
|
|
|
disable_quicksync()
|
2021-04-11 00:51:26 +00:00
|
|
|
stop_bitcoin()
|
2020-01-11 02:04:31 +00:00
|
|
|
stop_quicksync()
|
2020-10-08 02:59:44 +00:00
|
|
|
disable_quicksync() # Try disable again (some users had disable fail)
|
2020-01-11 02:04:31 +00:00
|
|
|
delete_quicksync_data()
|
|
|
|
reboot_device()
|
|
|
|
|
|
|
|
def settings_enable_quicksync():
|
2021-04-11 00:51:26 +00:00
|
|
|
stop_bitcoin()
|
2020-01-11 02:04:31 +00:00
|
|
|
stop_quicksync()
|
|
|
|
enable_quicksync()
|
|
|
|
delete_quicksync_data()
|
|
|
|
reboot_device()
|
|
|
|
|
|
|
|
def delete_quicksync_data():
|
|
|
|
os.system("rm -rf /mnt/hdd/mynode/quicksync")
|
|
|
|
os.system("rm -rf /home/bitcoin/.config/transmission") # Old dir
|
|
|
|
os.system("rm -rf /mnt/hdd/mynode/.config/transmission")
|
|
|
|
|
|
|
|
def stop_quicksync():
|
|
|
|
os.system("systemctl stop quicksync")
|
2019-08-01 02:46:22 +00:00
|
|
|
|
2020-01-11 02:04:31 +00:00
|
|
|
def restart_quicksync():
|
2020-08-21 18:31:47 +00:00
|
|
|
os.system('echo "quicksync_reset" > /tmp/.mynode_status')
|
2021-04-11 00:51:26 +00:00
|
|
|
stop_bitcoin()
|
2020-01-11 02:04:31 +00:00
|
|
|
stop_quicksync()
|
|
|
|
delete_bitcoin_data()
|
|
|
|
delete_quicksync_data()
|
|
|
|
enable_quicksync()
|
|
|
|
reboot_device()
|
|
|
|
|
2021-04-14 04:53:20 +00:00
|
|
|
def get_quicksync_log():
|
|
|
|
log = "UNKNOWN"
|
|
|
|
if is_quicksync_enabled():
|
|
|
|
try:
|
2022-01-30 19:58:00 +00:00
|
|
|
log = to_string(subprocess.check_output(["mynode-get-quicksync-status"]).decode("utf8"))
|
2021-04-14 04:53:20 +00:00
|
|
|
except:
|
|
|
|
log = "ERROR"
|
|
|
|
else:
|
|
|
|
log = "Disabled"
|
|
|
|
return log
|
|
|
|
|
2020-01-11 02:04:31 +00:00
|
|
|
|
|
|
|
#==================================
|
|
|
|
# Product Key Functions
|
|
|
|
#==================================
|
2019-06-15 23:02:44 +00:00
|
|
|
def set_skipped_product_key():
|
2022-01-30 07:05:57 +00:00
|
|
|
touch("/home/bitcoin/.mynode/.product_key_skipped")
|
|
|
|
touch("/mnt/hdd/mynode/settings/.product_key_skipped")
|
2019-06-15 23:02:44 +00:00
|
|
|
def unset_skipped_product_key():
|
2022-01-30 07:05:57 +00:00
|
|
|
delete_file("/home/bitcoin/.mynode/.product_key_skipped")
|
|
|
|
delete_file("/mnt/hdd/mynode/settings/.product_key_skipped")
|
2019-06-15 23:02:44 +00:00
|
|
|
def skipped_product_key():
|
2019-08-01 00:47:04 +00:00
|
|
|
return os.path.isfile("/home/bitcoin/.mynode/.product_key_skipped") or \
|
|
|
|
os.path.isfile("/mnt/hdd/mynode/settings/.product_key_skipped")
|
2019-09-02 02:08:55 +00:00
|
|
|
def is_community_edition():
|
|
|
|
return skipped_product_key()
|
2019-06-15 23:02:44 +00:00
|
|
|
|
|
|
|
def delete_product_key():
|
2022-01-30 07:05:57 +00:00
|
|
|
delete_file("/home/bitcoin/.mynode/.product_key")
|
|
|
|
delete_file("/mnt/hdd/mynode/settings/.product_key")
|
2019-06-15 23:02:44 +00:00
|
|
|
def has_product_key():
|
|
|
|
return os.path.isfile("/home/bitcoin/.mynode/.product_key")
|
|
|
|
def get_product_key():
|
|
|
|
product_key = "no_product_key"
|
|
|
|
if skipped_product_key():
|
|
|
|
return "community_edition"
|
|
|
|
|
|
|
|
if not has_product_key():
|
|
|
|
return "product_key_missing"
|
|
|
|
|
|
|
|
try:
|
|
|
|
with open("/home/bitcoin/.mynode/.product_key", "r") as f:
|
|
|
|
product_key = f.read().strip()
|
|
|
|
except:
|
|
|
|
product_key = "product_key_error"
|
|
|
|
return product_key
|
|
|
|
def is_valid_product_key():
|
|
|
|
return not os.path.isfile("/home/bitcoin/.mynode/.product_key_error")
|
|
|
|
def save_product_key(product_key):
|
|
|
|
pk = product_key.replace("-","")
|
|
|
|
os.system("echo '{}' > /home/bitcoin/.mynode/.product_key".format(pk))
|
2019-07-06 01:45:42 +00:00
|
|
|
os.system("echo '{}' > /mnt/hdd/mynode/settings/.product_key".format(pk))
|
2019-06-15 23:02:44 +00:00
|
|
|
def delete_product_key_error():
|
|
|
|
os.system("rm -rf /home/bitcoin/.mynode/.product_key_error")
|
2019-07-06 01:45:42 +00:00
|
|
|
os.system("rm -rf /mnt/hdd/mynode/settings/.product_key_error")
|
2019-12-23 18:20:09 +00:00
|
|
|
|
2022-01-14 06:28:33 +00:00
|
|
|
def recheck_product_key():
|
|
|
|
delete_product_key_error()
|
|
|
|
os.system("systemctl restart check_in")
|
|
|
|
|
2019-12-23 18:20:09 +00:00
|
|
|
|
2020-01-11 02:04:31 +00:00
|
|
|
#==================================
|
|
|
|
# Drive Repair Functions
|
|
|
|
#==================================
|
2019-12-22 03:27:14 +00:00
|
|
|
def is_drive_being_repaired():
|
|
|
|
return os.path.isfile("/tmp/repairing_drive")
|
2019-12-12 01:34:34 +00:00
|
|
|
def has_fsck_error():
|
|
|
|
return os.path.isfile("/tmp/fsck_error")
|
2020-05-01 17:47:41 +00:00
|
|
|
def clear_fsck_error():
|
|
|
|
os.system("rm -f /tmp/fsck_error")
|
2019-12-12 01:34:34 +00:00
|
|
|
def get_fsck_results():
|
|
|
|
try:
|
|
|
|
with open("/tmp/fsck_results", "r") as f:
|
|
|
|
return f.read()
|
|
|
|
except:
|
|
|
|
return "ERROR"
|
|
|
|
return "ERROR"
|
2019-08-27 01:36:15 +00:00
|
|
|
|
2021-05-18 05:27:49 +00:00
|
|
|
def set_skip_fsck(skip):
|
|
|
|
if skip:
|
2022-01-30 07:05:57 +00:00
|
|
|
touch("/home/bitcoin/.mynode/skip_fsck")
|
2021-05-18 05:27:49 +00:00
|
|
|
else:
|
2022-01-30 07:05:57 +00:00
|
|
|
delete_file("/home/bitcoin/.mynode/skip_fsck")
|
2021-05-18 05:27:49 +00:00
|
|
|
def skip_fsck():
|
|
|
|
return os.path.isfile("/home/bitcoin/.mynode/skip_fsck")
|
|
|
|
|
2020-04-07 17:36:30 +00:00
|
|
|
def has_sd_rw_error():
|
|
|
|
return os.path.isfile("/tmp/sd_rw_error")
|
|
|
|
|
2019-12-23 18:20:09 +00:00
|
|
|
|
2021-03-03 02:06:53 +00:00
|
|
|
#==================================
|
|
|
|
# Out of Memory Error Functions
|
|
|
|
#==================================
|
|
|
|
def has_oom_error():
|
|
|
|
return os.path.isfile("/tmp/oom_error")
|
|
|
|
def clear_oom_error():
|
2022-01-30 07:05:57 +00:00
|
|
|
delete_file("/tmp/oom_error")
|
|
|
|
delete_file("/tmp/oom_info")
|
2021-03-03 02:06:53 +00:00
|
|
|
def set_oom_error(oom_error):
|
2022-01-30 07:05:57 +00:00
|
|
|
touch("/tmp/oom_error")
|
2021-03-03 02:06:53 +00:00
|
|
|
set_file_contents("/tmp/oom_info", oom_error)
|
|
|
|
def get_oom_error_info():
|
|
|
|
try:
|
|
|
|
with open("/tmp/oom_info", "r") as f:
|
|
|
|
return f.read()
|
|
|
|
except:
|
|
|
|
return "ERROR"
|
|
|
|
return "ERROR"
|
|
|
|
|
|
|
|
|
2020-01-11 02:04:31 +00:00
|
|
|
#==================================
|
|
|
|
# Docker Functions
|
|
|
|
#==================================
|
2019-12-23 18:20:09 +00:00
|
|
|
def is_installing_docker_images():
|
|
|
|
return os.path.isfile("/tmp/installing_docker_images")
|
|
|
|
|
2020-01-11 02:04:31 +00:00
|
|
|
def get_docker_image_build_status():
|
|
|
|
status_code = get_service_status_code("docker_images")
|
2019-12-23 18:20:09 +00:00
|
|
|
|
2020-01-11 02:04:31 +00:00
|
|
|
if status_code != 0:
|
|
|
|
return "Failed... Retrying Later"
|
2019-09-10 03:15:14 +00:00
|
|
|
|
2020-01-11 02:04:31 +00:00
|
|
|
if is_installing_docker_images():
|
|
|
|
return "Installing..."
|
|
|
|
else:
|
|
|
|
return "Installation Complete"
|
2019-09-10 03:15:14 +00:00
|
|
|
|
2020-01-11 02:04:31 +00:00
|
|
|
return "Unknown"
|
2019-10-20 03:20:03 +00:00
|
|
|
|
2020-01-11 02:04:31 +00:00
|
|
|
def get_docker_image_build_status_color():
|
|
|
|
status_code = get_service_status_code("docker_images")
|
|
|
|
if status_code != 0:
|
|
|
|
return "red"
|
|
|
|
return "green"
|
2019-10-26 16:32:06 +00:00
|
|
|
|
2020-03-24 17:19:18 +00:00
|
|
|
def reset_docker():
|
|
|
|
# Delete docker data
|
2022-01-30 07:05:57 +00:00
|
|
|
touch("/home/bitcoin/reset_docker")
|
2020-03-24 17:19:18 +00:00
|
|
|
|
|
|
|
# Reset marker files
|
2021-04-11 00:51:26 +00:00
|
|
|
os.system("rm -f /mnt/hdd/mynode/settings/webssh2_version")
|
|
|
|
os.system("rm -f /mnt/hdd/mynode/settings/mempool_version")
|
|
|
|
os.system("rm -f /mnt/hdd/mynode/settings/dojo_version")
|
2020-03-24 17:19:18 +00:00
|
|
|
|
2020-03-25 03:28:42 +00:00
|
|
|
# Delete Dojo files
|
2021-01-23 04:55:44 +00:00
|
|
|
os.system("rm -rf /opt/download/dojo")
|
|
|
|
os.system("rm -rf /mnt/hdd/mynode/dojo")
|
2020-03-25 03:28:42 +00:00
|
|
|
|
2020-03-24 17:19:18 +00:00
|
|
|
os.system("sync")
|
|
|
|
reboot_device()
|
|
|
|
|
2020-05-12 01:31:49 +00:00
|
|
|
def get_docker_running_containers():
|
|
|
|
containers = []
|
2021-11-20 02:39:47 +00:00
|
|
|
|
|
|
|
# If docker not running, return empty
|
|
|
|
if get_service_status_code("docker") != 0:
|
|
|
|
return containers
|
|
|
|
|
|
|
|
# TODO: switch to subprocess after switch to python3 for web ui (timeout doesn't work w/ subprocess32, causes issues)
|
2020-05-12 01:31:49 +00:00
|
|
|
try:
|
2021-04-11 00:51:26 +00:00
|
|
|
text = subprocess32.check_output("docker ps --format '{{.Names}}'", shell=True, timeout=3).decode("utf8")
|
2020-05-12 01:31:49 +00:00
|
|
|
containers = text.splitlines()
|
2021-04-11 00:51:26 +00:00
|
|
|
except Exception as e:
|
|
|
|
containers = [str(e)]
|
2020-05-12 01:31:49 +00:00
|
|
|
return containers
|
|
|
|
|
2021-12-29 18:50:03 +00:00
|
|
|
|
|
|
|
#==================================
|
|
|
|
# USB Extras Functions
|
|
|
|
#==================================
|
|
|
|
def get_usb_extras():
|
|
|
|
devices = []
|
|
|
|
json_path = "/tmp/usb_extras.json"
|
|
|
|
if os.path.isfile(json_path):
|
|
|
|
try:
|
|
|
|
with open(json_path) as f:
|
|
|
|
devices = json.load(f)
|
|
|
|
except Exception as e:
|
|
|
|
log_message("EXCEPTION in get_usb_extras: " + str(e))
|
|
|
|
devices = []
|
|
|
|
log_message("get_usb_extras: {}".format(len(devices)))
|
|
|
|
return devices
|
|
|
|
|
|
|
|
|
2020-01-11 02:04:31 +00:00
|
|
|
#==================================
|
|
|
|
# Bitcoin Functions
|
|
|
|
#==================================
|
2019-10-26 16:32:06 +00:00
|
|
|
def get_bitcoin_rpc_password():
|
|
|
|
try:
|
|
|
|
with open("/mnt/hdd/mynode/settings/.btcrpcpw", "r") as f:
|
|
|
|
return f.read()
|
|
|
|
except:
|
|
|
|
return "ERROR"
|
2019-11-04 04:50:47 +00:00
|
|
|
return "ERROR"
|
|
|
|
|
2021-04-11 00:51:26 +00:00
|
|
|
def stop_bitcoin():
|
|
|
|
os.system("systemctl stop bitcoin")
|
2019-11-04 04:50:47 +00:00
|
|
|
|
2021-03-09 03:55:39 +00:00
|
|
|
def get_bitcoin_log_file():
|
|
|
|
if is_testnet_enabled():
|
|
|
|
return "/mnt/hdd/mynode/bitcoin/testnet3/debug.log"
|
|
|
|
return "/mnt/hdd/mynode/bitcoin/debug.log"
|
|
|
|
|
2019-11-04 04:50:47 +00:00
|
|
|
def reset_bitcoin_env_file():
|
|
|
|
os.system("echo 'BTCARGS=' > "+BITCOIN_ENV_FILE)
|
|
|
|
|
|
|
|
def delete_bitcoin_data():
|
|
|
|
os.system("rm -rf /mnt/hdd/mynode/bitcoin")
|
|
|
|
os.system("rm -rf /mnt/hdd/mynode/quicksync/.quicksync_complete")
|
|
|
|
os.system("rm -rf /mnt/hdd/mynode/settings/.btcrpc_environment")
|
|
|
|
os.system("rm -rf /mnt/hdd/mynode/settings/.btcrpcpw")
|
|
|
|
|
2020-01-11 02:04:31 +00:00
|
|
|
def reset_blockchain():
|
2021-04-11 00:51:26 +00:00
|
|
|
stop_bitcoin()
|
2020-01-11 02:04:31 +00:00
|
|
|
delete_bitcoin_data()
|
|
|
|
reboot_device()
|
2019-11-04 04:50:47 +00:00
|
|
|
|
|
|
|
|
2020-01-11 02:04:31 +00:00
|
|
|
#==================================
|
|
|
|
# LND Functions
|
|
|
|
#==================================
|
2019-11-04 04:50:47 +00:00
|
|
|
def delete_lnd_data():
|
|
|
|
os.system("rm -rf "+LND_DATA_FOLDER)
|
2021-03-13 21:57:23 +00:00
|
|
|
os.system("rm -rf /tmp/lnd_deposit_address")
|
2019-11-04 04:50:47 +00:00
|
|
|
os.system("rm -rf /home/bitcoin/.lnd-admin/credentials.json")
|
|
|
|
os.system("rm -rf /mnt/hdd/mynode/settings/.lndpw")
|
|
|
|
os.system("rm -rf /home/admin/.lnd/")
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
2021-03-09 03:55:39 +00:00
|
|
|
#==================================
|
|
|
|
# Mainnet / Testnet Functions
|
|
|
|
#==================================
|
|
|
|
def is_testnet_enabled():
|
|
|
|
return os.path.isfile("/mnt/hdd/mynode/settings/.testnet_enabled")
|
|
|
|
def enable_testnet():
|
2022-01-30 07:05:57 +00:00
|
|
|
touch("/mnt/hdd/mynode/settings/.testnet_enabled")
|
2021-03-09 03:55:39 +00:00
|
|
|
def disable_testnet():
|
2022-01-30 07:05:57 +00:00
|
|
|
delete_file("/mnt/hdd/mynode/settings/.testnet_enabled")
|
2021-03-09 03:55:39 +00:00
|
|
|
def toggle_testnet():
|
|
|
|
if is_testnet_enabled():
|
|
|
|
disable_testnet()
|
|
|
|
else:
|
|
|
|
enable_testnet()
|
|
|
|
|
2020-02-06 01:15:32 +00:00
|
|
|
#==================================
|
|
|
|
# Electrum Server Functions
|
|
|
|
#==================================
|
|
|
|
def stop_electrs():
|
|
|
|
os.system("systemctl stop electrs")
|
|
|
|
|
2021-03-03 04:11:03 +00:00
|
|
|
def restart_electrs_actual():
|
|
|
|
os.system("systemctl restart electrs")
|
|
|
|
|
|
|
|
def restart_electrs():
|
|
|
|
t = Timer(0.1, restart_electrs_actual)
|
|
|
|
t.start()
|
|
|
|
|
2020-02-06 01:15:32 +00:00
|
|
|
def delete_electrs_data():
|
2021-10-23 14:25:58 +00:00
|
|
|
os.system("rm -rf /mnt/hdd/mynode/electrs/bitcoin")
|
|
|
|
os.system("rm -rf /mnt/hdd/mynode/electrs/testnet")
|
2020-02-06 01:15:32 +00:00
|
|
|
|
|
|
|
def reset_electrs():
|
|
|
|
stop_electrs()
|
|
|
|
delete_electrs_data()
|
2021-10-23 14:25:58 +00:00
|
|
|
restart_electrs()
|
2020-02-06 01:15:32 +00:00
|
|
|
|
2021-12-18 05:18:25 +00:00
|
|
|
#==================================
|
|
|
|
# RTL Functions
|
|
|
|
#==================================
|
|
|
|
def reset_rtl_config():
|
|
|
|
os.system("rm -rf /mnt/hdd/mynode/rtl/RTL-Config.json")
|
|
|
|
os.system("systemctl restart rtl")
|
2020-02-06 01:15:32 +00:00
|
|
|
|
2021-03-24 05:06:15 +00:00
|
|
|
#==================================
|
|
|
|
# Sphinx Relay Server Functions
|
|
|
|
#==================================
|
|
|
|
def stop_sphinxrelay():
|
|
|
|
os.system("systemctl stop sphinxrelay")
|
|
|
|
|
|
|
|
def restart_sphinxrelay_actual():
|
|
|
|
os.system("systemctl restart sphinxrelay")
|
|
|
|
|
|
|
|
def restart_sphinxrelay():
|
|
|
|
t = Timer(0.1, restart_sphinxrelay_actual)
|
|
|
|
t.start()
|
|
|
|
|
|
|
|
def delete_sphinxrelay_data():
|
|
|
|
os.system("rm -rf /mnt/hdd/mynode/sphinxrelay/sphinx.db")
|
|
|
|
os.system("rm -rf /opt/mynode/sphinxrelay/connection_string.txt")
|
|
|
|
|
|
|
|
def reset_sphinxrelay():
|
|
|
|
stop_sphinxrelay()
|
|
|
|
delete_sphinxrelay_data()
|
|
|
|
restart_sphinxrelay()
|
|
|
|
|
2021-07-06 04:01:38 +00:00
|
|
|
#==================================
|
|
|
|
# Mempool Functions
|
|
|
|
#==================================
|
|
|
|
def clear_mempool_cache():
|
|
|
|
os.system("rm -rf /mnt/hdd/mynode/mempool/data/*")
|
|
|
|
os.system("rm -rf /mnt/hdd/mynode/mempool/mysql/data/*")
|
|
|
|
os.system("sync")
|
|
|
|
os.system("systemctl restart mempool")
|
|
|
|
|
2021-06-21 03:26:33 +00:00
|
|
|
#==================================
|
|
|
|
# Specter Functions
|
|
|
|
#==================================
|
|
|
|
def reset_specter_config():
|
|
|
|
os.system("rm -rf /mnt/hdd/mynode/specter/config.json")
|
|
|
|
os.system("systemctl restart specter")
|
2020-02-06 01:15:32 +00:00
|
|
|
|
2021-11-20 23:39:10 +00:00
|
|
|
#==================================
|
|
|
|
# BTC RPC Explorer Functions
|
|
|
|
#==================================
|
|
|
|
def is_btcrpcexplorer_token_enabled():
|
|
|
|
if os.path.isfile("/mnt/hdd/mynode/settings/.btcrpcexplorer_disable_token"):
|
|
|
|
return False
|
|
|
|
return True
|
|
|
|
|
|
|
|
def enable_btcrpcexplorer_token():
|
2022-01-30 07:05:57 +00:00
|
|
|
delete_file("/mnt/hdd/mynode/settings/.btcrpcexplorer_disable_token")
|
2021-11-20 23:39:10 +00:00
|
|
|
if is_service_enabled("btcrpcexplorer"):
|
|
|
|
restart_service("btcrpcexplorer")
|
|
|
|
|
|
|
|
|
|
|
|
def disable_btcrpcexplorer_token():
|
2022-01-30 07:05:57 +00:00
|
|
|
touch("/mnt/hdd/mynode/settings/.btcrpcexplorer_disable_token")
|
2021-11-20 23:39:10 +00:00
|
|
|
if is_service_enabled("btcrpcexplorer"):
|
|
|
|
restart_service("btcrpcexplorer")
|
|
|
|
|
2020-01-11 02:04:31 +00:00
|
|
|
#==================================
|
|
|
|
# Tor Functions
|
|
|
|
#==================================
|
2019-11-04 04:50:47 +00:00
|
|
|
def reset_tor():
|
|
|
|
os.system("rm -rf /var/lib/tor/*")
|
2021-03-24 01:17:57 +00:00
|
|
|
os.system("rm -rf /mnt/hdd/mynode/tor_backup/*")
|
2019-11-04 04:50:47 +00:00
|
|
|
os.system("rm -rf /mnt/hdd/mynode/bitcoin/onion_private_key")
|
|
|
|
os.system("rm -rf /mnt/hdd/mynode/lnd/v2_onion_private_key")
|
2020-03-10 02:10:37 +00:00
|
|
|
os.system("rm -rf /mnt/hdd/mynode/lnd/v3_onion_private_key")
|
2020-01-29 01:59:46 +00:00
|
|
|
|
|
|
|
def is_btc_lnd_tor_enabled():
|
|
|
|
return os.path.isfile("/mnt/hdd/mynode/settings/.btc_lnd_tor_enabled")
|
|
|
|
|
|
|
|
def enable_btc_lnd_tor():
|
2022-01-30 07:05:57 +00:00
|
|
|
touch("/mnt/hdd/mynode/settings/.btc_lnd_tor_enabled")
|
2020-01-29 01:59:46 +00:00
|
|
|
|
|
|
|
def disable_btc_lnd_tor():
|
2022-01-30 07:05:57 +00:00
|
|
|
delete_file("/mnt/hdd/mynode/settings/.btc_lnd_tor_enabled")
|
2020-05-11 03:43:22 +00:00
|
|
|
|
|
|
|
def is_aptget_tor_enabled():
|
|
|
|
return os.path.isfile("/mnt/hdd/mynode/settings/torify_apt_get")
|
|
|
|
|
|
|
|
def enable_aptget_tor():
|
2022-01-30 07:05:57 +00:00
|
|
|
touch("/mnt/hdd/mynode/settings/torify_apt_get")
|
2020-05-11 03:43:22 +00:00
|
|
|
|
|
|
|
def disable_aptget_tor():
|
2022-01-30 07:05:57 +00:00
|
|
|
delete_file("/mnt/hdd/mynode/settings/torify_apt_get")
|
2020-02-14 00:47:51 +00:00
|
|
|
|
2020-03-10 02:10:37 +00:00
|
|
|
def get_onion_url_ssh():
|
2021-11-18 04:27:41 +00:00
|
|
|
if is_community_edition(): return "not_available"
|
2020-03-10 02:10:37 +00:00
|
|
|
try:
|
|
|
|
if os.path.isfile("/var/lib/tor/mynode_ssh/hostname"):
|
|
|
|
with open("/var/lib/tor/mynode_ssh/hostname") as f:
|
|
|
|
return f.read()
|
|
|
|
except:
|
|
|
|
pass
|
|
|
|
return "error"
|
|
|
|
|
2020-03-09 04:20:45 +00:00
|
|
|
def get_onion_url_general():
|
2021-11-18 04:27:41 +00:00
|
|
|
if is_community_edition(): return "not_available"
|
2020-03-09 04:20:45 +00:00
|
|
|
try:
|
|
|
|
if os.path.isfile("/var/lib/tor/mynode/hostname"):
|
|
|
|
with open("/var/lib/tor/mynode/hostname") as f:
|
2020-03-15 22:47:15 +00:00
|
|
|
return f.read().strip()
|
2020-03-09 04:20:45 +00:00
|
|
|
except:
|
|
|
|
pass
|
|
|
|
return "error"
|
|
|
|
|
|
|
|
def get_onion_url_btc():
|
2021-11-18 04:27:41 +00:00
|
|
|
if is_community_edition(): return "not_available"
|
2020-03-09 04:20:45 +00:00
|
|
|
try:
|
|
|
|
if os.path.isfile("/var/lib/tor/mynode_btc/hostname"):
|
|
|
|
with open("/var/lib/tor/mynode_btc/hostname") as f:
|
2020-03-15 22:47:15 +00:00
|
|
|
return f.read().strip()
|
2020-03-09 04:20:45 +00:00
|
|
|
except:
|
|
|
|
pass
|
|
|
|
return "error"
|
|
|
|
|
|
|
|
def get_onion_url_lnd():
|
2021-11-18 04:27:41 +00:00
|
|
|
if is_community_edition(): return "not_available"
|
2020-03-09 04:20:45 +00:00
|
|
|
try:
|
|
|
|
if os.path.isfile("/var/lib/tor/mynode_lnd/hostname"):
|
|
|
|
with open("/var/lib/tor/mynode_lnd/hostname") as f:
|
2020-03-15 22:47:15 +00:00
|
|
|
return f.read().strip()
|
2020-03-09 04:20:45 +00:00
|
|
|
except:
|
|
|
|
pass
|
|
|
|
return "error"
|
|
|
|
|
2020-03-10 02:10:37 +00:00
|
|
|
def get_onion_url_electrs():
|
2021-11-18 04:27:41 +00:00
|
|
|
if is_community_edition(): return "not_available"
|
2020-03-10 02:10:37 +00:00
|
|
|
try:
|
|
|
|
if os.path.isfile("/var/lib/tor/mynode_electrs/hostname"):
|
|
|
|
with open("/var/lib/tor/mynode_electrs/hostname") as f:
|
2020-03-15 22:47:15 +00:00
|
|
|
return f.read().strip()
|
2020-03-10 02:10:37 +00:00
|
|
|
except:
|
|
|
|
pass
|
|
|
|
return "error"
|
|
|
|
|
2021-04-02 03:54:40 +00:00
|
|
|
def get_onion_url_lndhub():
|
2021-11-18 04:27:41 +00:00
|
|
|
if is_community_edition(): return "not_available"
|
2021-04-02 03:54:40 +00:00
|
|
|
try:
|
|
|
|
if os.path.isfile("/var/lib/tor/mynode_lndhub/hostname"):
|
|
|
|
with open("/var/lib/tor/mynode_lndhub/hostname") as f:
|
|
|
|
return f.read().strip()
|
|
|
|
except:
|
|
|
|
pass
|
|
|
|
return "error"
|
|
|
|
|
2021-05-08 20:59:06 +00:00
|
|
|
def get_onion_url_lnbits():
|
2021-11-18 04:27:41 +00:00
|
|
|
if is_community_edition(): return "not_available"
|
2021-05-08 20:59:06 +00:00
|
|
|
try:
|
|
|
|
if os.path.isfile("/var/lib/tor/mynode_lnbits/hostname"):
|
|
|
|
with open("/var/lib/tor/mynode_lnbits/hostname") as f:
|
|
|
|
return f.read().strip()
|
|
|
|
except:
|
|
|
|
pass
|
|
|
|
return "error"
|
|
|
|
|
2020-05-11 03:16:02 +00:00
|
|
|
def get_onion_url_btcpay():
|
2021-11-18 04:27:41 +00:00
|
|
|
if is_community_edition(): return "not_available"
|
2020-05-11 03:16:02 +00:00
|
|
|
try:
|
|
|
|
if os.path.isfile("/var/lib/tor/mynode_btcpay/hostname"):
|
|
|
|
with open("/var/lib/tor/mynode_btcpay/hostname") as f:
|
|
|
|
return f.read().strip()
|
|
|
|
except:
|
|
|
|
pass
|
|
|
|
return "error"
|
|
|
|
|
2021-03-28 02:39:14 +00:00
|
|
|
def get_onion_url_sphinxrelay():
|
2021-11-18 04:27:41 +00:00
|
|
|
if is_community_edition(): return "not_available"
|
2021-03-28 02:39:14 +00:00
|
|
|
try:
|
|
|
|
if os.path.isfile("/var/lib/tor/mynode_sphinx/hostname"):
|
|
|
|
with open("/var/lib/tor/mynode_sphinx/hostname") as f:
|
|
|
|
return f.read().strip()
|
|
|
|
except:
|
|
|
|
pass
|
|
|
|
return "error"
|
|
|
|
|
2020-04-12 01:49:36 +00:00
|
|
|
def get_onion_info_btc_v2():
|
|
|
|
info = {}
|
|
|
|
info["url"] = "unknown"
|
|
|
|
info["pass"] = "unknown"
|
|
|
|
try:
|
|
|
|
if os.path.isfile("/var/lib/tor/mynode_btc_v2/hostname"):
|
|
|
|
with open("/var/lib/tor/mynode_btc_v2/hostname") as f:
|
|
|
|
content = f.read().strip()
|
|
|
|
parts = content.split(" ")
|
|
|
|
info["url"] = parts[0]
|
|
|
|
info["pass"] = parts[1]
|
|
|
|
return info
|
|
|
|
except:
|
|
|
|
pass
|
|
|
|
return info
|
|
|
|
|
2020-06-10 02:10:32 +00:00
|
|
|
def get_tor_version():
|
|
|
|
global cached_data
|
|
|
|
if "tor_version" in cached_data:
|
|
|
|
return cached_data["tor_version"]
|
|
|
|
|
2021-11-07 04:40:57 +00:00
|
|
|
v = to_string( subprocess.check_output("tor --version | head -n 1 | egrep -o '[0-9\\.]+[0-9]'", shell=True) )
|
|
|
|
v = v.strip()
|
|
|
|
cached_data["tor_version"] = v
|
2020-06-10 02:10:32 +00:00
|
|
|
return cached_data["tor_version"]
|
|
|
|
|
2020-02-14 00:47:51 +00:00
|
|
|
|
|
|
|
#==================================
|
|
|
|
# Firewall Functions
|
|
|
|
#==================================
|
|
|
|
def reload_firewall():
|
|
|
|
os.system("ufw reload")
|
|
|
|
|
|
|
|
def get_firewall_rules():
|
|
|
|
try:
|
2022-01-30 19:58:00 +00:00
|
|
|
rules = to_string(subprocess.check_output("ufw status", shell=True).decode("utf8"))
|
2020-02-14 00:47:51 +00:00
|
|
|
except:
|
|
|
|
rules = "ERROR"
|
|
|
|
return rules
|
2021-01-26 01:57:04 +00:00
|
|
|
|
2021-03-26 05:19:36 +00:00
|
|
|
|
2021-01-26 01:57:04 +00:00
|
|
|
#==================================
|
2021-11-07 04:40:57 +00:00
|
|
|
# SSO Functions
|
2021-01-26 01:57:04 +00:00
|
|
|
#==================================
|
2021-11-07 04:40:57 +00:00
|
|
|
def get_sso_token(short_name):
|
|
|
|
if short_name == "btcrpcexplorer":
|
|
|
|
token = get_file_contents("/opt/mynode/btc-rpc-explorer/token")
|
|
|
|
elif short_name == "thunerhub":
|
|
|
|
token = get_file_contents("/opt/mynode/thunderhub/.cookie")
|
|
|
|
else:
|
|
|
|
token = "UNKOWN_APP"
|
|
|
|
return to_string(token)
|
2021-03-27 23:17:18 +00:00
|
|
|
|
2021-11-20 23:39:10 +00:00
|
|
|
def get_sso_token_enabled(short_name):
|
|
|
|
enabled = False
|
|
|
|
if short_name == "btcrpcexplorer":
|
|
|
|
enabled = is_btcrpcexplorer_token_enabled()
|
|
|
|
return enabled
|
|
|
|
|
2021-03-27 23:17:18 +00:00
|
|
|
|
2021-03-26 05:19:36 +00:00
|
|
|
#==================================
|
|
|
|
# QR Code Functions
|
|
|
|
#==================================
|
|
|
|
def generate_qr_code(url):
|
2021-05-01 04:37:59 +00:00
|
|
|
try:
|
|
|
|
qr = qrcode.QRCode(version=1,
|
|
|
|
error_correction=qrcode.constants.ERROR_CORRECT_H,
|
|
|
|
box_size=5,
|
|
|
|
border=1)
|
|
|
|
|
|
|
|
qr.add_data(url)
|
|
|
|
qr.make(fit=True)
|
|
|
|
img = qr.make_image()
|
|
|
|
return img
|
2021-11-07 04:40:57 +00:00
|
|
|
except Exception as e:
|
|
|
|
print("generate_qr_code exception: {}".format(str(e)))
|
|
|
|
return None
|