def create_ssl_context(webserver=False, server_side=False, verify_mode=ssl.CERT_OPTIONAL, check_hostname=False, certfile=None, keyfile=None): c = ssl.create_default_context( ssl.Purpose.CLIENT_AUTH if server_side else ssl.Purpose.SERVER_AUTH) if verify_mode is not None: c.verify_mode = verify_mode if check_hostname is not None: c.check_hostname = check_hostname if not certfile: cfg_cert = config.web_cert.value if webserver else config.server_cert.value certfile = cfg_cert.get("certfile") keyfile = cfg_cert.get("keyfile") if certfile is None and webserver: cfg_cert = config.server_cert.value certfile = cfg_cert.get("certfile") keyfile = cfg_cert.get("keyfile") if certfile is None: certfile = os.path.join(constants.dir_certs, "happypandax.crt") keyfile = os.path.join(constants.dir_certs, "happypandax.key") pemfile = os.path.join(constants.dir_certs, "happypandax.pem") pfxfile = os.path.join(constants.dir_certs, "happypandax.pfx") if not os.path.exists(certfile): create_self_signed_cert(certfile, keyfile, pemfile, pfxfile) if not os.path.exists(pfxfile): export_cert_to_pfx(pfxfile, certfile, keyfile) if server_side and not webserver: log.i("Certs not provided, using self-signed certificate", stdout=True) else: if not os.path.exists(certfile) and not (os.path.exists(keyfile) if keyfile else False): raise exceptions.CoreError( this_function(), "Non-existent certificate or private key file") if not keyfile: keyfile = None try: if server_side: c.load_cert_chain(certfile=certfile, keyfile=keyfile) else: c.load_verify_locations(certfile) except OSError as e: if e.errno == errno.EINVAL: raise exceptions.CoreError( this_function(), "Invalid certificate or private key filepath") raise exceptions.CoreError( this_function(), "Invalid certificate or private key: {}".format(e)) return c
def plugin_load(path, *args, **kwargs): """ Attempts to load a plugin Params: - path -- path to plugin directory - *args -- additional arguments for plugin - **kwargs -- additional keyword arguments for plugin """ args = ["test"] kwargs = {"1": 2} plugfile = None for f in os.scandir(path): if f.name.lower() == "hplugin.py": plugfile = f break if not plugfile: raise exceptions.CoreError( "Plugin loader", "No main entry file named 'HPlugin.py' found in '{}'".format( f.path)) plug = os.path.splitext(plugfile.name)[0] sys.path.insert(0, os.path.realpath(path)) try: _plugin_load(plug, path, *args, **kwargs) finally: sys.path.pop(0)
def scan_galleries(path: str, scan_options: dict = {}): """ Scan for galleries in the given directory/archive Args: path: path to directory/archive that exists on this system scan_options: options to apply to the scanning process, see :ref:`Settings` for available scanning options Returns: .. code-block:: guess { 'command_id': int, 'view_id': int } |async command| |temp view| """ path = io_cmd.CoreFS(path) if not path.exists: raise exceptions.CoreError( utils.this_function(), f"Path does not exists on this system: '{path.path}'") view_id = next(constants.general_counter) cmd_id = gallery_cmd.ScanGallery(services.AsyncService.generic).run( path, scan_options, view_id=view_id) return message.Identity('data', {'command_id': cmd_id, 'view_id': view_id})
def __init__(self, fpath): self._archive = None self._path = pathlib.Path(fpath) self._ext = self._path.suffix.lower() if not self._path.exists(): raise exceptions.ArchiveError( "Archive file does not exist. File '{}' not found.".format( str(self._path))) if not self._path.suffix.lower() in CoreFS.archive_formats(): raise exceptions.UnsupportedArchiveError(str(self._path)) try: with self._init.call_capture(self._ext, self._path) as plg: self._archive = plg.first_or_none() if not self._archive: raise exceptions.CoreError( utils.this_function(), "No valid archive handler found for this archive type: '{}'" .format(self._ext)) with self._test_corrupt.call_capture(self._ext, self._archive) as plg: r = plg.first_or_none() if r is not None: if r: raise exceptions.BadArchiveError(str(self._path)) with self._path_sep.call_capture(self._ext, self._archive) as plg: p = plg.first_or_none() self.path_separator = p if p else '/' except: if self._archive: self.close() raise
def main(self, model_name: str) -> db.Base: if not hasattr(db, model_name): raise exceptions.CoreError( utils.this_command(self), "No database model named '{}'".format(model_name)) return getattr(db, model_name)
async def check_daemon_absence(): try: async with ControlClient(): pass except RuntimeError: pass else: raise exceptions.CoreError("torrent daemon", 'A daemon on this port is already running')
def update(self, key, value): "Update a setting. Returns value" assert self._current_ns, "No namespace has been set" if key not in self._cfg[self._current_ns]: raise exceptions.CoreError( "Config.update", "key '{}' doesn't exist in namespace '{}'".format( key, self._current_ns)) self.define(key, value) return value
def _msg_and_model(item_type, allowed=tuple(), error=True): """ Get the equivalent Message and Database object classes for ItemType member Args: allowed: a tuple of ItemType members which are allowed, empty tuple for all members error: raise error if equivalent is not found, else return generic message object class """ if allowed and repr(item_type) not in (repr(x) for x in allowed): raise exceptions.APIError( utils.this_function(), "ItemType must be on of {} not '{}'".format( allowed, repr(item_type))) db_model = None try: db_model = getattr(db, item_type.name) except AttributeError: if error: raise exceptions.CoreError( utils.this_function(), "Equivalent database object class for {} was not found". format(item_type)) obj = None try: obj = getattr(message, item_type.name) except AttributeError: try: if db_model and issubclass(db_model, db.NameMixin): obj = getattr(message, db.NameMixin.__name__) except AttributeError: pass if not obj: if error: raise exceptions.CoreError( utils.this_function(), "Equivalent Message object class for {} was not found". format(item_type)) obj = message.DatabaseMessage return obj, db_model
async def _add(filename, download_dir=None, files=None, mode=None): tf = TorrentInfo.from_file(filename, download_dir=download_dir) if mode: if tf.download_info.single_file_mode: raise exceptions.CoreError( "torrent addition", "Can't select files in a single-file torrent") files = [PATH_SPLIT_RE.split(path) for path in files] tf.download_info.select_files(files, mode) async with ControlClient() as client: await client.execute(partial(ControlManager.add, torrent_info=tf))
def main(self, model_name: str) -> db.Base: e = False try: if not hasattr(db, model_name) or not issubclass( getattr(db, model_name), db.Base): e = True except TypeError: e = True if e: raise exceptions.CoreError( utils.this_command(self), "No database model named '{}'".format(model_name)) return getattr(db, model_name)
def open(self, *args, **kwargs): self._init_archive() try: if self.inside_archive: f = self._archive.open(self.archive_name, *args, **kwargs) else: f = open(self.get(), *args, **kwargs) except PermissionError: if self.is_dir: raise exceptions.CoreError( utils.this_function(), "Tried to open a folder which is not possible") raise yield f f.close()
def _init_plugin(self, pluginid): "" if pluginid in self._nodes: node = self._nodes[pluginid] try: self._ensure_valid_signature(node) node.instanced = node.plugin(*node.args, **node.kwargs) except Exception as e: self.disable_plugin(pluginid) if not isinstance(e, exceptions.PluginError): raise exceptions.PluginError(node, "{}".format(e)) raise node.state = PluginState.Enabled else: raise exceptions.CoreError( utils.this_function(), "Plugin node has not been registered with this manager")
def update(self, key, value, user=True, create=False): "Update a setting. Returns value" assert self._current_ns, "No namespace has been set" if not create: if key not in self._cfg[self._current_ns]: raise exceptions.CoreError( "Config.update", "key '{}' doesn't exist in namespace '{}'".format( key, self._current_ns)) if user: user_cfg = self._files_map.get(self._user_file) if user_cfg is not None: u_cfg = user_cfg.setdefault(self._current_ns, {}) u_cfg[key] = value if u_cfg not in self._cfg[self._current_ns].maps: self._cfg[self._current_ns].maps.insert( self._get_user_config_idx(), u_cfg) else: self._cfg[self._current_ns][key] = value return value
def _update(self, items, options): with db.safe_session() as sess: with db.no_autoflush(sess): obj_types = set() for i in items: if not i.id: raise exceptions.CoreError( utils.this_function(), "Cannot update an item without an id") if isinstance(i, io_cmd.GalleryFS): i = i.gallery obj_types.add(type(i)) i_sess = db.object_session(i) if i_sess and i_sess != sess: i_sess.expunge_all( ) # HACK: what if other sess was in use? sess.add(i) self.next_progress() sess.commit() if db.Gallery in obj_types: constants.invalidator.similar_gallery = True
def _check_link(self): if not self.item: raise exceptions.CoreError( "This object has no linked database item")
def _raise_default_error(self): raise exceptions.CoreError( self.name, "No default handler is connected to this command")
def from_json(cls, msg, ignore_empty=True, skip_updating_existing=True, skip_descriptors=False, _type=None, ignore_private=True, _from_attr=''): db_obj = None if not msg: return db_obj if not isinstance(msg, dict): raise exceptions.InvalidMessage( utils.this_function(), f"Expected message object on '{_from_attr}' not '{type(msg).__name__}'") with db.no_autoflush(constants.db_session()) as sess: if not cls.db_type and _type is None: raise ValueError("A database type has not been set") db_type = _type or cls.db_type item_attrs = db.table_attribs(db_type, id=None, descriptors=True) if msg and not all((k in item_attrs.keys() for k in msg.keys())): m_keys = set(msg.keys()).difference(set(item_attrs.keys())) raise exceptions.InvalidMessage( utils.this_function(), f"Message object mismatch. '{_from_attr}' contains keys that are not present in the corresponding database item: {m_keys}") if msg: new_obj = True obj_id = msg.get('id', False) if obj_id: db_obj = sess.query(db_type).get(obj_id) if not db_obj: raise exceptions.CoreError(utils.this_function(), f"Existing item from message object with id '{obj_id}' was not found") new_obj = False else: db_obj = db_type() if new_obj and isinstance(db_obj, db.UniqueMixin): if isinstance(db_obj, db.NameMixin) and msg.get('name') is not None: db_obj = db_type.as_unique(name=msg.get('name')) new_obj = bool(db_obj.id) elif isinstance(db_obj, db.NamespaceTags): ns_name = None tag_name = None try: ns_name = utils.get_dict_value('namespace.name', msg) tag_name = utils.get_dict_value('tag.name', msg) except KeyError: pass if ns_name is not None and tag_name is not None: db_obj = db_type.as_unique(ns=ns_name, tag=tag_name) new_obj = bool(db_obj.id) elif isinstance(db_obj, (db.Artist, db.Parody)): a_names = set() if msg.get('preferred_name') and msg['preferred_name'].get('name') is not None: a_names.add(msg['preferred_name']['name']) if msg.get('names'): for n in msg['names']: if n.get('name') is not None: a_names.add(n['name']) if a_names: db_obj = db_type.as_unique(names=a_names) new_obj = bool(db_obj.id) if db_obj and not (obj_id and db_obj and skip_updating_existing): for attr, value in msg.items(): if attr == 'id': continue if ignore_private and attr.startswith('_'): continue if ignore_empty: if value is None: continue elif isinstance(value, (list, dict)) and not value: continue cls_attr = item_attrs[attr] if skip_descriptors and db.is_descriptor(cls_attr): continue obj_attr = getattr(db_obj, attr) # noqa: F841 try: col_model = db.column_model(cls_attr) except TypeError: # most likely a hybrid_property descriptor col_model = None if not issubclass(col_model, db.Base) if inspect.isclass( col_model) else not isinstance(col_model, db.Base): if isinstance(col_model, (db.Boolean, db.Integer, db.Password, db.String, db.Text, db.LowerCaseString, db.CapitalizedString)): setattr(db_obj, attr, value) elif isinstance(col_model, db.ArrowType): setattr(db_obj, attr, arrow.Arrow.fromtimestamp(value)) elif db.is_descriptor(cls_attr): if db.descriptor_has_setter(cls_attr): raise NotImplementedError else: raise NotImplementedError( f"Value deserializing for this database type does not exist ({col_model})") continue msg_obj = cls._get_message_object(cls, attr, col_model, check_recursive=False, class_type=True) if col_model == db.Taggable and isinstance(value, dict): if db_obj.taggable and db_obj.taggable.id: value['id'] = db_obj.taggable.id if issubclass(col_model, db.MetaTag): setattr(db_obj, attr, msg_obj._pack_metatags(value)) elif db.is_list(cls_attr) or db.is_query(cls_attr): n_l = [] for v in value: o = msg_obj.from_json( v, _type=col_model, ignore_empty=ignore_empty, skip_updating_existing=skip_updating_existing, skip_descriptors=skip_descriptors, _from_attr=_from_attr + '.' + attr if _from_attr else attr, ) if o is not None: n_l.append(o) setattr(db_obj, attr, n_l) elif db.is_descriptor(cls_attr): if db.descriptor_has_setter(cls_attr): raise NotImplementedError else: setattr( db_obj, attr, msg_obj.from_json( value, _type=col_model, _from_attr=_from_attr + '.' + attr if _from_attr else attr, ignore_empty=ignore_empty, skip_updating_existing=skip_updating_existing, skip_descriptors=skip_descriptors)) return db_obj