Skip to content

Instantly share code, notes, and snippets.

@hikari-no-yume
Created July 19, 2011 22:34
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save hikari-no-yume/1093913 to your computer and use it in GitHub Desktop.
Save hikari-no-yume/1093913 to your computer and use it in GitHub Desktop.
GG2 Forums Signature Rotation Service
from urllib.request import build_opener, HTTPCookieProcessor
import urllib.parse
from http.cookiejar import CookieJar
def htmlentencode(text):
result = ""
for i in text:
if ord(i) < 128:
result += i
else:
result += "&#%s;" % ord(i)
return result
class GG2ForumResponseParser:
"""
A class to help with html parsing.
"""
def __init__(self, html):
self.html = html
def getHTML(self):
"""
Returns the HTML
"""
return self.html
def getPlaintext(self):
"""
Returns the HTML stripped of tags and with <script> tag content removed
"""
text = self.html
tags = 0
while "<" in text:
start = text.find("<")
end = text.find(">", start)+1
if text[start:start+7] == "<script":
end = text.find("</script>", end)+9
text = text[:start] + text[end:]
tags += 1
return text
def getTitle(self):
"""
Gets the title of the page. If it cannot be found, None is returned.
"""
if "<title>" in self.html:
start = self.html.find("<title>")+7
end = self.html.find("</title>", start)
return self.html[start:end]
else:
return None
def getHiddenValue(self, hidden):
"""
Gets the value of an <input type="hidden" ... /> tag.
If it cannot be found, None is returned.
"""
begin = "<input type=\"hidden\" name=\"%s\" value=\"" % hidden
if begin in self.html:
start = self.html.find(begin)+len(begin)
end = self.html.find("\" />", start)
return self.html[start:end]
else:
print(begin)
return None
class GG2ForumInterface:
"""
A class providing a simple interface to make HTTP requests to the forum.
"""
def __init__(self):
cookieprocessor = HTTPCookieProcessor(CookieJar())
self.opener = build_opener(cookieprocessor)
def request(self, urlparams=None, params={}):
"""
Makes a request. urlparams contains parameters in the URL, and
params contains POST parameters.
"""
# Build URL
url = "http://www.ganggarrison.com/forums/index.php?"
for k, v in urlparams.items():
url += k+"="+v+";"
# Encode POST params
params = urllib.parse.urlencode(params)
params = params.encode("utf-8")
# Request and decode
fp = self.opener.open(url, params)
text = fp.read().decode("utf-8", "ignore")
return text
def changeProfile(self, **items):
"""
Changes a field on the profile. Keyword arguments specify the field
and its new value. Returns True if successful, False on failure.
"""
# Request forum profile info page
html = self.request({"action": "profile", "sa": "forumProfile"})
html = GG2ForumResponseParser(html)
title = html.getTitle()
if title != "Profile - Forum Profile Information":
return False
# Extract sc and userID values
sc = html.getHiddenValue("sc")
userid = html.getHiddenValue("userID")
if not sc or not userid:
return False
# Request changes
params = items
for k, v in params.items():
params[k] = htmlentencode(v)
params["sc"] = sc
params["userID"] = userid
params["sa"] = "forumProfile"
params["submit"] = "Change profile"
self.request({"action": "profile2"}, params)
return True
def login(self, username, password):
"""
Logs in. Returns True if successful, False on failure.
"""
params = {"user": username, "passwrd": password, "cookielength": "60",
"cookieneverexp": "checked", "hash_passwrd": ""}
html = self.request({"action": "login2"}, params)
html = GG2ForumResponseParser(html)
return ("- Index" in html.getTitle())
#!/usr/bin/env python3
import builtins
import codecs
import sys
writer = codecs.getwriter('utf8')(sys.stdout.buffer)
def print(*x):
builtins.print(*x, file=writer)
import cgitb
cgitb.enable()
import cgi
import gg2interface
import sqlite3
from random import choice
from time import time
form = cgi.FieldStorage()
conn = sqlite3.connect("/var/www-db/sigchange.db")
cursor = conn.cursor()
TIMEOUT = 120
numusers = len(cursor.execute("select lastchange from signatures").fetchall())
html = """
<!DOCTYPE html>
<html>
<head>
<title>GG2 Forums Random Signature</title>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
</head>
<body>
<h1>GG2 Forums Random Signature</h1>
This is a service to change your signature to a new random one. It currently has <strong>""" + str(numusers) + """ users</strong>!<br />
At the moment, the signature will change when it is viewed """+str(TIMEOUT)+""" seconds after it was last changed.
(This is to prevent overloading the GG2 Forums server with requests, see
<a href="http://www.ganggarrison.com/forums/index.php?topic=26577.msg857244#msg857244">this</a>)<br />
Yes, your password <strong>is</strong> stored on the server in plaintext. No, I won't steal it. I want to provide a useful service, not to scam you.<br />
<ul>
<li>Adding a signature set - Enter username, password, and signatures</li>
<li>Editing a signature set - Enter username, no password or signatures, click button then see "Adding a signature set"</li>
<li>Deleting a signature set - Enter username, password, and no signatures</li>
</ul>
<strong style="color: red;">%s</strong><br />
<form action="main.py" method="POST" accept-charset="utf-8">
Username: <input type="text" name="username" /><br />
Password: <input type="password" name="password" /><br />
Signatures (seperate with &lt;&lt;&gt;&gt;, e.g. quote 1&lt;&lt;&gt;&gt;quote 2&lt;&lt;&gt;&gt;quote 3):<br />
<textarea name="signatures" rows="15" cols="50" style="font-family: sans-serif;">%s</textarea><br />
<input type="submit" name="set" value="Submit" />
</form>
</body>
</html>
"""
def changesig(username, password, newsig):
interface = gg2interface.GG2ForumInterface()
if interface.login(username, password):
return interface.changeProfile(signature=newsig)
else:
return False
def changerandsig(username):
row = cursor.execute("select * from signatures where username=?", (username,)).fetchone()
if row:
if row[3] == None or row[3] < time() - TIMEOUT:
signatures = row[2].split("<<>>")
signatures = [i.strip() for i in signatures]
if signatures:
sig = choice(signatures)
else:
sig = "ERROR: No signatures specified"
sig += "\n[url=http://ajf.me/sigchange][img]http://ajf.me/sigchange?rotate=%s[/img][/url]" % username
cursor.execute("update signatures set lastchange=? where username=?", (time(), username))
conn.commit()
return changesig(username, row[1], sig)
return True
else:
return False
if not "rotate" in form:
print("Content-Type: text/html; charset=utf-8")
print()
if "rotate" in form:
changerandsig(form.getvalue("rotate"))
#print("Content-Type: image/png")
#print()
#with open("sigchange.png") as fp:
# sys.stdout.write(fp.read())
#print("Location: sigchange.png")
fname = "sigchange"+str(choice(range(2)))+".gif"
print("Location: %s" % fname)
print("Expires: Mon, 01 Jan 1970 00:00:00 GMT")
print()
elif "username" in form and "password" in form: # Update/Add/Delete
username, password = form.getvalue("username"), form.getvalue("password")
signatures = form.getvalue("signatures")
# Search for username/password combo
result = cursor.execute("select * from signatures where username=? and password=?",
(username, password))
exists = (len(result.fetchall())>0)
if signatures and exists:
# Update record
cursor.execute("update signatures set signatures=? where username=? and password=?",
(signatures, username, password))
if changerandsig(username):
conn.commit()
print(html % ("Updated signature set", ""))
else:
print(html % ("Error: Could not change signature (bad username/password?)", ""))
elif signatures:
# Add new record
cursor.execute("insert into signatures(username, password, signatures, lastchange) values(?, ?, ?, ?)",
(username, password, signatures, 0.0))
if changerandsig(username):
conn.commit()
print(html % ("Created new signature set", ""))
else:
print(html % ("Error: Could not change signature (bad username/password?)", ""))
elif exists:
# Delete record
cursor.execute("delete from signatures where username=? and password=?",
(username, password))
conn.commit()
print(html % ("Deleted signature set", ""))
else:
print(html % ("Could not find username/password", ""))
elif "username" in form: # Load
# Search for username/password combo
username = form.getvalue("username")
result = cursor.execute("select * from signatures where username=?", (username,))
rows = result.fetchall()
if len(rows) > 0:
print(html % ("Signature set loaded", rows[0][2]))
else:
print(html % ("Could not find username", ""))
else:
print(html % ("", ""))
conn.close()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment