diff --git a/app.py b/app.py index 70a8bfa..da65f3b 100644 --- a/app.py +++ b/app.py @@ -7,16 +7,18 @@ import random import sqlite3 import time import html +import zipfile from argparse import ArgumentParser from flask import Flask, request, render_template, send_file from datetime import datetime +from io import BytesIO # stuff with open(f"{os.getcwd()}/config.json", "r") as f: config = json.load(f) -parser = ArgumentParser(prog="syscheck_receiver", description="Server that saves SysCheck report uploads.") -parser.add_argument("-d", "--debug", dest="debug", action='store_true', help="Runs with Flask debug server instead of Waitress. DO NOT USE IN PRODUCTION!!!!") +parser = ArgumentParser() +parser.add_argument("-d", "--debug", dest="debug") args = parser.parse_args() def id_generator(size=6, chars=string.ascii_uppercase + string.digits): @@ -30,17 +32,6 @@ def get_console_id(txt): return "0" -def return_error(message: string, code: int): - jsonstring = {"message": message, "code": code, "error": True} - resp = flask.Response(json.dumps(jsonstring)) - resp.headers["Content-Type"] = "application/json" - return resp - -def no_cf_chunking(txt): - resp = flask.Response(txt) - resp.headers["X-Content-Length"] = len(txt.encode("utf-8")) # Cloudflares Proxy strips "Content-Length" when chunking, so we just re-add it manually. - return resp - # docker if config["docker"]: report_dir = "/data/reports" @@ -69,28 +60,22 @@ def index(): return render_template("index.html", uploadIndex=uploadIndex, report_count=report_count[0][0], svr_ver=config["version"]), 200 -@app.route("/syscheck_receiver.php", methods=["POST"]) +@app.route("/syscheck_up.php", methods=["POST"]) # SysCheckME-dev +@app.route("/syscheck_receiver.php", methods=["POST"]) # literally anything else (DNS?) def syscheck_report(): form_data = request.form.to_dict(flat=False) report_txt = form_data["syscheck"][0] - console_id = get_console_id(report_txt)[:-4] - - # check if console id: is present + console_id = get_console_id(report_txt) if console_id == "0": - return no_cf_chunking("ERROR: Not a valid sysCheck!"), 200 - # check if syscheck isn't too small or too large - if len(report_txt.encode("utf-8")) > 6144: - return no_cf_chunking("ERROR: Report is too large! Max is 6KB."), 200 - elif len(report_txt.encode("utf-8")) < 1330: - return no_cf_chunking("ERROR: Report is too small! Min is 1.3KB."), 200 - + return "ERROR: Not a valid sysCheck!", 200 + console_id_censor = console_id[:-4]+"***" timestamp = int(time.time()) report_id = id_generator(6, 'AaBbCcDdFfeEgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWXxYyZz1234567890') - if form_data["password"][0] == config["upload_password"]: + if form_data["password"][0] in config["upload_passwords"]: try: with open(f"{report_dir}/{report_id}.csv", "a+") as report: - report.write(report_txt) + report.write(report_txt.replace(console_id, console_id_censor)) db = sqlite3.connect(db_dir) cursor = db.cursor() @@ -98,26 +83,50 @@ def syscheck_report(): db.commit() db.close() - return no_cf_chunking(f"Success! Report ID: {report_id}"), 200 + return f"Success! Report ID: {report_id}", 200 except Exception as ex: print(ex) - return no_cf_chunking("ERROR: Failed to save SysCheck report!"), 200 + return "ERROR: Failed to save SysCheck report!", 200 + else: - return no_cf_chunking("ERROR: Unauthorized"), 200 + return "ERROR: Unauthorized", 200 -@app.route("/download_csv", methods=["GET"], defaults={'_route': 'direct'}) -@app.route("/view_report", methods=["GET"], defaults={'_route': 'template'}) -def view_report(_route): +@app.route("/view_report", methods=["GET"]) +def view_report(): report_id = request.args.get("id") if os.path.isfile(f"{report_dir}/{report_id}.csv"): - if _route == "template": - with open(f"{report_dir}/{report_id}.csv", "r") as report: - return render_template("view_report.html", report_id=report_id, report_content=html.escape(report.read()), svr_ver=config["version"]), 200 - else: - return send_file(f"{report_dir}/{report_id}.csv", as_attachment=True, download_name="report.csv") + with open(f"{report_dir}/{report_id}.csv", "r") as report: + return render_template("view_report.html", report_id=report_id, report_content=html.escape(report.read()), svr_ver=config["version"]), 200 else: return "Report does not exist.", 404 +@app.route("/syscheck_dl", methods=["GET"]) +def syscheck(): + if len("http://syscheck.rc24.xyz/syscheck_receiver.php") < len(config["replace_str"]): + return "Replacement host has to be exactly 46 characters; Specified URL is too long!", 400 + elif len("http://syscheck.rc24.xyz/syscheck_receiver.php") > len(config["replace_str"]): + return "Replacement host has to be exactly 46 characters; Specified URL is too short!", 400 + + dol = BytesIO() + zip = BytesIO() + + # hex edit boot.dol + dol2 = open(f"{os.getcwd()}/static/syscheck/boot.dol", "rb") + dol.write(dol2.read().replace("http://syscheck.rc24.xyz/syscheck_receiver.php".encode("utf-8"), config["replace_str"].encode("utf-8"))) + dol.seek(0) + dol2.close() + + zf = zipfile.ZipFile(zip, "w", zipfile.ZIP_DEFLATED, False) + zf.writestr("apps/SysCheckME/boot.dol", dol.read()) + dol.close() + zf.write(f"{os.getcwd()}/static/syscheck/icon.png", "apps/SysCheckME/icon.png") + zf.write(f"{os.getcwd()}/static/syscheck/meta.xml", "apps/SysCheckME/meta.xml") + zf.close() + zip.seek(0) + + # send zipfile + return send_file(zip, mimetype="application/zip", as_attachment=True, download_name="SysCheckME.zip"), 200 + # handle errors @app.errorhandler(400) @app.errorhandler(404) @@ -125,13 +134,25 @@ def view_report(_route): @app.errorhandler(502) def errorhandler(e): if e.code == 400: - return return_error("Bad request", 400), 400 + jsonstring = {"message": "Bad Request.", "code": 400, "error": True} + resp = flask.Response(json.dumps(jsonstring)) + resp.headers["Content-Type"] = "application/json" + return resp, 400 elif e.code == 404: - return return_error("Not found", 404), 404 + jsonstring = {"message": "Not found.", "code": 404, "error": True} + resp = flask.Response(json.dumps(jsonstring)) + resp.headers["Content-Type"] = "application/json" + return resp, 404 elif e.code == 405: - return return_error("Method not allowed", 405), 405 + jsonstring = {"message": "Method not allowed.", "code": 405, "error": True} + resp = flask.Response(json.dumps(jsonstring)) + resp.headers["Content-Type"] = "application/json" + return resp, 405 elif e.code == 502: - return return_error("Bad gateway", 502), 502 + jsonstring = {"message": "Bad Gateway.", "code": 502, "error": True} + resp = flask.Response(json.dumps(jsonstring)) + resp.headers["Content-Type"] = "application/json" + return resp, 502 # run server @@ -159,7 +180,7 @@ if __name__ == "__main__": os.mkdir(report_dir) # start server - if args.debug: + if args.debug == "1": print("Debug mode: on") app.run(host=config["ip"], port=config["port"], debug=True) else: diff --git a/config.json b/config.json index b7695db..0ac8049 100644 --- a/config.json +++ b/config.json @@ -1,7 +1,11 @@ { "ip": "0.0.0.0", "port": "6969", - "version": "1.1.2", - "upload_password": "B277eNGp789a", + "version": "1.0.7", + "upload_passwords": [ + "d2wRuTEObSAN", + "B277eNGp789a" + ], + "replace_str": "http://syscheck.crafterpika.cc/syscheck_up.php", "docker": false } diff --git a/reports/example.csv b/reports/example.csv deleted file mode 100644 index 81855b8..0000000 --- a/reports/example.csv +++ /dev/null @@ -1,52 +0,0 @@ -sysCheck v2.1.0b19 by Double_A and R2-D2199, Nano -...runs on IOS58 (rev 32033). - -Region: PAL -System Menu 4.3E (v4610) -Priiloader installed -Drive date: 2012.06.29 -Homebrew Channel 1.1.2 running on IOS58 -HomebrewFilter ist nicht installiert -Console ID: 23620*** -Boot2 v4 -Found 45 titles. -Found 34 IOS on this console. 2 of them are stub. - -IOS3 (rev 65280): Stub -IOS4 (rev 65280): Stub -IOS9 (rev 26891): No Patches -IOS12 (rev 26383): No Patches -IOS13 (rev 26889): No Patches -IOS14 (rev 26889): No Patches -IOS15 (rev 26889): No Patches -IOS17 (rev 26889): No Patches -IOS21 (rev 26896): No Patches -IOS22 (rev 27151): No Patches -IOS28 (rev 27664): No Patches -IOS31 (rev 29465): No Patches -IOS33 (rev 29465): No Patches -IOS34 (rev 29465): No Patches -IOS35 (rev 29465): No Patches -IOS36 (rev 29465): No Patches -IOS37 (rev 31520): No Patches -IOS38 (rev 29981): No Patches -IOS41 (rev 29464): No Patches -IOS43 (rev 29464): No Patches -IOS45 (rev 29464): No Patches -IOS46 (rev 29464): No Patches -IOS48 (rev 29981): No Patches -IOS53 (rev 31520): No Patches -IOS55 (rev 31520): No Patches -IOS56 (rev 31519): No Patches -IOS57 (rev 31776): No Patches -IOS58 (rev 32033): USB 2.0 -IOS59 (rev 32802): No Patches -IOS61 (rev 31519): No Patches -IOS62 (rev 31264): No Patches -IOS80 (rev 32801): No Patches -IOS236[36] (rev 65535, Info: rev 29465): Trucha Bug, ES Identify, NAND Access -IOS249[57] (rev 21001, Info: d2xl-v1beta2): Trucha Bug, NAND Access, USB 2.0 -BC v6 -MIOS v10 - -Report generated on 2024/10/13. diff --git a/static/favicon.ico b/static/favicon.ico deleted file mode 100644 index 1caa3d8..0000000 Binary files a/static/favicon.ico and /dev/null differ diff --git a/static/syscheck/boot.dol b/static/syscheck/boot.dol new file mode 100644 index 0000000..710ca3f Binary files /dev/null and b/static/syscheck/boot.dol differ diff --git a/static/syscheck/icon.png b/static/syscheck/icon.png new file mode 100644 index 0000000..5f682e7 Binary files /dev/null and b/static/syscheck/icon.png differ diff --git a/static/syscheck/meta.xml b/static/syscheck/meta.xml new file mode 100644 index 0000000..d60ccac --- /dev/null +++ b/static/syscheck/meta.xml @@ -0,0 +1,29 @@ + + + SysCheck ModMii Edition + blackb0x, JoostinOnline, Double_A, R2-D2199, Nano + 2.5.0 + 20230309000000 + System Checker ModMii Edition + Homebrew application which does several checks on installed IOS and custom IOS: + - Base IOS Detection + - vIOS Detection + - Beer Ticket + - IOS Stub + - Fake Signature (aka Trucha Bug) + - ES_DiVerify (aka ES_Identify) + - Flash Access + - NAND Access + - Boot2 Access + - USB 2.0 + +SysCheck generates a report on the root of your storage device (e.g. usb:/SysCheck.csv). + +The author can not be held responsible for any damage SysCheck might cause! + + --debug=false + --forceNoAHBPROT=false + --skipIOS=0 + + + diff --git a/templates/index.html b/templates/index.html index 046e2a2..d603cce 100644 --- a/templates/index.html +++ b/templates/index.html @@ -5,12 +5,10 @@ -
- Download SysCheckME - How to use + Download SysCheckME

Latest Uploads:

diff --git a/templates/view_report.html b/templates/view_report.html index 8f4e53a..0c168a4 100644 --- a/templates/view_report.html +++ b/templates/view_report.html @@ -5,7 +5,6 @@ -