diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..6e67130 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,12 @@ +root = true + +[*] +indent_style = space +indent_size = 2 +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true + +[*.php] +indent_size = 4 diff --git a/.github/workflows/action.yml b/.github/workflows/action.yml new file mode 100644 index 0000000..0a3c917 --- /dev/null +++ b/.github/workflows/action.yml @@ -0,0 +1,16 @@ +on: push +name: Main Workflow +jobs: + tests: + strategy: + matrix: + node: ['16', '14', '12'] + name: Run NPM Stuff + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v1 + - uses: actions/setup-node@v2 + with: + node-version: ${{matrix.node}} + - run: npm install + - run: npm test diff --git a/.npmignore b/.npmignore index 32b3262..1dbbfcc 100644 --- a/.npmignore +++ b/.npmignore @@ -2,4 +2,6 @@ .git node_modules/ hashes/ -versions.txt \ No newline at end of file +versions.txt +HACKING.md +.editorconfig diff --git a/README.md b/README.md index c487ab7..7827495 100644 --- a/README.md +++ b/README.md @@ -34,89 +34,19 @@ You can sort or filter the returned versions if needed. All Stable electron releases for the following architectures are fingerprinted: - linux-x64 +- linux-arm64 - darwin-x64 (Mac OS) - win32-x64 (Windows) +- win32-arm64 (Windows) +- darwin-arm64 (Apple Silicon) A list of release fingerprints is under the `hashes` directory. -## todo - -- [ ] Add support for darwin-arm - ## which files are present? -Here's a count of file extensions present across all releases: +Here's a count of the most common extensions present across all releases: ``` - 9 framework/Frameworks - 9 Frameworks - 13 app/Contents/MacOS/crash_report_sender - 13 crash_report_sender - 13 framework/Versions/A/Libraries/Libraries - 13 framework/Versions/A/Resources/Inspector - 13 Inspector - 14 htaccess - 15 npmignore - 15 txt - 26 1 - 26 strings - 30 yml - 45 markdown - 50 framework/ReactiveObjC - 50 framework/Versions/A/ReactiveObjC - 59 4 - 70 11 - 72 app/Contents/MacOS/Electron Helper (GPU) - 72 app/Contents/MacOS/Electron Helper (Plugin) - 72 app/Contents/MacOS/Electron Helper (Renderer) - 72 framework/Helpers - 72 framework/Versions/A/Helpers/chrome_crashpad_handler - 94 chrome_crashpad_handler - 94 Helpers - 100 ReactiveObjC - 171 (GPU) - 171 (Plugin) - 171 (Renderer) - 185 chrome-sandbox - 223 app/Contents/MacOS/Electron Helper EH - 223 app/Contents/MacOS/Electron Helper NP - 223 EH - 223 NP - 230 framework/Versions/A/Resources/crashpad_handler - 238 svg - 262 framework/ReactiveCocoa - 262 framework/Versions/A/ReactiveCocoa - 312 app/Contents/MacOS/Electron - 312 app/Contents/MacOS/Electron Helper - 312 DS_Store - 312 framework/Electron Framework - 312 framework/Libraries - 312 framework/Mantle - 312 framework/Squirrel - 312 framework/Versions/A/Electron Framework - 312 framework/Versions/A/Mantle - 312 framework/Versions/A/Resources/ShipIt - 312 framework/Versions/A/Squirrel - 357 crashpad_handler - 436 electron - 436 exe - 436 ShipIt - 449 Libraries - 745 json - 772 ReactiveCocoa - 773 nib - 774 icns - 786 framework/Headers - 786 framework/Modules - 872 Framework - 872 Mantle - 872 Squirrel - 1120 png - 1158 Headers - 1158 Modules - 1248 framework/Resources - 1248 framework/Versions/Current - 1299 app/Contents/PkgInfo 1620 dat 1620 version 1650 LICENSE @@ -161,6 +91,11 @@ electron (Renderer) ``` +`which-electron` uses the following extensions and filenames to fingerprint: + +- `.h`, `.dll`, `.bin`, `.asar`, `.dylib`, `.so`, `.exe` +- `electron framework`, `squirrel`, `electron`, `electron helper`, `chrome_100_percent`, `chrome_200_percent` + ## license Released under WTFPL. diff --git a/fingerprint.php b/fingerprint.php index 8dbe500..7b199ef 100644 --- a/fingerprint.php +++ b/fingerprint.php @@ -11,57 +11,76 @@ function rsearch($dir) { } function generateFingerprint($version, $output, $hash_file) { - $manifest = []; - foreach(rsearch($output) as $file) { - $path = substr($file, strlen($output) + 1); - $manifest[$path] = sha1_file($file); - } - $json = json_encode($manifest, JSON_PRETTY_PRINT|JSON_UNESCAPED_SLASHES); - file_put_contents($hash_file, $json); + $manifest = []; + foreach(rsearch($output) as $file) { + $path = substr($file, strlen($output) + 1); + $manifest[$path] = sha1_file($file); + } + $json = json_encode($manifest, JSON_PRETTY_PRINT|JSON_UNESCAPED_SLASHES); + file_put_contents($hash_file, $json); } function download_release($url, $output) { - @unlink($output); - system("wget --quiet --max-redirect=5 '$url' -O /dev/shm/test.zip", $ret); + @unlink($output); + system("wget --quiet --max-redirect=5 '$url' -O /dev/shm/test.zip", $ret); - return ($ret === 0); + return ($ret === 0); } function extract_release($input, $output) { - $zip = new ZipArchive(); - if (!$zip->open($input)) { - die("Download failed?"); - } - `rm -rf $output`; - mkdir($output); - - if(!$zip->extractTo($output)) { - die("Failed extraction"); - } + $zip = new ZipArchive(); + if (!$zip->open($input)) { + die("Download failed?"); + } + `rm -rf $output`; + mkdir($output); - $zip->close(); + if(!$zip->extractTo($output)) { + die("Failed extraction"); + } + + $zip->close(); } -$archs = ['x64']; +$archs = ['x64', 'arm64']; $oses = ['linux', 'darwin', 'win32']; foreach(file('versions.txt', FILE_IGNORE_NEW_LINES) as $version) { - foreach($oses as $os) { - foreach($archs as $arch) { - $hash_file = "hashes/$os-$arch-$version.json"; - if (!file_exists($hash_file)) { - $zipfile = '/dev/shm/test.zip'; - $output = '/dev/shm/electron'; - $url = "https://github.com/electron/electron/releases/download/$version/electron-$version-$os-$arch.zip"; - echo $url . PHP_EOL; + foreach($oses as $os) { + foreach($archs as $arch) { - if (download_release($url, $zipfile)) { - extract_release($zipfile, $output); - generateFingerprint($version, $output, $hash_file); - } else { - echo "[DL:FAIL] $version\n"; - } - } - } - } + // No releases were made for these combinations + // Apple Silicon support added in v11: https://www.electronjs.org/blog/apple-silicon + if (version_compare($version, 'v11.0.0', '<') and $os=='darwin' and $arch=='arm64') { + continue; + } + + // https://github.com/electron/electron/pull/10219 + // v1.8.0 was the first arm64 release + if (version_compare($version, 'v1.8.0', '<') and $os=='linux' and $arch=='arm64') { + continue; + } + + // 6.0.9 was the first ARM64 windows release (backport) + // https://github.com/electron/electron/pull/20260 + if (version_compare($version, 'v6.0.9', '<') and $os=='win32' and $arch=='arm64') { + continue; + } + + $hash_file = "hashes/$os-$arch-$version.json"; + if (!file_exists($hash_file)) { + $zipfile = '/dev/shm/test.zip'; + $output = '/dev/shm/electron'; + $url = "https://github.com/electron/electron/releases/download/$version/electron-$version-$os-$arch.zip"; + echo $url . PHP_EOL; + + if (download_release($url, $zipfile)) { + extract_release($zipfile, $output); + generateFingerprint($version, $output, $hash_file); + } else { + echo "[DL:FAIL] $version\n"; + } + } + } + } } diff --git a/index.js b/index.js new file mode 100644 index 0000000..c993ab2 --- /dev/null +++ b/index.js @@ -0,0 +1,8 @@ +module.exports = { + "linux-x64": require('./linux-x64'), + "linux-arm64": require('./linux-arm64'), + "darwin-x64": require('./darwin-x64'), + "darwin-arm64": require('./darwin-arm64'), + "win32-x64": require('./win32-x64'), + "win32-arm64": require('./win32-arm64'), +} diff --git a/lookup-table.php b/lookup-table.php index a4b7be3..f510a4f 100644 --- a/lookup-table.php +++ b/lookup-table.php @@ -1,27 +1,32 @@ [], - 'linux-x64' => [], - 'darwin-x64' => [] + 'darwin-x64' => [], + 'darwin-arm64' => [], + 'linux-x64' => [], + 'linux-arm64' => [], + 'win32-x64' => [], + 'win32-arm64' => [], ]; foreach(glob('hashes/*.json') as $h) { - $data = json_decode(file_get_contents($h)); - $name = basename($h, '.json'); - list($os, $arch, $version) = explode('-', $name, 3); - foreach($data as $file=>$hash) { - // Including locales increases the file size by too much. - if (strpos($file, '.pak') !== false) { - continue; - } - $subTable = "$os-$arch"; - if(!isset($lookup[$subTable][$hash])) { - $lookup[$subTable][$hash] = []; - } - $lookup[$subTable][$hash][] = $version; - } + $data = json_decode(file_get_contents($h)); + $name = basename($h, '.json'); + list($os, $arch, $version) = explode('-', $name, 3); + foreach($data as $file=>$hash) { + // Including locales increases the file size by too much. + if (strpos($file, '.pak') !== false and strlen(basename($file, '.pak') < 3)) { + continue; + } + $subTable = "$os-$arch"; + if(!isset($lookup[$subTable][$hash])) { + $lookup[$subTable][$hash] = []; + } + $lookup[$subTable][$hash][] = $version; + } } -$json = json_encode($lookup); -file_put_contents('lookup.json', $json); \ No newline at end of file +foreach($lookup as $file => $data) { + $json = json_encode($data); + file_put_contents("$file.json", $json); +} diff --git a/test.js b/test.js new file mode 100644 index 0000000..5e39ced --- /dev/null +++ b/test.js @@ -0,0 +1,143 @@ +const L = require("."); +const assert = require("assert"); + +// ffmpeg.dll +assert.deepEqual(L["win32-x64"]["baf786083f482c1f035e50e105b5f7475af1e00b"], [ + "v1.4.3", + "v1.4.4", + "v1.4.5", +]); + +// libEGL.dylib +assert.deepEqual(L["darwin-x64"]["b904574843c22f7b39e986253b0c798548d2f01d"], [ + "v12.0.10", + "v12.0.11", + "v12.0.12", + "v12.0.13", + "v12.0.14", + "v12.0.15", + "v12.0.2", + "v12.0.3", + "v12.0.4", + "v12.0.5", + "v12.0.6", + "v12.0.7", + "v12.0.8", + "v12.0.9", +]); + +// chrome_100_percent.pak +assert.deepEqual(L["linux-arm64"]["942e5f5414a24a1aa1769b9f8614ff8fbf40dba3"], [ + "v12.0.0", + "v12.0.1", + "v12.0.10", + "v12.0.11", + "v12.0.12", + "v12.0.13", + "v12.0.14", + "v12.0.15", + "v12.0.2", + "v12.0.3", + "v12.0.4", + "v12.0.5", + "v12.0.6", + "v12.0.7", + "v12.0.8", + "v12.0.9", +]); + +// snapshot_blob.bin +assert.deepEqual(L["linux-x64"]["3fc441bcbacac544ba4af18dcd2b084694ae9409"], [ + "v12.0.10", + "v12.0.11", + "v12.0.12", + "v12.0.13", + "v12.0.14", + "v12.0.15", + "v12.0.5", + "v12.0.6", + "v12.0.7", + "v12.0.8", + "v12.0.9", +]); + +// libGLESv2.dll +assert.deepEqual(L["win32-arm64"]["21f751ea45147f9e0b7107b8129ae4dd2fd1ccd6"], [ + "v12.0.15", +]); + +// d3dcompiler_47.dll +assert.deepEqual(L["win32-x64"]["2256644f69435ff2fee76deb04d918083960d1eb"], [ + "v10.0.0", + "v10.0.1", + "v10.1.0", + "v10.1.1", + "v10.1.2", + "v10.1.3", + "v10.1.4", + "v10.1.5", + "v10.1.6", + "v10.1.7", + "v10.2.0", + "v10.3.0", + "v10.3.1", + "v10.3.2", + "v10.4.0", + "v10.4.1", + "v10.4.2", + "v10.4.3", + "v10.4.4", + "v10.4.5", + "v10.4.6", + "v10.4.7", + "v11.0.0", + "v11.0.1", + "v11.0.2", + "v11.0.3", + "v11.0.4", + "v11.0.5", + "v11.1.0", + "v11.1.1", + "v11.2.0", + "v11.2.1", + "v11.2.2", + "v11.2.3", + "v11.3.0", + "v11.4.0", + "v11.4.1", + "v11.4.10", + "v11.4.2", + "v11.4.3", + "v11.4.4", + "v11.4.5", + "v11.4.6", + "v11.4.7", + "v11.4.8", + "v11.4.9", + "v12.0.0", + "v12.0.1", + "v12.0.10", + "v12.0.11", + "v12.0.12", + "v12.0.13", + "v12.0.14", + "v12.0.15", + "v12.0.2", + "v12.0.3", + "v12.0.4", + "v12.0.5", + "v12.0.6", + "v12.0.7", + "v12.0.8", + "v12.0.9", + "v13.0.0", + "v13.0.1", + "v13.1.0", + "v13.1.1", + "v13.1.2", + "v13.1.3", + "v13.1.4", + "v13.1.5", + "v13.1.6", + "v13.1.7", +]);