additions & fixes

* browser version checker
* normalkey extraction error fixed
This commit is contained in:
Jisagi 2018-05-11 18:54:07 +02:00
parent 984a0e3ab9
commit 0b6b31330e
6 changed files with 106 additions and 31 deletions

View File

@ -23,6 +23,7 @@
<script src="public/js/custom/fileAccess.js"></script>
<script src="public/js/custom/validation.js"></script>
<script src="public/js/custom/extraction.js"></script>
<script src="public/js/custom/signing.js"></script>
<script src="public/js/custom/injection.js"></script>
<script src="public/js/custom/building.js"></script>
<script src="public/js/custom/msed.js"></script>
@ -32,6 +33,12 @@
<meta name="description" content="DSiWare Injector for Seedminer.">
<meta property="og:image" content="https://i.imgur.com/CVSu1zc.png">
<script>
$(document).ready(() => {
checkBrowserVersion();
});
</script>
</head>
<body>
@ -76,11 +83,17 @@
</ul>
</ul>
<br/>
<h5>Compatible Browsers</h5>
<h5>Compatible Browser Versions:</h5>
<p>
<u>green:</u> recommended,
<u>orange:</u> probably works,
<u>red:</u> dont even try</p>
<u>red:</u> dont even try
</p>
<div class="div-browser-version" style="display:non;">
<p style="font-weight:bold;font-size:150%;float:left;">Your Browser:&nbsp;</p>
<p class="p-browser-version" style="font-weight:bold;font-size:150%;"></p>
<p class="p-browser-error" style="font-weight:bold;font-size:150%;"></p>
</div>
<ul>
<li class="li-browser-good">Chrome >= 60</li>
<li class="li-browser-good">Firefox >= 50</li>

View File

@ -7,7 +7,8 @@ function extractNormalKey(movableKeyY, keyXHex) {
n = n.xor(keyY).add(c).and(f128);
n = n.shiftLeft(87).or(n.shiftRight(128 - 87)).and(f128);
let arr = n.toArray(256).value;
return (arr[0] === 0) ? arr.slice(1) : arr;
while (arr.length < 16) arr = [0].concat(arr);
return arr;
}
function extractDsiware(dsiware, normalKey) {
@ -24,7 +25,7 @@ function extractDsiware(dsiware, normalKey) {
/* content list extr & decrypt */
let buffer = sliceArr(header, 0x48, 0x2C).buffer;
let sizes = new Int32Array(buffer)
let sizes = new Int32Array(buffer);
sizes.forEach((s, i) => { if (s === 0xB34) sizes[i] = 0xB40 });
let other = {};

View File

@ -8,7 +8,7 @@ function loadFiles() {
if (!fileDsiware.files.length || !fileMovable.files.length || !fileGame.files.length
|| !fileSave.files.length || !fileCtcert.files.length)
return resolve('Not all files provided');
return reject('Not all files provided');
let promises = [];
promises.push(loadFile(fileDsiware));

View File

@ -2,7 +2,6 @@ function start() {
$('.btn-startInjection')[0].disabled = true;
document.getElementById("p-error").innerHTML = '';
loadFiles().then(data => {
if (typeof data !== 'object') return abort(data);
let dsiware = data[0];
let movable = data[1];
let game = data[2];
@ -10,13 +9,13 @@ function start() {
let ctcert = data[4];
/* Validation */
if (movable.length !== 0x140) return abort('movable.sed not valid');
if (ctcert.length !== 0x19E) return abort('ctcert.bin not valid');
if (movable.length !== 0x140 && movable.length !== 0x120) throw new Error('movable.sed size not valid');
if (ctcert.length !== 0x19E) throw new Error('ctcert.bin not valid');
let crcGame = getCrc(game);
if (!constants.hashes.all.includes(crcGame)) return abort('game_XXX.app is not valid');
if (!constants.hashes.all.includes(crcGame)) throw new Error('game_XXX.app is not valid');
let crcSave = getCrc(save);
if (!constants.hashes.all.includes(crcSave)) return abort('public_XXX.sav is not valid');
if (!constants.hashes.all.includes(crcSave)) throw new Error('public_XXX.sav is not valid');
/* Data Extraction */
let locC = constants.dataLocations.ctcert;
@ -28,7 +27,7 @@ function start() {
let movableKeyY = sliceArr(movable, locM.keyY.off, locM.keyY.len);
let normalKey = extractNormalKey(movableKeyY, constants.keys.keyX);
let dsiwareData = extractDsiware(dsiware, normalKey);
if (!dsiwareData) return abort('Wrong movable.sed provided');
if (!dsiwareData) throw new Error('DSiWare.bin can not be decrypted with the provided movable.sed');
/* msed_data extraction */
let msedDataHex = extractMsedData(movable);
@ -36,7 +35,7 @@ function start() {
/* app replacing */
let srl = dsiwareData.other['srl.nds'];
if (game.length > srl.length) return abort('Game not compatible');
if (game.length > srl.length) throw new Error('Game not compatible');
let end = sliceArr(srl, game.length, srl.length - game.length);
let newApp = new Uint8Array(game.length + end.length);
newApp.set(game);
@ -44,7 +43,7 @@ function start() {
/* sav replacing */
let sav = dsiwareData.other['public.sav'];
if (save.length > sav.length) return abort('Save not compatible with this game');
if (save.length > sav.length) throw new Error('Save not compatible with this game');
end = sliceArr(sav, save.length, sav.length - save.length);
let newSav = new Uint8Array(save.length + end.length);
newSav.set(save);
@ -67,28 +66,35 @@ function start() {
msedDataHex: msedDataHex,
movableCrc: movableCrc,
};
$.post('https://tsign.jisagi.net/sign', body, data => {
data = JSON.parse(data);
if (data.error) return abort(`Signature Error: ${data.error}`);
let { sigHashesBlock, sigApcert } = JSON.parse(data.response);
sigHashesBlock = parseHexString(sigHashesBlock);
sigApcert = parseHexString(sigApcert);
dsiwareData.dsiwareLength = dsiware.length;
dsiwareData.keys = {
movableKeyY: movableKeyY,
normalKey: normalKey,
};
/* inject signatures */
dsiwareData = injectSignatures(dsiwareData, sigHashesBlock, sigApcert);
/* Signing */
return signData(body, dsiwareData);
}).then(sigData => {
let { sigHashesBlock, sigApcert } = sigData.signatures;
let dsiwareData = sigData.dsiwareData;
/* rebuild dsiware */
dsiwareData.keys = { movableKeyY: movableKeyY, normalKey: normalKey };
let dsiwareFinal = buildDsiware(dsiwareData, dsiware.length);
sigHashesBlock = parseHexString(sigHashesBlock);
sigApcert = parseHexString(sigApcert);
/* offer file to download */
download(dsiwareFinal);
/* inject signatures */
dsiwareData = injectSignatures(dsiwareData, sigHashesBlock, sigApcert);
/* End */
console.log('Done');
}).always(() => {
$('.btn-startInjection')[0].disabled = false;
});
/* rebuild dsiware */
let dsiwareFinal = buildDsiware(dsiwareData, dsiwareData.dsiwareLength);
/* offer file to download */
download(dsiwareFinal);
/* End */
console.log('Done');
$('.btn-startInjection')[0].disabled = false;
}).catch(error => {
abort(error.message || error);
});
}

View File

@ -0,0 +1,11 @@
function signData(postBody, dsiwareData) {
return new Promise((resolve, reject) => {
$.post('https://tsign.jisagi.net/sign', postBody, response => {
let data = JSON.parse(response);
if (data.error) return reject(`Signing Error: ${data.error}`);
resolve({ signatures: JSON.parse(data.response), dsiwareData: dsiwareData });
}).fail(() => {
reject('Couldn\'t connect to the signing server. Please check your internet connection or try again later');
});
});
}

View File

@ -38,3 +38,47 @@ function insertIntoArray(originalArr, toInsert, offset) {
orig.splice(offset, insert.length, ...insert);
return new Uint8Array(orig);
}
function checkBrowserVersion() {
try {
let browser = {
all: ['chrome', 'firefox', 'opera', 'edge', 'safari'],
good: { chrome: 60, firefox: 50 },
maybe: { opera: 45, edge: 15, safari: 10 },
};
let version = getBrowserVersion();
if (version.length !== 2) throw new Error('Failed to identify browser!');
$('.p-browser-version').text((version.join(' ').replace('MSIE', 'Internet Explorer')));
if (!browser.all.includes(version[0].toLowerCase())) throw new Error('Browser unsupported!');
let reqBrowser = version[0].toLowerCase();
let reqVersion = version[1];
let b = browser.good[reqBrowser] || browser.maybe[reqBrowser];
if (b > reqVersion) throw new Error('Browser version too old, please update!');
// some bugged browsers have 3+ version digits so anything >100 should be fine to filter
if (reqVersion > 100) throw new Error('Browser version unsupported!');
$('.p-browser-version').css('color', 'green');
} catch (e) {
$('.p-browser-error').text(e.message || 'Unknown Error');
$('.p-browser-error').css('color', 'red');
$('.p-browser-version').css('color', 'red');
}
}
function getBrowserVersion() {
let ua = navigator.userAgent;
let tem;
let M = ua.match(/(opera|chrome|safari|firefox|msie|trident(?=\/))\/?\s*(\d+)/i) || [];
if (/trident/i.test(M[1])) {
tem = /\brv[ :]+(\d+)/g.exec(ua) || [];
return 'IE ' + (tem[1] || '');
}
if (M[1] === 'Chrome') {
tem = ua.match(/\b(OPR|Edge)\/(\d+)/);
if (tem != null) return tem.slice(1).join(' ').replace('OPR', 'Opera');
}
M = M[2] ? [M[1], M[2]] : [navigator.appName, navigator.appVersion, '-?'];
if ((tem = ua.match(/version\/(\d+)/i)) != null) M.splice(1, 1, tem[1]);
return M;
}