diff --git a/admin_page_server.py b/admin_page_server.py index 9db2177..9dcd750 100644 --- a/admin_page_server.py +++ b/admin_page_server.py @@ -1,13 +1,10 @@ -#Make sure you change the password to something else and don't commit it to public github! -admin_username = "admin" -admin_password = "opensesame" - from twisted.web import server, resource from twisted.internet import reactor from twisted.internet.error import ReactorAlreadyRunning import base64 import codecs import sqlite3 +import collections import json import time import datetime @@ -23,6 +20,26 @@ logger_filename = "admin_page.log" logger = utils.create_logger(logger_name, logger_filename, -1, logger_output_to_console, logger_output_to_file) +#Example of adminpageconf.json +# +# {"username":"admin","password":"opensesame"} +# +# NOTE: Must use double-quotes or json module will fail +# NOTE2: Do not check the .json file into public git! +adminpageconf = None +try: + adminpageconf = file('adminpageconf.json').read().strip() +except Exception,e: + logger.log(logging.INFO,"ERROR reading adminpageconf.json: "+str(e)) + logger.log(logging.INFO," *** WARN: adminpageconf.json could not be read. Creating one with default values") + adminpageconf = '{"username":"admin","password":"opensesame"}' + fd = open('adminpageconf.json','w') + fd.write(adminpageconf) + fd.close() +adminpageconf = json.loads(adminpageconf) +admin_username = str(adminpageconf['username']) +admin_password = str(adminpageconf['password']) + class AdminPage(resource.Resource): isLeaf = True @@ -39,7 +56,7 @@ class AdminPage(resource.Resource): actual_auth = request.getAllHeaders()['authorization'].replace("Basic ","").strip() if actual_auth == expected_auth: if actual_auth == 'YWRtaW46b3BlbnNlc2FtZQ==': - error_message = ( 'You must change the default login info' + error_message = ( 'You must change the default values in adminpageconf.json' '[LOG OUT]' ) response_code = 500 else: @@ -54,9 +71,66 @@ class AdminPage(resource.Resource): request.write(error_message) return is_auth + def update_whitelist(self, request): + address = request.getClientIP() + dbconn = sqlite3.connect('gpcm.db') + userid = request.args['userid'][0].strip() + gameid = request.args['gameid'][0].upper().strip() + macadr = request.args['macadr'][0].strip() + actiontype = request.args['actiontype'][0] + if not userid.isdigit() or not gameid.isalnum() or not macadr.isalnum(): + request.setResponseCode(500) + logger.log(logging.INFO,address+" Bad data "+userid+" "+gameid+" "+macadr) + return "Bad data" + if actiontype == 'add': + dbconn.cursor().execute('insert into whitelist values(?,?,?)',(userid,gameid,macadr)) + responsedata = "Added macadr=%s for gameid=%s, userid=%s" % (macadr,gameid,userid) + else: + dbconn.cursor().execute('delete from whitelist where userid=? and gameid=? and macadr=?',(userid,gameid,macadr)) + responsedata = "Removed macadr=%s for gameid=%s, userid=%s" % (macadr,gameid,userid) + dbconn.commit() + dbconn.close() + logger.log(logging.INFO,address+" "+responsedata) + request.setHeader("Content-Type", "text/html; charset=utf-8") + return responsedata + + def render_whitelist(self, request): + address = request.getClientIP() + dbconn = sqlite3.connect('gpcm.db') + dbconn.cursor().execute('CREATE TABLE IF NOT EXISTS whitelist (userid TEXT, gameid TEXT, macadr TEXT)') + logger.log(logging.INFO,address+" Viewed whitelist") + responsedata = ("\r\n" + "altwfc admin page - WhiteList" + '[CLICK HERE TO LOG OUT]' + "
" + "userid:\r\n" + "gameid:\r\n" + "macadr:\r\n" + "\r\n" + "
\r\n" + "" + "\r\n") + for row in dbconn.cursor().execute("select * from whitelist"): + userid = str(row[0]) + gameid = str(row[1]) + macadr = str(row[2]) + responsedata += ("" + "\r\n") + responsedata += "
useridgameidmacadr
"+userid+""+gameid+""+macadr+"
" + "" + "" + "" + "\r\n" + "
" + dbconn.close() + request.setHeader("Content-Type", "text/html; charset=utf-8") + return responsedata + def render_GET(self, request): if not self.is_authorized(request): return "" + if request.path == "/whitelist": + return self.render_whitelist(request) if request.path != "/banhammer": request.setResponseCode(500) return "wrong url path" @@ -74,16 +148,19 @@ class AdminPage(resource.Resource): 'order by users.gameid ' '') dbconn = sqlite3.connect('gpcm.db') - responsedata = ("\r\n" + responsedata = ("\r\n" "altwfc admin page" '[CLICK HERE TO LOG OUT]' + "

" + 'WhiteList' + "
" "" "" "\r\n") for row in dbconn.cursor().execute(sqlstatement): dwc_pid = str(row[0]) enabled = str(row[1]) - nasdata = json.loads(row[2]) + nasdata = collections.defaultdict(lambda: '', json.loads(row[2])) gameid = str(row[3]) is_console = int(str(row[4])) userid = str(row[5]) @@ -113,14 +190,14 @@ class AdminPage(resource.Resource): "" "" "" - "") + "") else: responsedata += ("") - responsedata += "
ingamesn or devnamegameidEnablednewest dwc_pidgsbrcduserid
" "" "" "" - "
" + "") + responsedata += "" dbconn.close() request.setHeader("Content-Type", "text/html; charset=utf-8") return responsedata.encode('utf-8') @@ -128,6 +205,8 @@ class AdminPage(resource.Resource): def render_POST(self, request): if not self.is_authorized(request): return "" + if request.path == "/updatewhitelist": + return self.update_whitelist(request) if request.path != "/enableuser" and request.path != "/disableuser": request.setResponseCode(500) return "wrong url path" @@ -155,6 +234,7 @@ class AdminPage(resource.Resource): dbconn.commit() dbconn.close() logger.log(logging.INFO,address+" "+responsedata) + request.setHeader("Content-Type", "text/html; charset=utf-8") return responsedata diff --git a/gamespy/gs_database.py b/gamespy/gs_database.py index eec64b4..b51d5af 100644 --- a/gamespy/gs_database.py +++ b/gamespy/gs_database.py @@ -94,15 +94,15 @@ class GamespyDatabase(object): self.conn.row_factory = sqlite3.Row #self.initialize_database() - + def __del__(self): self.close() - def close(self): + def close(self): if self.conn != None: self.conn.close() self.conn = None - + def initialize_database(self): with Transaction(self.conn) as tx: row = tx.queryone("SELECT COUNT(*) FROM sqlite_master WHERE name = 'users' AND type = 'table'") @@ -119,7 +119,7 @@ class GamespyDatabase(object): tx.nonquery("CREATE TABLE buddies (userProfileId INT, buddyProfileId INT, time INT, status INT, notified INT, gameid TEXT, blocked INT)") tx.nonquery("CREATE TABLE pending_messages (sourceid INT, targetid INT, msg TEXT)") tx.nonquery("CREATE TABLE gamestat_profile (profileid INT, dindex TEXT, ptype TEXT, data TEXT)") - tx.nonquery("CREATE UNIQUE INDEX IF NOT EXISTS gamestatprofile_triple ON gamestat_profile (profileid, dindex, ptype)") + tx.nonquery("CREATE UNIQUE INDEX gamestatprofile_triple on gamestat_profile(profileid,dindex,ptype)") tx.nonquery("CREATE TABLE gameinfo (profileid INT, dindex TEXT, ptype TEXT, data TEXT)") tx.nonquery("CREATE TABLE nas_logins (userid TEXT, authtoken TEXT, data TEXT)") @@ -206,14 +206,16 @@ class GamespyDatabase(object): return profileid - def create_user(self, userid, password, email, uniquenick, gsbrcd, console, csnum, cfc, bssid, devname, birth, gameid): + def create_user(self, userid, password, email, uniquenick, gsbrcd, console, csnum, cfc, bssid, devname, birth, gameid, macadr): #Check for console ban with Transaction(self.conn) as tx: - row = tx.queryone("SELECT * FROM users WHERE userid = ? and gameid = ? and enabled = 0 limit 1", (userid, gameid)) + row = tx.queryone("SELECT * FROM users WHERE userid = ? and gameid = ? and enabled = 0 " + "and gameid not in (select gameid from whitelist where gameid=? and macadr=?) limit 1" + ,(userid, gameid, gameid, macadr)) r = self.get_dict(row) if r != None: - logger.log(logging.INFO, "--- REJECTING BANNED CONSOLE --- userid=%s,gameid=%s", userid,gameid) + logger.log(logging.INFO, "--- REJECTING BANNED CONSOLE --- userid=%s,gameid=%s,macadr=%s", userid,gameid,macadr) return None if self.check_user_exists(userid, gsbrcd) == 0: diff --git a/gamespy/gs_utility.py b/gamespy/gs_utility.py index ee1155b..d7b91f3 100644 --- a/gamespy/gs_utility.py +++ b/gamespy/gs_utility.py @@ -118,6 +118,7 @@ def login_profile_via_parsed_authtoken(authtoken_parsed, db): password = authtoken_parsed['gsbrcd'] gsbrcd = authtoken_parsed['gsbrcd'] gameid = gsbrcd[:4] + macadr = authtoken_parsed['macadr'] uniquenick = utils.base32_encode(int(userid)) + gsbrcd email = uniquenick + "@nds" # The Wii also seems to use @nds. @@ -128,7 +129,7 @@ def login_profile_via_parsed_authtoken(authtoken_parsed, db): valid_user = db.check_user_exists(userid, gsbrcd) if valid_user == False: - profileid = db.create_user(userid, password, email, uniquenick, gsbrcd, console, csnum, cfc, bssid, devname, birth, gameid) + profileid = db.create_user(userid, password, email, uniquenick, gsbrcd, console, csnum, cfc, bssid, devname, birth, gameid, macadr) else: profileid = db.perform_login(userid, password, gsbrcd)