Recently I began reading up a bit on this whole web thing (yes, I lost my interest in coding HTML and web pages back in grade school). Things have changed and I better learn a bit since it will be beneficial for my work on my thesis. I wanted to try out authentication and HTML forms. Here's the story.
SSSB is a company that rents out flats to students in Stockholm. Back in the good old days (see 2005) you registered and for every day you got a day in line. These days could be traded in for a flat when you needed one, the more days, the better the flat. But, those things changed, the rules of the game are basically the same but you need to log in now and then to show that you are active enough. This of course, is tedious, most other non-student flat renting companies in Stockholm either don't bother or charge a fee. Already back in 2005 this annoyed me a bit but now being in the US and all it's a gun to my head. If I forget I will not have anywhere to live when I get back, or worse, I may loose three years of days. This seemed like an excellent task for a small hack.
The script I created has been tested a bit, but as always, use it at your own risk and take into consideration any moral implications. I will most likely not deploy it, but at least it might prove useful to someone.
#!/usr/bin/env python
'''
Author: Pontus Stenetorp
Version: $Id: sssb.py,v 1.2 2008/12/21 08:07:04 ninjin Exp $
Simple script to keep logging on the SSSB website to keep your days in line
for a flat in Stockholm. Meant to be executed by cron now and then.
This does not violate the agreement on sssb.se but the morality of automating
this is somewhat questionable. *sigh* I remember the good old days before this
log in every 'n' days silliness.
'''
import os
import random
import sys
import time
import urllib
import urllib2
### Constants
## User settings
USERNAME = '1234567890'
PASSWORD = '1234'
# The maximum amount of days to wait between logins, this value should be
# lower than the actual required amount of days (90)
WAIT_MAX = 90/2
# The minimum amount of days to wait between logins, this is to not log in
# all too often
WAIT_MIN = 14
# Faking is _not_ nice, but it is sometimes the only option
FAKE_USERAGENT = True
# If you want to fake, you may choose from the list below and give the index
# here. If set to negative the script will choose one at random and note it
# in the data file for future logins.
FAKE_USERAGENT_INDEX = -1
## Web page specifics
SSSB_URL = 'http://www.sssb.se/index.php?page=login'
VALUES = {'m6input_username': USERNAME, 'm6input_password': PASSWORD,
'mact': 'FrontEndUsers,m6,do_login,1', 'm6returnid': '794',
'page': '794'}
## Script internals
DATA_FILE_PATH = os.path.expanduser('~/.sssb_data')
# Look for this to confirm a successful login
LOGGED_IN_MATCH = 'Du %sr inloggad som:' % ''.join(['&', 'auml;'])
SECONDS_PER_DAY = 60 * 60 * 24
# If you are honest you will show that you are actually running a script
REAL_USERAGENT = 'SSSB login Python script 1.0'
# Thank you http://www.zytrax.com/tech/web/browser_ids.htm for the user-agents
# A mix of user agents to choose from, ranging from MSIE to Opera on several
# operating systems.
FAKE_USERAGENTS = [
'Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0; WOW64; SLCC1; ' +
'.NET CLR 2.0.50727; .NET CLR 3.0.04506; Media Center PC 5.0; .NET ' +
'CLR 1.1.4322)',
'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0; SU 3.1; SLCC1; ' +
'.NET CLR 2.0.50727; .NET CLR 3.0.04506; .NET CLR 1.1.4322; Tablet ' +
'PC 2.0; .NET CLR 3.5.21022)',
'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.8pre) ' +
'Gecko/20071019 Firefox/2.0.0.8 Navigator/9.0.0.1',
'Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.5) ' +
'Gecko/20050519 Netscape/8.0.1',
'Opera/9.60 (X11; Linux i686; U; en) Presto/2.1.1, Opera/9.02 ' +
'(Windows NT 5.0; U; en)',
'Mozilla/5.0 (Windows NT 5.1; U; en) Opera 8.00',
'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/525.19 ' +
'(KHTML, like Gecko) Version/3.1.2 Safari/525.21']
###
def main(argv=None):
def read_data_file():
data_file = open(DATA_FILE_PATH, 'r')
last_login, next_login, user_agent = [line.strip() for line
in data_file]
data_file.close()
return int(last_login), int(next_login), user_agent
def write_data_file(last_login, next_login, user_agent):
if os.path.isfile(DATA_FILE_PATH):
os.remove(DATA_FILE_PATH)
data_file = open(DATA_FILE_PATH, 'w')
data_file.write(str(last_login) + '\n')
data_file.write(str(next_login) + '\n')
data_file.write(user_agent + '\n')
data_file.close()
return
if not os.path.isfile(DATA_FILE_PATH):
if not FAKE_USERAGENT:
user_agent = REAL_USERAGENT
elif FAKE_USERAGENT_INDEX < user_agent =" random.choice(FAKE_USERAGENTS)" user_agent =" FAKE_USERAGENTS[FAKE_USERAGENT_INDEX]" next_login =" 0," user_agent =" read_data_file()" current_time =" int(time.time())">= next_login:
opener = urllib2.build_opener(urllib2.HTTPCookieProcessor())
data = urllib.urlencode(VALUES)
request = urllib2.Request(SSSB_URL, data)
request.add_header('User-agent', user_agent)
response = opener.open(request)
logged_in_line = [line for line in response if
LOGGED_IN_MATCH in line]
if not logged_in_line:
print 'FATAL: Log-in failed'
return -1
next_login = random.randint(
current_time + WAIT_MIN * SECONDS_PER_DAY,
current_time + WAIT_MAX * SECONDS_PER_DAY)
last_login = current_time
write_data_file(last_login, next_login, user_agent)
return 0
if __name__ == '__main__':
sys.exit(main(argv=sys.argv))
At line #53 you may notice a strange ''.join(), Blogger finds it a good idea to translate my escaped Swedish characters. This is a remedy, so enjoy the special Blogger version which is slightly uglier than my own version.
EDIT:
Blogger is really _terrible_ at displaying code, one almost weeps when you take a look at it. All the 80 width formatting killed by static width. *sigh* Paste it into an editor and take it away from this awful place.