UNPKG

gattacker

Version:
400 lines (323 loc) 10.6 kB
/* jshint loopfunc: true */ var events = require('events'); var debug = require('debug')('slave'); var WebSocket = require('ws'); var noble = require('./index'); var serverMode = !process.argv[2]; var port = 0xB1e; var host = process.argv[2]; var ws; var wss; if (serverMode) { console.log('noble - ws slave - server mode'); wss = new WebSocket.Server({ port: 0xB1e }); wss.on('connection', function(ws_) { console.log('ws -> connection'); ws = ws_; sendEvent({ type: 'stateChange', state: noble.state }); ws.on('message', onMessage); ws.on('close', function() { console.log('ws -> close'); noble.stopScanning(); }); }); } else { ws = new WebSocket('ws://' + host + ':' + port); ws.on('open', function() { console.log('ws -> open'); }); ws.on('message', function(message) { onMessage(message); }); ws.on('close', function() { console.log('ws -> close'); noble.stopScanning(); }); } var peripherals = {}; // TODO: open/close ws on state change function sendEvent(event) { var message = JSON.stringify(event); console.log('ws -> send: ' + message); var clients = serverMode ? wss.clients : [ws]; for (var i = 0; i < clients.length; i++) { clients[i].send(message); } } var onMessage = function(message) { console.log('ws -> message: ' + message); var command = JSON.parse(message); var action = command.action; var peripheralUuid = command.peripheralUuid; var serviceUuids = command.serviceUuids; var serviceUuid = command.serviceUuid; var characteristicUuids = command.characteristicUuids; var characteristicUuid = command.characteristicUuid; var data = command.data ? new Buffer(command.data, 'hex') : null; var withoutResponse = command.withoutResponse; var broadcast = command.broadcast; var notify = command.notify; var descriptorUuid = command.descriptorUuid; var handle = handle; var peripheral = peripherals[peripheralUuid]; var service = null; var characteristic = null; var descriptor = null; if (peripheral && serviceUuid) { var services = peripheral.services; for (var i in services) { if (services[i].uuid === serviceUuid) { service = services[i]; if (characteristicUuid) { var characteristics = service.characteristics; for (var j in characteristics) { if (characteristics[j].uuid === characteristicUuid) { characteristic = characteristics[j]; if (descriptorUuid) { var descriptors = characteristic.descriptors; for (var k in descriptors) { if (descriptors[k].uuid === descriptorUuid) { descriptor = descriptors[k]; break; } } } break; } } } break; } } } if (action === 'startScanning') { noble.startScanning(serviceUuids, command.allowDuplicates); } else if (action === 'stopScanning') { noble.stopScanning(); } else if (action === 'connect') { peripheral.connect(); } else if (action === 'disconnect') { peripheral.disconnect(); } else if (action === 'updateRssi') { peripheral.updateRssi(); } else if (action === 'discoverServices') { peripheral.discoverServices(command.uuids); } else if (action === 'discoverIncludedServices') { service.discoverIncludedServices(serviceUuids); } else if (action === 'discoverCharacteristics') { service.discoverCharacteristics(characteristicUuids); } else if (action === 'read') { characteristic.read(); } else if (action === 'write') { characteristic.write(data, withoutResponse); } else if (action === 'broadcast') { characteristic.broadcast(broadcast); } else if (action === 'notify') { characteristic.notify(notify); } else if (action === 'discoverDescriptors') { characteristic.discoverDescriptors(); } else if (action === 'readValue') { descriptor.readValue(); } else if (action === 'writeValue') { descriptor.writeValue(data); } else if (action === 'readHandle') { peripheral.readHandle(handle); } else if (action === 'writeHandle') { peripheral.writeHandle(handle, data, withoutResponse); } }; noble.on('discover', function(peripheral) { peripherals[peripheral.uuid] = peripheral; peripheral.on('connect', function() { sendEvent({ type: 'connect', peripheralUuid: this.uuid }); }); peripheral.on('disconnect', function() { sendEvent({ type: 'disconnect', peripheralUuid: this.uuid }); for (var i in this.services) { for (var j in this.services[i].characteristics) { for (var k in this.services[i].characteristics[j].descriptors) { this.services[i].characteristics[j].descriptors[k].removeAllListeners(); } this.services[i].characteristics[j].removeAllListeners(); } this.services[i].removeAllListeners(); } this.removeAllListeners(); }); peripheral.on('rssiUpdate', function(rssi) { sendEvent({ type: 'rssiUpdate', peripheralUuid: this.uuid, rssi: rssi }); }); peripheral.on('servicesDiscover', function(services) { var peripheral = this; var serviceUuids = []; var includedServicesDiscover = function(includedServiceUuids) { sendEvent({ type: 'includedServicesDiscover', peripheralUuid: peripheral.uuid, serviceUuid: this.uuid, includedServiceUuids: includedServiceUuids }); }; var characteristicsDiscover = function(characteristics) { var service = this; var discoveredCharacteristics = []; var read = function(data, isNotification) { var characteristic = this; sendEvent({ type: 'read', peripheralUuid: peripheral.uuid, serviceUuid: service.uuid, characteristicUuid: characteristic.uuid, data: data.toString('hex'), isNotification: isNotification }); }; var write = function() { var characteristic = this; sendEvent({ type: 'write', peripheralUuid: peripheral.uuid, serviceUuid: service.uuid, characteristicUuid: characteristic.uuid }); }; var broadcast = function(state) { var characteristic = this; sendEvent({ type: 'broadcast', peripheralUuid: peripheral.uuid, serviceUuid: service.uuid, characteristicUuid: characteristic.uuid, state: state }); }; var notify = function(state) { var characteristic = this; sendEvent({ type: 'notify', peripheralUuid: peripheral.uuid, serviceUuid: service.uuid, characteristicUuid: characteristic.uuid, state: state }); }; var descriptorsDiscover = function(descriptors) { var characteristic = this; var discoveredDescriptors = []; var valueRead = function(data) { var descriptor = this; sendEvent({ type: 'valueRead', peripheralUuid: peripheral.uuid, serviceUuid: service.uuid, characteristicUuid: characteristic.uuid, descriptorUuid: descriptor.uuid, data: data.toString('hex') }); }; var valueWrite = function(data) { var descriptor = this; sendEvent({ type: 'valueWrite', peripheralUuid: peripheral.uuid, serviceUuid: service.uuid, characteristicUuid: characteristic.uuid, descriptorUuid: descriptor.uuid }); }; for (var k in descriptors) { descriptors[k].on('valueRead', valueRead); descriptors[k].on('valueWrite', valueWrite); discoveredDescriptors.push(descriptors[k].uuid); } sendEvent({ type: 'descriptorsDiscover', peripheralUuid: peripheral.uuid, serviceUuid: service.uuid, characteristicUuid: this.uuid, descriptors: discoveredDescriptors }); }; for (var j = 0; j < characteristics.length; j++) { characteristics[j].on('read', read); characteristics[j].on('write', write); characteristics[j].on('broadcast', broadcast); characteristics[j].on('notify', notify); characteristics[j].on('descriptorsDiscover', descriptorsDiscover); discoveredCharacteristics.push({ uuid: characteristics[j].uuid, properties: characteristics[j].properties }); } sendEvent({ type: 'characteristicsDiscover', peripheralUuid: peripheral.uuid, serviceUuid: this.uuid, characteristics: discoveredCharacteristics }); }; for (var i in services) { services[i].on('includedServicesDiscover', includedServicesDiscover); services[i].on('characteristicsDiscover', characteristicsDiscover); serviceUuids.push(services[i].uuid); } sendEvent({ type: 'servicesDiscover', peripheralUuid: this.uuid, serviceUuids: serviceUuids }); }); peripheral.on('handleRead', function(handle, data) { sendEvent({ type: 'handleRead', peripheralUuid: this.uuid, handle: handle, data: data.toString('hex') }); }); peripheral.on('handleWrite', function(handle) { sendEvent({ type: 'handleWrite', peripheralUuid: this.uuid, handle: handle }); }); peripheral.on('handleNotify', function(handle, data) { sendEvent({ type: 'handleNotify', peripheralUuid: this.uuid, handle: handle, data: data.toString('hex') }); }); sendEvent({ type: 'discover', peripheralUuid: peripheral.uuid, address: peripheral.address, addressType: peripheral.addressType, connectable: peripheral.connectable, advertisement: { localName: peripheral.advertisement.localName, txPowerLevel: peripheral.advertisement.txPowerLevel, serviceUuids: peripheral.advertisement.serviceUuids, manufacturerData: (peripheral.advertisement.manufacturerData ? peripheral.advertisement.manufacturerData.toString('hex') : null), serviceData: (peripheral.advertisement.serviceData ? peripheral.advertisement.serviceData.toString('hex') : null) }, rssi: peripheral.rssi }); });