Revision: 4976 Author: russblau Date: 2008-02-04 18:50:19 +0000 (Mon, 04 Feb 2008)
Log Message: ----------- made a copy
Added Paths: ----------- branches/rewrite/pywikibot/login.py
Copied: branches/rewrite/pywikibot/login.py (from rev 4975, trunk/pywikipedia/login.py) =================================================================== --- branches/rewrite/pywikibot/login.py (rev 0) +++ branches/rewrite/pywikibot/login.py 2008-02-04 18:50:19 UTC (rev 4976) @@ -0,0 +1,279 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +""" +Script to log the robot in to a wiki account. + +Suggestion is to make a special account to use for robot use only. Make +sure this robot account is well known on your home wikipedia before using. + +Parameters: + + -all Try to log in on all sites where a username is defined in + user-config.py. + + -pass Useful in combination with -all when you have accounts for + several sites and use the same password for all of them. + Asks you for the password, then logs in on all given sites. + + -pass:XXXX Uses XXXX as password. Be careful if you use this + parameter because your password will be shown on your + screen, and will probably be saved in your command line + history. This is NOT RECOMMENDED for use on computers + where others have either physical or remote access. + Use -pass instead. + + -sysop Log in with your sysop account. + + -force Ignores if the user is already logged in, and tries to log in. + +If not given as parameter, the script will ask for your username and password +(password entry will be hidden), log in to your home wiki using this +combination, and store the resulting cookies (containing your password hash, +so keep it secured!) in a file in the login-data subdirectory. + +All scripts in this library will be looking for this cookie file and will use the +login information if it is present. + +To log out, throw away the XX-login.data file that is created in the login-data +subdirectory. +""" +# +# (C) Rob W.W. Hooft, 2003 +# +# Distributed under the terms of the MIT license. +# +__version__='$Id$' + +import re +import urllib2 +import wikipedia, config + +# On some wikis you are only allowed to run a bot if there is a link to +# the bot's user page in a specific list. +botList = { + 'wikipedia': { + 'en': u'Wikipedia:Registered bots', + # Disabled because they are now using a template system which + # we can't check with our current code. + #'simple': u'Wikipedia:Bots', + }, + 'gentoo': { + 'en': u'Help:Bots', + } +} + + +class LoginManager: + def __init__(self, password = None, sysop = False, site = None): + self.site = site or wikipedia.getSite() + if sysop: + try: + self.username = config.sysopnames[self.site.family.name][self.site.lang] + except: + raise wikipedia.NoUsername(u'ERROR: Sysop username for %s:%s is undefined.\nIf you have a sysop account for that site, please add such a line to user-config.py:\n\nsysopnames['%s']['%s'] = 'myUsername'' % (self.site.family.name, self.site.lang, self.site.family.name, self.site.lang)) + else: + try: + self.username = config.usernames[self.site.family.name][self.site.lang] + except: + raise wikipedia.NoUsername(u'ERROR: Username for %s:%s is undefined.\nIf you have an account for that site, please add such a line to user-config.py:\n\nusernames['%s']['%s'] = 'myUsername'' % (self.site.family.name, self.site.lang, self.site.family.name, self.site.lang)) + self.password = password + if getattr(config, 'password_file', ''): + self.readPassword() + + def botAllowed(self): + """ + Checks whether the bot is listed on a specific page to comply with + the policy on the respective wiki. + """ + if botList.has_key(self.site.family.name) and botList[self.site.family.name].has_key(self.site.language()): + botListPageTitle = botList[self.site.family.name][self.site.language()] + botListPage = wikipedia.Page(self.site, botListPageTitle) + for linkedPage in botListPage.linkedPages(): + if linkedPage.titleWithoutNamespace() == self.username: + return True + return False + else: + # No bot policies on other + return True + + def getCookie(self, remember=True, captchaId = None, captchaAnswer = None): + """ + Login to the site. + + remember Remember login (default: True) + captchaId The id number of the captcha, if any + captcha The word displayed in the captcha, if any + + Returns cookie data if succesful, None otherwise. + """ + predata = { + "wpName": self.username.encode(self.site.encoding()), + "wpPassword": self.password, + "wpLoginattempt": "Aanmelden & Inschrijven", # dutch button label seems to work for all wikis + "wpRemember": str(int(bool(remember))) + } + if captchaId: + predata["wpCaptchaId"] = captchaId + predata["wpCaptchaWord"] = captchaAnswer + address = self.site.login_address() + + if self.site.hostname() in config.authenticate.keys(): + headers = { + "Content-type": "application/x-www-form-urlencoded", + "User-agent": wikipedia.useragent + } + data = self.site.urlEncode(predata) + response = urllib2.urlopen(urllib2.Request(self.site.protocol() + '://' + self.site.hostname() + address, data, headers)) + data = response.read() + wikipedia.cj.save(wikipedia.COOKIEFILE) + return "Ok" + else: + response, data = self.site.postForm(address, predata, useCookie=False) + n = 0 + Reat=re.compile(': (.*?);') + L = [] + + for eat in response.msg.getallmatchingheaders('set-cookie'): + m = Reat.search(eat) + if m: + n += 1 + L.append(m.group(1)) + + log_data = [] + for Ldata in L: + if (re.match('.*_session=.*', Ldata)): + log_data.append(Ldata) + elif (re.match('.*UserID=.*', Ldata)): + log_data.append(Ldata) + elif (re.match('.*UserName=.*', Ldata)): + log_data.append(Ldata) + elif (re.match('.*Token=.*', Ldata)): + log_data.append(Ldata) + + if len(log_data) == 4: + return "\n".join(L) + elif not captchaAnswer: + captchaR = re.compile('<input type="hidden" name="wpCaptchaId" id="wpCaptchaId" value="(?P<id>\d+)" />') + match = captchaR.search(data) + if match: + id = match.group('id') + if not config.solve_captcha: + raise wikipedia.CaptchaError(id) + url = self.site.protocol() + '://' + self.site.hostname() + self.site.captcha_image_address(id) + answer = wikipedia.ui.askForCaptcha(url) + return self.getCookie(remember = remember, captchaId = id, captchaAnswer = answer) + else: + return None + + def storecookiedata(self, data): + """ + Stores cookie data. + + The argument data is the raw data, as returned by getCookie(). + + Returns nothing.""" + filename = wikipedia.config.datafilepath('login-data', + '%s-%s-%s-login.data' + % (self.site.family.name, self.site.lang, self.username)) + f = open(filename, 'w') + f.write(data) + f.close() + + def readPassword(self): + """ + Reads 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) or (username, password) + to set a default password for an username. Default usernames + should occur above specific usernames. + + Example: + + ("my_username", "my_default_password") + ("my_sysop_user", "my_sysop_password") + ("en", "wikipedia", "my_en_user", "my_en_pass") + """ + file = open(config.password_file) + for line in file: + if not line.strip(): continue + entry = eval(line) + if len(entry) == 2: + if entry[0] == self.username: self.password = entry[1] + elif len(entry) == 4: + if entry[0] == self.site.lang and \ + entry[1] == self.site.family.name and \ + entry[2] == self.username: + self.password = entry[3] + file.close() + + def login(self, retry = False): + if not self.password: + # As we don't want the password to appear on the screen, we set + # password = True + self.password = wikipedia.input(u'Password for user %s on %s:' % (self.username, self.site), password = True) + + self.password = self.password.encode(self.site.encoding()) + + wikipedia.output(u"Logging in to %s as %s" % (self.site, self.username)) + cookiedata = self.getCookie() + if cookiedata: + self.storecookiedata(cookiedata) + wikipedia.output(u"Should be logged in now") + # Show a warning according to the local bot policy + if not self.botAllowed(): + wikipedia.output(u'*** Your username is not listed on [[%s]].\n*** Please make sure you are allowed to use the robot before actually using it!' % botList[self.site.family.name][self.site.lang]) + return True + else: + wikipedia.output(u"Login failed. Wrong password or CAPTCHA answer?") + if retry: + self.password = None + return self.login(retry = True) + else: + return False + + def showCaptchaWindow(self, url): + pass + +def main(): + username = password = None + sysop = False + logall = False + forceLogin = False + for arg in wikipedia.handleArgs(): + if arg.startswith("-pass"): + if len(arg) == 5: + password = wikipedia.input(u'Password for all accounts:', password = True) + else: + password = arg[6:] + elif arg == "-sysop": + sysop = True + elif arg == "-all": + logall = True + elif arg == "-force": + forceLogin = True + else: + wikipedia.showHelp('login') + return + if logall: + if sysop: + namedict = config.sysopnames + else: + namedict = config.usernames + for familyName in namedict.iterkeys(): + for lang in namedict[familyName].iterkeys(): + site = wikipedia.getSite(code=lang, fam=familyName) + if not forceLogin and site.loggedInAs(sysop = sysop) != None: + wikipedia.output(u'Already logged in on %s' % site) + else: + loginMan = LoginManager(password, sysop = sysop, site = site) + loginMan.login() + else: + loginMan = LoginManager(password, sysop = sysop) + loginMan.login() + +if __name__ == "__main__": + try: + main() + finally: + wikipedia.stopme()
pywikipedia-l@lists.wikimedia.org