Created
July 19, 2011 22:34
-
-
Save hikari-no-yume/1093913 to your computer and use it in GitHub Desktop.
GG2 Forums Signature Rotation Service
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
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()) | |
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
#!/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 <<>>, e.g. quote 1<<>>quote 2<<>>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