TADpole-Online/public/js/custom/main.js
2018-04-01 20:47:17 +02:00

95 lines
3.5 KiB
JavaScript

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];
let save = data[3];
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');
let crcGame = getCrc(game);
if (!constants.hashes.all.includes(crcGame)) return abort('game_XXX.app is not valid');
let crcSave = getCrc(save);
if (!constants.hashes.all.includes(crcSave)) return abort('public_XXX.sav is not valid');
/* Data Extraction */
let locC = constants.dataLocations.ctcert;
let publicKeyR = sliceArr(ctcert, locC.publicKeyR.off, locC.publicKeyR.len);
let publicKeyS = sliceArr(ctcert, locC.publicKeyS.off, locC.publicKeyS.len);
let privateKey = sliceArr(ctcert, locC.privateKey.off, locC.privateKey.len);
let locM = constants.dataLocations.movable;
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');
/* msed_data extraction */
let msedDataHex = extractMsedData(movable);
let movableCrc = getCrc(movable);
/* app replacing */
let srl = dsiwareData.other['srl.nds'];
if (game.length > srl.length) return abort('Game not compatible');
let end = sliceArr(srl, game.length, srl.length - game.length);
let newApp = new Uint8Array(game.length + end.length);
newApp.set(game);
newApp.set(end, game.length);
/* sav replacing */
let sav = dsiwareData.other['public.sav'];
if (save.length > sav.length) return abort('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);
newSav.set(end, save.length);
/* update data */
dsiwareData.other['srl.nds'] = newApp;
dsiwareData.other['public.sav'] = newSav;
/* update footer hashes & add ctcert/pubkey */
dsiwareData = rebuildFooter(dsiwareData, ctcert);
/* signing */
let body = {
publicKeyR: byteArrToHexStr(publicKeyR),
publicKeyS: byteArrToHexStr(publicKeyS),
privateKey: byteArrToHexStr(privateKey),
hashesBlock: byteArrToHexStr(sha256.array(dsiwareData.hashesBlock)),
apcert: byteArrToHexStr(sha256.array(dsiwareData.apcert)),
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);
/* inject signatures */
dsiwareData = injectSignatures(dsiwareData, sigHashesBlock, sigApcert);
/* rebuild dsiware */
dsiwareData.keys = { movableKeyY: movableKeyY, normalKey: normalKey };
let dsiwareFinal = buildDsiware(dsiwareData, dsiware.length);
/* offer file to download */
download(dsiwareFinal);
/* End */
console.log('Done');
}).always(() => {
$('.btn-startInjection')[0].disabled = false;
});
});
}