Files
2025-07-11 22:09:21 +08:00

175 lines
8.0 KiB
HTML

<!DOCTYPE HTML>
<html data-bs-theme="dark">
<head>
<title>WiiUCommonKeyExtractor</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous">
<style>
.form-control.disabled {
background-color: var(--bs-secondary-bg);
opacity: 1;
pointer-events: none;
}
</style>
</head>
<body>
<div class="row align-items-center justify-content-center">
<div class="col-lg-6 col-md-8 col-sm-12 col-xs-12 col">
<div class='card'>
<div class="card-header bg-primary h2">
WiiUCommonKeyExtractor
</div>
<div class="card-body">
<form class="form">
<div class="border-info mb-3">
<label for="formFile" class="form-label">Pick your OTP</label>
<input class="form-control form-control-lg" type="file" id="otp" disabled>
</div>
<div class="input-group mb-3">
<input id="ckey" type="text" class="form-control disabled" placeholder="Common Key" aria-label="Common Key" readonly>
<button id="ckeyCopy" class="btn btn-secondary" type="button" data-clipboard-target="#ckey" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Copy to Clipboard" disabled>Copy</button>
</div>
<div class="card border-info mb-3">
<div class="card-body" id="info">No file selected yet.</div>
</div>
</form>
</div>
</div>
</div>
</div>
<!-- script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-YvpcrYf0tY3lHB60NNkmXc5s9fDVZLESaAA55NDzOxhy9GkcIdslK1eN7N6jIeHz" crossorigin="anonymous"></script -->
<script>
const otpDom = document.querySelector("#otp");
const ckeyDom = document.querySelector("#ckey");
const ckeyCopyDom = document.querySelector("#ckeyCopy");
const infoDom = document.querySelector("#info");
const ckeyHash = new Uint8Array([
0x3b, 0x40, 0x11, 0xe5, 0x84, 0xae, 0x69, 0x4f, 0x59, 0xf4, 0x9d, 0xf1, 0x3a, 0xa5, 0xf4, 0x71,
0xa4, 0x23, 0x0f, 0xf7, 0xc2, 0xc7, 0x07, 0x83, 0x61, 0xb7, 0xd6, 0x24, 0xb8, 0xee, 0xaa, 0x9b
]);
// stolen from https://github.com/Maschell/fuse-wiiu/blob/f4793d1d0ef996e91626e3d0d42913a24b682a5a/src/main/java/de/mas/wiiu/jnus/fuse_wiiu/Settings.java#L9
ckeyDevHash1 = new Uint8Array([
0xE1,0x91,0xBF,0xDB,0x12,0x32,0x53,0x7D,0x7D,0xAD,0xEA,0xD8,0x1F,0x2A,0x48,0xFD,0x6F,0x18,0x8E,0x02
]);
async function _sha1(bytes) {
if (crypto && crypto.subtle && crypto.subtle.digest) {
return new Uint8Array(await crypto.subtle.digest("SHA-1", bytes));
} else {
return new Promise((resolve, reject) => reject("NO_SHA1_SUPPORT"));
}
}
async function _sha256(bytes) {
if (crypto && crypto.subtle && crypto.subtle.digest) {
return new Uint8Array(await crypto.subtle.digest("SHA-256", bytes));
} else if (window.sha256) {
return new Promise((resolve, reject) => {
const sha = window.sha256.create();
sha.update(bytes)
resolve(new Uint8Array(sha.digest()));
});
} else {
return new Promise((resolve, reject) => {
const script = document.createElement("script");
script.setAttribute("src", "https://cdn.jsdelivr.net/npm/js-sha256@0.11.1/src/sha256.min.js");
script.setAttribute("type", "text/javascript");
script.setAttribute("integrity", "sha384-770qA4HuffiCn2yxSxNLbMwOo4ASxYoGkCSKWiTJy8df4UKbkJ3fAtnE+iTegBWn");
script.setAttribute("crossorigin", "anonymous");
script.setAttribute("async", "async");
script.addEventListener("load", async () => {
resolve(await _sha256(bytes));
});
script.addEventListener("error", () => {
document.body.appendChild(script);
console.log("No SHA256 Support!");
infoDom.innerHTML = '<p class="text-warning">Can\'t calculate checksum to verify common key. You should try a different browser.</p>';
setCKeyColor(2);
reject("NO_SHA256_SUPPORT");
});
document.body.appendChild(script);
});
}
}
function setCKeyColor(success) {
ckeyDom.classList.remove("text-danger");
ckeyDom.classList.remove("text-warning");
ckeyDom.classList.remove("text-info");
ckeyDom.classList.remove("text-success");
if (success === true) {
ckeyDom.classList.add("text-success");
} else if (success === 2) {
ckeyDom.classList.add("text-warning");
} else if (success === 3) {
ckeyDom.classList.add("text-info");
} else {
ckeyDom.classList.add("text-danger");
}
if (!success) { // disable
ckeyDom.classList.add("disabled");
} else {
ckeyDom.classList.remove("disabled");
}
ckeyCopyDom.disabled = !success;
}
async function fileSelected(filelist) {
ckeyDom.value = "";
for (const file of filelist) {
console.log(file)
if (file.size === 1024) {
const ckey = await file.slice(0xE0, 0xF0).bytes();
ckeyDom.value = ckey.toHex().toUpperCase();
const sha = await _sha256(ckey);
if (indexedDB.cmp(sha, ckeyHash) === 0) {
infoDom.innerText = "Wii U Common Key is shown above!";
setCKeyColor(true);
return;
}
try {
const sha1 = await _sha1(ckey);
if (indexedDB.cmp(sha1, ckeyDevHash1) === 0) {
infoDom.innerText = "Dev Console detected ( ͡° ͜ʖ ͡°)";
setCKeyColor(3);
return;
}
} catch (err) {
}
}
}
setCKeyColor(false);
infoDom.innerText = "The file you selected is not valid.";
}
window.addEventListener("dragover", event => {
event.preventDefault();
});
window.addEventListener("drop", event => {
event.preventDefault();
otpDom.value = "";
fileSelected(event.dataTransfer.files);
});
otpDom.addEventListener("change", event => {
fileSelected(otpDom.files);
})
otpDom.disabled = false;
(() => {
const script = document.createElement("script");
script.setAttribute("src", "https://cdn.jsdelivr.net/npm/clipboard@2.0.11/dist/clipboard.min.js");
script.setAttribute("type", "text/javascript");
script.setAttribute("integrity", "sha384-J08i8An/QeARD9ExYpvphB8BsyOj3Gh2TSh1aLINKO3L0cMSH2dN3E22zFoXEi0Q");
script.setAttribute("crossorigin", "anonymous");
script.setAttribute("async", "async");
script.addEventListener("load", () => {
const clipboard = new ClipboardJS(ckeyCopyDom);
});
document.body.appendChild(script);
})();
</script>
</body>
</html>