├── .editorconfig ├── .eslintrc ├── .gitignore ├── .npmignore ├── LICENSE ├── README.md ├── assets └── settings.png ├── lib ├── darwin │ ├── index.js │ └── utils.js ├── index.js ├── linux │ └── index.js ├── utils.js └── win32 │ ├── index.js │ └── util.js ├── package-lock.json ├── package.json └── test ├── .eslintrc ├── all.test.cb.js ├── all.test.js ├── autoConfig.test.cb.js ├── autoConfig.test.js ├── autoDetect.test.js ├── autoDetect.text.cb.js ├── bypass.test.cb.js ├── bypass.test.js ├── get.test.cb.js ├── get.test.js ├── listNetworkServices.test.cb.js ├── listNetworkServices.test.js ├── proxyServer.test.cb.js ├── proxyServer.test.js ├── reset.test.cb.js └── reset.test.js /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | end_of_line = lf 7 | indent_size = 2 8 | indent_style = space 9 | insert_final_newline = true 10 | max_line_length = 80 11 | trim_trailing_whitespace = true 12 | 13 | [*.md] 14 | max_line_length = 0 15 | trim_trailing_whitespace = false 16 | 17 | [COMMIT_EDITMSG] 18 | max_line_length = 0 -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "eslint-config-imweb" 3 | } 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | 6 | # Runtime data 7 | pids 8 | *.pid 9 | *.seed 10 | .DS_Store 11 | 12 | # Directory for instrumented libs generated by jscoverage/JSCover 13 | lib-cov 14 | 15 | # Coverage directory used by tools like istanbul 16 | coverage 17 | 18 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 19 | .grunt 20 | 21 | # node-waf configuration 22 | .lock-wscript 23 | 24 | # Compiled binary addons (http://nodejs.org/api/addons.html) 25 | build/Release 26 | 27 | # Dependency directory 28 | node_modules 29 | 30 | # Optional npm cache directory 31 | .npm 32 | 33 | # Optional REPL history 34 | .node_repl_history 35 | .idea 36 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules/ 3 | test/ 4 | src/ 5 | .idea 6 | *.log 7 | .mcms 8 | logs 9 | /assets 10 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 IMWeb 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 | # lan-settings 2 | 用于设置操作系统的局域网设置的Node模块(Node >= v7.6), 支持 Windows、macOS, 后续会支持 Linux 3 | 4 | ![LAN Settings](https://raw.githubusercontent.com/imweb/lan-settings/master/assets/settings.png) 5 | 6 | 7 | ## 安装 8 | `npm i --save lan-settings` 9 | 10 | 11 | ## 使用 (Promise/Async) 12 | ```js 13 | const lan = require('lan-settings'); 14 | 15 | 16 | // 获取设备的所有可用 NetworkServices (macOS Only) 17 | lan.listNetworkServices() 18 | .then(console.log.bind(console, '获取成功: ')) 19 | .catch(console.log.bind(console, '获取失败: ')); 20 | 21 | 22 | // 获取当前局域网设置信息,如果err非空,表示获取失败 23 | lan.getSettings() 24 | .then(console.log.bind(console, '获取成功: ')) 25 | .catch(console.log.bind(console, '获取失败: ')); 26 | // output: 27 | // { autoDetect: false, 28 | // autoConfig: false, 29 | // autoConfigUrl: '', 30 | // proxyEnable: true, 31 | // proxyServer: '127.0.0.1:8888', 32 | // bypassLocal: false, 33 | // bypass: '' } 34 | 35 | 36 | // 自动检测设置 37 | lan.setSettings({ 38 | autoDetect: true 39 | }) 40 | .then(console.log.bind(console, '设置成功')) 41 | .catch(console.log.bind(console, '设置失败: ')); 42 | 43 | 44 | // 开启并这种PAC脚本 45 | lan.setSettings({ 46 | autoConfig: true, 47 | autoConfigUrl: 'http://127.0.0.1:50011' 48 | }) 49 | .then(console.log.bind(console, '设置成功')) 50 | .catch(console.log.bind(console, '设置失败: ')); 51 | 52 | 53 | // 开启并设置统一的代理服务器,开启本地代理白名单 54 | lan.setSettings({ 55 | proxyEnable: true, 56 | proxyServer: '127.0.0.1:8888', 57 | bypassLocal: true 58 | }) 59 | .then(console.log.bind(console, '设置成功')) 60 | .catch(console.log.bind(console, '设置失败: ')); 61 | 62 | 63 | // 高级设置,对http、https、ftp、socks分别设置不同的代理,并设置白名单域名前缀 64 | lan.setSettings({ 65 | proxyEnable: true, 66 | proxyServer: 'http=127.0.0.1:8888;https=127.0.0.1:8889;ftp=127.0.0.1:8890;socks=127.0.0.1:8891', 67 | bypassLocal: false, 68 | bypass: 'www.test;www.abc' 69 | }) 70 | .then(console.log.bind(console, '设置成功')) 71 | .catch(console.log.bind(console, '设置失败: ')); 72 | 73 | 74 | // 重置到修改前的设置 75 | lan.reset() 76 | .then(console.log.bind(console, '设置成功')) 77 | .catch(console.log.bind(console, '设置失败: ')); 78 | ``` 79 | 80 | 81 | ## 使用 (Callback) 82 | ```js 83 | const lan = require('lan-settings'); 84 | // 获取设备的所有可用 NetworkServices (macOS Only) 85 | lan.listNetworkServices(function(err, services) { 86 | console.log(err ? '获取失败' : '获取成功'); 87 | console.log(services); 88 | }); 89 | 90 | // 获取当前局域网设置信息,如果err非空,表示获取失败 91 | lan.getSettings(function(err, settings) { 92 | console.log(settings); 93 | // output: 94 | // { autoDetect: false, 95 | // autoConfig: false, 96 | // autoConfigUrl: '', 97 | // proxyEnable: true, 98 | // proxyServer: '127.0.0.1:8888', 99 | // bypassLocal: false, 100 | // bypass: '' } 101 | }); 102 | 103 | // 自动检测设置 104 | lan.setSettings({ autoDetect: true }, function(err) { 105 | console.log(err ? 'Fail' : 'Success'); 106 | }); 107 | 108 | // 开启并这种PAC脚本 109 | lan.setSettings({ 110 | autoConfig: true, 111 | autoConfigUrl: 'http://127.0.0.1:30001/' 112 | }, function(err) { 113 | console.log(err ? 'Fail' : 'Success'); 114 | }); 115 | 116 | // 开启并设置统一的代理服务器,开启本地代理白名单 117 | lan.setSettings({ 118 | proxyEnable: true, 119 | proxyServer: '127.0.0.1:8888', 120 | bypassLocal: true 121 | }, function(err) { 122 | console.log(err ? 'Fail' : 'Success'); 123 | }); 124 | 125 | // 高级设置,对http、https、ftp、socks分别设置不同的代理,并设置白名单域名前缀 126 | lan.setSettings({ 127 | proxyEnable: true, 128 | proxyServer: 'http=127.0.0.1:8888;https=127.0.0.1:8889;ftp=127.0.0.1:8890;socks=127.0.0.1:8891', 129 | bypassLocal: false, 130 | bypass: 'www.test;www.abc' 131 | }, function(err) { 132 | console.log(err ? 'Fail' : 'Success'); 133 | }); 134 | 135 | // 重置到修改前的设置 136 | lan.reset(function(err) { 137 | console.log(err ? 'Fail' : 'Success'); 138 | }); 139 | ``` 140 | 141 | 142 | 143 | ## API 144 | 145 | ### 注: networkservice 参数只适用于 macOS, 默认值为 "All", 即全部设置 146 | 147 | **lan.listNetworkServices([cb])**: 148 | 获取设备的所有可用 NetworkServices 149 | `cb(err)` 为可选回调函数,如果重置失败,则err不为空; (macOS only) 150 | 若不传入回调函数, 则返回 Promise 对象; 151 | 152 | ```js 153 | [ 'iPhone USB', 'Ethernet', 'Wi-Fi', 'Bluetooth PAN', 'Thunderbolt Bridge' ] 154 | ``` 155 | 156 | 157 | **lan.getSettings([cb, networkservice])**: 158 | 获取当前局域网设置信息 159 | 其中 `cb(err, settings)` 为可选回调函数,如果出错err不为空,否则settings为当前系统局域网设置信息; 160 | 若不传入回调函数, 则返回 Promise 对象; 161 | 162 | ```js 163 | { 164 | autoDetect: true, // 是否开启自动检查设置 165 | autoConfig: true, // 是否开启pac脚本 166 | autoConfigUrl: 'http://127.0.0.1:50011', // pac脚本的url 167 | proxyEnable: true, // 是否开启代理设置 168 | proxyServer: '127.0.0.1:8888', // 代理服务器ip和端口,如果使用高级设置,可能返回 `htt=127.0.0.1:8888;https=127.0.0.2:8889`等 169 | bypassLocal: true, // 是否启用对本地地址不使用代理 170 | bypass: 'www.test;www.abc' // 高级设置里面的白名单信息 171 | } 172 | ``` 173 | 174 | 175 | **lan.setSettings(settings, [cb, networkservice])**: 176 | 设置局域网信息 177 | settings如上,如果为null表示清空并关闭所有局域网设置项,`cb(err)` 为可选回调函数,如果设置失败,则err不为空。 178 | 若不传入回调函数, 则返回 Promise 对象; 179 | 180 | 181 | **lan.reset(cb[, networkservice])**: 182 | 将局域网设置重置到修改前 183 | `cb(err)` 为可选回调函数,如果重置失败,则err不为空。 184 | 若不传入回调函数, 则返回 Promise 对象; 185 | 186 | 187 | # License 188 | [MIT](https://github.com/imweb/lan-settings/blob/master/LICENSE) 189 | -------------------------------------------------------------------------------- /assets/settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imweb/lan-settings/c36e85da8f5ae9f728ad08ea639a6915556a52fa/assets/settings.png -------------------------------------------------------------------------------- /lib/darwin/index.js: -------------------------------------------------------------------------------- 1 | const { exec } = require('../utils'); 2 | const { 3 | parseInfo, 4 | callNetworkSetup, 5 | getSettingItems, 6 | } = require('./utils'); 7 | 8 | 9 | const proxyTypesMap = { 10 | // 网页代理 11 | http: 'webproxy', 12 | // 安全网页代理 13 | https: 'securewebproxy', 14 | }; 15 | 16 | const disableProxyTypesMap = { 17 | // FTP 代理 18 | ftp: 'ftpproxy', 19 | // Socks5 代理 20 | socks: 'socksfirewallproxy', 21 | // 流代理 22 | stream: 'streamingproxy', 23 | // Gopher 代理 24 | gopher: 'gopherproxy', 25 | }; 26 | 27 | const proxyTypes = Object.assign({}, proxyTypesMap, disableProxyTypesMap); 28 | 29 | let hadInited = false; 30 | let defaultWiFiSettings; 31 | let defaultEthernetSettings; 32 | let defaultUsbSettings; 33 | let networkServices; 34 | 35 | 36 | function multiClose(types, networkservice) { 37 | return Promise.all(Object.keys(types) 38 | .map(async (type) => { 39 | await callNetworkSetup(`set${types[type]}state`, 'off', networkservice); 40 | }) 41 | ); 42 | } 43 | 44 | async function listNetworkServices() { 45 | return (await exec('networksetup -listallnetworkservices')) 46 | .split('\n') 47 | .filter(i => i.trim() && !i.includes('*')) 48 | .filter(i => !['Bluetooth PAN', 'Thunderbolt Bridge', 'iPhone USB'].includes(i)); 49 | } 50 | 51 | async function getSettings(networkservice) { 52 | if (networkservice === 'All') { 53 | // 插上网线时, Wi-Fi 不生效, 直接获取 Ethernet 配置 54 | if (networkServices.includes('Ethernet')) { 55 | return await getSettings('Ethernet'); 56 | } 57 | return await getSettings('Wi-Fi'); 58 | } 59 | const settings = {}; 60 | settings.autoDetect = (await getSettingItems('getproxyautodiscovery', [], networkservice)) === 'On'; 61 | 62 | const autoProxy = await getSettingItems('getautoproxyurl', ['URL', 'Enabled'], networkservice); 63 | settings.autoConfig = autoProxy[1] === 'Yes'; 64 | const autoConfigUrl = autoProxy[0].trim(); 65 | if (autoConfigUrl && autoConfigUrl !== '(null)') { 66 | settings.autoConfigUrl = autoConfigUrl; 67 | } else { 68 | settings.autoConfigUrl = ''; 69 | } 70 | 71 | const bypass = (await callNetworkSetup('getproxybypassdomains', '', networkservice)).trim(); 72 | if (bypass !== `There aren't any bypass domains set on ${networkservice}.`) { 73 | settings.bypass = bypass.replace(/\n/g, ';'); 74 | } 75 | 76 | settings.proxies = {}; 77 | settings.proxyEnable = false; 78 | settings.proxyServer = ''; 79 | await Promise.all( 80 | Object.keys(proxyTypes) 81 | .map(async (type) => { 82 | try { 83 | const info = parseInfo(await callNetworkSetup(`get${proxyTypes[type]}`, '', networkservice)); 84 | if (info.Enabled === 'Yes') { 85 | const server = `${info.Server}:${info.Port}`; 86 | settings.proxies[`${type}ProxyEnable`] = true; 87 | settings.proxies[`${type}ProxyServer`] = server; 88 | settings.proxyEnable = true; 89 | settings.proxyServer += `${type}=${server};`; 90 | } else { 91 | settings.proxies[`${type}ProxyEnable`] = false; 92 | } 93 | } catch (e) {} 94 | }) 95 | ); 96 | 97 | return settings; 98 | } 99 | 100 | async function init() { 101 | if (!networkServices) { 102 | networkServices = await listNetworkServices(); 103 | } 104 | let wifi; 105 | if (networkServices.includes('Wi-Fi')) { 106 | wifi = await getSettings('Wi-Fi'); 107 | } 108 | let ether; 109 | if (networkServices.includes('Ethernet')) { 110 | ether = await getSettings('Ethernet'); 111 | } 112 | let usb; 113 | let usbName; 114 | networkServices.forEach((name) => { 115 | if (name.includes('USB')) { 116 | usbName = name; 117 | } 118 | }); 119 | if (usbName) { 120 | usb = await getSettings(usbName); 121 | } 122 | if (hadInited) { 123 | return; 124 | } 125 | hadInited = true; 126 | defaultWiFiSettings = wifi; 127 | defaultEthernetSettings = ether; 128 | defaultUsbSettings = usb; 129 | } 130 | 131 | async function setSettings(settings, networkservice) { 132 | if (!(defaultWiFiSettings || defaultEthernetSettings || defaultUsbSettings)) { 133 | await init(); 134 | } 135 | if (networkservice === 'All') { 136 | return await Promise.all(networkServices.map(setSettings.bind(null, settings))); 137 | } 138 | 139 | if ('autoDetect' in settings) { 140 | await callNetworkSetup( 141 | 'setproxyautodiscovery', 142 | settings.autoDetect ? 'on' : 'off', 143 | networkservice 144 | ); 145 | } 146 | if (settings.autoConfig) { 147 | await callNetworkSetup('setautoproxystate', 'on', networkservice); 148 | if (settings.autoConfigUrl.trim()) { 149 | await callNetworkSetup( 150 | 'setautoproxyurl', 151 | settings.autoConfigUrl, 152 | networkservice 153 | ); 154 | } 155 | } else { 156 | await callNetworkSetup('setautoproxystate', 'off', networkservice); 157 | } 158 | if ('bypass' in settings && settings.bypass.trim()) { 159 | await callNetworkSetup( 160 | 'setproxybypassdomains', 161 | settings.bypass.split(';').join(' '), 162 | networkservice 163 | ); 164 | } 165 | if (settings.proxyEnable) { 166 | // 启用 167 | if (settings.proxyServer.includes('=')) { 168 | // 分别设置 169 | await multiClose(proxyTypes, networkservice); 170 | await Promise.all(settings.proxyServer 171 | .split(';') 172 | .filter(s => s.trim()) 173 | .reduce((servers, item) => { 174 | const [key, value] = item.split('=').map(s => s.trim()); 175 | servers.push([key].concat(value.split(':'))); 176 | return servers; 177 | }, []) 178 | .map(async (item) => { 179 | // item: [type, address, port] 180 | const [type, address, port] = item; 181 | await callNetworkSetup(`set${proxyTypes[type]}state`, 'On', networkservice); 182 | await callNetworkSetup(`set${proxyTypes[type]}`, `${address} ${port}`, networkservice); 183 | }) 184 | ); 185 | } else { 186 | // 统一设置 187 | const [address, port] = settings.proxyServer.split(':'); 188 | await Promise.all(Object.keys(proxyTypesMap) 189 | .map(async (type) => { 190 | await callNetworkSetup(`set${proxyTypesMap[type]}state`, 'on', networkservice); 191 | await callNetworkSetup(`set${proxyTypesMap[type]}`, `${address} ${port}`, networkservice); 192 | }) 193 | ); 194 | await multiClose(disableProxyTypesMap, networkservice); 195 | } 196 | } else if (settings.proxyEnable === false) { 197 | await Promise.all(Object.keys(proxyTypesMap) 198 | .map(type => 199 | callNetworkSetup(`set${proxyTypesMap[type]}state`, 'off', networkservice) 200 | ) 201 | ); 202 | } 203 | } 204 | 205 | async function reset(networkservice) { 206 | if (!(defaultWiFiSettings || defaultEthernetSettings || defaultUsbSettings)) { 207 | await init(); 208 | } 209 | if (networkservice === 'All') { 210 | return await Promise.all(networkServices.map(reset)); 211 | } 212 | let defaultSettings; 213 | switch (networkservice) { 214 | case 'Wi-Fi': defaultSettings = defaultWiFiSettings; break; 215 | case 'Ethernet': defaultSettings = defaultEthernetSettings; break; 216 | default: { 217 | if (networkservice.includes('USB')) { 218 | defaultSettings = defaultUsbSettings; 219 | } 220 | } 221 | } 222 | if (defaultSettings) { 223 | return await setSettings(defaultSettings, networkservice); 224 | } 225 | } 226 | 227 | 228 | module.exports = { 229 | listNetworkServices: async (cb) => { 230 | if (typeof cb === 'function') { 231 | try { 232 | return cb(null, await listNetworkServices()); 233 | } catch (e) { 234 | return cb(e, null); 235 | } 236 | } 237 | /** 238 | * 不传入 callback, 使用 Promise 239 | */ 240 | return await listNetworkServices(); 241 | }, 242 | getSettings: async (cb, networkservice = 'All') => { 243 | if (!(defaultWiFiSettings || defaultEthernetSettings || defaultUsbSettings)) { 244 | await init(); 245 | } 246 | if (typeof cb === 'function') { 247 | try { 248 | return cb(null, await getSettings(networkservice)); 249 | } catch (e) { 250 | return cb(e, null); 251 | } 252 | } 253 | /** 254 | * 不传入 callback, 使用 Promise 255 | */ 256 | networkservice = typeof cb === 'string' ? cb : networkservice; 257 | return await getSettings(networkservice); 258 | }, 259 | setSettings: async (settings, cb, networkservice = 'All') => { 260 | if (typeof cb === 'function') { 261 | try { 262 | await setSettings(settings, networkservice); 263 | return cb(null); 264 | } catch (e) { 265 | return cb(e); 266 | } 267 | } 268 | /** 269 | * 不传入 callback, 使用 Promise 270 | */ 271 | networkservice = typeof cb === 'string' ? cb : networkservice; 272 | return await setSettings(settings, networkservice); 273 | }, 274 | reset: async (cb, networkservice = 'All') => { 275 | if (typeof cb === 'function') { 276 | try { 277 | await reset(networkservice); 278 | return cb(null); 279 | } catch (e) { 280 | return cb(e); 281 | } 282 | } 283 | /** 284 | * 不传入 callback, 使用 Promise 285 | */ 286 | networkservice = typeof cb === 'string' ? cb : networkservice; 287 | return await reset(networkservice); 288 | }, 289 | }; 290 | 291 | 292 | init(); 293 | -------------------------------------------------------------------------------- /lib/darwin/utils.js: -------------------------------------------------------------------------------- 1 | 2 | const { exec } = require('../utils'); 3 | 4 | 5 | function parseInfo(data) { 6 | return data 7 | .split('\n') 8 | .map(i => i.split(': ')) 9 | .reduce((info, item) => { 10 | if (item.length < 2) { return info; } 11 | const [key, value] = item.map(i => i.trim().replace(/\s+/g, '-')); 12 | info[key] = value; 13 | return info; 14 | }, {}); 15 | } 16 | 17 | function callNetworkSetup(type, args, networkservice) { 18 | const command = `networksetup -${type} "${networkservice}" ${args}`; 19 | return exec(command); 20 | } 21 | 22 | async function getSettingItems(arg, keys, networkservice) { 23 | const info = parseInfo(await callNetworkSetup(arg, '', networkservice)); 24 | if (!keys || keys.length === 0) { return info[Object.keys(info)[0]]; } 25 | if (typeof keys === 'string') { return info[keys]; } 26 | 27 | if (keys.length === 1) { return info[keys[0]]; } 28 | return keys.map(key => info[key]); 29 | } 30 | 31 | 32 | module.exports = { 33 | parseInfo, 34 | callNetworkSetup, 35 | getSettingItems, 36 | }; 37 | -------------------------------------------------------------------------------- /lib/index.js: -------------------------------------------------------------------------------- 1 | 2 | const path = require('path'); 3 | const platform = require('os').platform(); 4 | 5 | /* eslint-disable import/no-dynamic-require */ 6 | module.exports = require(path.join(__dirname, platform)); 7 | -------------------------------------------------------------------------------- /lib/linux/index.js: -------------------------------------------------------------------------------- 1 | 2 | throw new Error('Platform linux is unsupported for now!'); 3 | -------------------------------------------------------------------------------- /lib/utils.js: -------------------------------------------------------------------------------- 1 | 2 | const cp = require('child_process'); 3 | 4 | 5 | function exec(command) { 6 | return new Promise((resolve, reject) => { 7 | cp.exec(command, (error, stdout, stderr) => { 8 | if (error) { 9 | reject(error); 10 | } else if (stderr) { 11 | reject(stderr); 12 | } else { 13 | resolve(stdout); 14 | } 15 | }); 16 | }); 17 | } 18 | 19 | 20 | module.exports = { 21 | exec, 22 | }; 23 | -------------------------------------------------------------------------------- /lib/win32/index.js: -------------------------------------------------------------------------------- 1 | const regedit = require('regedit'); 2 | const util = require('./util'); 3 | 4 | 5 | const SETTINGS_PATH = 'HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings\\Connections'; 6 | const SETTINGS_KEY = 'DefaultConnectionSettings'; 7 | 8 | 9 | let defaultConnectionSettings; 10 | 11 | function getSettings() { 12 | return new Promise((resolve, reject) => { 13 | regedit.list(SETTINGS_PATH, (err, result) => { 14 | if (err) { 15 | return reject(err); 16 | } 17 | result = result && result[SETTINGS_PATH]; 18 | result = result && result.values; 19 | result = result && result[SETTINGS_KEY]; 20 | resolve(util.parseSettings(result && result.value)); 21 | }); 22 | }); 23 | } 24 | 25 | function setSettingValue(value) { 26 | return new Promise((resolve, reject) => { 27 | const valueToPut = {}; 28 | valueToPut[SETTINGS_PATH] = {}; 29 | valueToPut[SETTINGS_PATH][SETTINGS_KEY] = { 30 | type: 'REG_BINARY', 31 | value: util.toRegBinary(value), 32 | }; 33 | regedit.putValue(valueToPut, (err, result) => { 34 | if (err) { 35 | return reject(err); 36 | } 37 | return resolve(result); 38 | }); 39 | }); 40 | } 41 | 42 | async function init() { 43 | defaultConnectionSettings = await getSettings(); 44 | } 45 | 46 | module.exports = { 47 | listNetworkServices: () => { 48 | throw new Error('listNetworkServices is unsupported on win32 platform!'); 49 | }, 50 | getSettings: async (cb) => { 51 | if (!defaultConnectionSettings) { 52 | await init(); 53 | } 54 | if (typeof cb === 'function') { 55 | try { 56 | return cb(null, await getSettings()); 57 | } catch (e) { 58 | return cb(e, null); 59 | } 60 | } 61 | /** 62 | * 不传入 callback, 使用 Promise 63 | */ 64 | return await getSettings(); 65 | }, 66 | setSettings: async (settings, cb) => { 67 | if (!defaultConnectionSettings) { 68 | await init(); 69 | } 70 | if (typeof cb === 'function') { 71 | try { 72 | return cb(null, await setSettingValue(settings)); 73 | } catch (e) { 74 | return cb(e, null); 75 | } 76 | } 77 | /** 78 | * 不传入 callback, 使用 Promise 79 | */ 80 | return await setSettingValue(settings); 81 | }, 82 | reset: async (cb) => { 83 | if (!defaultConnectionSettings) { 84 | return; 85 | } 86 | if (typeof cb === 'function') { 87 | try { 88 | return cb(null, await setSettingValue(defaultConnectionSettings)); 89 | } catch (e) { 90 | return cb(e, null); 91 | } 92 | } 93 | /** 94 | * 不传入 callback, 使用 Promise 95 | */ 96 | return await setSettingValue(defaultConnectionSettings); 97 | }, 98 | }; 99 | -------------------------------------------------------------------------------- /lib/win32/util.js: -------------------------------------------------------------------------------- 1 | 2 | const DEFAULT_SETTINGS = [70, 0, 0, 0, 0, 0, 0, 0]; 3 | const SEP = [0, 0, 0]; 4 | const MIN_LENGTH = 4; 5 | 6 | const PROXY_SERVER_FLAG = 3; 7 | const AUTOCONFIG_FLAG = 5; 8 | const AUTODETECT_FLAG = 9; 9 | 10 | exports.DEFAULT_SETTINGS = DEFAULT_SETTINGS; 11 | /* eslint-disable no-bitwise */ 12 | function parseFlags(result, flags) { 13 | result.autoDetect = (flags & AUTODETECT_FLAG) === AUTODETECT_FLAG; 14 | result.autoConfig = (flags & AUTOCONFIG_FLAG) === AUTOCONFIG_FLAG; 15 | result.proxyEnable = (flags & PROXY_SERVER_FLAG) === PROXY_SERVER_FLAG; 16 | } 17 | 18 | function parseValue(value, isList) { 19 | if (!value || !value.length) { 20 | return ''; 21 | } 22 | value = new Buffer(value).toString(); 23 | value = value.replace(/\s+/g, ''); 24 | if (!value || !isList) { 25 | return value; 26 | } 27 | return value.toLowerCase().split(';'); 28 | } 29 | 30 | function parseBypass(result, bypass) { 31 | bypass = parseValue(bypass, true); 32 | const index = bypass.indexOf(''); 33 | if (index !== -1) { 34 | bypass.splice(index, 1); 35 | result.bypassLocal = true; 36 | result.bypass = bypass.join(';'); 37 | } 38 | return result; 39 | } 40 | 41 | exports.parseSettings = function (value) { 42 | value = Array.isArray(value) ? value.slice(DEFAULT_SETTINGS.length) : null; 43 | const result = { 44 | autoDetect: false, 45 | autoConfig: false, 46 | autoConfigUrl: '', 47 | proxyEnable: false, 48 | proxyServer: '', 49 | bypassLocal: false, 50 | bypass: '', 51 | }; 52 | if (!value || !value.length) { 53 | return result; 54 | } 55 | parseFlags(result, value[0]); 56 | value = value.slice(MIN_LENGTH); 57 | if (value.length <= MIN_LENGTH) { 58 | return result; 59 | } 60 | 61 | let end = MIN_LENGTH + value[0]; 62 | result.proxyServer = parseValue(value.slice(MIN_LENGTH, end)); 63 | value = value.slice(end); 64 | if (value.length <= MIN_LENGTH) { 65 | return result; 66 | } 67 | 68 | end = MIN_LENGTH + value[0]; 69 | parseBypass(result, value.slice(MIN_LENGTH, end)); 70 | value = value.slice(end); 71 | if (value.length <= MIN_LENGTH) { 72 | return result; 73 | } 74 | end = MIN_LENGTH + value[0]; 75 | result.autoConfigUrl = parseValue(value.slice(MIN_LENGTH, end)); 76 | return result; 77 | }; 78 | 79 | function toBinaryArray(value) { 80 | const result = [0].concat(SEP); 81 | if (value && typeof value === 'string') { 82 | value = new Buffer(value); 83 | let len = value.length; 84 | if (len > 255) { 85 | len = 255; 86 | value = value.slice(0, 255); 87 | } 88 | result[0] = len; 89 | result.push(...value); 90 | } 91 | return result; 92 | } 93 | 94 | exports.toRegBinary = function (settings) { 95 | if (!settings) { 96 | return DEFAULT_SETTINGS; 97 | } 98 | let flags = 0; 99 | if (settings.autoDetect) { 100 | flags |= AUTODETECT_FLAG; 101 | } 102 | if (settings.autoConfig) { 103 | flags |= AUTOCONFIG_FLAG; 104 | } 105 | if (settings.proxyEnable) { 106 | flags |= PROXY_SERVER_FLAG; 107 | } 108 | let result = DEFAULT_SETTINGS.concat([flags]).concat(SEP); 109 | let bypass = String(settings.bypass || ''); 110 | if (settings.bypassLocal) { 111 | bypass += ';'; 112 | } 113 | result = result.concat(toBinaryArray(settings.proxyServer)); 114 | result = result.concat(toBinaryArray(bypass)); 115 | return result.concat(toBinaryArray(settings.autoConfigUrl)); 116 | }; 117 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "lan-settings", 3 | "version": "1.0.0", 4 | "description": "LAN settings", 5 | "main": "lib/index.js", 6 | "keywords": [ 7 | "lan", 8 | "settings", 9 | "pac", 10 | "proxy" 11 | ], 12 | "homepage": "https://github.com/imweb/lan-settings", 13 | "repository": { 14 | "type": "git", 15 | "url": "https://github.com/imweb/lan-settings.git" 16 | }, 17 | "author": "avenwu ", 18 | "license": "MIT", 19 | "optionalDependencies": { 20 | "regedit": "^2.2.7" 21 | }, 22 | "devDependencies": { 23 | "babel-eslint": "10.0.3", 24 | "eslint": "^5.3.0", 25 | "eslint-config-imweb": "^0.2.19" 26 | }, 27 | "scripts": { 28 | "lint": "eslint ./lib ./test", 29 | "lintfix": "eslint --fix ./lib ./test" 30 | }, 31 | "engines": { 32 | "node": ">= 7.6" 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /test/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "rules": { 3 | "no-console": 0 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /test/all.test.cb.js: -------------------------------------------------------------------------------- 1 | const lan = require('../lib'); 2 | 3 | 4 | const settings = { 5 | autoDetect: true, 6 | autoConfig: true, 7 | autoConfigUrl: 'http://127.0.0.1:50011', 8 | proxyEnable: true, 9 | proxyServer: '127.0.0.1:8888', 10 | bypassLocal: true, 11 | bypass: 'www.test', 12 | }; 13 | 14 | 15 | lan.setSettings(settings, (err) => { 16 | console.log(err); 17 | console.log(err ? '设置失败' : '设置成功'); 18 | }); 19 | -------------------------------------------------------------------------------- /test/all.test.js: -------------------------------------------------------------------------------- 1 | const lan = require('../lib'); 2 | 3 | 4 | const settings = { 5 | autoDetect: true, 6 | autoConfig: true, 7 | autoConfigUrl: 'http://127.0.0.1:50011', 8 | proxyEnable: true, 9 | proxyServer: '127.0.0.1:8888', 10 | bypassLocal: true, 11 | bypass: 'www.test', 12 | }; 13 | 14 | 15 | lan.setSettings(settings) 16 | .then(console.log.bind(console, '设置成功')) 17 | .catch(console.log.bind(console, '设置失败')); 18 | -------------------------------------------------------------------------------- /test/autoConfig.test.cb.js: -------------------------------------------------------------------------------- 1 | const lan = require('../lib'); 2 | 3 | 4 | const settings = { 5 | autoConfig: true, 6 | autoConfigUrl: 'http://127.0.0.1:50011', 7 | }; 8 | 9 | 10 | lan.setSettings(settings, (err) => { 11 | console.log(err ? '设置失败' : '设置成功'); 12 | }); 13 | -------------------------------------------------------------------------------- /test/autoConfig.test.js: -------------------------------------------------------------------------------- 1 | const lan = require('../lib'); 2 | 3 | 4 | const settings = { 5 | autoConfig: true, 6 | autoConfigUrl: 'http://127.0.0.1:50011', 7 | }; 8 | 9 | 10 | lan.setSettings(settings) 11 | .then(console.log.bind(console, '设置成功')) 12 | .catch(console.log.bind(console, '设置失败')); 13 | -------------------------------------------------------------------------------- /test/autoDetect.test.js: -------------------------------------------------------------------------------- 1 | const lan = require('../lib'); 2 | 3 | 4 | const settings = { 5 | autoDetect: true, 6 | }; 7 | 8 | 9 | lan.setSettings(settings) 10 | .then(console.log.bind(console, '设置成功')) 11 | .catch(console.log.bind(console, '设置失败')); 12 | -------------------------------------------------------------------------------- /test/autoDetect.text.cb.js: -------------------------------------------------------------------------------- 1 | const lan = require('../lib'); 2 | 3 | 4 | const settings = { 5 | autoDetect: true, 6 | }; 7 | 8 | 9 | lan.setSettings(settings, (err) => { 10 | console.log(err ? '设置失败' : '设置成功'); 11 | }); 12 | -------------------------------------------------------------------------------- /test/bypass.test.cb.js: -------------------------------------------------------------------------------- 1 | const lan = require('../lib'); 2 | 3 | 4 | const settings = { 5 | bypassLocal: true, 6 | bypass: 'www.test.com;www.test1.com', 7 | }; 8 | 9 | 10 | lan.setSettings(settings, (err) => { 11 | console.log(err ? '设置失败' : '设置成功'); 12 | }); 13 | -------------------------------------------------------------------------------- /test/bypass.test.js: -------------------------------------------------------------------------------- 1 | const lan = require('../lib'); 2 | 3 | 4 | const settings = { 5 | bypassLocal: true, 6 | bypass: 'www.test.com;www.test1.com', 7 | }; 8 | 9 | 10 | lan.setSettings(settings) 11 | .then(console.log.bind(console, '设置成功')) 12 | .catch(console.log.bind(console, '设置失败')); 13 | -------------------------------------------------------------------------------- /test/get.test.cb.js: -------------------------------------------------------------------------------- 1 | const lan = require('../lib'); 2 | 3 | 4 | lan.getSettings((err, settings) => { 5 | if (err) { 6 | console.log('获取失败'); 7 | } else { 8 | console.log(settings); 9 | } 10 | // output: 11 | // { autoDetect: false, 12 | // autoConfig: false, 13 | // autoConfigUrl: '', 14 | // proxyEnable: true, 15 | // proxyServer: '127.0.0.1:8888', 16 | // bypassLocal: false, 17 | // bypass: '' } 18 | }); 19 | -------------------------------------------------------------------------------- /test/get.test.js: -------------------------------------------------------------------------------- 1 | const lan = require('../lib'); 2 | 3 | 4 | lan.getSettings() 5 | .then(console.log.bind(console)) 6 | .catch(console.log.bind(console, '获取失败')); 7 | -------------------------------------------------------------------------------- /test/listNetworkServices.test.cb.js: -------------------------------------------------------------------------------- 1 | const lan = require('../lib'); 2 | 3 | 4 | lan.listNetworkServices((err, services) => { 5 | console.log(err ? '获取失败' : '获取成功'); 6 | console.log(services); 7 | }); 8 | -------------------------------------------------------------------------------- /test/listNetworkServices.test.js: -------------------------------------------------------------------------------- 1 | const lan = require('../lib'); 2 | 3 | 4 | lan.listNetworkServices() 5 | .then(console.log.bind(console, '获取成功')) 6 | .catch(console.log.bind(console, '获取失败')); 7 | -------------------------------------------------------------------------------- /test/proxyServer.test.cb.js: -------------------------------------------------------------------------------- 1 | const lan = require('../lib'); 2 | 3 | 4 | const settings = { 5 | proxyEnable: true, 6 | // proxyServer: '127.0.0.1:8888' 7 | proxyServer: 'http=127.0.0.1:8888;https=127.0.0.1:8889;ftp=127.0.0.1:8890;socks=127.0.0.1:8891', 8 | }; 9 | 10 | 11 | lan.setSettings(settings, (err) => { 12 | console.log(err ? '设置失败' : '设置成功'); 13 | }); 14 | -------------------------------------------------------------------------------- /test/proxyServer.test.js: -------------------------------------------------------------------------------- 1 | const lan = require('../lib'); 2 | 3 | 4 | const settings = { 5 | proxyEnable: true, 6 | // proxyServer: '127.0.0.1:8888' 7 | proxyServer: 'http=127.0.0.1:8888;https=127.0.0.1:8889;ftp=127.0.0.1:8890;socks=127.0.0.1:8891', 8 | }; 9 | 10 | 11 | lan.setSettings(settings) 12 | .then(console.log.bind(console, '设置成功')) 13 | .catch(console.log.bind(console, '设置失败')); 14 | -------------------------------------------------------------------------------- /test/reset.test.cb.js: -------------------------------------------------------------------------------- 1 | const lan = require('../lib'); 2 | 3 | 4 | const settings = { 5 | autoDetect: true, 6 | autoConfig: true, 7 | autoConfigUrl: 'http://127.0.0.1:50011', 8 | proxyEnable: true, 9 | proxyServer: '127.0.0.1:8888', 10 | bypassLocal: true, 11 | bypass: 'www.test', 12 | }; 13 | 14 | 15 | lan.setSettings(settings, (err) => { 16 | if (err) { 17 | console.log('设置失败'); 18 | } else { 19 | console.log('设置成功'); 20 | setTimeout(() => { 21 | lan.reset((e) => { 22 | console.log(e ? '重置失败' : '重置成功'); 23 | }); 24 | }, 1000); 25 | } 26 | }); 27 | -------------------------------------------------------------------------------- /test/reset.test.js: -------------------------------------------------------------------------------- 1 | const lan = require('../lib'); 2 | 3 | 4 | const settings = { 5 | autoDetect: true, 6 | autoConfig: true, 7 | autoConfigUrl: 'http://127.0.0.1:50011', 8 | proxyEnable: true, 9 | proxyServer: '127.0.0.1:8888', 10 | bypassLocal: true, 11 | bypass: 'www.test', 12 | }; 13 | 14 | 15 | lan.setSettings(settings) 16 | .then(() => { 17 | console.log('设置成功'); 18 | setTimeout(() => { 19 | lan.reset() 20 | .then(console.log.bind(console, '重置成功')) 21 | .catch(console.log.bind(console, '重置失败')); 22 | }, 1000); 23 | }) 24 | .catch(console.log.bind(console, '设置失败')); 25 | --------------------------------------------------------------------------------