Beispiel #1
0
    def _decode(self):
        """ Try to decode certain names, ignore unicode values

        Try to decode str using utf-8. If the decode fail, raise FatalError.

        Certain config variables should contain unicode values, and
        should be defined with u'text' syntax. Python decode these if
        the file have a 'coding' line.

        This will allow utf-8 users to use simple strings using, without
        using u'string'. Other users will have to use u'string' for
        these names, because we don't know what is the charset of the
        config files.
        """
        charset = 'utf-8'
        message = """
"%(name)s" configuration variable is a string, but should be
unicode. Use %(name)s = u"value" syntax for unicode variables.

Also check your "-*- coding -*-" line at the top of your configuration
file. It should match the actual charset of the configuration file.
"""

        decode_names = (
            'sitename',
            'interwikiname',
            'user_homewiki',
            'interwiki_preferred',
            'item_license',
            'mail_from',
            'item_dict_regex',
            'item_group_regex',
            'acl_functions',
            'supplementation_item_names',
            'html_pagetitle',
            'theme_default',
            'timezone_default',
            'locale_default',
        )

        for name in decode_names:
            attr = getattr(self, name, None)
            if attr is not None:
                # Try to decode strings
                if isinstance(attr, bytes):
                    try:
                        setattr(self, name, str(attr, charset))
                    except UnicodeError:
                        raise error.ConfigurationError(message %
                                                       {'name': name})
                # Look into lists and try to decode strings inside them
                elif isinstance(attr, list):
                    for i in range(len(attr)):
                        item = attr[i]
                        if isinstance(item, bytes):
                            try:
                                attr[i] = str(item, charset)
                            except UnicodeError:
                                raise error.ConfigurationError(message %
                                                               {'name': name})
Beispiel #2
0
def _loadPluginModule(cfg):
    """
    import all plugin modules

    To be able to import plugin from arbitrary path, we have to load the base
    package. Later, we can use standard mechanisms to load plugins in this package.

    Since each configured plugin path has unique plugins, we load the plugin
    packages as "moin_p_<sha1(path)>".
    """
    assert isinstance(cfg.plugin_dirs, (list, tuple))
    cfg._plugin_modules = []
    for pdir in cfg.plugin_dirs:
        assert isinstance(pdir, str)
        modname = 'moin_p_{0}'.format(hashlib.new('sha1', pdir.encode()).hexdigest())
        if modname not in sys.modules:
            init_path = os.path.join(os.path.abspath(pdir), '__init__.py')
            spec = importlib.util.spec_from_file_location(modname, init_path)
            if spec is not None:
                module = importlib.util.module_from_spec(spec)
                spec.loader.exec_module(module)
                sys.modules[modname] = module
            else:
                msg = """\
Could not import plugin package "%(path)s":

Make sure your data directory path is correct, check permissions, and
that the data/plugin directory has an __init__.py file.
""" % dict(path=pdir)
                raise error.ConfigurationError(msg)
        if modname not in cfg._plugin_modules:
            cfg._plugin_modules.append(modname)
Beispiel #3
0
def _loadPluginModule(cfg):
    """
    import all plugin modules

    To be able to import plugin from arbitrary path, we have to load
    the base package once using imp.load_module. Later, we can use
    standard __import__ call to load plugins in this package.

    Since each configured plugin path has unique plugins, we load the
    plugin packages as "moin_plugin_<sha1(path)>.plugin".
    """
    cfg._plugin_modules = []

    try:
        # Lock other threads while we check and import
        imp.acquire_lock()
        try:
            for pdir in cfg.plugin_dirs:
                csum = 'p_{0}'.format(hashlib.new('sha1', pdir).hexdigest())
                modname = '{0}.{1}'.format(cfg.siteid, csum)
                # If the module is not loaded, try to load it
                if modname not in sys.modules:
                    # Find module on disk and try to load - slow!
                    abspath = os.path.abspath(pdir)
                    parent_dir, pname = os.path.split(abspath)
                    fp, path, info = imp.find_module(pname, [parent_dir])
                    try:
                        # Load the module and set in sys.modules
                        module = imp.load_module(modname, fp, path, info)
                        # XXX for what was this good for?:
                        # setattr(sys.modules[cfg.siteid], 'csum', module)
                    finally:
                        # Make sure fp is closed properly
                        if fp:
                            fp.close()
                if modname not in cfg._plugin_modules:
                    cfg._plugin_modules.append(modname)
        finally:
            imp.release_lock()
    except ImportError as err:
        msg = """
Could not import plugin package "%(path)s" because of ImportError:
%(err)s.

Make sure your data directory path is correct, check permissions, and
that the data/plugin directory has an __init__.py file.
""" % dict(path=pdir, err=str(err))
        raise error.ConfigurationError(msg)
Beispiel #4
0
    def _config_check(self):
        """ Check namespace and warn about unknown names

        Warn about names which are not used by DefaultConfig, except
        modules, classes, _private or __magic__ names.

        This check is disabled by default, when enabled, it will show an
        error message with unknown names.
        """
        unknown = ['"{0}"'.format(name) for name in dir(self)
                   if not name.startswith('_') and
                   name not in DefaultConfig.__dict__ and
                   not isinstance(getattr(self, name), (type(re), type(DefaultConfig)))]
        if unknown:
            msg = """
Unknown configuration options: {0}.

For more information, see configuration docs. Please check your
configuration for typos before requesting support or reporting a bug.
""".format(', '.join(unknown))
            raise error.ConfigurationError(msg)
Beispiel #5
0
    def __init__(self):
        """ Init Config instance """
        self.cache = CacheClass()

        if self.config_check_enabled:
            self._config_check()

        # define directories
        data_dir = os.path.normpath(self.data_dir)
        self.data_dir = data_dir

        # Try to decode certain names which allow unicode
        self._decode()

        # After that, pre-compile some regexes
        self.cache.item_dict_regex = re.compile(self.item_dict_regex,
                                                re.UNICODE)
        self.cache.item_group_regex = re.compile(self.item_group_regex,
                                                 re.UNICODE)

        # the ..._regexact versions only match if nothing is left (exact match)
        self.cache.item_dict_regexact = re.compile(
            '^{0}$'.format(self.item_dict_regex), re.UNICODE)
        self.cache.item_group_regexact = re.compile(
            '^{0}$'.format(self.item_group_regex), re.UNICODE)

        # compiled functions ACL
        self.cache.acl_functions = AccessControlList(
            [self.acl_functions], valid=self.acl_rights_functions)

        plugins._loadPluginModule(self)

        if self.user_defaults[TIMEZONE] is None:
            self.user_defaults[TIMEZONE] = self.timezone_default
        if self.user_defaults[THEME_NAME] is None:
            self.user_defaults[THEME_NAME] = self.theme_default
        # Note: do not assign user_defaults['locale'] = locale_default
        # to give browser language detection a chance.
        try:
            self.language_default = parse_locale(self.locale_default)[0]
        except ValueError:
            raise error.ConfigurationError(
                "Invalid locale_default value (give something like 'en_US').")

        # post process
        self.auth_can_logout = []
        self.auth_login_inputs = []
        found_names = []
        for auth in self.auth:
            if not auth.name:
                raise error.ConfigurationError(
                    "Auth methods must have a name.")
            if auth.name in found_names:
                raise error.ConfigurationError(
                    "Auth method names must be unique.")
            found_names.append(auth.name)
            if auth.logout_possible and auth.name:
                self.auth_can_logout.append(auth.name)
            for input in auth.login_inputs:
                if input not in self.auth_login_inputs:
                    self.auth_login_inputs.append(input)
        self.auth_have_login = len(self.auth_login_inputs) > 0
        self.auth_methods = found_names

        # internal dict for plugin 'modules' lists
        self._site_plugin_lists = {}

        # check if mail is possible and set flag:
        self.mail_enabled = (self.mail_smarthost is not None or
                             self.mail_sendmail is not None) and self.mail_from
        self.mail_enabled = self.mail_enabled and True or False

        if self.namespace_mapping is None:
            raise error.ConfigurationError(
                "No storage configuration specified! You need to define a namespace_mapping."
            )

        if self.backend_mapping is None:
            raise error.ConfigurationError(
                "No storage configuration specified! You need to define a backend_mapping."
            )

        if self.acl_mapping is None:
            raise error.ConfigurationError(
                "No acl configuration specified! You need to define a acl_mapping."
            )

        if self.secrets is None:  # admin did not setup a real secret
            raise error.ConfigurationError(
                "No secret configured! You need to set secrets = 'somelongsecretstring' in your wiki config."
            )

        if self.interwikiname is None:  # admin did not setup a real interwikiname
            raise error.ConfigurationError(
                "No interwikiname configured! "
                "You need to set interwikiname = u'YourUniqueStableInterwikiName' in your wiki config."
            )

        secret_key_names = [
            'security/ticket',
        ]

        secret_min_length = 10
        if isinstance(self.secrets, str):
            if len(self.secrets) < secret_min_length:
                raise error.ConfigurationError(
                    "The secrets = '...' wiki config setting is a way too short string "
                    "(minimum length is {0} chars)!".format(secret_min_length))
            # for lazy people: set all required secrets to same value
            secrets = {}
            for key in secret_key_names:
                secrets[key] = self.secrets
            self.secrets = secrets

        # we check if we have all secrets we need and that they have minimum length
        for secret_key_name in secret_key_names:
            try:
                secret = self.secrets[secret_key_name]
                if len(secret) < secret_min_length:
                    raise ValueError
            except (KeyError, ValueError):
                raise error.ConfigurationError(
                    "You must set a (at least {0} chars long) secret string for secrets['{1}']!"
                    .format(secret_min_length, secret_key_name))

        from passlib.context import CryptContext
        try:
            self.cache.pwd_context = CryptContext(**self.passlib_crypt_context)
        except ValueError as err:
            raise error.ConfigurationError(
                "passlib_crypt_context configuration is invalid [{0}].".format(
                    err))