def https_enable(): board.set("tls", { "what": "enable", "state": "pending", }) job_queue.put("EnableHTTPS") return success("HTTPS enabling pending")
def signal_handler(sig, frame): global job_queue, worker log.info("signal-handler, sending 'exit' as job for graceful termination") job_queue.put("exit") worker.join() log.info("joined background-worker - exiting now...") log.info("^" * 60) sys.exit(1)
def set_led_state(self, state): """ Top-level access to LED by state * 'ready' => green * 'started' => yellow * 'updating' => yellow-blinking * 'stopped' => red * 'factory-reset' => red-blinking * 'button' => blue * 'maintenance' => purple * 'docker-wait' => green-fast-blink """ if state == "ready": self.set_led(0, 1, 0) shield.button.when_pressed = lambda: self.set_led_state("button") shield.button.when_released = lambda: self.set_led_state("ready") shield.button.when_held = lambda: (job_queue.put( "FactoryReset"), self.set_led_state("factory-reset")) elif state == "started": self.set_led(1, 1, 0) elif state == "updating": self.set_led_blink(1, 1, 0) elif state == "stopped": self.set_led(1, 0, 0) elif state == "factory-reset": self.set_led_blink(1, 0, 0) shield.button.when_pressed = None shield.button.when_released = None shield.button.when_held = None elif state == "button": self.set_led(0, 0, 1) elif state == "maintenance": self.set_led(0.5, 0, 1) shield.button.when_pressed = lambda: self.set_fast_blink(0.5, 0, 1) shield.button.when_released = lambda: (Nextcloud().soft_reset(), job_queue.put("LED")) shield.button.when_held = lambda: (job_queue.put( "FactoryReset"), self.set_led_state("factory-reset")) elif state == "docker-wait": self.set_fast_blink(0, 1, 0) else: self.set_led(0, 1, 0)
def restore_start(): src_path = request.form.get("src_path") if not backup_restore.check_backup(src_path): msg = "Invalid backup, cannot restore" log.error(msg) return error(msg) log.info(f"Initiating restore from: {src_path}") job_kwargs = {"tar_path": src_path, "mode": "restore"} job_queue.put(("BackupRestore", job_kwargs)) return success("restore started")
def register_proxy(): # assemble data for key in request.form: if key == "nk_token": token = request.form.get(key) elif key == "proxy_domain": proxy_domain = request.form.get(key) subdomain = proxy_domain.split(".")[0] scheme = "https" if cfg["config"]["https_port"] else "http" proxy_tunnel = ProxyTunnel() try: proxy_port = proxy_tunnel.setup(token, subdomain, scheme) except ProxySetupError as e: cfg["config"]["proxy_active"] = False cfg.save() log.error(str(e)) return error(str(e)) except Exception as e: cfg["config"]["proxy_active"] = False cfg.save() msg = "unexpected error during proxy setup" log.error(msg, exc_info=e) return error(msg) # configure nextcloud nc = Nextcloud() try: nc.set_config("overwriteprotocol", "https") nc.set_config("overwritecondaddr", "^172\\.18\\.238\\.1$") nc.set_config("trusted_proxies", ["172.18.238.1"]) except NextcloudError as e: cfg["config"]["proxy_active"] = False cfg.save() msg = "could not configure nextcloud for proxy usage" log.error(msg, exc_info=e) return error(msg) cfg["config"]["proxy_domain"] = proxy_domain cfg["config"]["proxy_active"] = True cfg["config"]["proxy_port"] = proxy_port cfg.save() # ensure trusted domains are set job_queue.put("TrustedDomains") return success("Proxy successfully registered")
def backup_start(): tar_path = request.form.get("tar_path") found = False for dev in partitions.backup_devices: if tar_path.startswith(dev["path"]): found = dev break if not found: msg = "Invalid backup location provided" log.error(msg) return error(msg) log.info( f"Initiating backup onto: {dev['friendly_name']} @ {dev['path']} with target: {tar_path}" ) job_kwargs = {"tar_path": tar_path, "mode": "backup"} job_queue.put(("BackupRestore", job_kwargs)) return success("backup started")
def handle_config(): if request.method == "GET": data = dict(cfg["config"]) try: data["conf"] = Path(DDCLIENT_CONFIG_PATH).read_text("utf-8") except FileNotFoundError: data["conf"] = "" return success(data=data) # save dyndns related values to configuration elif request.method == "POST": run_jobs = [] for key in request.form: val = request.form.get(key) # special config-value 'conf' represents ddclient-config-contents if key == "conf": old_conf = Path(DDCLIENT_CONFIG_PATH).read_text("utf-8") if old_conf != val: log.info("writing ddclient config and restarting service") Path(DDCLIENT_CONFIG_PATH).write_text(val, "utf-8") elif len(val.strip()) == 0: log.info("writing empty ddclient config") Path(DDCLIENT_CONFIG_PATH).write_text(val, "utf-8") services.stop("ddclient") services.disable("ddclient") if len(val.strip()) > 0: services.enable("ddclient") services.restart("ddclient") run_jobs.append("DynDNSUpdate") elif key in AVAIL_CONFIGS and val is not None: # only allow valid DYNDNS_MODES if key == "dns_mode" and val not in DYNDNS_MODES: log.warning( f"key: 'dns_mode' has invalid value: {val} - skipping") continue # start DynDNS update on "desec_done" elif key == "dns_mode" and val == "desec_done": run_jobs.append("DynDNSUpdate") # start TrustedDomains update on new domain elif "domain" in key: run_jobs.append("TrustedDomains") # deactivate proxy on request elif key == "proxy_active" and val.lower() == "false": proxy_tunnel = ProxyTunnel() proxy_tunnel.stop() # skip if 'val' is empty elif val is None: log.debug(f"skipping key: '{key}' -> no value provided") continue # convert to bool, ugly? if val.lower() in ["true", "false"]: val = val.lower() == "true" # put key-value into cfg and save (yes, saving each value) cfg["config"][key] = val log.debug(f"saving key: '{key}' with value: '{val}'") cfg.save() # run jobs collected during configuration update if len(run_jobs) > 0: for job in run_jobs: job_queue.put(job) return success("DynDNS configuration saved")