Last active
August 29, 2015 14:01
-
-
Save vweevers/e8c3863759fd8f9659ce to your computer and use it in GitHub Desktop.
Test script to fix Windows browser detection (https://github.com/substack/browser-launcher/issues/7)
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
var util = require('util') | |
, exec = require('child_process').exec | |
, execOptions = { timeout: 3000 } | |
, wmicCommand = 'wmic datafile where Name="%s" get Version /format:value' | |
, rootKeys = ['HKEY_LOCAL_MACHINE', 'HKEY_CURRENT_USER'] | |
// Convenient access to environment variables | |
var env = process.env | |
, pf = env['ProgramFiles(x86)'] || env['ProgramFiles'] | |
, pf64 = env.ProgramW6432 // "C:\Program Files" on x64 | |
, home = env.USERPROFILE || (env.HOMEDRIVE + env.HOMEPATH) | |
// "%USERPROFILE%\AppData\Local" or | |
// "%USERPROFILE%\Local Settings\Application Data" (XP) | |
, local = env.LOCALAPPDATA || (home + '\\Local Settings\\Application Data') | |
// Default locations and registry keys | |
var browsers = { | |
chrome: { | |
registry: [ // Expanded to HKEY_LOCAL_MACHINE and HKEY_CURRENT_USER | |
'"%s\\Software\\Google\\Update" /v LastInstallerSuccessLaunchCmdLine', | |
'"%s\\Software\\Wow6432Node\\Google\\Update" /v LastInstallerSuccessLaunchCmdLine', | |
'"%s\\Software\\Clients\\StartMenuInternet\\Google Chrome\\shell\\open\\command"', | |
'"%s\\SOFTWARE\\Wow6432Node\\Clients\\StartMenuInternet\\Google Chrome\\shell\\open\\command"', | |
'"%s\\SOFTWARE\\Classes\\ChromeHTML\\shell\\open\\command"', | |
// Parsing this seems to fail, needs testing | |
'"%s\\SOFTWARE\\Wow6432Node\\Microsoft\\Windows\\CurrentVersion\\App Paths\\chrome.exe"' | |
], | |
locations: [ // Joined with filename (or [browsername].exe) | |
[pf, 'Google\\Chrome\\Application'], | |
[local, 'Google\\Chrome\\Application'] | |
] | |
}, | |
ff: { | |
registry: [ | |
'"%s\\Software\\Clients\\StartMenuInternet\\FIREFOX.EXE\\shell\\open\\command"', | |
'"%s\\Software\\Mozilla\\Mozilla Firefox\\" /s /v PathToExe', | |
// First get version, then path | |
[ '"%s\\Software\\Mozilla\\Mozilla Firefox" /v CurrentVersion', | |
'"%s\\Software\\Mozilla\\Mozilla Firefox\\%s\\Main\\" /s /v PathToExe' ] | |
], | |
file: 'firefox.exe', | |
locations: [ | |
[pf, 'Mozilla Firefox'] | |
] | |
}, | |
ie: { | |
registry: [ | |
'"%s\\Software\\Clients\\StartMenuInternet\\IEXPLORE.EXE\\shell\\open\\command"' | |
], | |
file: 'iexplore.exe', | |
locations: [ | |
[pf64, 'Internet Explorer'], | |
[pf, 'Internet Explorer'] | |
] | |
}, | |
// Untested and incomplete (Safari for Windows is dead anyway) | |
safari: { | |
registry: [ | |
'"%s\\Software\\Apple Computer, Inc.\\Safari" /v BrowserExe' | |
] | |
} | |
} | |
// TODO: get all paths, merge, then query WMIC | |
Object.keys(browsers).forEach(function(browser){ | |
var entry = browsers[browser] | |
, file = entry.file || (browser + '.exe') | |
// 1st strategy: registry | |
if (entry.registry) { | |
entry.registry.forEach(function(query){ | |
var withVersion = Array.isArray(query) | |
rootKeys.forEach(function(root){ | |
if (withVersion) { | |
var cmd = 'reg query ' + util.format(query[0], root) | |
exec(cmd, parseVersionQuery.bind(null, query[1])) | |
return | |
} | |
var cmd = 'reg query ' + util.format(query, root) | |
exec(cmd, parsePathQuery()) | |
}) | |
}) | |
} | |
// 2nd strategy: common locations | |
if (entry.locations) | |
iterate.call({ | |
browser: browser, | |
paths: entry.locations.filter(notEmpty).map(join), | |
strategy: 'common location' | |
}) | |
// 3rd strategy: find in PATH | |
// - "where" utility is available on > XP | |
exec('where '+file, parseWhere, execOptions) | |
// Functions (todo: without closures) | |
function parseVersionQuery(pathQuery, err, stdout) { | |
if (err) return | |
var matches = /([\d\.]+)/.exec(stdout.toString()) | |
if (!matches || !matches[1]) { | |
return console.log("can't parse reg version", stdout) | |
} | |
var version = matches[1] | |
rootKeys.forEach(function(root){ | |
var cmd = 'reg query ' + util.format(pathQuery, root, version) | |
exec(cmd, parsePathQuery(function(path){ | |
found(browser, version, path, 'registry with version') | |
})) | |
}) | |
} | |
function parsePathQuery(cb) { | |
return function(err, stdout) { | |
if (err) return | |
var matches = /([A-Z]:\\[^"$]+)/i.exec(stdout.toString()) | |
if (!matches || !matches[1]) { | |
return console.log("can't parse reg path", stdout) | |
} | |
var path = matches[1].trim(); | |
if (cb) return cb(path); | |
getVersion(path, function(version){ | |
if (version) found( | |
browser, version, path, 'registry' | |
) | |
}) | |
} | |
} | |
function parseWhere(err, out){ | |
if (err) return | |
out = out.toString() | |
.trim() | |
.split(/\s*\n\s*/) | |
.filter(drive) | |
if (out.length) iterate.call({ | |
browser: browser, | |
paths: out, | |
strategy: 'in PATH' | |
}) | |
} | |
function join(path) { | |
path.push(file) | |
return path.join('\\') | |
} | |
}) | |
function notEmpty(path) { | |
return path && path[0] | |
} | |
function drive(path) { | |
return path[1] === ':' && path[2] === '\\' | |
} | |
function iterate(version) { | |
if (!this.i) this.i = 0 | |
if (version) | |
found( | |
this.browser, version, | |
this.path, this.strategy | |
) | |
if (this.path = this.paths[this.i++]) | |
getVersion(this.path, iterate.bind(this)) | |
} | |
function found(browser, version, path, strategy) { | |
console.log(util.format( | |
"\n%s %s [%s]\n @ %s", | |
browser, version, strategy, path | |
)) | |
} | |
function getVersion(path, cb) { | |
// WMIC wants double slashes | |
var escaped = path.replace(/\\/g, '\\\\') | |
, cmd = util.format(wmicCommand, escaped) | |
exec(cmd, parse, execOptions) | |
function parse (err, stdout, stderr){ | |
if (err) return cb() | |
// "Version=xx" | |
var a = stdout.toString().trim().split('=') | |
if (a.length===2) cb(a[1]) | |
else cb() | |
} | |
} |
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
chrome 35.0.1916.114 [common location] | |
@ C:\Program Files (x86)\Google\Chrome\Application\chrome.exe | |
ff 23.0.1.4974 [common location] | |
@ C:\Program Files (x86)\Mozilla Firefox\firefox.exe | |
ie 11.0.9600.17041 [common location] | |
@ C:\Program Files\Internet Explorer\iexplore.exe | |
ie 11.0.9600.17041 [registry] | |
@ C:\Program Files\Internet Explorer\iexplore.exe | |
chrome 35.0.1916.114 [registry] | |
@ C:\Program Files (x86)\Google\Chrome\Application\chrome.exe | |
chrome 35.0.1916.114 [registry] | |
@ C:\Program Files (x86)\Google\Chrome\Application\chrome.exe | |
chrome 35.0.1916.114 [registry] | |
@ C:\Program Files (x86)\Google\Chrome\Application\chrome.exe | |
ff 23.0.1.4974 [registry] | |
@ C:\Program Files (x86)\Mozilla Firefox\firefox.exe | |
ie 11.0.9600.17041 [common location] | |
@ C:\Program Files (x86)\Internet Explorer\iexplore.exe |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Other things that might be interesting: