diff --git a/lib/ble/index.js b/lib/ble/index.js index 5b6b5fc..3e27678 100644 --- a/lib/ble/index.js +++ b/lib/ble/index.js @@ -1,254 +1,230 @@ -'use strict' - +'use strict'; /** @module ble */ /** Bluetooth Low Energy module */ - -const util = require('util') -const os = require('os') - -const log = require('../log')('ble') -const wifi = require('../wifi') - -const DEVICE_NAME = process.env.DEVICE_NAME || 'intval3' -const SERVICE_ID = process.env.SERVICE_ID || 'intval3_ble' -const CHAR_ID = process.env.CHAR_ID || 'intval3char' -const WIFI_ID = process.env.WIFI_ID || 'wifichar' -const NETWORK = os.networkInterfaces() -const MAC = getMac() || spoofMac() - +const util = require('util'); +const os = require('os'); +const log = require('../log')('ble'); +const wifi = require('../wifi'); +const DEVICE_NAME = process.env.DEVICE_NAME || 'intval3'; +const SERVICE_ID = process.env.SERVICE_ID || 'intval3_ble'; +const CHAR_ID = process.env.CHAR_ID || 'intval3char'; +const WIFI_ID = process.env.WIFI_ID || 'wifichar'; +const NETWORK = os.networkInterfaces(); +const MAC = getMac() || spoofMac(); //Give the device a unique device name, needs to be in env -process.env.BLENO_DEVICE_NAME += '_' + MAC -const bleno = require('bleno') - - -let currentWifi = 'disconnected' -let currentAddr = null -let getState - -const chars = [] - +process.env.BLENO_DEVICE_NAME += '_' + MAC; +const bleno = require('bleno'); +let currentWifi = 'disconnected'; +let currentAddr = null; +let getState; +const chars = []; function createChar(name, uuid, prop, write, read) { - function characteristic () { - bleno.Characteristic.call(this, { - uuid : uuid, - properties: prop - }) - } - util.inherits(characteristic, bleno.Characteristic) - if (prop.indexOf('read') !== -1) { - //data, offset, withoutResponse, callback - characteristic.prototype.onReadRequest = read - } - if (prop.indexOf('write') !== -1) { - characteristic.prototype.onWriteRequest = write - } - chars.push(new characteristic()) + function characteristic() { + bleno.Characteristic.call(this, { + uuid: uuid, + properties: prop + }); + } + util.inherits(characteristic, bleno.Characteristic); + if (prop.indexOf('read') !== -1) { + //data, offset, withoutResponse, callback + characteristic.prototype.onReadRequest = read; + } + if (prop.indexOf('write') !== -1) { + characteristic.prototype.onWriteRequest = write; + } + chars.push(new characteristic()); } - -function createChars (onWrite, onRead) { - createChar('intval3', CHAR_ID, ['read', 'write'], onWrite, onRead) - createChar('wifi', WIFI_ID, ['read', 'write'], onWifiWrite, onWifiRead) +function createChars(onWrite, onRead) { + createChar('intval3', CHAR_ID, ['read', 'write'], onWrite, onRead); + createChar('wifi', WIFI_ID, ['read', 'write'], onWifiWrite, onWifiRead); } - -function onWifiWrite (data, offset, withoutResponse, callback) { - let result - let utf8 - let obj - let ssid - let pwd - if (offset) { - log.warn(`Offset scenario`) - result = bleno.Characteristic.RESULT_ATTR_NOT_LONG - return callback(result) - } - utf8 = data.toString('utf8') - obj = JSON.parse(utf8) - ssid = obj.ssid - pwd = obj.pwd - log.info(`connecting to AP`, { ssid : ssid }) - return wifi.createPSK(ssid, pwd, (err, hash, plaintext) => { - if (err) { - log.error('Error hashing wifi password', err) - result = bleno.Characteristic.RESULT_UNLIKELY_ERROR - return callback(result) - } - return wifi.setNetwork(ssid, plaintext, hash, (err, data) => { - if (err) { - log.error('Error configuring wifi', err) - result = bleno.Characteristic.RESULT_UNLIKELY_ERROR - return callback(result) - } - currentWifi = ssid - currentAddr = getIp() - log.info(`Connected to AP`, { ssid : ssid, ip : currentAddr }) - result = bleno.Characteristic.RESULT_SUCCESS - return callback(result) - }) - }) +function onWifiWrite(data, offset, withoutResponse, callback) { + let result; + let utf8; + let obj; + let ssid; + let pwd; + if (offset) { + log.warn(`Offset scenario`); + result = bleno.Characteristic.RESULT_ATTR_NOT_LONG; + return callback(result); + } + utf8 = data.toString('utf8'); + obj = JSON.parse(utf8); + ssid = obj.ssid; + pwd = obj.pwd; + log.info(`connecting to AP`, { ssid: ssid }); + return wifi.createPSK(ssid, pwd, (err, hash, plaintext) => { + if (err) { + log.error('Error hashing wifi password', err); + result = bleno.Characteristic.RESULT_UNLIKELY_ERROR; + return callback(result); + } + return wifi.setNetwork(ssid, plaintext, hash, (err, data) => { + if (err) { + log.error('Error configuring wifi', err); + result = bleno.Characteristic.RESULT_UNLIKELY_ERROR; + return callback(result); + } + currentWifi = ssid; + currentAddr = getIp(); + log.info(`Connected to AP`, { ssid: ssid, ip: currentAddr }); + result = bleno.Characteristic.RESULT_SUCCESS; + return callback(result); + }); + }); } - -function onWifiRead (offset, callback) { - let result = bleno.Characteristic.RESULT_SUCCESS - let wifiRes = {} - let data - wifi.list((err, list) => { - if (err) { - result = bleno.Characteristic.RESULT_UNLIKELY_ERROR - return callback(result) - } - wifiRes.available = list - wifiRes.current = currentWifi - wifiRes.ip = currentAddr - log.info('Discovered available APs', { found : list.length }) - data = new Buffer(JSON.stringify(wifiRes)) - callback(result, data.slice(offset, data.length)) - }) +function onWifiRead(offset, callback) { + let result = bleno.Characteristic.RESULT_SUCCESS; + let wifiRes = {}; + let data; + wifi.list((err, list) => { + if (err) { + result = bleno.Characteristic.RESULT_UNLIKELY_ERROR; + return callback(result); + } + wifiRes.available = list; + wifiRes.current = currentWifi; + wifiRes.ip = currentAddr; + log.info('Discovered available APs', { found: list.length }); + data = new Buffer(JSON.stringify(wifiRes)); + callback(result, data.slice(offset, data.length)); + }); } - -function getMac () { - const colonRe = new RegExp(':', 'g') - if (NETWORK && NETWORK.wlan0 && NETWORK.wlan0[0] && NETWORK.wlan0[0].mac) { - return NETWORK.wlan0[0].mac.replace(colonRe, '') - } - return undefined +function getMac() { + const colonRe = new RegExp(':', 'g'); + if (NETWORK && NETWORK.wlan0 && NETWORK.wlan0[0] && NETWORK.wlan0[0].mac) { + return NETWORK.wlan0[0].mac.replace(colonRe, ''); + } + return undefined; } - -function spoofMac () { - const fs = require('fs') - const FSPATH = require.resolve('uuid') - const IDFILE = os.homedir() + '/.intval3id' - let uuid - let UUIDPATH - let TMP - let MACTMP - let dashRe - delete require.cache[FSPATH] - if (fs.existsSync(IDFILE)) { - return fs.readFileSync(IDFILE, 'utf8') - } - uuid = require('uuid').v4 - UUIDPATH = require.resolve('uuid') - delete require.cache[UUIDPATH] - TMP = uuid() - MACTMP = TMP.replace(dashRe, '').substring(0, 12) - dashRe = new RegExp('-', 'g') - fs.writeFileSync(IDFILE, MACTMP, 'utf8') - return MACTMP +function spoofMac() { + const fs = require('fs'); + const FSPATH = require.resolve('uuid'); + const IDFILE = os.homedir() + '/.intval3id'; + let uuid; + let UUIDPATH; + let TMP; + let MACTMP; + let dashRe; + delete require.cache[FSPATH]; + if (fs.existsSync(IDFILE)) { + return fs.readFileSync(IDFILE, 'utf8'); + } + uuid = require('uuid').v4; + UUIDPATH = require.resolve('uuid'); + delete require.cache[UUIDPATH]; + TMP = uuid(); + MACTMP = TMP.replace(dashRe, '').substring(0, 12); + dashRe = new RegExp('-', 'g'); + fs.writeFileSync(IDFILE, MACTMP, 'utf8'); + return MACTMP; } - -function getIp () { - let addr = null - let ipv4 - const ifaces = os.networkInterfaces() - if (ifaces && ifaces.wlan0) { - ipv4 = ifaces.wlan0.filter(iface => { - if (iface.family === 'IPv4') { - return iface - } - }) - if (ipv4.length === 1) { - addr = ipv4[0].address - } - } - return addr +function getIp() { + let addr = null; + let ipv4; + const ifaces = os.networkInterfaces(); + if (ifaces && ifaces.wlan0) { + ipv4 = ifaces.wlan0.filter(iface => { + if (iface.family === 'IPv4') { + return iface; + } + }); + if (ipv4.length === 1) { + addr = ipv4[0].address; + } + } + return addr; } - - -function capitalize (s) { - return s[0].toUpperCase() + s.slice(1) +function capitalize(s) { + return s[0].toUpperCase() + s.slice(1); } - /** Class representing the bluetooth interface */ class BLE { - /** - * Establishes Bluetooth Low Energy services, accessible to process through this class - * - * @constructor - */ - constructor (bleGetState) { - log.info('Starting bluetooth service') - - getState = bleGetState - - bleno.on('stateChange', state => { - log.info('stateChange', { state : state }) - if (state === 'poweredOn') { - log.info('Starting advertising', { DEVICE_NAME, DEVICE_ID : process.env.BLENO_DEVICE_NAME }) - bleno.startAdvertising(DEVICE_NAME, [CHAR_ID]) - } else { - bleno.stopAdvertising() - } - }) - - bleno.on('advertisingStart', err => { - log.info('advertisingStart', { res : (err ? 'error ' + err : 'success') }) - createChars(this._onWrite.bind(this), this._onRead.bind(this)) - if (!err) { - bleno.setServices([ - new bleno.PrimaryService({ - uuid : SERVICE_ID, //hardcoded across panels - characteristics : chars - }) - ]) - } - }) - - bleno.on('accept', clientAddress => { - log.info('accept', { clientAddress : clientAddress }) - }) - - bleno.on('disconnect', clientAddress => { - log.info('disconnect', { clientAddress : clientAddress }) - }) - - wifi.getNetwork((err, ssid) => { - if (err) { - return log.error('wifi.getNetwork', err) - } - currentWifi = ssid - currentAddr = getIp() - log.info('wifi.getNetwork', {ssid : ssid, ip : currentAddr }) - }) - } - _onWrite (data, offset, withoutResponse, callback) { - let result = {} - let utf8 - let obj - let fn - if (offset) { - log.warn(`Offset scenario`) - result = bleno.Characteristic.RESULT_ATTR_NOT_LONG - return callback(result) - } - utf8 = data.toString('utf8') - obj = JSON.parse(utf8) - result = bleno.Characteristic.RESULT_SUCCESS - fn = `_on${capitalize(obj.type)}` - if (obj.type && this[fn]) { - return this[fn](obj, () => { - callback(result) - }) - } else { - return callback(result) - } - - } - _onRead (offset, callback) { - const result = bleno.Characteristic.RESULT_SUCCESS - const state = getState() - const data = new Buffer(JSON.stringify( state )) - callback(result, data.slice(offset, data.length)) - } - /** - * Binds functions to events that are triggered by BLE messages - * - * @param {string} eventName Name of the event to to bind - * @param {function} callback Invoked when the event is triggered - */ - on (eventName, callback) { - this[`_on${capitalize(eventName)}`] = callback - } - + /** + * Establishes Bluetooth Low Energy services, accessible to process through this class + * + * @constructor + */ + constructor(bleGetState) { + log.info('Starting bluetooth service'); + getState = bleGetState; + bleno.on('stateChange', state => { + log.info('stateChange', { state: state }); + if (state === 'poweredOn') { + log.info('Starting advertising', { DEVICE_NAME, DEVICE_ID: process.env.BLENO_DEVICE_NAME }); + bleno.startAdvertising(DEVICE_NAME, [CHAR_ID]); + } + else { + bleno.stopAdvertising(); + } + }); + bleno.on('advertisingStart', err => { + log.info('advertisingStart', { res: (err ? 'error ' + err : 'success') }); + createChars(this._onWrite.bind(this), this._onRead.bind(this)); + if (!err) { + bleno.setServices([ + new bleno.PrimaryService({ + uuid: SERVICE_ID, + characteristics: chars + }) + ]); + } + }); + bleno.on('accept', clientAddress => { + log.info('accept', { clientAddress: clientAddress }); + }); + bleno.on('disconnect', clientAddress => { + log.info('disconnect', { clientAddress: clientAddress }); + }); + wifi.getNetwork((err, ssid) => { + if (err) { + return log.error('wifi.getNetwork', err); + } + currentWifi = ssid; + currentAddr = getIp(); + log.info('wifi.getNetwork', { ssid: ssid, ip: currentAddr }); + }); + } + _onWrite(data, offset, withoutResponse, callback) { + let result = {}; + let utf8; + let obj; + let fn; + if (offset) { + log.warn(`Offset scenario`); + result = bleno.Characteristic.RESULT_ATTR_NOT_LONG; + return callback(result); + } + utf8 = data.toString('utf8'); + obj = JSON.parse(utf8); + result = bleno.Characteristic.RESULT_SUCCESS; + fn = `_on${capitalize(obj.type)}`; + if (obj.type && this[fn]) { + return this[fn](obj, () => { + callback(result); + }); + } + else { + return callback(result); + } + } + _onRead(offset, callback) { + const result = bleno.Characteristic.RESULT_SUCCESS; + const state = getState(); + const data = new Buffer(JSON.stringify(state)); + callback(result, data.slice(offset, data.length)); + } + /** + * Binds functions to events that are triggered by BLE messages + * + * @param {string} eventName Name of the event to to bind + * @param {function} callback Invoked when the event is triggered + */ + on(eventName, callback) { + this[`_on${capitalize(eventName)}`] = callback; + } } - -module.exports = BLE \ No newline at end of file +module.exports = BLE; +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/lib/ble/index.js.map b/lib/ble/index.js.map new file mode 100644 index 0000000..a8dc81c --- /dev/null +++ b/lib/ble/index.js.map @@ -0,0 +1 @@ +{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/ble/index.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/lib/wifi/index.js b/lib/wifi/index.js index 59a2766..dba95f0 100644 --- a/lib/wifi/index.js +++ b/lib/wifi/index.js @@ -1,209 +1,208 @@ -'use strict' - -const networkPattern = /network[\s\S]*?=[\s\S]*?{([\s\S]*?)}/gi -const quoteRe = new RegExp('"', 'g') - -const filePath = '/etc/wpa_supplicant/wpa_supplicant.conf' -const reconfigure = '/sbin/wpa_cli reconfigure' -const refresh = 'ip link set wlan0 down && ip link set wlan0 up' -const iwlist = '/sbin/iwlist wlan0 scanning | grep "ESSID:"' -const iwgetid = '/sbin/iwgetid' - -const log = require('../log')('wifi') -const exec = require('child_process').exec -const fs = require('fs') - -let _entry = null -let _ssid = null -let _cb = null - +'use strict'; +const networkPattern = /network[\s\S]*?=[\s\S]*?{([\s\S]*?)}/gi; +const quoteRe = new RegExp('"', 'g'); +const filePath = '/etc/wpa_supplicant/wpa_supplicant.conf'; +const reconfigure = '/sbin/wpa_cli reconfigure'; +const refresh = 'ip link set wlan0 down && ip link set wlan0 up'; +const iwlist = '/sbin/iwlist wlan0 scanning | grep "ESSID:"'; +const iwgetid = '/sbin/iwgetid'; +const log = require('../log')('wifi'); +const exec = require('child_process').exec; +const fs = require('fs'); +let _entry = null; +let _ssid = null; +let _cb = null; /** Class representing the wifi features */ class Wifi { - constructor () { - - } - /** - * List available wifi access points - * - * @param {function} callback Function which gets invoked after list is returned - */ - list (callback) { - exec(iwlist, (err, stdout, stderr) => { - if (err) { - console.error(err) - return callback(err) - } - const limit = 20; - const lines = stdout.split('\n') - let output = [] - let line - let i = 0 - for (let l of lines) { - line = l.replace('ESSID:', '').trim() - if (line !== '""' && i < limit) { - line = line.replace(quoteRe, '') - output.push(line) - } - i++ - } - output = output.filter(ap => { - if (ap !== '') return ap - }) - return callback(null, output) - }) - } - /** - * (internal function) Invoked after config file is read, - * then invokes file write on the config file - * - * @param {object} err (optional) Error object only present if problem reading config file - * @param {string} data Contents of the config file - */ - _readConfigCb (err, data) { - let parsed - let current - if (err) { - console.error(err) - return _cb(err) - } - parsed = this._parseConfig(data) - current = parsed.find(network => { - return network.ssid === _ssid - }) - if (typeof current !== 'undefined') { - data = data.replace(current.raw, _entry) - } else { - data += '\n\n' + _entry - } - _entry = null - fs.writeFile(filePath, data, 'utf8', this._writeConfigCb.bind(this)) - } - /** - * (internal function) Invoked after config file is written, - * then executes reconfiguration command - * - * @param {object} err (optional) Error object only present if problem writing config file - */ - _writeConfigCb (err) { - if (err) { - console.error(err) - return _cb(err) - } - exec(reconfigure, this._reconfigureCb.bind(this)) - } - /** - * (internal function) Invoked after reconfiguration command is complete - * - * @param {object} err (optional) Error object only present if configuration command fails - * @param {string} stdout Standard output from reconfiguration command - * @param {string} stderr Error output from command if fails - */ - _reconfigureCb (err, stdout, stderr) { - if (err) { - console.error(err) - return _cb(err) - } - console.log('Wifi reconfigured') - exec(refresh, this._refreshCb.bind(this)) - } - /** - * (internal function) Invoked after wifi refresh command is complete - * - * @param {object} err (optional) Error object only present if refresh command fails - * @param {string} stdout Standard output from refresh command - * @param {string} stderr Error output from command if fails - */ - _refreshCb (err, stdout, stderr) { - if (err) { - console.error(err) - return _cb(err) - } - console.log('Wifi refreshed') - _cb(null, { ssid : _ssid }) - _cb = () => {} - } - _parseConfig (str) { - const networks = [] - const lines = str.split('\n') - let network = {} - for (let line of lines) { - if (line.substring(0, 9) === 'network={') { - network = {} - network.raw = line - } else if (network.raw && line.indexOf('ssid=') !== -1) { - network.ssid = line.replace('ssid=', '').trim().replace(quoteRe, '') - if (network.raw) { - network.raw += '\n' + line - } - } else if (network.raw && line.substring(0, 1) === '}') { - network.raw += '\n' + line - networks.push(network) - network = {} - } else if (network.raw) { - network.raw += '\n' + line - } - } - return networks - } - /** - * Create sanitized wpa_supplicant.conf stanza for - * configuring wifi without storing plaintext passwords - * @example - * network={ - * ssid="YOUR_SSID" - * #psk="YOUR_PASSWORD" - * psk=6a24edf1592aec4465271b7dcd204601b6e78df3186ce1a62a31f40ae9630702 - * } - * - * @param {string} ssid SSID of wifi network - * @param {string} pwd Plaintext passphrase of wifi network - * @param {function} callback Function called after psk hash is generated - */ - createPSK (ssid, pwd, callback) { - const cmd = `wpa_passphrase '${ssid.replace(/'/g, `'\\''`)}' '${pwd.replace(/'/g, `'\\''`)}' | grep "psk="` - let lines - let hash - let plaintext - exec(cmd, (err, stdout, stderr) => { - if (err) { - return callback(err) - } - lines = stdout.replace('#psk=', '').split('psk=') - hash = lines[1] - plaintext = lines[0] - callback(null, hash.trim(), plaintext.trim()) - }) - } - /** - * Function which initializes the processes for adding a wifi access point authentication - * - * @param {string} ssid SSID of network to configure - * @param {string} pwd Password of access point, plaintext to be masked - * @param {string} hash Password/SSID of access point, securely hashed - * @param {function} callback Function invoked after process is complete, or fails - */ - setNetwork (ssid, pwd, hash, callback) { - let masked = pwd.split('').map(char => { return char !== '"' ? '*' : '"' }).join('') - _entry = `network={\n\tssid="${ssid}"\n\t#psk=${masked}\n\tpsk=${hash}\n}\n` - _cb = callback - _ssid = ssid - fs.readFile(filePath, 'utf8', this._readConfigCb.bind(this)) - } - /** - * Executes command which gets the currently connected network - * - * @param {function} callback Function which is invoked after command is completed - */ - getNetwork (callback) { - let output - exec(iwgetid, (err, stdout, stderr) => { - if (err) { - return callback(err) - } - output = stdout.split('ESSID:')[1].replace(quoteRe, '').trim() - callback(null, output) - }) - } + constructor() { + } + /** + * List available wifi access points + * + * @param {function} callback Function which gets invoked after list is returned + */ + list(callback) { + exec(iwlist, (err, stdout, stderr) => { + if (err) { + console.error(err); + return callback(err); + } + const limit = 20; + const lines = stdout.split('\n'); + let output = []; + let line; + let i = 0; + for (let l of lines) { + line = l.replace('ESSID:', '').trim(); + if (line !== '""' && i < limit) { + line = line.replace(quoteRe, ''); + output.push(line); + } + i++; + } + output = output.filter(ap => { + if (ap !== '') + return ap; + }); + return callback(null, output); + }); + } + /** + * (internal function) Invoked after config file is read, + * then invokes file write on the config file + * + * @param {object} err (optional) Error object only present if problem reading config file + * @param {string} data Contents of the config file + */ + _readConfigCb(err, data) { + let parsed; + let current; + if (err) { + console.error(err); + return _cb(err); + } + parsed = this._parseConfig(data); + current = parsed.find(network => { + return network.ssid === _ssid; + }); + if (typeof current !== 'undefined') { + data = data.replace(current.raw, _entry); + } + else { + data += '\n\n' + _entry; + } + _entry = null; + fs.writeFile(filePath, data, 'utf8', this._writeConfigCb.bind(this)); + } + /** + * (internal function) Invoked after config file is written, + * then executes reconfiguration command + * + * @param {object} err (optional) Error object only present if problem writing config file + */ + _writeConfigCb(err) { + if (err) { + console.error(err); + return _cb(err); + } + exec(reconfigure, this._reconfigureCb.bind(this)); + } + /** + * (internal function) Invoked after reconfiguration command is complete + * + * @param {object} err (optional) Error object only present if configuration command fails + * @param {string} stdout Standard output from reconfiguration command + * @param {string} stderr Error output from command if fails + */ + _reconfigureCb(err, stdout, stderr) { + if (err) { + console.error(err); + return _cb(err); + } + console.log('Wifi reconfigured'); + exec(refresh, this._refreshCb.bind(this)); + } + /** + * (internal function) Invoked after wifi refresh command is complete + * + * @param {object} err (optional) Error object only present if refresh command fails + * @param {string} stdout Standard output from refresh command + * @param {string} stderr Error output from command if fails + */ + _refreshCb(err, stdout, stderr) { + if (err) { + console.error(err); + return _cb(err); + } + console.log('Wifi refreshed'); + _cb(null, { ssid: _ssid }); + _cb = () => { }; + } + _parseConfig(str) { + const networks = []; + const lines = str.split('\n'); + let network = {}; + for (let line of lines) { + if (line.substring(0, 9) === 'network={') { + network = {}; + network.raw = line; + } + else if (network.raw && line.indexOf('ssid=') !== -1) { + network.ssid = line.replace('ssid=', '').trim().replace(quoteRe, ''); + if (network.raw) { + network.raw += '\n' + line; + } + } + else if (network.raw && line.substring(0, 1) === '}') { + network.raw += '\n' + line; + networks.push(network); + network = {}; + } + else if (network.raw) { + network.raw += '\n' + line; + } + } + return networks; + } + /** + * Create sanitized wpa_supplicant.conf stanza for + * configuring wifi without storing plaintext passwords + * @example + * network={ + * ssid="YOUR_SSID" + * #psk="YOUR_PASSWORD" + * psk=6a24edf1592aec4465271b7dcd204601b6e78df3186ce1a62a31f40ae9630702 + * } + * + * @param {string} ssid SSID of wifi network + * @param {string} pwd Plaintext passphrase of wifi network + * @param {function} callback Function called after psk hash is generated + */ + createPSK(ssid, pwd, callback) { + const cmd = `wpa_passphrase '${ssid.replace(/'/g, `'\\''`)}' '${pwd.replace(/'/g, `'\\''`)}' | grep "psk="`; + let lines; + let hash; + let plaintext; + exec(cmd, (err, stdout, stderr) => { + if (err) { + return callback(err); + } + lines = stdout.replace('#psk=', '').split('psk='); + hash = lines[1]; + plaintext = lines[0]; + callback(null, hash.trim(), plaintext.trim()); + }); + } + /** + * Function which initializes the processes for adding a wifi access point authentication + * + * @param {string} ssid SSID of network to configure + * @param {string} pwd Password of access point, plaintext to be masked + * @param {string} hash Password/SSID of access point, securely hashed + * @param {function} callback Function invoked after process is complete, or fails + */ + setNetwork(ssid, pwd, hash, callback) { + let masked = pwd.split('').map(char => { return char !== '"' ? '*' : '"'; }).join(''); + _entry = `network={\n\tssid="${ssid}"\n\t#psk=${masked}\n\tpsk=${hash}\n}\n`; + _cb = callback; + _ssid = ssid; + fs.readFile(filePath, 'utf8', this._readConfigCb.bind(this)); + } + /** + * Executes command which gets the currently connected network + * + * @param {function} callback Function which is invoked after command is completed + */ + getNetwork(callback) { + let output; + exec(iwgetid, (err, stdout, stderr) => { + if (err) { + return callback(err); + } + output = stdout.split('ESSID:')[1].replace(quoteRe, '').trim(); + callback(null, output); + }); + } } - -module.exports = new Wifi() \ No newline at end of file +module.exports = new Wifi(); +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/lib/wifi/index.js.map b/lib/wifi/index.js.map new file mode 100644 index 0000000..612d75a --- /dev/null +++ b/lib/wifi/index.js.map @@ -0,0 +1 @@ +{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/wifi/index.ts"],"names":[],"mappings":"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"} \ No newline at end of file