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})
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)
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)
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)
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))