Created
July 19, 2015 18:01
-
-
Save Taiiwo/0a718f09d894553f2be2 to your computer and use it in GitHub Desktop.
A python class for verifying login details for any website
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import mechanize | |
import cookielib | |
import re | |
class Login: | |
def __init__(self): | |
# set a bunch of properties as default settings | |
self.url = False | |
self.formIndex = 0 | |
self.dualPage = False | |
self.userField = "email" | |
self.passField = "pass" | |
self.success = False | |
self.invalid = False | |
self.rateLimited = False | |
# set up the /browser/ | |
self.br = mechanize.Browser() | |
cj = cookielib.LWPCookieJar() | |
self.br.set_cookiejar(cj) | |
self.br.set_handle_equiv(True) | |
self.br.set_handle_redirect(True) | |
self.br.set_handle_referer(True) | |
self.br.set_handle_robots(False) | |
self.br.set_handle_refresh( | |
mechanize._http.HTTPRefreshProcessor(), | |
max_time=1 | |
) | |
# Google says we're using an outdated browser ;_; | |
self.br.addheaders = [( | |
'User-agent', | |
'Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.1) ' | |
'Gecko/2008071615 Fedora/3.0.1-1.fc9 Firefox/3.0.1' | |
)] | |
# this function uses our browsers instance to log into the page | |
def login(self, username, password): | |
# make sure all of the required arguments are set | |
if not self.url or not self.userField or not self.passField: | |
raise ArgumentError('Specify properties: url, userField, passField') | |
else: | |
if not (self.success or self.invalid): | |
raise ArgumentError('Specify atleast one of properties' | |
' `success` of ` invalid`') | |
else: | |
# we definitely have all of values we need, let's get to work | |
# renamed for simplicity | |
br = self.br | |
# browse to the page | |
r = br.open(self.url) | |
# check if the username and password are on different pages | |
if self.dualPage: | |
# we're making a bunch of assumtions here mainly to support | |
# google. | |
# | |
# this checks if the form index is a list, and if it is, it | |
# uses both values; one for each page. See also comment !1 | |
if type(self.formIndex) == int: | |
formIndex = self.formIndex | |
indexIsList = False | |
else: | |
formIndex = self.formIndex[0] | |
indexIsList = True | |
# select the NRth form on the page, the first if there's one | |
br.select_form(nr=formIndex) | |
# put the username in the username field | |
br.form[self.userField] = username | |
# submit the form, and wait until the next page loads | |
br.submit() | |
# !1 | |
if indexIsList: | |
formIndex = self.formIndex[1] | |
# select the correct form on the next page | |
br.select_form(nr=formIndex) | |
# enter the password into the passowrd field | |
br.form[self.passField] = password | |
# submit the form, hopefully logging us in | |
br.submit() | |
else: | |
# all the fields are on the same page | |
# select the NRth form on the page, the first if there's one | |
br.select_form(nr=self.formIndex) | |
# put the username and password into their respective field | |
br.form[self.userField] = username | |
br.form[self.passField] = password | |
# submit the form | |
br.submit() | |
# get the HTML of the resulting page | |
html = br.response().read() | |
# check to see if it was the response we were looking for | |
return self.verify( | |
html, | |
self.success, | |
self.invalid, | |
self.rateLimited | |
) | |
# tries to work out if html is of a success, invalid, or rate limited page | |
def verify(self, html, success, invalid, rateLimited): | |
# make a blank object, just to keep things pretty | |
r = ReturnObject() | |
# add the html to the object so the developer can use it for debugging | |
r.html = html | |
# prioritize rate limiting message, as it's the least likely to appear | |
if rateLimited and re.search(rateLimited, html): | |
r.valid = False | |
r.desc = "The rateLimited regex matched in the page." | |
r.rateLimited = True | |
# check if the invalid regex matches | |
elif invalid and re.search(invalid, html): | |
r.valid = False | |
r.desc = "The invalid regex matched in the page." | |
r.rateLimited = False | |
# check if the success regex matches | |
elif success and re.search(success, html): | |
r.valid = True | |
r.desc = "The success regex matched in the page." | |
r.rateLimited = False | |
# if only invalid is specified, and it didn't match, then we're probably | |
# authenticated | |
elif invalid and not success: | |
r.valid = True | |
r.desc = "Success. The invalid regex was not found in the page." | |
r.rateLimited = False | |
# nothing we provided matched, so it prbably failed to authenticate | |
else: | |
r.valid = False | |
r.desc = "None of the regexes matched the page" | |
r.rateLimited = False | |
return r | |
# just something to allow us to return an object instead of a dict | |
class ReturnObject: | |
pass | |
# a custom error to raise when insufficuent parameters are supplied | |
class ArgumentError(Exception): | |
def __init__(self, value): | |
self.value = value | |
def __str__(self): | |
return repr(self.value) | |
if __name__ == "__main__": | |
# a test script that logs into google | |
# instantiate the class | |
l = Login() | |
# supply all of the required parameters | |
l.url = "https://accounts.google.com/ServiceLogin" | |
l.dualPage = True | |
l.userField = "Email" | |
l.passField = "Passwd" | |
l.success = "To access all of your Google account settings, upgrade to " \ | |
"the latest version of any of the following browsers" | |
# print the description of a login attempt | |
print l.login('[email protected]', 'notanactualpassword').desc |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment