def readPassword(self): """ Read passwords from a file. DO NOT FORGET TO REMOVE READ ACCESS FOR OTHER USERS!!! Use chmod 600 password-file. All lines below should be valid Python tuples in the form (code, family, username, password), (family, username, password) or (username, password) to set a default password for an username. The last matching entry will be used, so default usernames should occur above specific usernames. The file must be either encoded in ASCII or UTF-8. Example: (u"my_username", u"my_default_password") (u"my_sysop_user", u"my_sysop_password") (u"wikipedia", u"my_wikipedia_user", u"my_wikipedia_pass") (u"en", u"wikipedia", u"my_en_wikipedia_user", u"my_en_wikipedia_pass") """ # We fix password file permission first, # lift upper permission (regular file) from st_mode # to compare it with private_files_permission. if os.stat(config.password_file).st_mode - stat.S_IFREG \ != config.private_files_permission: os.chmod(config.password_file, config.private_files_permission) password_f = codecs.open(config.password_file, encoding='utf-8') for line_nr, line in enumerate(password_f): if not line.strip(): continue try: entry = eval(line) except SyntaxError: entry = None if type(entry) is not tuple: warn('Invalid tuple in line {0}'.format(line_nr), _PasswordFileWarning) continue if not 2 <= len(entry) <= 4: warn( 'The length of tuple in line {0} should be 2 to 4 ({1} ' 'given)'.format(line_nr, entry), _PasswordFileWarning) continue # When the tuple is inverted the default family and code can be # easily appended which makes the next condition easier as it does # not need to know if it's using the default value or not. entry = list(entry[::-1]) + [ self.site.family.name, self.site.code ][len(entry) - 2:] if (normalize_username(entry[1]) == self.username and entry[2] == self.site.family.name and entry[3] == self.site.code): self.password = entry[0] password_f.close()
def readPassword(self): """ Read passwords from a file. DO NOT FORGET TO REMOVE READ ACCESS FOR OTHER USERS!!! Use chmod 600 password-file. All lines below should be valid Python tuples in the form (code, family, username, password), (family, username, password) or (username, password) to set a default password for an username. The last matching entry will be used, so default usernames should occur above specific usernames. The file must be either encoded in ASCII or UTF-8. Example: (u"my_username", u"my_default_password") (u"my_sysop_user", u"my_sysop_password") (u"wikipedia", u"my_wikipedia_user", u"my_wikipedia_pass") (u"en", u"wikipedia", u"my_en_wikipedia_user", u"my_en_wikipedia_pass") """ # We fix password file permission first, # lift upper permission (regular file) from st_mode # to compare it with private_files_permission. if os.stat(config.password_file).st_mode - stat.S_IFREG \ != config.private_files_permission: os.chmod(config.password_file, config.private_files_permission) password_f = codecs.open(config.password_file, encoding='utf-8') for line_nr, line in enumerate(password_f): if not line.strip(): continue try: entry = eval(line) except SyntaxError: entry = None if type(entry) is not tuple: warn('Invalid tuple in line {0}'.format(line_nr), _PasswordFileWarning) continue if not 2 <= len(entry) <= 4: warn('The length of tuple in line {0} should be 2 to 4 ({1} ' 'given)'.format(line_nr, entry), _PasswordFileWarning) continue # When the tuple is inverted the default family and code can be # easily appended which makes the next condition easier as it does # not need to know if it's using the default value or not. entry = list(entry[::-1]) + [self.site.family.name, self.site.code][len(entry) - 2:] if (normalize_username(entry[1]) == self.username and entry[2] == self.site.family.name and entry[3] == self.site.code): self.password = entry[0] password_f.close()
def Site(code=None, fam=None, user=None, sysop=None, interface=None, url=None): """A factory method to obtain a Site object. Site objects are cached and reused by this method. By default rely on config settings. These defaults may all be overridden using the method parameters. @param code: language code (override config.mylang) @type code: str @param fam: family name or object (override config.family) @type fam: str or Family @param user: bot user name to use on this site (override config.usernames) @type user: str @param sysop: sysop user to use on this site (override config.sysopnames) @type sysop: str @param interface: site class or name of class in pywikibot.site (override config.site_interface) @type interface: subclass of L{pywikibot.site.BaseSite} or string @param url: Instead of code and fam, does try to get a Site based on the URL. Still requires that the family supporting that URL exists. @type url: str @rtype: pywikibot.site.APISite @raises ValueError: URL and pair of code and family given @raises ValueError: Invalid interface name @raises SiteDefinitionError: Unknown URL """ _logger = 'wiki' if url: # Either code and fam or only url if code or fam: raise ValueError( 'URL to the wiki OR a pair of code and family name ' 'should be provided') code, fam = _code_fam_from_url(url) else: # Fallback to config defaults code = code or config.mylang fam = fam or config.family if not isinstance(fam, Family): fam = Family.load(fam) interface = interface or fam.interface(code) # config.usernames is initialised with a defaultdict for each family name family_name = str(fam) code_to_user = config.usernames['*'].copy() code_to_user.update(config.usernames[family_name]) user = user or code_to_user.get(code) or code_to_user.get('*') code_to_sysop = config.sysopnames['*'].copy() code_to_sysop.update(config.sysopnames[family_name]) sysop = sysop or code_to_sysop.get(code) or code_to_sysop.get('*') if not isinstance(interface, type): # If it isn't a class, assume it is a string if PY2: # Must not be unicode in Python 2 interface = str(interface) try: tmp = __import__('pywikibot.site', fromlist=[interface]) except ImportError: raise ValueError('Invalid interface name: {0}'.format(interface)) else: interface = getattr(tmp, interface) if not issubclass(interface, BaseSite): warning('Site called with interface=%s' % interface.__name__) user = normalize_username(user) key = '%s:%s:%s:%s' % (interface.__name__, fam, code, user) if key not in _sites or not isinstance(_sites[key], interface): _sites[key] = interface(code=code, fam=fam, user=user, sysop=sysop) debug("Instantiated %s object '%s'" % (interface.__name__, _sites[key]), _logger) if _sites[key].code != code: warn('Site %s instantiated using different code "%s"' % (_sites[key], code), UserWarning, 2) return _sites[key]
def Site(code=None, fam=None, user=None, sysop=None, interface=None, url=None): """A factory method to obtain a Site object. Site objects are cached and reused by this method. By default rely on config settings. These defaults may all be overridden using the method parameters. @param code: language code (override config.mylang) @type code: string @param fam: family name or object (override config.family) @type fam: string or Family @param user: bot user name to use on this site (override config.usernames) @type user: unicode @param sysop: sysop user to use on this site (override config.sysopnames) @type sysop: unicode @param interface: site class or name of class in pywikibot.site (override config.site_interface) @type interface: subclass of L{pywikibot.site.BaseSite} or string @param url: Instead of code and fam, does try to get a Site based on the URL. Still requires that the family supporting that URL exists. @type url: string @rtype: pywikibot.site.APISite """ # Either code and fam or only url if url and (code or fam): raise ValueError('URL to the wiki OR a pair of code and family name ' 'should be provided') _logger = "wiki" if url: if url not in _url_cache: matched_sites = [] # Iterate through all families and look, which does apply to # the given URL for fam in config.family_files: family = Family.load(fam) code = family.from_url(url) if code is not None: matched_sites += [(code, family)] if matched_sites: if len(matched_sites) > 1: warning( 'Found multiple matches for URL "{0}": {1} (use first)' .format(url, ', '.join(str(s) for s in matched_sites))) _url_cache[url] = matched_sites[0] else: # TODO: As soon as AutoFamily is ready, try and use an # AutoFamily _url_cache[url] = None cached = _url_cache[url] if cached: code = cached[0] fam = cached[1] else: raise SiteDefinitionError("Unknown URL '{0}'.".format(url)) else: # Fallback to config defaults code = code or config.mylang fam = fam or config.family if not isinstance(fam, Family): fam = Family.load(fam) interface = interface or fam.interface(code) # config.usernames is initialised with a defaultdict for each family name family_name = str(fam) code_to_user = config.usernames['*'].copy() code_to_user.update(config.usernames[family_name]) user = user or code_to_user.get(code) or code_to_user.get('*') code_to_sysop = config.sysopnames['*'].copy() code_to_sysop.update(config.sysopnames[family_name]) sysop = sysop or code_to_sysop.get(code) or code_to_sysop.get('*') if not isinstance(interface, type): # If it isnt a class, assume it is a string try: tmp = __import__('pywikibot.site', fromlist=[interface]) interface = getattr(tmp, interface) except ImportError: raise ValueError('Invalid interface name: {0}'.format(interface)) if not issubclass(interface, BaseSite): warning('Site called with interface=%s' % interface.__name__) user = normalize_username(user) key = '%s:%s:%s:%s' % (interface.__name__, fam, code, user) if key not in _sites or not isinstance(_sites[key], interface): _sites[key] = interface(code=code, fam=fam, user=user, sysop=sysop) debug(u"Instantiated %s object '%s'" % (interface.__name__, _sites[key]), _logger) if _sites[key].code != code: warn('Site %s instantiated using different code "%s"' % (_sites[key], code), UserWarning, 2) return _sites[key]
def readPassword(self): """ Read passwords from a file. DO NOT FORGET TO REMOVE READ ACCESS FOR OTHER USERS!!! Use chmod 600 password-file. All lines below should be valid Python tuples in the form (code, family, username, password), (family, username, password) or (username, password) to set a default password for an username. The last matching entry will be used, so default usernames should occur above specific usernames. For BotPasswords the password should be given as a BotPassword object. The file must be either encoded in ASCII or UTF-8. Example:: ('my_username', 'my_default_password') ('my_sysop_user', 'my_sysop_password') ('wikipedia', 'my_wikipedia_user', 'my_wikipedia_pass') ('en', 'wikipedia', 'my_en_wikipedia_user', 'my_en_wikipedia_pass') ('my_username', BotPassword( 'my_BotPassword_suffix', 'my_BotPassword_password')) """ # Set path to password file relative to the user_config # but fall back on absolute path for backwards compatibility password_file = os.path.join(config.base_dir, config.password_file) if not os.path.isfile(password_file): password_file = config.password_file # We fix password file permission first. file_mode_checker(password_file, mode=config.private_files_permission) with codecs.open(password_file, encoding='utf-8') as f: lines = f.readlines() line_nr = len(lines) + 1 for line in reversed(lines): line_nr -= 1 if not line.strip() or line.startswith('#'): continue try: entry = eval(line) except SyntaxError: entry = None if type(entry) is not tuple: warn('Invalid tuple in line {0}'.format(line_nr), _PasswordFileWarning) continue if not 2 <= len(entry) <= 4: warn( 'The length of tuple in line {0} should be 2 to 4 ({1} ' 'given)'.format(line_nr, entry), _PasswordFileWarning) continue code, family, username, password = ( self.site.code, self.site.family.name)[:4 - len(entry)] + entry if (normalize_username(username) == self.username and family == self.site.family.name and code == self.site.code): if isinstance(password, UnicodeType): self.password = password break elif isinstance(password, BotPassword): self.password = password.password self.login_name = password.login_name(self.username) break else: warn('Invalid password format', _PasswordFileWarning)
def Site(code: Optional[str] = None, fam=None, user: Optional[str] = None, *, interface=None, url: Optional[str] = None) -> Union[APISite, DataSite, ClosedSite]: """A factory method to obtain a Site object. Site objects are cached and reused by this method. By default rely on config settings. These defaults may all be overridden using the method parameters. @param code: language code (override config.mylang) code may also be a sitename like 'wikipedia:test' @param fam: family name or object (override config.family) @type fam: str or pywikibot.family.Family @param user: bot user name to use on this site (override config.usernames) @param interface: site class or name of class in pywikibot.site (override config.site_interface) @type interface: subclass of L{pywikibot.site.BaseSite} or string @param url: Instead of code and fam, does try to get a Site based on the URL. Still requires that the family supporting that URL exists. @raises ValueError: URL and pair of code and family given @raises ValueError: Invalid interface name """ _logger = 'wiki' if url: # Either code and fam or url with optional fam for AutoFamily name if code: raise ValueError( 'URL to the wiki OR a pair of code and family name ' 'should be provided') code, fam = _code_fam_from_url(url, fam) elif code and ':' in code: if fam: raise ValueError('sitename OR a pair of code and family name ' 'should be provided') fam, _, code = code.partition(':') else: # Fallback to config defaults code = code or config.mylang fam = fam or config.family if not isinstance(fam, Family): fam = Family.load(fam) interface = interface or fam.interface(code) # config.usernames is initialised with a defaultdict for each family name family_name = str(fam) code_to_user = {} if '*' in config.usernames: # T253127: usernames is a defaultdict code_to_user = config.usernames['*'].copy() code_to_user.update(config.usernames[family_name]) user = user or code_to_user.get(code) or code_to_user.get('*') if not isinstance(interface, type): # If it isn't a class, assume it is a string try: tmp = __import__('pywikibot.site', fromlist=[interface]) except ImportError: raise ValueError('Invalid interface name: {0}'.format(interface)) else: interface = getattr(tmp, interface) if not issubclass(interface, BaseSite): warning('Site called with interface=%s' % interface.__name__) user = normalize_username(user) key = '%s:%s:%s:%s' % (interface.__name__, fam, code, user) if key not in _sites or not isinstance(_sites[key], interface): _sites[key] = interface(code=code, fam=fam, user=user) debug( "Instantiated %s object '%s'" % (interface.__name__, _sites[key]), _logger) if _sites[key].code != code: warn( 'Site %s instantiated using different code "%s"' % (_sites[key], code), UserWarning, 2) return _sites[key]
def Site(code=None, fam=None, user=None, sysop=None, interface=None, url=None): """A factory method to obtain a Site object. Site objects are cached and reused by this method. By default rely on config settings. These defaults may all be overridden using the method parameters. @param code: language code (override config.mylang) @type code: string @param fam: family name or object (override config.family) @type fam: string or Family @param user: bot user name to use on this site (override config.usernames) @type user: unicode @param sysop: sysop user to use on this site (override config.sysopnames) @type sysop: unicode @param interface: site class or name of class in pywikibot.site (override config.site_interface) @type interface: subclass of L{pywikibot.site.BaseSite} or string @param url: Instead of code and fam, does try to get a Site based on the URL. Still requires that the family supporting that URL exists. @type url: string @rtype: pywikibot.site.APISite """ # Either code and fam or only url if url and (code or fam): raise ValueError('URL to the wiki OR a pair of code and family name ' 'should be provided') _logger = "wiki" if url: if url not in _url_cache: matched_sites = [] # Iterate through all families and look, which does apply to # the given URL for fam in config.family_files: family = Family.load(fam) code = family.from_url(url) if code is not None: matched_sites += [(code, family)] if matched_sites: if len(matched_sites) > 1: warning( 'Found multiple matches for URL "{0}": {1} (use first)' .format(url, ', '.join(str(s) for s in matched_sites))) _url_cache[url] = matched_sites[0] else: # TODO: As soon as AutoFamily is ready, try and use an # AutoFamily _url_cache[url] = None cached = _url_cache[url] if cached: code = cached[0] fam = cached[1] else: raise SiteDefinitionError("Unknown URL '{0}'.".format(url)) else: # Fallback to config defaults code = code or config.mylang fam = fam or config.family if not isinstance(fam, Family): fam = Family.load(fam) interface = interface or fam.interface(code) # config.usernames is initialised with a defaultdict for each family name family_name = str(fam) code_to_user = config.usernames['*'].copy() code_to_user.update(config.usernames[family_name]) user = user or code_to_user.get(code) or code_to_user.get('*') code_to_sysop = config.sysopnames['*'].copy() code_to_sysop.update(config.sysopnames[family_name]) sysop = sysop or code_to_sysop.get(code) or code_to_sysop.get('*') if not isinstance(interface, type): # If it isnt a class, assume it is a string try: tmp = __import__('pywikibot.site', fromlist=[interface]) interface = getattr(tmp, interface) except ImportError: raise ValueError('Invalid interface name: {0}'.format(interface)) if not issubclass(interface, BaseSite): warning('Site called with interface=%s' % interface.__name__) user = normalize_username(user) key = '%s:%s:%s:%s' % (interface.__name__, fam, code, user) if key not in _sites or not isinstance(_sites[key], interface): _sites[key] = interface(code=code, fam=fam, user=user, sysop=sysop) debug( u"Instantiated %s object '%s'" % (interface.__name__, _sites[key]), _logger) if _sites[key].code != code: warn( 'Site %s instantiated using different code "%s"' % (_sites[key], code), UserWarning, 2) return _sites[key]
def Site(code: Optional[str] = None, fam: Union[str, 'Family', None] = None, user: Optional[str] = None, *, interface: Union[str, 'BaseSite', None] = None, url: Optional[str] = None) -> BaseSite: """A factory method to obtain a Site object. Site objects are cached and reused by this method. By default rely on config settings. These defaults may all be overridden using the method parameters. Creating the default site using config.mylang and config.family:: site = pywikibot.Site() Override default site code:: site = pywikibot.Site('fr') Override default family:: site = pywikibot.Site(family='wikisource') Setting a specific site:: site = pywikibot.Site('fr', 'wikisource') which is equal to:: site = pywikibot.Site('wikisource:fr') :Note: An already created site is cached an a new variable points to the same object if interface, family, code and user are equal: >>> import pywikibot >>> site_1 = pywikibot.Site('wikisource:fr') >>> site_2 = pywikibot.Site('fr', 'wikisource') >>> site_1 is site_2 True >>> site_1 APISite("fr", "wikisource") ``APISite`` is the default interface. Refer :py:obj:`pywikibot.site` for other interface types. **Never create a site object via interface class directly.** Always use this factory method. :param code: language code (override config.mylang) code may also be a sitename like 'wikipedia:test' :param fam: family name or object (override config.family) :param user: bot user name to use on this site (override config.usernames) :param interface: site class or name of class in :py:obj:`pywikibot.site` (override config.site_interface) :param url: Instead of code and fam, does try to get a Site based on the URL. Still requires that the family supporting that URL exists. :raises ValueError: URL and pair of code and family given :raises ValueError: Invalid interface name :raises ValueError: Missing Site code :raises ValueError: Missing Site family """ _logger = 'wiki' if url: # Either code and fam or url with optional fam for AutoFamily name if code: raise ValueError( 'URL to the wiki OR a pair of code and family name ' 'should be provided') code, fam = _code_fam_from_url(url, fam) elif code and ':' in code: if fam: raise ValueError('sitename OR a pair of code and family name ' 'should be provided') fam, _, code = code.partition(':') else: # Fallback to config defaults code = code or _config.mylang fam = fam or _config.family if not (code and fam): raise ValueError( 'Missing Site {}'.format('code' if not code else 'family')) if not isinstance(fam, Family): fam = Family.load(fam) interface = interface or fam.interface(code) # config.usernames is initialised with a defaultdict for each family name family_name = str(fam) code_to_user = {} if '*' in _config.usernames: # T253127: usernames is a defaultdict code_to_user = _config.usernames['*'].copy() code_to_user.update(_config.usernames[family_name]) user = user or code_to_user.get(code) or code_to_user.get('*') if not isinstance(interface, type): # If it isn't a class, assume it is a string try: tmp = __import__('pywikibot.site', fromlist=[interface]) except ImportError: raise ValueError('Invalid interface name: {}'.format(interface)) else: interface = getattr(tmp, interface) if not issubclass(interface, BaseSite): warning('Site called with interface={}'.format(interface.__name__)) user = normalize_username(user) key = '{}:{}:{}:{}'.format(interface.__name__, fam, code, user) if key not in _sites or not isinstance(_sites[key], interface): _sites[key] = interface(code=code, fam=fam, user=user) debug( "Instantiated {} object '{}'".format(interface.__name__, _sites[key]), _logger) if _sites[key].code != code: warn( 'Site {} instantiated using different code "{}"'.format( _sites[key], code), UserWarning, 2) return _sites[key]
def __init__(self, code: str, fam=None, user=None) -> None: """ Initializer. @param code: the site's language code @type code: str @param fam: wiki family name (optional) @type fam: str or pywikibot.family.Family @param user: bot user name (optional) @type user: str """ if code.lower() != code: # Note the Site function in __init__ also emits a UserWarning # for this condition, showing the callers file and line no. pywikibot.log('BaseSite: code "{}" converted to lowercase' .format(code)) code = code.lower() if not all(x in pywikibot.family.CODE_CHARACTERS for x in code): pywikibot.log('BaseSite: code "{}" contains invalid characters' .format(code)) self.__code = code if isinstance(fam, str) or fam is None: self.__family = pywikibot.family.Family.load(fam) else: self.__family = fam self.obsolete = False # if we got an outdated language code, use the new one instead. if self.__code in self.__family.obsolete: if self.__family.obsolete[self.__code] is not None: self.__code = self.__family.obsolete[self.__code] # Note the Site function in __init__ emits a UserWarning # for this condition, showing the callers file and line no. pywikibot.log('Site {} instantiated using aliases code of {}' .format(self, code)) else: # no such language anymore self.obsolete = True pywikibot.log('Site %s instantiated and marked "obsolete" ' 'to prevent access' % self) elif self.__code not in self.languages(): if self.__family.name in self.__family.langs and \ len(self.__family.langs) == 1: self.__code = self.__family.name if self.__family == pywikibot.config.family \ and code == pywikibot.config.mylang: pywikibot.config.mylang = self.__code warn('Global configuration variable "mylang" changed to ' '"%s" while instantiating site %s' % (self.__code, self), UserWarning) else: raise UnknownSite("Language '%s' does not exist in family %s" % (self.__code, self.__family.name)) self._username = normalize_username(user) self.use_hard_category_redirects = ( self.code in self.family.use_hard_category_redirects) # following are for use with lock_page and unlock_page methods self._pagemutex = threading.Condition() self._locked_pages = set()
def readPassword(self): """ Read passwords from a file. DO NOT FORGET TO REMOVE READ ACCESS FOR OTHER USERS!!! Use chmod 600 password-file. All lines below should be valid Python tuples in the form (code, family, username, password), (family, username, password) or (username, password) to set a default password for an username. The last matching entry will be used, so default usernames should occur above specific usernames. For BotPasswords the password should be given as a BotPassword object. The file must be either encoded in ASCII or UTF-8. Example:: ('my_username', 'my_default_password') ('my_sysop_user', 'my_sysop_password') ('wikipedia', 'my_wikipedia_user', 'my_wikipedia_pass') ('en', 'wikipedia', 'my_en_wikipedia_user', 'my_en_wikipedia_pass') ('my_username', BotPassword( 'my_BotPassword_suffix', 'my_BotPassword_password')) """ # Set path to password file relative to the user_config # but fall back on absolute path for backwards compatibility password_file = os.path.join(config.base_dir, config.password_file) if not os.path.isfile(password_file): password_file = config.password_file # We fix password file permission first. file_mode_checker(password_file, mode=config.private_files_permission) with codecs.open(password_file, encoding='utf-8') as f: lines = f.readlines() line_nr = len(lines) + 1 for line in reversed(lines): line_nr -= 1 if not line.strip() or line.startswith('#'): continue try: entry = eval(line) except SyntaxError: entry = None if type(entry) is not tuple: warn('Invalid tuple in line {0}'.format(line_nr), _PasswordFileWarning) continue if not 2 <= len(entry) <= 4: warn('The length of tuple in line {0} should be 2 to 4 ({1} ' 'given)'.format(line_nr, entry), _PasswordFileWarning) continue code, family, username, password = ( self.site.code, self.site.family.name)[:4 - len(entry)] + entry if (normalize_username(username) == self.username and family == self.site.family.name and code == self.site.code): if isinstance(password, UnicodeType): self.password = password break elif isinstance(password, BotPassword): self.password = password.password self.login_name = password.login_name(self.username) break else: warn('Invalid password format', _PasswordFileWarning)
def readPassword(self): """ Read passwords from a file. DO NOT FORGET TO REMOVE READ ACCESS FOR OTHER USERS!!! Use chmod 600 password-file. All lines below should be valid Python tuples in the form (code, family, username, password), (family, username, password) or (username, password) to set a default password for an username. The last matching entry will be used, so default usernames should occur above specific usernames. For BotPasswords the password should be given as a BotPassword object. The file must be either encoded in ASCII or UTF-8. Example: (u"my_username", u"my_default_password") (u"my_sysop_user", u"my_sysop_password") (u"wikipedia", u"my_wikipedia_user", u"my_wikipedia_pass") (u"en", u"wikipedia", u"my_en_wikipedia_user", u"my_en_wikipedia_pass") (u"my_username", BotPassword(u"my_BotPassword_suffix", u"my_BotPassword_password")) """ # Set path to password file relative to the user_config # but fall back on absolute path for backwards compatibility password_file = os.path.join(config.base_dir, config.password_file) if not os.path.isfile(password_file): password_file = config.password_file # We fix password file permission first. file_mode_checker(password_file, mode=config.private_files_permission) password_f = codecs.open(password_file, encoding='utf-8') for line_nr, line in enumerate(password_f): if not line.strip(): continue try: entry = eval(line) except SyntaxError: entry = None if type(entry) is not tuple: warn('Invalid tuple in line {0}'.format(line_nr), _PasswordFileWarning) continue if not 2 <= len(entry) <= 4: warn( 'The length of tuple in line {0} should be 2 to 4 ({1} ' 'given)'.format(line_nr, entry), _PasswordFileWarning) continue # When the tuple is inverted the default family and code can be # easily appended which makes the next condition easier as it does # not need to know if it's using the default value or not. entry = list(entry[::-1]) + [ self.site.family.name, self.site.code ][len(entry) - 2:] if (normalize_username(entry[1]) == self.username and entry[2] == self.site.family.name and entry[3] == self.site.code): if isinstance(entry[0], basestring): self.password = entry[0] elif isinstance(entry[0], BotPassword): self.password = entry[0].password self.login_name = entry[0].login_name(self.username) else: warn('Invalid password format', _PasswordFileWarning) password_f.close()
def readPassword(self): """ Read passwords from a file. DO NOT FORGET TO REMOVE READ ACCESS FOR OTHER USERS!!! Use chmod 600 password-file. All lines below should be valid Python tuples in the form (code, family, username, password), (family, username, password) or (username, password) to set a default password for an username. The last matching entry will be used, so default usernames should occur above specific usernames. For BotPasswords the password should be given as a BotPassword object. The file must be either encoded in ASCII or UTF-8. Example: (u"my_username", u"my_default_password") (u"my_sysop_user", u"my_sysop_password") (u"wikipedia", u"my_wikipedia_user", u"my_wikipedia_pass") (u"en", u"wikipedia", u"my_en_wikipedia_user", u"my_en_wikipedia_pass") (u"my_username", BotPassword(u"my_BotPassword_suffix", u"my_BotPassword_password")) """ # Set path to password file relative to the user_config # but fall back on absolute path for backwards compatibility password_file = os.path.join(config.base_dir, config.password_file) if not os.path.isfile(password_file): password_file = config.password_file # We fix password file permission first. file_mode_checker(password_file, mode=config.private_files_permission) password_f = codecs.open(password_file, encoding='utf-8') for line_nr, line in enumerate(password_f): if not line.strip(): continue try: entry = eval(line) except SyntaxError: entry = None if type(entry) is not tuple: warn('Invalid tuple in line {0}'.format(line_nr), _PasswordFileWarning) continue if not 2 <= len(entry) <= 4: warn('The length of tuple in line {0} should be 2 to 4 ({1} ' 'given)'.format(line_nr, entry), _PasswordFileWarning) continue # When the tuple is inverted the default family and code can be # easily appended which makes the next condition easier as it does # not need to know if it's using the default value or not. entry = list(entry[::-1]) + [self.site.family.name, self.site.code][len(entry) - 2:] if (normalize_username(entry[1]) == self.username and entry[2] == self.site.family.name and entry[3] == self.site.code): if isinstance(entry[0], basestring): self.password = entry[0] elif isinstance(entry[0], BotPassword): self.password = entry[0].password self.login_name = entry[0].login_name(self.username) else: warn('Invalid password format', _PasswordFileWarning) password_f.close()