Compare commits
No commits in common. "main" and "1.0.7" have entirely different histories.
9 changed files with 99 additions and 100 deletions
105
app.py
105
app.py
|
@ -7,16 +7,18 @@ import random
|
||||||
import sqlite3
|
import sqlite3
|
||||||
import time
|
import time
|
||||||
import html
|
import html
|
||||||
|
import zipfile
|
||||||
from argparse import ArgumentParser
|
from argparse import ArgumentParser
|
||||||
from flask import Flask, request, render_template, send_file
|
from flask import Flask, request, render_template, send_file
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
from io import BytesIO
|
||||||
|
|
||||||
# stuff
|
# stuff
|
||||||
with open(f"{os.getcwd()}/config.json", "r") as f:
|
with open(f"{os.getcwd()}/config.json", "r") as f:
|
||||||
config = json.load(f)
|
config = json.load(f)
|
||||||
|
|
||||||
parser = ArgumentParser(prog="syscheck_receiver", description="Server that saves SysCheck report uploads.")
|
parser = ArgumentParser()
|
||||||
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.add_argument("-d", "--debug", dest="debug")
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
def id_generator(size=6, chars=string.ascii_uppercase + string.digits):
|
def id_generator(size=6, chars=string.ascii_uppercase + string.digits):
|
||||||
|
@ -30,17 +32,6 @@ def get_console_id(txt):
|
||||||
|
|
||||||
return "0"
|
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
|
# docker
|
||||||
if config["docker"]:
|
if config["docker"]:
|
||||||
report_dir = "/data/reports"
|
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
|
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():
|
def syscheck_report():
|
||||||
form_data = request.form.to_dict(flat=False)
|
form_data = request.form.to_dict(flat=False)
|
||||||
report_txt = form_data["syscheck"][0]
|
report_txt = form_data["syscheck"][0]
|
||||||
console_id = get_console_id(report_txt)[:-4]
|
console_id = get_console_id(report_txt)
|
||||||
|
|
||||||
# check if console id: is present
|
|
||||||
if console_id == "0":
|
if console_id == "0":
|
||||||
return no_cf_chunking("ERROR: Not a valid sysCheck!"), 200
|
return "ERROR: Not a valid sysCheck!", 200
|
||||||
# check if syscheck isn't too small or too large
|
console_id_censor = console_id[:-4]+"***"
|
||||||
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
|
|
||||||
|
|
||||||
timestamp = int(time.time())
|
timestamp = int(time.time())
|
||||||
report_id = id_generator(6, 'AaBbCcDdFfeEgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWXxYyZz1234567890')
|
report_id = id_generator(6, 'AaBbCcDdFfeEgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWXxYyZz1234567890')
|
||||||
|
|
||||||
if form_data["password"][0] == config["upload_password"]:
|
if form_data["password"][0] in config["upload_passwords"]:
|
||||||
try:
|
try:
|
||||||
with open(f"{report_dir}/{report_id}.csv", "a+") as report:
|
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)
|
db = sqlite3.connect(db_dir)
|
||||||
cursor = db.cursor()
|
cursor = db.cursor()
|
||||||
|
@ -98,26 +83,50 @@ def syscheck_report():
|
||||||
db.commit()
|
db.commit()
|
||||||
db.close()
|
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:
|
except Exception as ex:
|
||||||
print(ex)
|
print(ex)
|
||||||
return no_cf_chunking("ERROR: Failed to save SysCheck report!"), 200
|
return "ERROR: Failed to save SysCheck report!", 200
|
||||||
|
|
||||||
else:
|
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"])
|
||||||
@app.route("/view_report", methods=["GET"], defaults={'_route': 'template'})
|
def view_report():
|
||||||
def view_report(_route):
|
|
||||||
report_id = request.args.get("id")
|
report_id = request.args.get("id")
|
||||||
if os.path.isfile(f"{report_dir}/{report_id}.csv"):
|
if os.path.isfile(f"{report_dir}/{report_id}.csv"):
|
||||||
if _route == "template":
|
with open(f"{report_dir}/{report_id}.csv", "r") as report:
|
||||||
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
|
||||||
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")
|
|
||||||
else:
|
else:
|
||||||
return "Report does not exist.", 404
|
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
|
# handle errors
|
||||||
@app.errorhandler(400)
|
@app.errorhandler(400)
|
||||||
@app.errorhandler(404)
|
@app.errorhandler(404)
|
||||||
|
@ -125,13 +134,25 @@ def view_report(_route):
|
||||||
@app.errorhandler(502)
|
@app.errorhandler(502)
|
||||||
def errorhandler(e):
|
def errorhandler(e):
|
||||||
if e.code == 400:
|
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:
|
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:
|
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:
|
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
|
# run server
|
||||||
|
@ -159,7 +180,7 @@ if __name__ == "__main__":
|
||||||
os.mkdir(report_dir)
|
os.mkdir(report_dir)
|
||||||
|
|
||||||
# start server
|
# start server
|
||||||
if args.debug:
|
if args.debug == "1":
|
||||||
print("Debug mode: on")
|
print("Debug mode: on")
|
||||||
app.run(host=config["ip"], port=config["port"], debug=True)
|
app.run(host=config["ip"], port=config["port"], debug=True)
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -1,7 +1,11 @@
|
||||||
{
|
{
|
||||||
"ip": "0.0.0.0",
|
"ip": "0.0.0.0",
|
||||||
"port": "6969",
|
"port": "6969",
|
||||||
"version": "1.1.2",
|
"version": "1.0.7",
|
||||||
"upload_password": "B277eNGp789a",
|
"upload_passwords": [
|
||||||
|
"d2wRuTEObSAN",
|
||||||
|
"B277eNGp789a"
|
||||||
|
],
|
||||||
|
"replace_str": "http://syscheck.crafterpika.cc/syscheck_up.php",
|
||||||
"docker": false
|
"docker": false
|
||||||
}
|
}
|
||||||
|
|
|
@ -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.
|
|
|
Binary file not shown.
Before Width: | Height: | Size: 1.1 KiB |
BIN
static/syscheck/boot.dol
Normal file
BIN
static/syscheck/boot.dol
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.3 MiB |
BIN
static/syscheck/icon.png
Normal file
BIN
static/syscheck/icon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 6.8 KiB |
29
static/syscheck/meta.xml
Normal file
29
static/syscheck/meta.xml
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||||
|
<app version="1">
|
||||||
|
<name>SysCheck ModMii Edition</name>
|
||||||
|
<coder>blackb0x, JoostinOnline, Double_A, R2-D2199, Nano</coder>
|
||||||
|
<version>2.5.0</version>
|
||||||
|
<release_date>20230309000000</release_date>
|
||||||
|
<short_description>System Checker ModMii Edition</short_description>
|
||||||
|
<long_description>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!</long_description>
|
||||||
|
<arguments>
|
||||||
|
<arg>--debug=false</arg>
|
||||||
|
<arg>--forceNoAHBPROT=false</arg>
|
||||||
|
<arg>--skipIOS=0</arg>
|
||||||
|
</arguments>
|
||||||
|
<no_ios_reload/>
|
||||||
|
</app>
|
|
@ -5,12 +5,10 @@
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<link type="text/css" rel="stylesheet" href="{{ url_for('static', filename='main.css') }}"/>
|
<link type="text/css" rel="stylesheet" href="{{ url_for('static', filename='main.css') }}"/>
|
||||||
<link rel="shortcut icon" href="{{ url_for('static', filename='favicon.ico') }}" type="image/vnd.microsoft.icon" />
|
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div class="topnav">
|
<div class="topnav">
|
||||||
<a href="https://github.com/modmii/SysCheck-ModMii-Edition/releases/latest" target="_blank">Download SysCheckME</a>
|
<a href="/syscheck_dl">Download SysCheckME</a>
|
||||||
<a href="https://wii.hacks.guide/syscheck" target="_blank">How to use</a>
|
|
||||||
</div>
|
</div>
|
||||||
<center>
|
<center>
|
||||||
<h1>Latest Uploads:</h1>
|
<h1>Latest Uploads:</h1>
|
||||||
|
|
|
@ -5,7 +5,6 @@
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<link type="text/css" rel="stylesheet" href="{{ url_for('static', filename='main.css') }}"/>
|
<link type="text/css" rel="stylesheet" href="{{ url_for('static', filename='main.css') }}"/>
|
||||||
<link rel="shortcut icon" href="{{ url_for('static', filename='favicon.ico') }}" type="image/vnd.microsoft.icon" />
|
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue