Last active
August 26, 2022 12:35
-
-
Save remixer-dec/f109b10c72b2796c613b588b8a191ac9 to your computer and use it in GitHub Desktop.
Node script for hashing J2ME JAR files, excluding editable parts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// MULTI-CORE J2ME JAR HASHER | EXCLUDES EVERYTHING INSIDE MANIFEST FOLDER TO IGNORE MANIFEST-ONLY-CHANGES | (c) Remixer Dec 2019 | License: CC BY-NC 4.0 | |
// usage: node jarhasher.js "C:/path/to/folder_with_jar_files_only_with_forward_slashes" CPU_LOGICAL_CORES HASHLIMIT | |
// output: 2 files hashed.json, corrupted.json | |
// output format: [["filename","md5","sha1"],...] | |
const os = require('os') | |
const JSZip = require("jszip"); | |
const fs = require("fs") | |
const crypto = require('crypto') | |
const cluster = require('cluster'); | |
const path = require('path') | |
// configuration | |
const DIR = process.argv[2] || 'C:/Users/Admin/Downloads/J2ME' | |
const HASHLIMIT = process.argv[4] || Infinity //hash only n files in JAR instead of all of them | |
const CPUCORES = process.argv[3] || os.cpus().length / 2 //It's recommended to set PHYSICAL core count | |
function zipHash(fn){ | |
return new Promise((rs,rj)=>{ | |
fs.readFile(path.posix.join(DIR,fn),(err,f)=>{ | |
JSZip.loadAsync(f).then(function (zip) { | |
let files = Object.values(zip.files).sort((a,b)=>a.name.localeCompare(b.name)) | |
let md5 = crypto.createHash("md5"); | |
let sha = crypto.createHash("sha1"); | |
for(let i=0,l=files.length;i<l;i++){ | |
if(files[i].name.slice(0,8).toLowerCase() != 'meta-inf'){ | |
if(i==HASHLIMIT) break | |
let b = new Buffer(4) | |
b.writeInt32LE(files[i]._data.crc32) | |
md5.update(b) | |
sha.update(b) | |
} | |
} | |
let md5h = md5.digest().toString('hex') | |
let shah = sha.digest().toString('hex') | |
rs([fn,md5h,shah]) | |
}).catch(e=>{ | |
corrupted.push(fn) | |
rj() | |
}); | |
}) | |
}) | |
} | |
function arrSplit(arr,chunkSize){ | |
return new Array(Math.ceil(arr.length / chunkSize)).fill().map(_ => arr.splice(0,chunkSize)) | |
} | |
const progress = [] | |
let allData = [] | |
let corrupted = [] | |
let jobsDone = 0 | |
if (cluster.isMaster) { | |
//main process | |
let t1 = Date.now() | |
let fl = fs.readdirSync(DIR).filter(x=>x.toLowerCase().endsWith('jar')) | |
let arrs = arrSplit(fl,Math.ceil(fl.length/CPUCORES)) | |
for(let y=0;y<CPUCORES;y++){ | |
let fr = cluster.fork() | |
progress.push(0) | |
fr.on('message',(msg)=>{ | |
if('progress' in msg){ | |
progress[msg.id-1] = msg.progress | |
process.title = 'Hashing: '+progress.map(x=>x+'%').join(' | ') | |
return | |
} | |
console.log(`worker #${msg.id} is done!`) | |
allData = [].concat(allData,msg.data) | |
corrupted = [].concat(corrupted, msg.corrupted) | |
jobsDone++ | |
if(jobsDone == CPUCORES){ | |
let t2 = Date.now() | |
console.log(`job's done in ${(t2-t1)} ms, hashed ${allData.length} files, found ${corrupted.length} corrupted files`); | |
fs.writeFileSync('hashed.json',JSON.stringify(allData)) | |
fs.writeFileSync('corrupted.json',JSON.stringify(corrupted)) | |
process.exit() | |
} | |
}) | |
fr.send({files:arrs[y]}); | |
} | |
} else { | |
process.on('message', async (msg)=>{ | |
console.log(`Worker #${cluster.worker.id} started.`) | |
let results = [] | |
for(let j=0,l=msg.files.length;j<l;j++){ | |
let file = msg.files[j] | |
let hash = await zipHash(file).catch(e=>console.error(file+' failed, archive corrupted')) | |
if(hash){ | |
results.push(hash) | |
} | |
if(j % 100 == 0){ | |
process.send({progress:Math.round(j*100/l),id:cluster.worker.id}) | |
} | |
} | |
process.send({data: results,corrupted: corrupted,id:cluster.worker.id}) | |
}) | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"name": "multicore-jar-hasher", | |
"version": "1.0.1", | |
"description": "script for hashing J2ME JAR files, excluding editable parts", | |
"main": "jarhasher.js", | |
"dependencies": { | |
"jszip": "^3.2.2" | |
}, | |
"devDependencies": {}, | |
"scripts": { | |
"test": "echo \"Error: no test specified\" && exit 1" | |
}, | |
"author": "Remixer Dec", | |
"license": "MIT" | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment