next version

- switch to uvu
- switch to ESM
- still broken
need to fix
This commit is contained in:
Nemo 2022-04-17 20:14:32 +05:30
parent 65049c9ed2
commit 2833c36bf1
16 changed files with 647 additions and 345 deletions

29
elftest.js Normal file
View File

@ -0,0 +1,29 @@
const E = require('elfinfo')
const fs = require('fs')
// Parse the specified ELF file.
const path ='../aur-notable/notable'
const elfdata = fs.readFileSync(path);
let info = null
E.open(elfdata).then((info)=>{
let rodata = info.elf.sections.filter((x)=>{return x.name=='.rodata'})[0]
const data = fs.createReadStream(path, {
start: Number(rodata.addr),
end: Number(rodata.addr) + rodata.size,
highWaterMark: rodata.addralign
})
data.on('data', function(data){
let found = data.toString().match(/Electron\/(\d+\.\d+\.\d+)/)
if(found) {
console.log(found[1])
}
});
})

175
package-lock.json generated
View File

@ -10,7 +10,9 @@
"license": "MIT",
"dependencies": {
"7zip-bin": "^5.1.1",
"disassembler": "^0.3.0-beta",
"electron-fingerprints": "*",
"elfinfo": "^0.3.0-beta",
"hasha": "^5.2.2",
"is-valid-http-url": "^1.0.3",
"node-7z": "^3.0.0",
@ -23,7 +25,11 @@
"which-electron": "src/index.js"
},
"devDependencies": {
"kuta": "*"
"kuta": "*",
"uvu": "^0.5.3"
},
"engines": {
"node": " >=14.13.1 || >=16.0.0"
}
},
"node_modules/7zip-bin": {
@ -110,11 +116,50 @@
}
}
},
"node_modules/dequal": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.2.tgz",
"integrity": "sha512-q9K8BlJVxK7hQYqa6XISGmBZbtQQWVXSrRrWreHC94rMt1QL/Impruc+7p2CYSYuVIUr+YCt6hjrs1kkdJRTug==",
"dev": true,
"engines": {
"node": ">=6"
}
},
"node_modules/diff": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz",
"integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==",
"dev": true,
"engines": {
"node": ">=0.3.1"
}
},
"node_modules/disassembler": {
"version": "0.3.0-beta",
"resolved": "https://registry.npmjs.org/disassembler/-/disassembler-0.3.0-beta.tgz",
"integrity": "sha512-mcuYZPmWOhv0S28ou9qYfWswXEJ+5oKUh8GVheLTRcqiMeQisQRDfsAdh80WByB144gT6FLjSFwVBRYX+wMIAw=="
},
"node_modules/electron-fingerprints": {
"version": "2022.3.30",
"resolved": "https://registry.npmjs.org/electron-fingerprints/-/electron-fingerprints-2022.3.30.tgz",
"integrity": "sha512-RciBhcnMYqNFqeibbKICOqTsCPPFgU+I2KQp3wt77Xw+3YOE3FOPD1XkE/u5k8B/c9tilJ78uowJjElnaRUtHA=="
},
"node_modules/elfinfo": {
"version": "0.3.0-beta",
"resolved": "https://registry.npmjs.org/elfinfo/-/elfinfo-0.3.0-beta.tgz",
"integrity": "sha512-pmKnUCHGTkloCxKMoP3GL6j0IzH2MC30STKhv+GJA4uGw1Zv9dfZ3OQQjXF30IHKQlPVW3eECRWCuPJtHqkCIQ==",
"bin": {
"elfinfo": "dist/src/elfinfo.js"
},
"peerDependencies": {
"disassembler": "^0.3.0-beta"
},
"peerDependenciesMeta": {
"disassembler": {
"optional": true
}
}
},
"node_modules/follow-redirects": {
"version": "1.14.9",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.9.tgz",
@ -174,9 +219,9 @@
}
},
"node_modules/https-proxy-agent": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz",
"integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==",
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz",
"integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==",
"dependencies": {
"agent-base": "6",
"debug": "4"
@ -223,6 +268,15 @@
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
"integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA="
},
"node_modules/kleur": {
"version": "4.1.4",
"resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.4.tgz",
"integrity": "sha512-8QADVssbrFjivHWQU7KkMgptGTl6WAcSdlbBPY4uNF+mWr6DGcKrvY2w4FQJoXch7+fKMjj0dRrL75vk3k23OA==",
"dev": true,
"engines": {
"node": ">=6"
}
},
"node_modules/kuta": {
"version": "2.0.0-beta.7",
"resolved": "https://registry.npmjs.org/kuta/-/kuta-2.0.0-beta.7.tgz",
@ -321,6 +375,15 @@
"integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==",
"dev": true
},
"node_modules/mri": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz",
"integrity": "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==",
"dev": true,
"engines": {
"node": ">=4"
}
},
"node_modules/ms": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
@ -426,6 +489,18 @@
"url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/sade": {
"version": "1.8.1",
"resolved": "https://registry.npmjs.org/sade/-/sade-1.8.1.tgz",
"integrity": "sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==",
"dev": true,
"dependencies": {
"mri": "^1.1.0"
},
"engines": {
"node": ">=6"
}
},
"node_modules/sanitize-filename": {
"version": "1.6.3",
"resolved": "https://registry.npmjs.org/sanitize-filename/-/sanitize-filename-1.6.3.tgz",
@ -435,9 +510,9 @@
}
},
"node_modules/semver": {
"version": "7.3.5",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz",
"integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==",
"version": "7.3.7",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz",
"integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==",
"dependencies": {
"lru-cache": "^6.0.0"
},
@ -475,6 +550,24 @@
"resolved": "https://registry.npmjs.org/utf8-byte-length/-/utf8-byte-length-1.0.4.tgz",
"integrity": "sha1-9F8VDExm7uloGGUFq5P8u4rWv2E="
},
"node_modules/uvu": {
"version": "0.5.3",
"resolved": "https://registry.npmjs.org/uvu/-/uvu-0.5.3.tgz",
"integrity": "sha512-brFwqA3FXzilmtnIyJ+CxdkInkY/i4ErvP7uV0DnUVxQcQ55reuHphorpF+tZoVHK2MniZ/VJzI7zJQoc9T9Yw==",
"dev": true,
"dependencies": {
"dequal": "^2.0.0",
"diff": "^5.0.0",
"kleur": "^4.0.3",
"sade": "^1.7.3"
},
"bin": {
"uvu": "bin.js"
},
"engines": {
"node": ">=8"
}
},
"node_modules/which": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
@ -562,11 +655,34 @@
"ms": "2.1.2"
}
},
"dequal": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.2.tgz",
"integrity": "sha512-q9K8BlJVxK7hQYqa6XISGmBZbtQQWVXSrRrWreHC94rMt1QL/Impruc+7p2CYSYuVIUr+YCt6hjrs1kkdJRTug==",
"dev": true
},
"diff": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz",
"integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==",
"dev": true
},
"disassembler": {
"version": "0.3.0-beta",
"resolved": "https://registry.npmjs.org/disassembler/-/disassembler-0.3.0-beta.tgz",
"integrity": "sha512-mcuYZPmWOhv0S28ou9qYfWswXEJ+5oKUh8GVheLTRcqiMeQisQRDfsAdh80WByB144gT6FLjSFwVBRYX+wMIAw=="
},
"electron-fingerprints": {
"version": "2022.3.30",
"resolved": "https://registry.npmjs.org/electron-fingerprints/-/electron-fingerprints-2022.3.30.tgz",
"integrity": "sha512-RciBhcnMYqNFqeibbKICOqTsCPPFgU+I2KQp3wt77Xw+3YOE3FOPD1XkE/u5k8B/c9tilJ78uowJjElnaRUtHA=="
},
"elfinfo": {
"version": "0.3.0-beta",
"resolved": "https://registry.npmjs.org/elfinfo/-/elfinfo-0.3.0-beta.tgz",
"integrity": "sha512-pmKnUCHGTkloCxKMoP3GL6j0IzH2MC30STKhv+GJA4uGw1Zv9dfZ3OQQjXF30IHKQlPVW3eECRWCuPJtHqkCIQ==",
"requires": {}
},
"follow-redirects": {
"version": "1.14.9",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.9.tgz",
@ -600,9 +716,9 @@
}
},
"https-proxy-agent": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz",
"integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==",
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz",
"integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==",
"requires": {
"agent-base": "6",
"debug": "4"
@ -637,6 +753,12 @@
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
"integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA="
},
"kleur": {
"version": "4.1.4",
"resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.4.tgz",
"integrity": "sha512-8QADVssbrFjivHWQU7KkMgptGTl6WAcSdlbBPY4uNF+mWr6DGcKrvY2w4FQJoXch7+fKMjj0dRrL75vk3k23OA==",
"dev": true
},
"kuta": {
"version": "2.0.0-beta.7",
"resolved": "https://registry.npmjs.org/kuta/-/kuta-2.0.0-beta.7.tgz",
@ -717,6 +839,12 @@
"integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==",
"dev": true
},
"mri": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz",
"integrity": "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==",
"dev": true
},
"ms": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
@ -798,6 +926,15 @@
"glob": "^7.1.3"
}
},
"sade": {
"version": "1.8.1",
"resolved": "https://registry.npmjs.org/sade/-/sade-1.8.1.tgz",
"integrity": "sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==",
"dev": true,
"requires": {
"mri": "^1.1.0"
}
},
"sanitize-filename": {
"version": "1.6.3",
"resolved": "https://registry.npmjs.org/sanitize-filename/-/sanitize-filename-1.6.3.tgz",
@ -807,9 +944,9 @@
}
},
"semver": {
"version": "7.3.5",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz",
"integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==",
"version": "7.3.7",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz",
"integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==",
"requires": {
"lru-cache": "^6.0.0"
}
@ -838,6 +975,18 @@
"resolved": "https://registry.npmjs.org/utf8-byte-length/-/utf8-byte-length-1.0.4.tgz",
"integrity": "sha1-9F8VDExm7uloGGUFq5P8u4rWv2E="
},
"uvu": {
"version": "0.5.3",
"resolved": "https://registry.npmjs.org/uvu/-/uvu-0.5.3.tgz",
"integrity": "sha512-brFwqA3FXzilmtnIyJ+CxdkInkY/i4ErvP7uV0DnUVxQcQ55reuHphorpF+tZoVHK2MniZ/VJzI7zJQoc9T9Yw==",
"dev": true,
"requires": {
"dequal": "^2.0.0",
"diff": "^5.0.0",
"kleur": "^4.0.3",
"sade": "^1.7.3"
}
},
"which": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",

View File

@ -2,18 +2,21 @@
"name": "which-electron",
"version": "1.1.5",
"description": "Guess which electron version is bundled in an application",
"main": "src/index.js",
"bin": {
"which-electron": "src/index.js"
},
"scripts": {
"test": "kuta tests/*.js",
"test": "uvu tests",
"release": "npm update && php _scripts/gen_versions.php && git add src/versions.json package-lock.json && git commit -m 'new release' && npm version patch"
},
"type": "module",
"repository": {
"type": "git",
"url": "git+https://github.com/captn3m0/which-electron.git"
},
"engines": {
"node": " >=14.13.1 || >=16.0.0"
},
"keywords": [
"find",
"electron",
@ -29,7 +32,9 @@
"homepage": "https://github.com/captn3m0/which-electron#readme",
"dependencies": {
"7zip-bin": "^5.1.1",
"disassembler": "^0.3.0-beta",
"electron-fingerprints": "*",
"elfinfo": "^0.3.0-beta",
"hasha": "^5.2.2",
"is-valid-http-url": "^1.0.3",
"node-7z": "^3.0.0",
@ -38,7 +43,9 @@
"semver": "^7.3.5",
"which": "^2.0.2"
},
"exports": "./src/index.js",
"devDependencies": {
"kuta": "*"
"kuta": "*",
"uvu": "^0.5.3"
}
}

View File

@ -1,50 +1,50 @@
const Seven = require("node-7z");
const which = require('which');
const path = require("path");
const fs = require("fs");
import { list, extract } from "node-7z";
import which from "which";
import path from "path";
import fs from "fs";
let sevenBin = null;
try {
sevenBin = which.sync('7z')
} catch(e) {
sevenBin = require('7zip-bin').path7za
console.error("Couldn't find 7-zip installed. Using the 7zip-bin package, which uses an older version of 7-zip. Not all files may work properly.")
sevenBin = which.sync("7z");
} catch (e) {
import { path7za } from "7zip-bin";
console.error(
"Couldn't find 7-zip installed. Using the 7zip-bin package, which uses an older version of 7-zip. Not all files may work properly."
);
}
module.exports = {
readFileContents: function(archive, filepath, dir, cb) {
let stream = Seven.extract(archive, dir, {
recursive: true,
$cherryPick: filepath,
$bin: sevenBin
});
let fn = path.basename(filepath);
stream.on("end", ()=>{
cb(fs.readFileSync(`${dir}/${fn}`, {encoding: 'utf8'}))
});
},
extractSomeFiles: function(archive, list, dir, cb) {
let stream = Seven.extract(archive, dir, {
$cherryPick: list,
$bin: sevenBin
})
stream.on('end', ()=>{
cb()
})
},
listFileContents: function(archive, cb) {
let zip = Seven.list(archive, {
$bin: sevenBin,
alternateStreamExtract: true,
alternateStreamReplace: true,
});
let entries = [];
zip.on("data", (data) => {
entries.push(data);
});
zip.on("end", () => {
cb(entries);
});
},
};
export function readFileContents(archive, filepath, dir, cb) {
let stream = extract(archive, dir, {
recursive: true,
$cherryPick: filepath,
$bin: sevenBin,
});
let fn = path.basename(filepath);
stream.on("end", () => {
cb(fs.readFileSync(`${dir}/${fn}`, { encoding: "utf8" }));
});
}
export function extractSomeFiles(archive, list, dir, cb) {
let stream = extract(archive, dir, {
$cherryPick: list,
$bin: sevenBin,
});
stream.on("end", () => {
cb();
});
}
export function listFileContents(archive, cb) {
let zip = list(archive, {
$bin: sevenBin,
alternateStreamExtract: true,
alternateStreamReplace: true,
});
let entries = [];
zip.on("data", (data) => {
entries.push(data);
});
zip.on("end", () => {
cb(entries);
});
}

35
src/elf.js Normal file
View File

@ -0,0 +1,35 @@
import elfinfo from "elfinfo";
import fs from "fs";
// Parse the specified ELF file.
export function getVersion(path, cb) {
const elfdata = fs.readFileSync(path);
let info = null;
elfinfo.open(elfdata).then((info) => {
let rodata = info.elf.sections.filter((x) => {
return x.name == ".rodata";
})[0];
const data = fs.createReadStream(path, {
start: Number(rodata.addr),
end: Number(rodata.addr) + rodata.size,
highWaterMark: rodata.addralign,
});
let ret = false;
data.on("data", function (data) {
let found = data.toString().match(/Electron\/(\d+\.\d+\.\d+)/);
if (found) {
ret = true;
cb(found[1]);
}
});
data.on("end", function (e) {
if (!ret) {
cb(false);
}
});
});
}

View File

@ -1,56 +1,62 @@
// finds specific files from a list
const path = require("path");
const isDirectory = require('./utils').isDirectory;
import path from "path";
import { isDirectory } from "./utils.js";
module.exports = {
// Finds the electron asar file, if we can
asar: function(entries) {
return entries
.filter((e) => {
return (
isDirectory(e.attributes) == false &&
path.basename(e.file) == "electron.asar"
);
})
.map((e) => e.file);
},
binary: function(entries) {
entries = entries.sort((a, b) => b.size - a.size);
for (const entry of entries) {
if (isDirectory(entry.attributes)) {
continue;
}
let ext = path.extname(entry.file);
let size = entry.size;
// Return the first exe file
if (ext == ".exe") {
return entry.file;
} else if (ext == "") {
// or the largest file with no extension
return entry.file;
}
// Finds the electron asar file, if we can
export function asar(entries) {
return entries
.filter((e) => {
return (
isDirectory(e.attributes) == false &&
path.basename(e.file) == "electron.asar"
);
})
.map((e) => e.file);
}
export function binaries(entries) {
entries = entries.sort((a, b) => b.size - a.size);
for (const entry of entries) {
if (isDirectory(entry.attributes)) {
continue;
}
},
let ext = path.extname(entry.file);
let size = entry.size;
// Return the first exe file
if (ext == ".exe") {
return [entry.file];
} else if (ext == "") {
// or the largest file with no extension
return [entry.file];
}
}
}
version: function(entries) {
return entries
.filter((e) => {
return isDirectory(e.attributes) == false && path.basename(e.file) == "version";
})
.map((e) => e.file);
},
export function version(entries) {
return entries
.filter((e) => {
return (
isDirectory(e.attributes) == false && path.basename(e.file) == "version"
);
})
.map((e) => e.file);
}
findElectronPackageInsideNodeModules: function(entries) {
return entries
.filter((e) => {
return isDirectory(e.attributes) == false && e.file.match(/node_modules\/electron\/package\.json$/);
})
.map((e) => e.file);
},
export function findElectronPackageInsideNodeModules(entries) {
return entries
.filter((e) => {
return (
isDirectory(e.attributes) == false &&
e.file.match(/node_modules\/electron\/package\.json$/)
);
})
.map((e) => e.file);
}
// Return a list of files that might be worth fingerprinting
fingerprintable: function(entries) {
return entries.filter((e) =>{
// Return a list of files that might be worth fingerprinting
export function fingerprintable(entries) {
return entries
.filter((e) => {
if (isDirectory(e.attributes)) {
return false;
}
@ -58,17 +64,29 @@ module.exports = {
return false;
}
let ext = path.extname(e.file);
if (['.h', '.dll', '.bin', '.asar', '.dylib', '.so', '.exe'].indexOf(ext) !== -1) {
return true
if (
[".h", ".dll", ".bin", ".asar", ".dylib", ".so", ".exe"].indexOf(
ext
) !== -1
) {
return true;
}
let b = path.basename(e.file);
if (['electron framework', 'squirrel', 'electron', 'electron helper', 'chrome_100_percent', 'chrome_200_percent'].indexOf(b)!== -1) {
if (
[
"electron framework",
"squirrel",
"electron",
"electron helper",
"chrome_100_percent",
"chrome_200_percent",
].indexOf(b) !== -1
) {
return true;
}
return false;
})
.map((e)=>e.file)
}
};
.map((e) => e.file);
}

View File

@ -1,54 +1,52 @@
const DB = require("electron-fingerprints");
const fs = require("fs");
const hasha = require("hasha");
const allVersions = require("./versions")["all"];
import DB from "electron-fingerprints";
import fs from "fs";
import hasha from "hasha";
import crypto from "crypto";
import V from "./versions.json" assert { type: "json" };
const allVersions = V["all"];
function checksumFile(algorithm, path) {
return new Promise(function(resolve, reject) {
let fs = require("fs");
let crypto = require("crypto");
return new Promise(function (resolve, reject) {
let hash = crypto.createHash(algorithm).setEncoding("hex");
fs.createReadStream(path)
.once("error", reject)
.pipe(hash)
.once("finish", function() {
.once("finish", function () {
resolve(hash.read());
});
});
}
module.exports = {
guessFromHashes: function(os, arch, hashList) {
let lookupTable = DB[`${os}-${arch}`];
let allPossibleHashes = Object.keys(lookupTable);
const intersectingHashes = allPossibleHashes.filter((value) =>
hashList.includes(value)
);
// Set it to the starting list of versions.
let possibleVersions = allVersions;
for (i in hashList) {
let hash = hashList[i];
let versions = lookupTable[hash];
if (versions) {
possibleVersions = possibleVersions.filter((value) =>
versions.includes(value)
);
}
export function guessFromHashes(os, arch, hashList) {
let lookupTable = DB[`${os}-${arch}`];
let allPossibleHashes = Object.keys(lookupTable);
const intersectingHashes = allPossibleHashes.filter((value) =>
hashList.includes(value)
);
// Set it to the starting list of versions.
let possibleVersions = allVersions;
for (i in hashList) {
let hash = hashList[i];
let versions = lookupTable[hash];
if (versions) {
possibleVersions = possibleVersions.filter((value) =>
versions.includes(value)
);
}
}
if (possibleVersions == allVersions) {
return [];
} else {
return possibleVersions;
}
},
if (possibleVersions == allVersions) {
return [];
} else {
return possibleVersions;
}
}
getHashes: function(dir) {
let list = fs.readdirSync(dir);
return list.map((f) => {
let fn = `${dir}/${f}`;
return hasha.fromFileSync(fn, { algorithm: "sha1" });
});
},
};
export function getHashes(dir) {
let list = fs.readdirSync(dir);
return list.map((f) => {
let fn = `${dir}/${f}`;
return hasha.fromFileSync(fn, { algorithm: "sha1" });
});
}

View File

@ -3,54 +3,59 @@ const finder = require("./finder");
const archive = require("./archive");
const fp = require("./fingerprint");
const V = require("./version");
const elf = require("./elf");
const magic = require("file-identity");
const isUrl = require("is-valid-http-url");
const cleanup = require("rimraf");
const dl = require('nodejs-file-downloader')
const dl = require("nodejs-file-downloader");
const path = require("path");
const fs = require('fs');
const os = require('os');
const process = require('process');
const TMPDIR = path.join(os.tmpdir(), 'which-electron')
const fs = require("fs");
const os = require("os");
const process = require("process");
const TMPDIR = path.join(os.tmpdir(), "which-electron");
// Input file comes from process.argv[2]
let FILENAME = process.argv[2];
if (!FILENAME) {
console.error("Please pass a valid URL or file as the first argument");
process.exit(1)
process.exit(1);
}
if(isUrl(FILENAME)) {
if (isUrl(FILENAME)) {
let url = FILENAME;
// Download to temporary directory
let tmpdir = fs.mkdtempSync(TMPDIR);
let fn = `${tmpdir}/${path.basename(url)}`;
const downloader = new dl({
url: url,
directory: tmpdir,//This folder will be created, if it doesn't exist.
})
downloader.download().then(()=> {
console.log(`Downloaded ${url}`)
validateFile(fn)
}).catch((e)=> {
console.error(`Error while downloading ${url}`)
console.error(e)
process.exit(1)
})
directory: tmpdir, //This folder will be created, if it doesn't exist.
});
downloader
.download()
.then(() => {
console.log(`Downloaded ${url}`);
validateFile(fn);
})
.catch((e) => {
console.error(`Error while downloading ${url}`);
console.error(e);
process.exit(1);
});
} else {
validateFile(FILENAME)
validateFile(FILENAME);
}
function validateFile(fn) {
fs.access(fn, fs.constants.R_OK, (err) => {
if (err) {
console.error(`${fn} not readable`)
console.error(`${fn} not readable`);
process.exit(1);
} else {
console.log(fn);
whichElectron(fn)
whichElectron(fn);
}
});
}
@ -63,47 +68,63 @@ function logSupport(version) {
}
}
let whichElectron = function(filename) {
let whichElectron = function (filename) {
archive.listFileContents(filename, (entries) => {
let osguess1 = osguess.guessFromFilename(filename);
let osguess2 = osguess.guessFromContents(entries);
if (osguess1 !== osguess2 && osguess1 && osguess2) {
console.log(`Unsure about operating system. Going with ${osguess2}. Other option was ${osguess1}`);
console.log(
`Unsure about operating system. Going with ${osguess2}. Other option was ${osguess1}`
);
}
if (osguess1 && !osguess2) {
osguess2 = osguess1
osguess2 = osguess1;
}
let arch = osguess.guessArch(filename, entries);
let asar = finder.asar(entries);
let binary = finder.binary(entries);
let binaries = finder.binaries(entries);
let versionFiles = finder.version(entries);
let enm = finder.findElectronPackageInsideNodeModules(entries);
let filesToHash = finder.fingerprintable(entries);
archive.extractSomeFiles(filename, filesToHash, TMPDIR, () => {
hashes = fp.getHashes(TMPDIR);
guesses = fp.guessFromHashes(osguess2, arch, hashes);
if (guesses.length == 1) {
console.log("Fingerprint: " + guesses[0]);
logSupport(guesses[0])
} else if (guesses.length > 1) {
console.log("Fingerprint: " + V.asText(guesses));
logSupport(V.max(guesses))
archive.extractSomeFiles(
filename,
filesToHash.concat(binaries),
TMPDIR,
() => {
hashes = fp.getHashes(TMPDIR);
guesses = fp.guessFromHashes(osguess2, arch, hashes);
if (guesses.length == 1) {
console.log("Fingerprint: " + guesses[0]);
logSupport(guesses[0]);
} else if (guesses.length > 1) {
console.log("Fingerprint: " + V.asText(guesses));
logSupport(V.max(guesses));
}
if (binaries.length > 0) {
for (i in binaries) {
let binary = binaries[i];
let type = magic.fromFile(`${TMPDIR}/${binary}`);
if (type) {
console.log(type);
} else {
console.log(fs.existsSync(`${TMPDIR}/${binary}`));
}
}
}
cleanup.sync(TMPDIR);
}
);
cleanup.sync(TMPDIR);
});
// if (binary) {
// console.log(`${process.argv[2]}:${binary}`);
// }
if (versionFiles.length > 0) {
versionFiles.map((f) => {
archive.readFileContents(filename, f, TMPDIR, (c) => {
console.log("Found Version file: " + c);
logSupport(`${c}`)
logSupport(`${c}`);
});
});
}
@ -120,7 +141,7 @@ let whichElectron = function(filename) {
console.log(
"Found version in package.json file: " + packageData["version"]
);
logSupport(`v${packageData["version"]}`)
logSupport(`v${packageData["version"]}`);
} catch (e) {
// TODO: Do something
}
@ -128,6 +149,4 @@ let whichElectron = function(filename) {
});
}
});
}
};

View File

@ -1,43 +1,44 @@
// Guess the OS
import path from 'path'
const path = require('path')
module.exports = {
guessFromFilename(inputFile) {
let fn = path.basename(inputFile)
if (fn.match(/linux/)) {
return 'linux'
} else if (fn.match(/mac/)) {
return 'darwin'
} else if (fn.match(/darwin/)) {
return 'darwin'
} else if (fn.match(/win/)) {
return 'win32'
} else {
let ext = path.extname(inputFile).toLowerCase()
if (ext == '.dmg') {return 'darwin'}
if (ext == '.exe') {return 'win32'}
if (['.deb', '.appimage', '.pacman'].indexOf(ext) !== -1) {
return 'linux'
}
}
return null;
},
guessArch(filename, entries) {
return 'x64';
},
guessFromContents(entries) {
for (i in entries) {
let entry = entries[i]
if (path.extname(entry.file) == ".so") {
return 'linux'
} else if (path.extname(entry.file) == '.dll') {
return 'win32'
} else if (path.extname(entry.file) == '.dylib') {
return 'darwin'
} else if (path.extname(entry.file) == '.plist') {
return 'darwin'
}
}
}
export function guessFromFilename(inputFile) {
let fn = path.basename(inputFile);
if (fn.match(/linux/)) {
return "linux";
} else if (fn.match(/mac/)) {
return "darwin";
} else if (fn.match(/darwin/)) {
return "darwin";
} else if (fn.match(/win/)) {
return "win32";
} else {
let ext = path.extname(inputFile).toLowerCase();
if (ext == ".dmg") {
return "darwin";
}
if (ext == ".exe") {
return "win32";
}
if ([".deb", ".appimage", ".pacman"].indexOf(ext) !== -1) {
return "linux";
}
}
return null;
}
export function guessArch(filename, entries) {
return "x64";
}
export function guessFromContents(entries) {
for (let i in entries) {
let entry = entries[i];
if (path.extname(entry.file) == ".so") {
return "linux";
} else if (path.extname(entry.file) == ".dll") {
return "win32";
} else if (path.extname(entry.file) == ".dylib") {
return "darwin";
} else if (path.extname(entry.file) == ".plist") {
return "darwin";
}
}
}

View File

@ -1,5 +1,3 @@
module.exports = {
isDirectory: function(a) {
return (a? a[0] == "D" : null)
},
};
export function isDirectory(a) {
return a ? a[0] == "D" : null;
}

View File

@ -1,18 +1,15 @@
const semver = require("semver");
const VERSIONS = require("./versions");
import semver from "semver";
import VERSIONS from "./versions.json" assert { type: "json" };
module.exports = {
asText: function (listOfVersions) {
sorted = listOfVersions.sort(semver.compare);
return `${sorted[0]}-${sorted[sorted.length - 1]}`;
},
export function asText(listOfVersions) {
sorted = listOfVersions.sort(semver.compare);
return `${sorted[0]}-${sorted[sorted.length - 1]}`;
}
max: function (listOfVersions) {
sorted = listOfVersions.sort(semver.compare);
return sorted[sorted.length - 1];
},
isSupported: function (v) {
return VERSIONS["supported"].indexOf(v) !== -1;
},
};
export function max(listOfVersions) {
sorted = listOfVersions.sort(semver.compare);
return sorted[sorted.length - 1];
}
export function isSupported(v) {
return VERSIONS["supported"].indexOf(v) !== -1;
}

View File

@ -1,9 +1,9 @@
{
"supported": [
"v15.5.0",
"v16.2.0",
"v17.3.0",
"v18.0.0"
"v15.5.2",
"v16.2.2",
"v17.4.0",
"v18.0.4"
],
"all": [
"v0.24.0",
@ -495,6 +495,7 @@
"v14.2.6",
"v14.2.7",
"v14.2.8",
"v14.2.9",
"v15.0.0",
"v15.1.0",
"v15.1.1",
@ -512,6 +513,8 @@
"v15.4.1",
"v15.4.2",
"v15.5.0",
"v15.5.1",
"v15.5.2",
"v16.0.0",
"v16.0.1",
"v16.0.2",
@ -526,6 +529,8 @@
"v16.1.0",
"v16.1.1",
"v16.2.0",
"v16.2.1",
"v16.2.2",
"v17.0.0",
"v17.0.1",
"v17.1.0",
@ -533,6 +538,12 @@
"v17.1.2",
"v17.2.0",
"v17.3.0",
"v18.0.0"
"v17.3.1",
"v17.4.0",
"v18.0.0",
"v18.0.1",
"v18.0.2",
"v18.0.3",
"v18.0.4"
]
}

View File

@ -1,50 +1,50 @@
const test = require("kuta").test;
const finder = require("../src/finder");
const assert = require("assert");
const _ = require("./utils");
import * as finder from "../src/finder.js";
import { test } from "uvu";
import * as assert from "uvu/assert";
import { getEntries } from "./utils.js";
test("it should find the electron.asar file", () => {
assert.deepEqual(
assert.equal(
["Hyper.app/Contents/Resources/electron.asar"],
finder.asar(_.getEntries("Hyper-3.0.2-mac.zip"))
finder.asar(getEntries("Hyper-3.0.2-mac.zip"))
);
});
test("it should find the correct binary file", () => {
assert.deepEqual(
assert.equal(
"Hyper.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Electron Framework",
finder.binary(_.getEntries("Hyper-3.0.2-mac.zip"))
finder.binary(getEntries("Hyper-3.0.2-mac.zip"))
);
assert.deepEqual(
assert.equal(
"Notable.exe",
finder.binary(_.getEntries("Notable-1.8.4-win.zip"))
finder.binary(getEntries("Notable-1.8.4-win.zip"))
);
assert.deepEqual(
assert.equal(
"rambox",
finder.binary(_.getEntries("Rambox-0.7.7-linux-x64.zip"))
finder.binary(getEntries("Rambox-0.7.7-linux-x64.zip"))
);
});
test("it should find the version file", () => {
assert.deepEqual(
assert.equal(
["chronobreak-linux-x64/version"],
finder.version(_.getEntries("chronobreak-linux-x64.zip"))
finder.version(getEntries("chronobreak-linux-x64.zip"))
);
assert.deepEqual(
assert.equal(
["release-builds/encrypt0r-darwin-x64/version"],
finder.version(_.getEntries("encrypt0r-mac.zip"))
finder.version(getEntries("encrypt0r-mac.zip"))
);
assert.deepEqual(
assert.equal(
[
"Arizona v.1.0.0/resources/app/node_modules/electron/dist/version",
"Arizona v.1.0.0/version",
],
finder.version(_.getEntries("Arizona-v1.0.0-beta-Windows.zip"))
finder.version(getEntries("Arizona-v1.0.0-beta-Windows.zip"))
);
});
test("it should find fingerprinteable files", () => {
assert.deepEqual(
assert.equal(
[
"Arizona v.1.0.0/Arizona.exe",
"Arizona v.1.0.0/d3dcompiler_47.dll",
@ -74,9 +74,9 @@ test("it should find fingerprinteable files", () => {
"Arizona v.1.0.0/vk_swiftshader.dll",
"Arizona v.1.0.0/vulkan-1.dll",
],
finder.fingerprintable(_.getEntries("Arizona-v1.0.0-beta-Windows.zip"))
finder.fingerprintable(getEntries("Arizona-v1.0.0-beta-Windows.zip"))
);
assert.deepEqual(
assert.equal(
[
"Lax-win32-x64/v8_context_snapshot.bin",
"Lax-win32-x64/d3dcompiler_47.dll",
@ -89,10 +89,10 @@ test("it should find fingerprinteable files", () => {
"Lax-win32-x64/swiftshader/libEGL.dll",
"Lax-win32-x64/swiftshader/libGLESv2.dll",
],
finder.fingerprintable(_.getEntries("Lax-win32-x64.zip"))
finder.fingerprintable(getEntries("Lax-win32-x64.zip"))
);
assert.deepEqual(
assert.equal(
[
"resources/app.asar",
"swiftshader/libvk_swiftshader.so",
@ -105,10 +105,10 @@ test("it should find fingerprinteable files", () => {
"libEGL.so",
"natives_blob.bin",
],
finder.fingerprintable(_.getEntries("Rambox-0.7.7-linux-x64.zip"))
finder.fingerprintable(getEntries("Rambox-0.7.7-linux-x64.zip"))
);
assert.deepEqual(
assert.equal(
[
"chronobreak-linux-x64/libEGL.so",
"chronobreak-linux-x64/libffmpeg.so",
@ -121,10 +121,10 @@ test("it should find fingerprinteable files", () => {
"chronobreak-linux-x64/swiftshader/libGLESv2.so",
"chronobreak-linux-x64/v8_context_snapshot.bin",
],
finder.fingerprintable(_.getEntries("chronobreak-linux-x64.zip"))
finder.fingerprintable(getEntries("chronobreak-linux-x64.zip"))
);
assert.deepEqual(
assert.equal(
[
"Hyper.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Libraries/libnode.dylib",
"Hyper.app/Contents/Resources/app.asar",
@ -203,10 +203,10 @@ test("it should find fingerprinteable files", () => {
"Hyper.app/Contents/Frameworks/ReactiveCocoa.framework/Versions/A/Headers/RACUnit.h",
"Hyper.app/Contents/Frameworks/ReactiveCocoa.framework/Versions/A/Headers/NSFileHandle+RACSupport.h",
],
finder.fingerprintable(_.getEntries("Hyper-3.0.2-mac.zip"))
finder.fingerprintable(getEntries("Hyper-3.0.2-mac.zip"))
);
assert.deepEqual(
assert.equal(
[
"Notable.exe",
"libGLESv2.dll",
@ -220,10 +220,10 @@ test("it should find fingerprinteable files", () => {
"libEGL.dll",
"natives_blob.bin",
],
finder.fingerprintable(_.getEntries("Notable-1.8.4-win.zip"))
finder.fingerprintable(getEntries("Notable-1.8.4-win.zip"))
);
assert.deepEqual(
assert.equal(
[
"release-builds/encrypt0r-darwin-x64/encrypt0r.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Libraries/libGLESv2.dylib",
"release-builds/encrypt0r-darwin-x64/encrypt0r.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Libraries/libswiftshader_libGLESv2.dylib",
@ -247,6 +247,8 @@ test("it should find fingerprinteable files", () => {
"release-builds/encrypt0r-darwin-x64/encrypt0r.app/Contents/Frameworks/Electron Framework.framework/Libraries/libswiftshader_libEGL.dylib",
"release-builds/encrypt0r-darwin-x64/encrypt0r.app/Contents/Frameworks/Electron Framework.framework/Resources/v8_context_snapshot.x86_64.bin",
],
finder.fingerprintable(_.getEntries("encrypt0r-mac.zip"))
finder.fingerprintable(getEntries("encrypt0r-mac.zip"))
);
});
test.run();

View File

@ -1,19 +1,19 @@
const test = require("kuta").test;
const fp = require("../src/fingerprint");
const assert = require("assert");
import { test } from "uvu";
import * as assert from "uvu/assert";
import { guessFromHashes, getHashes } from "../src/fingerprint.js";
test("it should work with a single fingerprint", () => {
guess = fp.guessFromHashes("win32", "x64", [
guess = guessFromHashes("win32", "x64", [
"cbdbe566564c323032c02c1a838358a314af63b4",
]);
assert.deepEqual(guess, ["v0.24.0"]);
assert.equal(guess, ["v0.24.0"]);
});
test("it should work with a ffmpeg hash", () => {
guess = fp.guessFromHashes("win32", "x64", [
guess = guessFromHashes("win32", "x64", [
"baf786083f482c1f035e50e105b5f7475af1e00b",
]);
assert.deepEqual(guess, ["v1.4.3", "v1.4.4", "v1.4.5"]);
assert.equal(guess, ["v1.4.3", "v1.4.4", "v1.4.5"]);
});
test("it should work with multiple fingerprints", () => {
@ -22,6 +22,8 @@ test("it should work with multiple fingerprints", () => {
"944bff8704d4b152279fbdacb911b516502be056",
"3c592e2cdadbb0bcd8f522071a63da5febe9aa37",
];
guess = fp.guessFromHashes("darwin", "x64", hashes);
assert.deepEqual(guess, ["v1.7.6"]);
guess = guessFromHashes("darwin", "x64", hashes);
assert.equal(guess, ["v1.7.6"]);
});
test.run();

View File

@ -1,37 +1,75 @@
const test = require('kuta').test;
const os = require('../src/os')
const assert = require('assert')
const _ = require('./utils')
import { test } from "uvu";
import * as assert from "uvu/assert";
test('it should linux correctly from filename', ()=> {
assert.deepEqual('linux', os.guessFromFilename('kube-dev-dashboard-0.10.1-linux.zip'))
assert.deepEqual('linux', os.guessFromFilename('magiccap-linux.zip'))
assert.deepEqual('linux', os.guessFromFilename('Rambox-0.7.7-linux-ia32.zip'))
assert.deepEqual('linux', os.guessFromFilename('authme-2.6.0-linux-x64-portable.zip'))
assert.deepEqual('linux', os.guessFromFilename('mojibar-linux.zip'))
assert.deepEqual('linux', os.guessFromFilename('mojibar-linux.deb'))
assert.deepEqual('linux', os.guessFromFilename('mojibar.AppImage'))
assert.deepEqual('linux', os.guessFromFilename('mojibar.pacman'))
import { guessFromFilename, guessFromContents } from "../src/os.js";
import { getEntries } from "./utils.js";
test("it should linux correctly from filename", () => {
assert.equal(
"linux",
guessFromFilename("kube-dev-dashboard-0.10.1-linux.zip")
);
assert.equal("linux", guessFromFilename("magiccap-linux.zip"));
assert.equal("linux", guessFromFilename("Rambox-0.7.7-linux-ia32.zip"));
assert.equal(
"linux",
guessFromFilename("authme-2.6.0-linux-x64-portable.zip")
);
assert.equal("linux", guessFromFilename("mojibar-linux.zip"));
assert.equal("linux", guessFromFilename("mojibar-linux.deb"));
assert.equal("linux", guessFromFilename("mojibar.AppImage"));
assert.equal("linux", guessFromFilename("mojibar.pacman"));
});
test('it should darwin correctly from filename', ()=> {
assert.deepEqual('darwin', os.guessFromFilename('Merge-Request-Notifier-1.9.0-mac.zip'))
assert.deepEqual('darwin', os.guessFromFilename('Merge-Request-Notifier-1.9.0.dmg'))
test("it should darwin correctly from filename", () => {
assert.equal(
"darwin",
guessFromFilename("Merge-Request-Notifier-1.9.0-mac.zip")
);
assert.equal(
"darwin",
guessFromFilename("Merge-Request-Notifier-1.9.0.dmg")
);
});
test('it should windows correctly from filename', ()=> {
assert.deepEqual('win32', os.guessFromFilename('particl-desktop-2.3.6-win-ia32.zip'))
assert.deepEqual('win32', os.guessFromFilename('Multrin-1.3.0-ia32-win.zip'))
assert.deepEqual('win32', os.guessFromFilename('Multrin-1.3.0-ia32-win.exe'))
assert.deepEqual('win32', os.guessFromFilename('Assessment.Disaggregation-1.1.4.Setup.exe'))
test("it should windows correctly from filename", () => {
assert.equal(
"win32",
guessFromFilename("particl-desktop-2.3.6-win-ia32.zip")
);
assert.equal("win32", guessFromFilename("Multrin-1.3.0-ia32-win.zip"));
assert.equal("win32", guessFromFilename("Multrin-1.3.0-ia32-win.exe"));
assert.equal(
"win32",
guessFromFilename("Assessment.Disaggregation-1.1.4.Setup.exe")
);
});
test('it should guess correctly from file list', ()=> {
assert.deepEqual('win32', os.guessFromContents(_.getEntries('Arizona-v1.0.0-beta-Windows.zip')));
assert.deepEqual('win32', os.guessFromContents(_.getEntries('Notable-1.8.4-win.zip')));
assert.deepEqual('darwin', os.guessFromContents(_.getEntries('encrypt0r-mac.zip')));
assert.deepEqual('darwin', os.guessFromContents(_.getEntries('Hyper-3.0.2-mac.zip')));
assert.deepEqual('linux', os.guessFromContents(_.getEntries('chronobreak-linux-x64.zip')));
assert.deepEqual('linux', os.guessFromContents(_.getEntries('Rambox-0.7.7-linux-x64.zip')));
test("it should guess correctly from file list", () => {
assert.equal(
"win32",
guessFromContents(getEntries("Arizona-v1.0.0-beta-Windows.zip"))
);
assert.equal(
"win32",
guessFromContents(getEntries("Notable-1.8.4-win.zip"))
);
assert.equal(
"darwin",
guessFromContents(getEntries("encrypt0r-mac.zip"))
);
assert.equal(
"darwin",
guessFromContents(getEntries("Hyper-3.0.2-mac.zip"))
);
assert.equal(
"linux",
guessFromContents(getEntries("chronobreak-linux-x64.zip"))
);
assert.equal(
"linux",
guessFromContents(getEntries("Rambox-0.7.7-linux-x64.zip"))
);
});
test.run();

View File

@ -1,14 +1,12 @@
const fs = require("fs");
entries = {};
import fs from "fs";
let entries = {};
module.exports = {
getEntries: function(f) {
if (entries[f]) {
return entries[f];
} else {
return (entries[f] = JSON.parse(
fs.readFileSync(`./tests/fixtures/${f}.json`)
));
}
},
};
export function getEntries(f) {
if (entries[f]) {
return entries[f];
} else {
return (entries[f] = JSON.parse(
fs.readFileSync(`./tests/fixtures/${f}.json`)
));
}
}