├── .gitignore ├── LICENSE ├── README.md ├── lib ├── configUtil.js └── index.js ├── package.json └── test └── open.js /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Runtime data 9 | pids 10 | *.pid 11 | *.seed 12 | *.pid.lock 13 | 14 | # Directory for instrumented libs generated by jscoverage/JSCover 15 | lib-cov 16 | 17 | # Coverage directory used by tools like istanbul 18 | coverage 19 | 20 | # nyc test coverage 21 | .nyc_output 22 | 23 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 24 | .grunt 25 | 26 | # Bower dependency directory (https://bower.io/) 27 | bower_components 28 | 29 | # node-waf configuration 30 | .lock-wscript 31 | 32 | # Compiled binary addons (http://nodejs.org/api/addons.html) 33 | build/Release 34 | 35 | # Dependency directories 36 | node_modules/ 37 | jspm_packages/ 38 | 39 | # Typescript v1 declaration files 40 | typings/ 41 | 42 | # Optional npm cache directory 43 | .npm 44 | 45 | # Optional eslint cache 46 | .eslintcache 47 | 48 | # Optional REPL history 49 | .node_repl_history 50 | 51 | # Output of 'npm pack' 52 | *.tgz 53 | 54 | # Yarn Integrity file 55 | .yarn-integrity 56 | 57 | # dotenv environment variables file 58 | .env 59 | 60 | # system 61 | .DS_Store 62 | 63 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 张代应 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # open-browser 2 | Open browser window and set proxy 3 | 4 | # Install 5 | 6 | ```bash 7 | npm install op-browser --save 8 | ``` 9 | 10 | # Usage 11 | 12 | ```js 13 | const openBrowser = require('op-browser'); 14 | 15 | // Automatic proxy selection 16 | openBrowser.open('chrome', 'https://google.com', 'http://127.0.0.1:8800', ''); 17 | // Proxy auto-configuration (PAC) 18 | openBrowser.open('chrome', 'https://google.com', '', 'http://127.0.0.1:8800/proxy.pac'); 19 | ``` 20 | 21 | # API 22 | 23 | 24 | 25 | ## op-browser : object 26 | Browser 27 | 28 | **Kind**: global namespace 29 | 30 | * [op-browser](#op-browser) : object 31 | * [.open(browser, url, proxyURL, pacFileURL)](#op-browser.open) ⇒ Promise 32 | * [.detect(name)](#op-browser.detect) ⇒ Promise 33 | 34 | 35 | 36 | ### op-browser.open(browser, url, proxyURL, pacFileURL, bypassList) ⇒ Promise 37 | open browser window, if the `pacFileURL` is not empty, will use `proxy auto-configuration` 38 | 39 | **Kind**: static method of [op-browser](#op-browser) 40 | 41 | | Param | Type | Description | 42 | | --- | --- | --- | 43 | | browser | String | the browser's name | 44 | | url | String | the url that to open | 45 | | proxyURL | String | the proxy url, format: `http://[:[port]]` | 46 | | pacFileURL | String | the proxy url, format: `http://[:[port]]/[pac-file-name]` | 47 | | bypassList | String | the list of hosts for whom we bypass proxy settings and use direct connections, See: "[net/proxy/proxy_bypass_rules.h](https://cs.chromium.org/chromium/src/net/proxy_resolution/proxy_bypass_rules.h?sq=package:chromium&type=cs)" for the format of these rules | 48 | 49 | 50 | 51 | ### op-browser.detect(name) ⇒ Promise 52 | detect browser, return the browser's path 53 | 54 | **Kind**: static method of [op-browser](#op-browser) 55 | 56 | | Param | Type | Description | 57 | | --- | --- | --- | 58 | | name | String | the browser name | 59 | 60 | -------------------------------------------------------------------------------- /lib/configUtil.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @file 3 | * @author zdying 4 | */ 5 | 'use strict'; 6 | 7 | var fs = require('fs'); 8 | var path = require('path'); 9 | var urlParser = require('url'); 10 | var childProcess = require('child_process'); 11 | 12 | module.exports = { 13 | chrome: function (dataDir, url, chromePath, proxyURL, pacFileURL, bypassList) { 14 | // List of Chromium Command Line Switches 15 | // https://peter.sh/experiments/chromium-command-line-switches/ 16 | var proxyOption = pacFileURL 17 | ? '--proxy-pac-url=' + pacFileURL 18 | : '--proxy-server=' + proxyURL; 19 | 20 | bypassList = bypassList === undefined ? '' : bypassList; 21 | 22 | dataDir = path.resolve(path.join(dataDir, 'chrome-cache')); 23 | 24 | return [ 25 | // '--proxy-pac-url="' + proxy + '"', 26 | // '--proxy-server="' + proxy + '"', 27 | proxyOption, 28 | '--proxy-bypass-list=' + bypassList, 29 | '--user-data-dir=' + dataDir, 30 | '--lang=local', 31 | url 32 | ]; 33 | }, 34 | 35 | opera: function (dataDir, url, operaPath, proxyURL, pacFileURL, bypassList) { 36 | var proxyOption = pacFileURL 37 | ? '--proxy-pac-url=' + pacFileURL 38 | : '--proxy-server=' + proxyURL + ''; 39 | 40 | bypassList = bypassList === undefined ? '' : bypassList; 41 | 42 | dataDir = path.resolve(path.join(dataDir, 'opera-cache')); 43 | 44 | return [ 45 | proxyOption, 46 | '--proxy-bypass-list=' + bypassList, 47 | '--user-data-dir=' + dataDir, 48 | '--lang=local', 49 | url 50 | ]; 51 | }, 52 | 53 | safari: function (dataDir, url, safariPath, proxy) { 54 | return ''; 55 | }, 56 | 57 | firefox: function (dataDir, url, firefoxPath, proxyURL, pacFileURL, bypassList) { 58 | // Firefox pac set 59 | // http://www.indexdata.com/connector-platform/enginedoc/proxy-auto.html 60 | // http://kb.mozillazine.org/Network.proxy.autoconfig_url 61 | // user_pref("network.proxy.autoconfig_url", "http://us2.indexdata.com:9005/id/cf.pac"); 62 | // user_pref("network.proxy.type", 2); 63 | 64 | var dir = path.join(dataDir, 'firefox-cache'); 65 | var prefsPath = path.join(dir, 'prefs.js'); 66 | var prefs = []; 67 | 68 | bypassList = bypassList === undefined ? 'localhost, 127.0.0.1, ::1' : bypassList; 69 | 70 | if (!fs.existsSync(dir)) { 71 | fs.mkdirSync(dir); 72 | } 73 | 74 | if (!fs.existsSync(prefsPath)) { 75 | if (pacFileURL) { 76 | // 自动代理 77 | prefs = [ 78 | 'user_pref("network.proxy.autoconfig_url", "' + pacFileURL + '");', 79 | 'user_pref("network.proxy.type", 2);' 80 | ]; 81 | } else { 82 | // 直接代理 83 | var urlObj = urlParser.parse(proxyURL); 84 | prefs = [ 85 | 'user_pref("network.proxy.http", "' + urlObj.hostname + '");', 86 | 'user_pref("network.proxy.http_port", ' + urlObj.port + ');', 87 | 'user_pref("network.proxy.type", 1);', 88 | 'user_pref("network.proxy.no_proxies_on", "' + bypassList + '")' 89 | ]; 90 | } 91 | 92 | // https://developer.mozilla.org/en-US/docs/Mozilla/Command_Line_Options 93 | childProcess.execFileSync(path.resolve(firefoxPath), [ 94 | '-CreateProfile', 95 | '"firefox_op_browser_pref ' + path.resolve(dir) + '"' 96 | ]); 97 | fs.writeFileSync(prefsPath, prefs.join('\n')); 98 | } 99 | 100 | return [ 101 | '-P', 102 | 'firefox_op_browser_pref', 103 | '-no-remote', 104 | '--new-instance', 105 | url 106 | ]; 107 | } 108 | }; 109 | -------------------------------------------------------------------------------- /lib/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @file open browser window 3 | * @author zdying 4 | */ 5 | 6 | var os = require('os'); 7 | var path = require('path'); 8 | var configUtil = require('./configUtil'); 9 | 10 | var childProcess = require('child_process'); 11 | 12 | var platform = os.platform(); 13 | 14 | var browsers = { 15 | 'chrome': { 16 | darwin: 'com.google.Chrome', 17 | appName: 'Google Chrome', 18 | win32: 'chrome.exe', 19 | linux: 'google-chrome' 20 | }, 21 | 'firefox': { 22 | darwin: 'org.mozilla.firefox', 23 | appName: 'firefox', 24 | win32: 'firefox.exe' 25 | }, 26 | 'opera': { 27 | darwin: 'com.operasoftware.Opera', 28 | appName: 'Opera', 29 | win32: 'opera.exe' 30 | }, 31 | 'safari': { 32 | darwin: 'com.apple.Safari', 33 | appName: 'Safari', 34 | win32: 'safari.exe' 35 | }, 36 | }; 37 | 38 | /** 39 | * Browser 40 | * @namespace op-browser 41 | */ 42 | module.exports = { 43 | /** 44 | * open browser window, if the `pacFileURL` is not empty, will use `proxy auto-configuration` 45 | * @memberof op-browser 46 | * @param {String} browser the browser's name 47 | * @param {String} url the url that to open 48 | * @param {String} proxyURL the proxy url, format: `http://[:[port]]` 49 | * @param {String} pacFileURL the proxy url, format: `http://[:[port]]/[pac-file-name]` 50 | * @param {String} dataDir the user data directory 51 | * @param {String} bypassList the list of hosts for whom we bypass proxy settings and use direct connections. the list of hosts for whom we bypass proxy settings and use direct connections, See: "[net/proxy/proxy_bypass_rules.h](https://cs.chromium.org/chromium/src/net/proxy_resolution/proxy_bypass_rules.h?sq=package:chromium&type=cs)" for the format of these rules 52 | * @return {Promise} 53 | */ 54 | open: function (browser, url, proxyURL, pacFileURL, dataDir, bypassList) { 55 | // Firefox pac set 56 | // http://www.indexdata.com/connector-platform/enginedoc/proxy-auto.html 57 | // http://kb.mozillazine.org/Network.proxy.autoconfig_url 58 | // user_pref("network.proxy.autoconfig_url", "http://us2.indexdata.com:9005/id/cf.pac"); 59 | // user_pref("network.proxy.type", 2); 60 | 61 | return this.detect(browser).then(function (browserPath) { 62 | if (!browserPath) { 63 | throw Error('[Error] can not find browser ' + browser); 64 | } else { 65 | dataDir = dataDir || path.join(os.tmpdir(), 'op-browser'); 66 | 67 | var commandOptions = configUtil[browser](dataDir, url, browserPath, proxyURL, pacFileURL, bypassList); 68 | 69 | return new Promise(function (resolve, reject) { 70 | childProcess.execFile(path.resolve(browserPath), commandOptions, {maxBuffer: 50000 * 1024}, function (err) { 71 | if (err) { 72 | reject(err); 73 | } else { 74 | resolve({ 75 | path: browserPath, 76 | cmdOptions: commandOptions, 77 | proxyURL: proxyURL, 78 | pacFileURL: pacFileURL 79 | }); 80 | } 81 | }); 82 | }); 83 | } 84 | }); 85 | }, 86 | 87 | /** 88 | * detect browser, return the browser's path 89 | * @memberof op-browser 90 | * @param {String} name the browser name 91 | * @return {Promise} 92 | */ 93 | detect: function (name) { 94 | var result = ''; 95 | var cmd = ''; 96 | var info = browsers[name]; 97 | 98 | return new Promise(function (resolve, reject) { 99 | if (!info) { 100 | reject(Error('Browser not supported.')); 101 | } 102 | 103 | try { 104 | switch (platform) { 105 | case 'darwin': 106 | cmd = 'mdfind "kMDItemCFBundleIdentifier==' + info.darwin + '" | head -1'; 107 | result = childProcess.execSync(cmd).toString().trim(); 108 | result += '/Contents/MacOS/' + info.appName; 109 | result = result.replace(/\s/g, '\\ '); 110 | break; 111 | 112 | case 'win32': 113 | // windows chrome path: 114 | // HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\chrome.exe 115 | // reg query "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\chrome.exe" /v Path 116 | 117 | cmd = 'reg query "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\App Paths\\' + info.win32 + '" /ve'; 118 | // result: 119 | /* 120 | HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\firefox.exe 121 | (默认) REG_SZ C:\Program Files\Mozilla Firefox\firefox.exe 122 | */ 123 | 124 | result = childProcess.execSync(cmd).toString().trim(); 125 | result = result.split('\n').pop().split(/\s+REG_SZ\s+/).pop(); 126 | result = result.replace(/^"|"$/g, ''); 127 | break; 128 | 129 | case 'linux': 130 | if(info.linux){ 131 | result = path.join('/usr/bin',info.linux) 132 | } 133 | break; 134 | default: 135 | result = name; 136 | } 137 | } catch (e) { 138 | reject(Error('Can not find browser info', name)); 139 | } 140 | 141 | resolve(result.trim()); 142 | }); 143 | } 144 | }; 145 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "op-browser", 3 | "version": "1.0.9", 4 | "description": "Open browser window and set proxy", 5 | "main": "lib/index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "git+https://github.com/zdying/open-browser.git" 12 | }, 13 | "keywords": [ 14 | "open", 15 | "browser" 16 | ], 17 | "author": "zdying", 18 | "license": "MIT", 19 | "bugs": { 20 | "url": "https://github.com/zdying/open-browser/issues" 21 | }, 22 | "homepage": "https://github.com/zdying/open-browser#readme" 23 | } 24 | -------------------------------------------------------------------------------- /test/open.js: -------------------------------------------------------------------------------- 1 | var op = require('../lib/index'); 2 | 3 | 'chrome safari firefox opera'.split(' ').forEach(function (browser) { 4 | op.detect(browser).then(function (path) { 5 | console.log(browser, '==>', path); 6 | op.open(browser, 'https://www.google.com/', 'http://127.0.0.1:5525'); 7 | }).catch(function (err) { 8 | console.error(browser, 'detect fail:', err); 9 | }); 10 | }); 11 | --------------------------------------------------------------------------------