def initialize_upnp(svcs): """ Initialize uPnP port forwarding with the IGD. :param SecurityPolicy svcs: SecurityPolicies to open """ upnpc = _upnp_igd_connect() if not upnpc: return for svc in svcs: if svc.policy != 2: continue for protocol, port in svc.ports: if upnpc.getspecificportmapping(port, protocol.upper()): try: upnpc.deleteportmapping(port, protocol.upper()) except: pass try: pf = 'arkOS Port Forwarding: {0}' upnpc.addportmapping(port, protocol.upper(), upnpc.lanaddr, port, pf.format(port), '') except Exception as e: msg = "Failed to register {0} with uPnP IGD: {1}"\ .format(port, str(e)) logger.warning("TrSv", msg)
def create_token(user): """ Create a JSON Web Token (JWT) for the specified user. :param User user: an arkOS user :returns: JSON Web Token (JWT) :rtype: str """ iat = systemtime.get_unix_time() try: offset = systemtime.get_offset() if offset < -3600 or offset > 3600: systemtime.set_datetime() iat = systemtime.get_unix_time() except: twarn = ("System time is not accurate or could not be verified." " Access tokens will not expire.") logger.warning("System", twarn) iat = None payload = { "uid": user.name, "ufn": user.first_name, "uln": user.last_name, } if iat: payload["iat"] = iat payload["exp"] = iat + config.get("genesis", "token_valid_for", 3600) tjwss = TimedJSONWebSignatureSerializer( secret_key=current_app.config["SECRET_KEY"], expires_in=config.get("genesis", "token_valid_for", 3600), algorithm_name="HS256") return tjwss.dumps(payload).decode("utf-8")
def _upnp_igd_connect(): logger.debug("TrSv", "Attempting to connect to uPnP IGD") upnpc = miniupnpc.UPnP() upnpc.discoverdelay = 3000 devs = upnpc.discover() if devs == 0: msg = "Failed to connect to uPnP IGD: no devices found" logger.warning("TrSv", msg) return try: upnpc.selectigd() except Exception as e: msg = "Failed to connect to uPnP IGD: {0}" logger.warning("TrSv", msg.format(str(e))) return upnpc
def scan_shares(): """ Retrieve a list of all file shares registered with arkOS. :return: Share(s) :rtype: Share or list thereof """ storage.shares.clear() for x in get_sharers(): try: for y in x.get_shares(): storage.shares[y.id] = y except Exception as e: logger.warning("Sharers", "Could not get shares for {0}".format(x.name)) logger.debug("Sharers", str(e)) return storage.shares
def _install(id, load=True, cry=True): """ Utility function to download and install arkOS app packages. :param str id: ID of arkOS app to install :param bool load: Load the app after install? :param bool cry: Raise exception on dependency install failure? """ app_dir = config.get("apps", "app_dir") # Download and extract the app source package api_url = "https://{0}/api/v1/apps/{1}" data = api(api_url.format(config.get("general", "repo_server"), id), returns="raw", crit=True) path = os.path.join(app_dir, "{0}.tar.gz".format(id)) with open(path, "wb") as f: f.write(data) with tarfile.open(path, "r:gz") as t: t.extractall(app_dir) os.unlink(path) # Read the app's metadata and create an object with open(os.path.join(app_dir, id, "manifest.json")) as f: data = json.loads(f.read()) app = get(id) for x in data: setattr(app, x, data[x]) app.upgradable = "" app.installed = True for x in app.services: if x.get("type") == "system" and x.get("binary") \ and not x.get("ignore_on_install"): s = services.get(x["binary"]) if s: s.enable() if s.state != "running": try: s.start() except services.ActionError as e: logger.warning( "Apps", "{0} could not be automatically started." .format(s.name)) if load: app.load(cry=cry)
def run_daemon(environment, config_file, secrets_file, policies_file, debug): """Run the Kraken server daemon.""" app.debug = debug or environment in ["dev", "vagrant"] app.config["SECRET_KEY"] = random_string() # Open and load configuraton config = arkos.init(config_file, secrets_file, policies_file, app.debug, environment in ["dev", "vagrant"], app.logger) storage.connect() if environment not in ["dev", "vagrant"]: filehdlr = RotatingFileHandler( '/var/log/kraken.log', maxBytes=2097152, backupCount=5 ) st = "{asctime} [{cls}] [{levelname}] {comp}: {message}" filehdlr.setLevel(logging.DEBUG if app.debug else logging.INFO) filehdlr.setFormatter(FileFormatter(st)) logger.logger.addHandler(filehdlr) apihdlr = APIHandler() apihdlr.setLevel(logging.DEBUG if app.debug else logging.INFO) apihdlr.addFilter(NotificationFilter()) logger.logger.addHandler(apihdlr) logger.info("Init", "arkOS Kraken {0}".format(arkos.version)) if environment in ["dev", "vagrant"]: logger.debug("Init", "*** TEST MODE ***") logger.info("Init", "Using config file at {0}".format(config.filename)) app.conf = config arch = config.get("enviro", "arch", "Unknown") board = config.get("enviro", "board", "Unknown") platform = detect_platform() hwstr = "Detected architecture/hardware: {0}, {1}" logger.info("Init", hwstr.format(arch, board)) logger.info("Init", "Detected platform: {0}".format(platform)) logger.info("Init", "Environment: {0}".format(environment)) config.set("enviro", "run", environment) for code in list(default_exceptions.keys()): app.register_error_handler(code, make_json_error) app.register_blueprint(auth.backend) logger.info("Init", "Loading applications and scanning system...") arkos.initial_scans() # Load framework blueprints logger.info("Init", "Loading frameworks...") register_frameworks(app) logger.info("Init", "Initializing Genesis (if present)...") app.register_blueprint(genesis.backend) hasgen = genesis.verify_genesis() if not hasgen: errmsg = ("A compiled distribution of Genesis was not found. " "Kraken will finish loading but you may not be able to " "access the Web interface.") logger.warning("Init", errmsg) app.after_request(add_cors_to_response) logger.info("Init", "Server is up and ready") try: import eventlet pubsub = storage.redis.pubsub(ignore_subscribe_messages=True) pubsub.subscribe(["arkos:notifications", "arkos:records:push", "arkos:records:purge"]) eventlet.spawn(handle_pubsub, pubsub, socketio) eventlet_socket = eventlet.listen( (config.get("genesis", "host"), config.get("genesis", "port")) ) if config.get("genesis", "ssl", False): eventlet_socket = eventlet.wrap_ssl( eventlet_socket, certfile=config.get("genesis", "cert_file"), keyfile=config.get("genesis", "cert_key"), ssl_version=ssl.PROTOCOL_TLSv1_2, server_side=True) eventlet.wsgi.server( eventlet_socket, app, log=WSGILogWrapper(), log_format=('%(client_ip)s - "%(request_line)s" %(status_code)s ' '%(body_length)s %(wall_seconds).6f')) except KeyboardInterrupt: logger.info("Init", "Received interrupt") raise
def scan(verify=True, cry=True): """ Search app directory for applications, load them and store metadata. Also contacts arkOS repo servers to obtain current list of available apps, and merges in any updates as necessary. :param bool verify: Verify app dependencies as the apps are scanned :param bool cry: Raise exception on dependency install failure? :return: list of Application objects :rtype: list """ signals.emit("apps", "pre_scan") logger.debug("Apps", "Scanning for applications") app_dir = config.get("apps", "app_dir") if not os.path.exists(app_dir): os.makedirs(app_dir) pacman.refresh() logger.debug("Apps", "Getting system/python/ruby installed list") inst_list = { "sys": pacman.get_installed(), "py": python.get_installed(), "py2": python.get_installed(py2=True), "rb": ruby.get_installed() } # Get paths for installed apps, metadata for available ones installed_apps = [x for x in os.listdir(app_dir) if not x.startswith(".")] api_url = ("https://{0}/api/v1/apps" .format(config.get("general", "repo_server"))) logger.debug("Apps", "Fetching available apps: {0}".format(api_url)) try: available_apps = api(api_url) except Exception as e: available_apps = [] logger.error("Apps", "Could not get available apps from GRM.") logger.error("Apps", str(e)) if available_apps: available_apps = available_apps["applications"] else: available_apps = [] # Create objects for installed apps with appropriate metadata for x in installed_apps: try: with open(os.path.join(app_dir, x, "manifest.json"), "r") as f: data = json.loads(f.read()) except ValueError: warn_str = "Failed to load {0} due to a JSON parsing error" logger.warning("Apps", warn_str.format(x)) continue except IOError: warn_str = "Failed to load {0}: manifest file inaccessible "\ "or not present" logger.warning("Apps", warn_str.format(x)) continue logger.debug("Apps", " *** Loading {0}".format(data["id"])) app = App(**data) app.installed = True for y in enumerate(available_apps): if app.id == y[1]["id"] and app.version != y[1]["version"]: app.upgradable = y[1]["version"] if app.id == y[1]["id"]: app.assets = y[1]["assets"] available_apps[y[0]]["installed"] = True app.load(verify=verify, cry=cry, installed=inst_list) storage.applications[app.id] = app # Convert available apps payload to objects for x in available_apps: if not x.get("installed"): app = App(**x) app.installed = False storage.applications[app.id] = app if verify: verify_app_dependencies() signals.emit("apps", "post_scan") return storage.applications