Exemple #1
0
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
Exemple #2
0
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)
Exemple #3
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})
Exemple #4
0
    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
Exemple #5
0
    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)
Exemple #6
0
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')
Exemple #7
0
 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
Exemple #8
0
    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
Exemple #9
0
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))
Exemple #10
0
    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)
Exemple #11
0
 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()
Exemple #12
0
 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")
Exemple #13
0
 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
Exemple #14
0
 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
Exemple #15
0
 def _check_link(self):
     if not self.item:
         raise exceptions.CoreError(
             "This object has no linked database item")
Exemple #16
0
 def _raise_default_error(self):
     raise exceptions.CoreError(
         self.name, "No default handler is connected to this command")
Exemple #17
0
    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