diff --git a/DreamTown/cgi-bin/code/getLogoutCode b/DreamTown/cgi-bin/code/getLogoutCode new file mode 100644 index 0000000..a5060c0 --- /dev/null +++ b/DreamTown/cgi-bin/code/getLogoutCode @@ -0,0 +1,237 @@ +#!/usr/bin/python3 +from dreamtown_config import * +import sys +import os +import json +import sqlite3 +import time +import hashlib +import random + +# +# Bassed off https://github.com/MrBlinky/Tamagotchi-friends-code-generator +# +# MIT License +# +# Copyright (c) 2021 Mr.Blinky +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + + + +passwordchars1 = "0123456789ABCDEF" +passwordchars2 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0" +namechars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ " +namechars_xor = [0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0xA0] +checksum_xor = [0x11, 0x32, 0x53, 0x74, 0x15, 0x36, 0x58, 0x77, 0x29, 0x4F, 0x6E, 0x0D, 0x2C, 0x4B, 0x6A, 0x7F] +step3count_xor = [0x57, 0x3A] +nameorder = [6, 8, 10, 7, 9, 13, 11, 12] #digit order of name characters +step13count_add = [[1, 2, 3, 4, 5, 6, 7, 8], + [2, 3, 4, 5, 6, 7, 8, 1], + [3, 4, 5, 6, 7, 8, 1, 2], + [4, 5, 6, 7, 8, 1, 2, 3], + [5, 6, 7, 8, 1, 2, 3, 4], + [6, 7, 8, 1, 2, 3, 4, 5], + [7, 2, 1, 2, 3, 4, 5, 6], + [8, 1, 2, 3, 4, 5, 6, 7]] + + + +print("Content-Type: application/json") +print("") + +content_len = int(os.environ["CONTENT_LENGTH"]) +post = sys.stdin.read(content_len) +jsonData = json.loads(post) +result = {"status":SUCCESS} + +method = os.environ["REQUEST_METHOD"] +if method != "POST": + print("Expected POST") + os._exit() + +def GetTamaName(tama_id): + if tama_id >= len(tamagotchi) or tama_id < 0: + return "Unknown #"+str(tama_id) + + tamaName = tamagotchi[tama_id] + if tamaName == "": + tamaName = "Unknown #"+str(tama_id) + + return tamaName + +def InputValidation(password): + if len(password) != 14: + return False + + for i in range(0,6): + if passwordchars1.find(password[i]) == -1: + return False + + for i in range(6,14): + if passwordchars2.find(password[i]) == -1: + return False + + return True + +def GetItem(special): + #check item input + if not special: + itemType = random.randrange(0, 2) + else: + itemType = random.randrange(2, 6) + itemId = random.randrange(0, 30) + if itemType == 0: + pass + if itemType == 1: + itemId += 30; + else: + if itemId > 14: + itemId = 14; + itemId += (itemType-2) * 15; + itemType = 2; + return [itemId, itemType] + + + +def GetName(password, stepCount): + name = ''; + for i in range(0,8): #get user name + c = passwordchars2.find(password[nameorder[i]]) - step13count_add[stepCount][i]; + if c < 0: + c += 0x1B; + name += namechars[c]; + return name + +def TryGet(): + authToken = jsonData['authToken'] + + c = db.cursor() + cur = c.execute('SELECT COUNT(1) from users WHERE LastSession=?',(authToken,)) + rows = cur.fetchone() + count = rows[0] + if count == 0: + result['status'] = USER_DOES_NOT_EXIST + return 0 + + #validate + loginPassword = jsonData["code"].upper() + ticketNumber = jsonData['ticketNumber'] + if not InputValidation(loginPassword): + result['status'] = 2 # code invalid + return 0 + + #decode + checksum = passwordchars1.find(loginPassword[0]) + step13count = passwordchars1.find(loginPassword[1]) >> 1 + step3count = passwordchars1.find(loginPassword[1]) & 1 + + name = GetName(loginPassword, step13count) + + #login data for decoding and checksum verifying + logindata = [ + (passwordchars1.find(loginPassword[4]) << 4) | passwordchars1.find(loginPassword[5]), + (passwordchars1.find(loginPassword[2]) << 4) | passwordchars1.find(loginPassword[3]), + ((namechars.find(name[1]) & 0x3) << 6) | namechars.find(name[0]), + ((namechars.find(name[2]) & 0xF) << 4) | (namechars.find(name[1]) >> 2), + (namechars.find(name[3]) << 2) | (namechars.find(name[2]) >> 4), + ((namechars.find(name[5]) & 0x3) << 6) | namechars.find(name[4]), + ((namechars.find(name[6]) & 0xF) << 4) | (namechars.find(name[5]) >> 2), + (namechars.find(name[7]) << 2) | (namechars.find(name[6]) >> 4), + (passwordchars1.find(loginPassword[0]) << 4) | passwordchars1.find(loginPassword[1]) + ] + + + # step 3 counter xoring + logindata[0] ^= step3count_xor[step3count] + logindata[1] ^= step3count_xor[step3count] + + #name xor + logindata[0] ^= namechars_xor[namechars.find(name[1])]; + logindata[1] ^= namechars_xor[namechars.find(name[3])]; + + #checksum xor + logindata[0] ^= checksum_xor[checksum]; + logindata[1] ^= checksum_xor[checksum]; + + # Check checksum + c = 0; + for i in range(0, 17): + if (i & 1) == 1: + c -= (logindata[i >> 1] >> 4); + else: + c -= (logindata[i >> 1] & 0xF); + + if (c & 0xF) != checksum: + result['status'] = 2 # code invalid + return 0 + + tama_id = logindata[0] & 0x3F + step7count = logindata[1] >> 4; + device_id = (logindata[0] >> 6) | ((logindata[1] & 0xF) << 2); + + special = False + if ticketNumber > 1: + special = True + + itemResult = GetItem(special) + itemId = itemResult[0] + itemType = itemResult[1] + + #create logout data + logoutdata = [ + logindata[0], + logindata[1] | 0x80, + itemId, + (step3count << 3) | itemType + ] + checksum = (0 - (logoutdata[1] >> 4) - (logoutdata[1] & 0xF) - + (logoutdata[0] >> 4) - (logoutdata[0] & 0xF) - + (logoutdata[2] >> 4) - (logoutdata[2] & 0xF) - + (logoutdata[3] & 0xF)) & 0XF; + + #xor checksum + for i in range(0,3): + logoutdata[i] ^= checksum_xor[checksum]; + + #player name xoring + logoutdata[0] ^= namechars_xor[namechars.find(name[1])]; + logoutdata[1] ^= namechars_xor[namechars.find(name[3])]; + logoutdata[2] ^= namechars_xor[namechars.find(name[5])]; + #step 3 counter xoring + for i in range(0,3): + logoutdata[i] ^= step3count_xor[step3count]; + + logoutPassword = '%X%X%X%X%X%X%X%X' % ( + logoutdata[1] >> 4, logoutdata[1] & 0xF, + logoutdata[0] >> 4, logoutdata[0] & 0xF, + checksum , logoutdata[3] & 0xF, + logoutdata[2] >> 4, logoutdata[2] & 0xF) + + result["code"] = logoutPassword +try: + db = sqlite3.connect(SQLLITE_DB_PATH) + TryGet() + db.commit() + db.close() +except Exception as e: + print(e) + os._exit() + +print(json.dumps(result)) \ No newline at end of file diff --git a/DreamTown/cgi-bin/code/getPlayerData b/DreamTown/cgi-bin/code/getPlayerData index 19e6c2a..76034c2 100644 --- a/DreamTown/cgi-bin/code/getPlayerData +++ b/DreamTown/cgi-bin/code/getPlayerData @@ -1,4 +1,179 @@ #!/usr/bin/python3 +from dreamtown_config import * +import sys +import os +import json +import sqlite3 +import time +import hashlib + +# +# Bassed off https://github.com/MrBlinky/Tamagotchi-friends-code-generator +# +# MIT License +# +# Copyright (c) 2021 Mr.Blinky +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + + +tamagotchi = ["", "Aokumotchi", "Pinkbotchi"] + +passwordchars1 = "0123456789ABCDEF" +passwordchars2 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0" +namechars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ " +namechars_xor = [0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0xA0] +checksum_xor = [0x11, 0x32, 0x53, 0x74, 0x15, 0x36, 0x58, 0x77, 0x29, 0x4F, 0x6E, 0x0D, 0x2C, 0x4B, 0x6A, 0x7F] +step3count_xor = [0x57, 0x3A] +nameorder = [6, 8, 10, 7, 9, 13, 11, 12] #digit order of name characters +step13count_add = [[1, 2, 3, 4, 5, 6, 7, 8], + [2, 3, 4, 5, 6, 7, 8, 1], + [3, 4, 5, 6, 7, 8, 1, 2], + [4, 5, 6, 7, 8, 1, 2, 3], + [5, 6, 7, 8, 1, 2, 3, 4], + [6, 7, 8, 1, 2, 3, 4, 5], + [7, 2, 1, 2, 3, 4, 5, 6], + [8, 1, 2, 3, 4, 5, 6, 7]] + + + print("Content-Type: application/json") print("") -print("{'playerName':'Mametchi','characterName':'Mametchi','status':1}") \ No newline at end of file + +content_len = int(os.environ["CONTENT_LENGTH"]) +post = sys.stdin.read(content_len) +jsonData = json.loads(post) +result = {"status":SUCCESS} + +method = os.environ["REQUEST_METHOD"] +if method != "POST": + print("Expected POST") + os._exit() + +def GetTamaName(tama_id): + if tama_id >= len(tamagotchi) or tama_id < 0: + return "Unknown #"+str(tama_id) + + tamaName = tamagotchi[tama_id] + if tamaName == "": + tamaName = "Unknown #"+str(tama_id) + + return tamaName + +def InputValidation(password): + if len(password) != 14: + return False + + for i in range(0,6): + if passwordchars1.find(password[i]) == -1: + return False + + for i in range(6,14): + if passwordchars2.find(password[i]) == -1: + return False + + return True + +def GetName(password, stepCount): + name = ''; + for i in range(0,8): #get user name + c = passwordchars2.find(password[nameorder[i]]) - step13count_add[stepCount][i]; + if c < 0: + c += 0x1B; + name += namechars[c]; + return name + +def TryGet(): + authToken = jsonData['authToken'] + + c = db.cursor() + cur = c.execute('SELECT COUNT(1) from users WHERE LastSession=?',(authToken,)) + rows = cur.fetchone() + count = rows[0] + if count == 0: + result['status'] = USER_DOES_NOT_EXIST + return 0 + + #validate + loginPassword = jsonData["code"].upper() + if not InputValidation(loginPassword): + result['status'] = 2 # code invalid + return 0 + + #decode + checksum = passwordchars1.find(loginPassword[0]) + step13count = passwordchars1.find(loginPassword[1]) >> 1 + step3count = passwordchars1.find(loginPassword[1]) & 1 + + name = GetName(loginPassword, step13count) + + #login data for decoding and checksum verifying + logindata = [ + (passwordchars1.find(loginPassword[4]) << 4) | passwordchars1.find(loginPassword[5]), + (passwordchars1.find(loginPassword[2]) << 4) | passwordchars1.find(loginPassword[3]), + ((namechars.find(name[1]) & 0x3) << 6) | namechars.find(name[0]), + ((namechars.find(name[2]) & 0xF) << 4) | (namechars.find(name[1]) >> 2), + (namechars.find(name[3]) << 2) | (namechars.find(name[2]) >> 4), + ((namechars.find(name[5]) & 0x3) << 6) | namechars.find(name[4]), + ((namechars.find(name[6]) & 0xF) << 4) | (namechars.find(name[5]) >> 2), + (namechars.find(name[7]) << 2) | (namechars.find(name[6]) >> 4), + (passwordchars1.find(loginPassword[0]) << 4) | passwordchars1.find(loginPassword[1]) + ] + + + # step 3 counter xoring + logindata[0] ^= step3count_xor[step3count] + logindata[1] ^= step3count_xor[step3count] + + #name xor + logindata[0] ^= namechars_xor[namechars.find(name[1])]; + logindata[1] ^= namechars_xor[namechars.find(name[3])]; + + #checksum xor + logindata[0] ^= checksum_xor[checksum]; + logindata[1] ^= checksum_xor[checksum]; + + tama_id = logindata[0] & 0x3F + + # Check checksum + c = 0; + for i in range(0, 17): + if (i & 1) == 1: + c -= (logindata[i >> 1] >> 4); + else: + c -= (logindata[i >> 1] & 0xF); + + if (c & 0xF) != checksum: + result['status'] = 2 # code invalid + return 0 + + result['playerName'] = name.strip() + result['characterName'] = GetTamaName(tama_id) + + +try: + db = sqlite3.connect(SQLLITE_DB_PATH) + TryGet() + db.commit() + db.close() +except Exception as e: + print(e) + os._exit() + +print(json.dumps(result)) \ No newline at end of file