Advertisement
Guest User

Untitled

a guest
Dec 27th, 2011
65
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 17.71 KB | None | 0 0
  1. #!/usr/bin/python
  2. # -*- coding: utf-8  -*-
  3. """
  4. Script to log the robot in to a wiki account.
  5.  
  6. Suggestion is to make a special account to use for robot use only. Make
  7. sure this robot account is well known on your home wiki before using.
  8.  
  9. Parameters:
  10.  
  11.   -all         Try to log in on all sites where a username is defined in
  12.                user-config.py.
  13.  
  14.   -clean       Use this option for logout. In combination with -all it
  15.                will log out on all sites where a username is defined.
  16.  
  17.   -force       Ignores if the user is already logged in, and tries to log in.
  18.  
  19.   -pass        Useful in combination with -all when you have accounts for
  20.                several sites and use the same password for all of them.
  21.                Asks you for the password, then logs in on all given sites.
  22.  
  23.   -pass:XXXX   Uses XXXX as password. Be careful if you use this
  24.                parameter because your password will be shown on your
  25.                screen, and will probably be saved in your command line
  26.                history. This is NOT RECOMMENDED for use on computers
  27.                where others have either physical or remote access.
  28.                Use -pass instead.
  29.  
  30.   -sysop       Log in with your sysop account.
  31.  
  32.   -test        test whether you are logged-in
  33.  
  34.   -v -v        (Doubly verbose) Shows http requests made when logging in. This
  35.                might leak private data (password, session id), so make sure to
  36.                check the output. Using -log is recommended: this will output a
  37.                lot of data
  38.  
  39. If not given as parameter, the script will ask for your username and
  40. password (password entry will be hidden), log in to your home wiki using
  41. this combination, and store the resulting cookies (containing your password
  42. hash, so keep it secured!) in a file in the login-data subdirectory.
  43.  
  44. All scripts in this library will be looking for this cookie file and will
  45. use the login information if it is present.
  46.  
  47. To log out, throw away the XX-login.data file that is created in the login-data
  48. subdirectory.
  49. """
  50. #
  51. # (C) Rob W.W. Hooft, 2003
  52. # (C) Pywikipedia bot team, 2003-2011
  53. #
  54. # Distributed under the terms of the MIT license.
  55. #
  56. __version__='$Id$'
  57.  
  58. import re, os, query
  59. import urllib2
  60. import wikipedia as pywikibot
  61. import config
  62.  
  63. # On some wikis you are only allowed to run a bot if there is a link to
  64. # the bot's user page in a specific list.
  65. # If bots are listed in a template, the templates name must be given as
  66. # second parameter, otherwise it must be None
  67. botList = {
  68.     'wikipedia': {
  69.         #'en': [u'Wikipedia:Bots/Status', 'BotS'],
  70.         'simple': [u'Wikipedia:Bots', '/links']
  71.     },
  72.     'gentoo': {
  73.         'en': [u'Help:Bots', None],
  74.     }
  75. }
  76.  
  77. def show (mysite, sysop = False):
  78.     if mysite.loggedInAs(sysop = sysop):
  79.         pywikibot.output(u"You are logged in on %s as %s."
  80.                          % (repr(mysite), mysite.loggedInAs(sysop=sysop)))
  81.     else:
  82.         pywikibot.output(u"You are not logged in on %s." % repr(mysite))
  83.  
  84. class LoginManager:
  85.     def __init__(self, password=None, sysop=False, site=None, username=None,
  86.                  verbose=False):
  87.         self.site = site or pywikibot.getSite()
  88.         self.sysop = sysop
  89.         if username:
  90.             self.username = username
  91.             # perform writeback.
  92.             if site.family.name not in config.usernames:
  93.                 config.usernames[site.family.name]={}
  94.             config.usernames[site.family.name][self.site.lang]=username
  95.         else:
  96.             if sysop:
  97.                 try:
  98.                     self.username = config.sysopnames\
  99.                                     [self.site.family.name][self.site.lang]
  100.                 except:
  101.                     raise pywikibot.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))
  102.             else:
  103.                 try:
  104.                     self.username = config.usernames[self.site.family.name][self.site.lang]
  105.                 except:
  106.                     raise pywikibot.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))
  107.         self.password = password
  108.         self.verbose = verbose
  109.         if getattr(config, 'password_file', ''):
  110.             self.readPassword()
  111.  
  112.     def botAllowed(self):
  113.         """
  114.        Checks whether the bot is listed on a specific page to comply with
  115.        the policy on the respective wiki.
  116.        """
  117.         if self.site.family.name in botList \
  118.            and self.site.language() in botList[self.site.family.name]:
  119.             botListPageTitle, botTemplate = botList[self.site.family.name][self.site.language()]
  120.             botListPage = pywikibot.Page(self.site, botListPageTitle)
  121.             if botTemplate:
  122.                 for template in botListPage.templatesWithParams():
  123.                     if template[0] == botTemplate \
  124.                        and template[1][0] == self.username:
  125.                         return True
  126.             else:
  127.                 for linkedPage in botListPage.linkedPages():
  128.                     if linkedPage.title(withNamespace=False) == self.username:
  129.                         return True
  130.             return False
  131.         else:
  132.             # No bot policies on other sites
  133.             return True
  134.  
  135.     def getCookie(self, api=config.use_api_login, remember=True, captcha = None):
  136.         """
  137.        Login to the site.
  138.  
  139.        remember    Remember login (default: True)
  140.        captchaId   A dictionary containing the captcha id and answer, if any
  141.  
  142.        Returns cookie data if succesful, None otherwise.
  143.        """
  144.         if api:
  145.             predata = {
  146.                 'action': 'login',
  147.                 'lgname': self.username,
  148.                 'lgpassword': self.password,
  149.             }
  150.             if self.site.family.ldapDomain:
  151.                 predata['lgdomain'] = self.site.family.ldapDomain
  152.             address = self.site.api_address()
  153.         else:
  154.             predata = {
  155.                 "wpName": self.username.encode(self.site.encoding()),
  156.                 "wpPassword": self.password,
  157.                 "wpLoginattempt": "Aanmelden & Inschrijven", # dutch button label seems to work for all wikis
  158.                 "wpRemember": str(int(bool(remember))),
  159.                 "wpSkipCookieCheck": '1'
  160.             }
  161.             if self.site.family.ldapDomain:     # VistaPrint fix
  162.                 predata["wpDomain"] = self.site.family.ldapDomain
  163.             if captcha:
  164.                 predata["wpCaptchaId"] = captcha['id']
  165.                 predata["wpCaptchaWord"] = captcha['answer']
  166.             login_address = self.site.login_address()
  167.             address = login_address + '&action=submit'
  168.  
  169.         if api:
  170.             while True:
  171.                 # build the cookie
  172.                 L = {}
  173.                 L["cookieprefix"] = None
  174.                 index = self.site._userIndex(self.sysop)
  175.                 if self.site._cookies[index]:
  176.                     #if user is trying re-login, update the new information
  177.                     self.site.updateCookies(L, self.sysop)
  178.                 else:
  179.                     # clean type login, setup the new cookies files.
  180.                     self.site._setupCookies(L, self.sysop)
  181.                 response, data = query.GetData(predata, self.site, sysop=self.sysop, back_response = True)
  182.                 result = data['login']['result']
  183.                 if result == "NeedToken":
  184.                     predata["lgtoken"] = data["login"]["token"]
  185.                     if ['lgtoken'] in data['login'].keys():
  186.                         self.site._userName[index] = data['login']['lgusername']
  187.                         self.site._token[index] = data['login']['lgtoken'] + "+\\"
  188.                     continue
  189.                 break
  190.             if result != "Success":
  191.                 #if result == "NotExists":
  192.                 #
  193.                 #elif result == "WrongPass":
  194.                 #
  195.                 #elif result == "Throttled":
  196.                 #
  197.                 return False
  198.         else:
  199.             response, data = self.site.postData(address, self.site.urlEncode(predata), sysop=self.sysop)
  200.             if self.verbose:
  201.                 fakepredata = predata
  202.                 fakepredata['wpPassword'] = u'XXXXX'
  203.                 pywikibot.output(u"self.site.postData(%s, %s)" % (address, self.site.urlEncode(fakepredata)))
  204.                 trans = config.transliterate
  205.                 config.transliterate = False #transliteration breaks for some reason
  206.                 #pywikibot.output(fakedata.decode(self.site.encoding()))
  207.                 config.transliterate = trans
  208.                 fakeresponsemsg = re.sub(r"(session|Token)=..........", r"session=XXXXXXXXXX", data)
  209.                 pywikibot.output(u"%s/%s\n%s" % (response.code, response.msg, fakeresponsemsg))
  210.             #pywikibot.cj.save(pywikibot.COOKIEFILE)
  211.  
  212.         Reat=re.compile(': (.*?)=(.*?);')
  213.  
  214.         L = {}
  215.         if hasattr(response, 'sheaders'):
  216.             ck = response.sheaders
  217.         else:
  218.             ck = response.info().getallmatchingheaders('set-cookie')
  219.         for eat in ck:
  220.             m = Reat.search(eat)
  221.             if m:
  222.                 L[m.group(1)] = m.group(2)
  223.  
  224.         got_token = got_user = False
  225.         for Ldata in L.keys():
  226.             if 'Token' in Ldata:
  227.                 got_token = True
  228.             if 'User' in Ldata or 'UserName' in Ldata:
  229.                 got_user = True
  230.  
  231.         if got_token and got_user:
  232.             #process the basic information to Site()
  233.             index = self.site._userIndex(self.sysop)
  234.             if api:
  235.                 #API result came back username, token and sessions.
  236.                 self.site._userName[index] = data['login']['lgusername']
  237.                 self.site._token[index] = data['login']['lgtoken'] + "+\\"
  238.             else:
  239.                 self.site._userName[index] = self.username
  240.  
  241.             if self.site._cookies[index]:
  242.                 #if user is trying re-login, update the new information
  243.                 self.site.updateCookies(L, self.sysop)
  244.             else:
  245.                 # clean type login, setup the new cookies files.
  246.                 self.site._setupCookies(L, self.sysop)
  247.  
  248.             return True
  249.         elif not captcha:
  250.             solve = self.site.solveCaptcha(data)
  251.             if solve:
  252.                 return self.getCookie(api = api, remember = remember, captcha = solve)
  253.         return None
  254.  
  255.     def storecookiedata(self, filename, data):
  256.         """
  257.        Store cookie data.
  258.  
  259.        The argument data is the raw data, as returned by getCookie().
  260.  
  261.        Returns nothing.
  262.        """
  263.         s = u''
  264.         for v, k in data.iteritems():
  265.             s += "%s=%s\n" % (v, k)
  266.         f = open(pywikibot.config.datafilepath('login-data',filename), 'w')
  267.         f.write(s)
  268.         f.close()
  269.  
  270.     def readPassword(self):
  271.         """
  272.        Read passwords from a file.
  273.  
  274.        DO NOT FORGET TO REMOVE READ ACCESS FOR OTHER USERS!!!
  275.        Use chmod 600 password-file.
  276.        All lines below should be valid Python tuples in the form
  277.        (code, family, username, password) or (username, password)
  278.        to set a default password for an username. Default usernames
  279.        should occur above specific usernames.
  280.  
  281.        Example:
  282.  
  283.        ("my_username", "my_default_password")
  284.        ("my_sysop_user", "my_sysop_password")
  285.        ("en", "wikipedia", "my_en_user", "my_en_pass")
  286.        """
  287.         password_f = open(pywikibot.config.datafilepath(config.password_file), 'r')
  288.         for line in password_f:
  289.             if not line.strip(): continue
  290.             entry = eval(line)
  291.             if len(entry) == 2:   #for default userinfo
  292.                 if entry[0] == self.username: self.password = entry[1]
  293.             elif len(entry) == 4: #for userinfo included code and family
  294.                 if entry[0] == self.site.lang and \
  295.                   entry[1] == self.site.family.name and \
  296.                   entry[2] == self.username:
  297.                     self.password = entry[3]
  298.         password_f.close()
  299.  
  300.     def login(self, api=config.use_api_login, retry = False):
  301.         if not self.password:
  302.             # As we don't want the password to appear on the screen, we set
  303.             # password = True
  304.             self.password = pywikibot.input(
  305.                                 u'Password for user %(name)s on %(site)s:'
  306.                                 % {'name': self.username, 'site': self.site},
  307.                                 password = True)
  308.  
  309.         self.password = self.password.encode(self.site.encoding())
  310.  
  311.         if api:
  312.             pywikibot.output(u"Logging in to %(site)s as %(name)s via API."
  313.                              % {'name': self.username, 'site': self.site})
  314.         else:
  315.             pywikibot.output(u"Logging in to %(site)s as %(name)s"
  316.                              % {'name': self.username, 'site': self.site})
  317.  
  318.         try:
  319.             cookiedata = self.getCookie(api)
  320.         except NotImplementedError:
  321.             pywikibot.output('API disabled because this site does not support.\nRetrying by ordinary way...')
  322.             api = False
  323.             return self.login(False, retry)
  324.         if cookiedata:
  325.             fn = '%s-%s-%s-login.data' % (self.site.family.name, self.site.lang, self.username)
  326.             #self.storecookiedata(fn,cookiedata)
  327.             pywikibot.output(u"Should be logged in now")
  328.             # Show a warning according to the local bot policy
  329.             if not self.botAllowed():
  330.                 pywikibot.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])
  331.             return True
  332.         else:
  333.             pywikibot.output(u"Login failed. Wrong password or CAPTCHA answer?")
  334.             if api:
  335.                 pywikibot.output(u"API login failed, retrying using standard webpage.")
  336.                 return self.login(False, retry)
  337.  
  338.             if retry:
  339.                 self.password = None
  340.                 return self.login(api, True)
  341.             else:
  342.                 return False
  343.  
  344.     def logout(self, api = config.use_api):
  345.         flushCk = False
  346.         if api and self.site.versionnumber() >= 12:
  347.             if query.GetData({'action':'logout'}, self.site) == []:
  348.                 flushCk = True
  349.         else:
  350.             text = self.site.getUrl(self.site.get_address("Special:UserLogout"))
  351.             if self.site.mediawiki_message('logouttext') in text: #confirm loggedout
  352.                 flushCk = True
  353.  
  354.         if flushCk:
  355.             self.site._removeCookies(self.username)
  356.             return True
  357.  
  358.         return False
  359.  
  360.     def showCaptchaWindow(self, url):
  361.         pass
  362.  
  363. def main():
  364.     username = password = None
  365.     sysop = False
  366.     logall = False
  367.     forceLogin = False
  368.     verbose = False
  369.     clean = False
  370.     testonly = False
  371.  
  372.     for arg in pywikibot.handleArgs():
  373.         if arg.startswith("-pass"):
  374.             if len(arg) == 5:
  375.                 password = pywikibot.input(u'Password for all accounts:',
  376.                                            password = True)
  377.             else:
  378.                 password = arg[6:]
  379.         elif arg == "-clean":
  380.             clean = True
  381.         elif arg == "-sysop":
  382.             sysop = True
  383.         elif arg == "-all":
  384.             logall = True
  385.         elif arg == "-force":
  386.             forceLogin = True
  387.         elif arg == "-test":
  388.             testonly = True
  389.         else:
  390.             pywikibot.showHelp('login')
  391.             return
  392.  
  393.     if pywikibot.verbose > 1:
  394.         pywikibot.output(u"WARNING: Using -v -v on login.py might leak private data. When sharing, please double check your password is not readable and log out your bots session.")
  395.         verbose = True # only use this verbose when running from login.py
  396.     if logall:
  397.         if sysop:
  398.             namedict = config.sysopnames
  399.         else:
  400.             namedict = config.usernames
  401.  
  402.         for familyName in namedict.iterkeys():
  403.             for lang in namedict[familyName].iterkeys():
  404.                 if testonly:
  405.                     show(pywikibot.getSite(lang, familyName), sysop)
  406.                 else:
  407.                     try:
  408.                         site = pywikibot.getSite(lang, familyName)
  409.                         loginMan = LoginManager(password, sysop=sysop,
  410.                                                 site=site, verbose=verbose)
  411.                         if clean:
  412.                             loginMan.logout()
  413.                         else:
  414.                             if not forceLogin and site.loggedInAs(sysop = sysop):
  415.                                 pywikibot.output(u'Already logged in on %s' % site)
  416.                             else:
  417.                                 loginMan.login()
  418.                     except pywikibot.NoSuchSite:
  419.                         pywikibot.output(lang+ u'.' + familyName + u' is not a valid site, please remove it from your config')
  420.  
  421.     elif testonly:
  422.         show(pywikibot.getSite(), sysop)
  423.     elif clean:
  424.         try:
  425.             site = pywikibot.getSite()
  426.             lgm = LoginManager(site = site)
  427.             lgm.logout()
  428.         except pywikibot.NoSuchSite:
  429.             pass
  430.     else:
  431.         loginMan = LoginManager(password, sysop = sysop, verbose=verbose)
  432.         loginMan.login()
  433.  
  434. if __name__ == "__main__":
  435.     try:
  436.         main()
  437.     finally:
  438.         pywikibot.stopme()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement