Socket
Socket
Sign inDemoInstall

unifi-events

Package Overview
Dependencies
55
Maintainers
1
Versions
16
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 0.4.3 to 2.0.0-beta.1

LICENSE

311

index.js

@@ -1,154 +0,199 @@

'use strict'
const url = require('url');
const EventEmitter = require('eventemitter2').EventEmitter2;
const WebSocket = require('ws');
const rp = require('request-promise');
const url = require('url')
const rp = require('request-promise')
const EventEmitter = require('events')
const WebSocket = require('@oznu/ws-connect')
module.exports = class UnifiEvents extends EventEmitter {
constructor (opts) {
super()
this.opts = opts
this.opts.site = this.opts.site || 'default'
this.userAgent = 'UniFi Events'
this.controller = url.parse(this.opts.controller)
this.jar = rp.jar()
this.rp = rp.defaults({
rejectUnauthorized: this.opts.rejectUnauthorized,
jar: this.jar,
headers: {
'User-Agent': this.userAgent
}
})
constructor(opts) {
super({
wildcard: true
});
// login and start listening
if (this.opts.listen !== false) {
this.connect()
this.opts = opts || {};
this.opts.host = this.opts.host || 'unifi';
this.opts.port = this.opts.port || 8443;
this.opts.username = this.opts.username || 'admin';
this.opts.password = this.opts.password || 'ubnt';
this.opts.site = this.opts.site || 'default';
this.opts.unifios = this.opts.unifios || false;
this.userAgent = 'node.js unifi-events UniFi Events';
this.controller = url.parse('https://' + this.opts.host + ':' + this.opts.port);
this.jar = rp.jar();
this.rp = rp.defaults({
rejectUnauthorized: !this.opts.insecure,
jar: this.jar,
headers: {
'User-Agent': this.userAgent
},
json: true
});
this.autoReconnectInterval = 5 * 1000;
this.connect();
}
// convenience emitters
this.helpers = {
'EVT_WU_Connected': 'connected',
'EVT_WU_Disconnected': 'disconnected',
'EVT_WG_Connected': 'connected',
'EVT_WG_Disconnected': 'disconnected',
'EVT_LU_CONNECTED': 'connected',
'EVT_LU_DISCONNECTED': 'disconnected',
'EVT_LG_CONNECTED': 'connected',
'EVT_LG_DISCONNECTED': 'disconnected'
connect(reconnect) {
this.isClosed = false;
return this._login(reconnect)
.then(() => {
return this._listen();
});
}
}
connect (reconnect) {
return this._login(reconnect)
.then(() => {
return this._listen()
})
}
close() {
this.isClosed = true;
this.ws.close();
}
_login (listen) {
return this.rp.post(`${this.controller.href}api/login`, {
resolveWithFullResponse: true,
json: {
username: this.opts.username,
password: this.opts.password,
strict: true
}
})
.then(() => {
if (this.socket) {
// inject new cookie into the ws handler
this.socket.options.headers.Cookie = this.jar.getCookieString(this.controller.href)
_login(reconnect) {
let endpointUrl = `${this.controller.href}api/login`;
if (this.opts.unifios) {
// unifios using one authorisation endpoint for protect and network.
endpointUrl = `${this.controller.href}api/auth/login`;
}
})
.catch((e) => {
this.emit('websocket-status', `UniFi Events: Login Failed ${e.message}`)
})
}
_listen () {
this.socket = new WebSocket(`wss://${this.controller.host}/wss/s/${this.opts.site}/events`, {
options: {
perMessageDeflate: false,
rejectUnauthorized: this.opts.rejectUnauthorized,
headers: {
'User-Agent': this.userAgent,
'Cookie': this.jar.getCookieString(this.controller.href)
}
},
beforeConnect: this._ensureLoggedIn.bind(this)
})
return this.rp.post(endpointUrl, {
resolveWithFullResponse: true,
body: {
username: this.opts.username,
password: this.opts.password
}
}).catch(() => {
if (!reconnect) {
this._reconnect();
}
});
}
this.socket.on('json', (payload, flags) => {
if ('data' in payload && Array.isArray(payload.data)) {
payload.data.forEach((entry) => {
this._event(entry)
})
}
})
_listen() {
const cookies = this.jar.getCookieString(this.controller.href);
let eventsUrl = `wss://${this.controller.host}/wss/s/${this.opts.site}/events`;
if (this.opts.unifios) {
eventsUrl = `wss://${this.controller.host}/proxy/network/wss/s/${this.opts.site}/events`;
}
this.ws = new WebSocket(eventsUrl, {
perMessageDeflate: false,
rejectUnauthorized: !this.opts.insecure,
headers: {
'User-Agent': this.userAgent,
Cookie: cookies
}
});
this.socket.on('websocket-status', (status) => {
this.emit('websocket-status', `UniFi Events: ${status}`)
})
}
const pingpong = setInterval(() => {
this.ws.send('ping');
}, 15000);
_event (data) {
this.emit(data.key, data)
this.emit('event', data)
this.ws.on('open', () => {
this.isReconnecting = false;
this.emit('ctrl.connect');
});
// send to convenience emitters
if (data.key in this.helpers) {
this.emit(this.helpers[data.key], data)
this.ws.on('message', data => {
if (data === 'pong') {
return;
}
try {
const parsed = JSON.parse(data);
if ('data' in parsed && Array.isArray(parsed.data)) {
parsed.data.forEach(entry => {
this._event(entry);
});
}
} catch (err) {
this.emit('ctrl.error', err);
}
});
this.ws.on('close', () => {
this.emit('ctrl.close');
clearInterval(pingpong);
this._reconnect();
});
this.ws.on('error', err => {
clearInterval(pingpong);
this.emit('ctrl.error', err);
this._reconnect();
});
}
}
_ensureLoggedIn () {
return this.rp.get(`${this.controller.href}api/self`)
.catch(() => {
return this._login()
})
}
_reconnect() {
if (!this.isReconnecting && !this.isClosed) {
this.isReconnecting = true;
setTimeout(() => {
this.emit('ctrl.reconnect');
this.isReconnecting = false;
this.connect(true);
}, this.autoReconnectInterval);
}
}
getClients () {
return this._ensureLoggedIn()
.then(() => {
return this.rp.get(`${this.controller.href}api/s/${this.opts.site}/stat/sta`, {
json: true
})
})
}
_event(data) {
if (data && data.key) {
// TODO clarifiy what to do with events without key...
const match = data.key.match(/EVT_([A-Z]{2})_(.*)/);
if (match) {
const [, group, event] = match;
this.emit([group.toLowerCase(), event.toLowerCase()].join('.'), data);
}
}
}
getClient (mac) {
return this._ensureLoggedIn()
.then(() => {
return this.rp.get(`${this.controller.href}api/s/${this.opts.site}/stat/user/${mac}`, {
json: true
})
.then((data) => {
return data.data[0]
})
})
}
_ensureLoggedIn() {
return this.rp.get(`${this.controller.href}api/self`)
.catch(() => {
return this._login();
});
}
getAp (mac) {
return this._ensureLoggedIn()
.then(() => {
return this.rp.get(`${this.controller.href}api/s/${this.opts.site}/stat/device/${mac}`, {
json: true
})
.then((data) => {
return data.data[0]
})
})
}
_url(path) {
if (this.opts.unifios) {
// unifios using an proxy, set extra path
if (path.indexOf('/') === 0) {
return `${this.controller.href}proxy/network/${path}`;
}
return `${this.controller.href}proxy/network/api/s/${this.opts.site}/${path}`;
}
else {
if (path.indexOf('/') === 0) {
return `${this.controller.href}${path}`;
}
return `${this.controller.href}api/s/${this.opts.site}/${path}`;
}
}
getSites () {
return this._ensureLoggedIn()
.then(() => {
return this.rp.get(`${this.controller.href}api/self/sites`, {
json: true
})
})
}
}
get(path) {
return this._ensureLoggedIn()
.then(() => {
return this.rp.get(this._url(path));
});
}
del(path) {
return this._ensureLoggedIn()
.then(() => {
return this.rp.del(this._url(path));
});
}
post(path, body) {
return this._ensureLoggedIn()
.then(() => {
return this.rp.post(this._url(path), {body});
});
}
put(path, body) {
return this._ensureLoggedIn()
.then(() => {
return this.rp.put(this._url(path), {body});
});
}
};
{
"name": "unifi-events",
"description": "UniFi Events is a Node.js module that allows you to listen for events generated by a UniFi Controller.",
"version": "0.4.3",
"description": "listen for events from and call methods on the UniFi API (Ubiquiti Wifi).",
"version": "2.0.0-beta.1",
"main": "index.js",
"devDependencies": {},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
"devDependencies": {
"camo-purge": "latest"
},
"engines": {
"node": ">=6.0.0"
},
"dependencies": {
"@oznu/ws-connect": "^0.0.4",
"request": "^2.88.0",
"request-promise": "^4.2.1"
"eventemitter2": "^5.0.1",
"request": "^2.83.0",
"request-promise": "^4.2.2",
"ws": "^4.0.0"
},

@@ -21,6 +24,13 @@ "repository": {

"unifi",
"node.js",
"ubiquiti",
"ubnt",
"wifi",
"api",
"events"
],
"author": "oznu <dev@oz.nu>",
"contributors": [
"oznu <dev@oz.nu>",
"hobbyquaker <https://github.com/hobbyquaker>"
],
"license": "MIT",

@@ -27,0 +37,0 @@ "bugs": {

@@ -1,5 +0,13 @@

# UniFi Events
# unifi-events
UniFi Events is a Node.js module that allows you to listen for events generated by a UniFi Controller.
[![NPM version](https://badge.fury.io/js/unifi-events.svg)](http://badge.fury.io/js/unifi-events)
[![Dependency Status](https://img.shields.io/gemnasium/oznu/unifi-events.svg?maxAge=2592000)](https://gemnasium.com/github.com/oznu/unifi-events)
[![Build Status](https://travis-ci.org/oznu/unifi-events.svg?branch=master)](https://travis-ci.org/oznu/unifi-events)
[![License][mit-badge]][mit-url]
> unifi-events is a Node.js module that allows you to listen for events from and call methods on the UniFi API (UniFi is
Ubiquiti Networks wifi controller software).
This is a merge-back from the fork [ubnt-unifi](https://github.com/hobbyquaker/ubnt-unifi) as it seems no longer maintained.
## Requirements

@@ -12,83 +20,178 @@

unifi-events can be installed using the following npm command:
`$ npm install unifi-events`
## Example
```javascript
const Unifi = require('unifi-events')
const unifi = new Unifi({
host: 'unifi', // The hostname or ip address of the unifi controller (default: 'unifi')
port: 8443, // Port of the unifi controller (default: 8443)
username: 'admin', // Username (default: 'admin').
password: 'ubnt', // Password (default: 'ubnt').
site: 'default', // The UniFi site to connect to (default: 'default').
insecure: true, // Allow connections if SSL certificate check fails (default: false).
unifios: false // For devices with UnifiOS turn this on
});
// Listen for any event
unifi.on('**', function (data) {
console.log(this.event, data);
});
```
npm install unifi-events
```
or yarn:
## Events
unifi-events uses [EventEmitter2](https://github.com/asyncly/EventEmitter2) and namespaced events.
### namespace `ctrl`
These events indicate the status of the connection to the UniFi controller
* `ctrl.connect` - emitted when the connection to the controller is established
* `ctrl.disconnect` - emitted when the connection to the controller is lost
* `ctrl.error` -
* `ctrl.reconnect` -
### namespaces `wu`, `wg`, `lu`, ...
This JSON file shows all possible events: https://demo.ubnt.com/manage/locales/en/eventStrings.json?v=5.4.11.2
The prefix `EVT_` gets stripped, the first underscore is replaced by the namespace separating dot, everything is
converted to lower case. Some events such as `EVT_AD_LOGIN` (Admin Login) are not emitted by the UniFi Controller.
#### Example Wireless User events
* `wu.connected` - Wireless User connected
* `wu.disconnected` - Wireless User disconnected
* `wu.roam` - Wireless User roamed from one AP to another
* `wu.roam_radio` - Wireless User changed channel on the same AP
#### Example Wireless Guest Events
* `wg.connected` - Wireless Guest connected
* `wg.disconnected` - Wireless Guest disconnected
* `wg.roam` - Wireless Guest roamed from one AP to another
* `wg.roam_radio` - Wireless Guest changed channel on the same AP
* `wg.authorization_ended` - Wireless Guest became unauthorised
#### Wildcard usage
Example listing for events on Guest Wireless networks only:
```javascript
unifi.on('wg.*', function (data) {
console.log(this.event, data);
})
```
yarn add unifi-events
```
## Example
Example listening for connected events on all network types:
```javascript
const UnifiEvents = require('unifi-events')
unifi.on('*.connected', function (data) {
console.log(this.event, data);
});
```
let unifi = new UnifiEvents({
controller: 'https://demo.ubnt.com', // Required. The url of the UniFi Controller
username: 'superadmin', // Required.
password: 'password', // Required.
site: 'default', // Optional. The UniFi site to connect to, if not set will use the default site.
rejectUnauthorized: true, // Optional. Set to false if you don't have a valid SSL
listen: true // Optional. Set to false if you don't want to listen for events
})
## Methods
// Listen for users and guests connecting to the network
unifi.on('connected', (data) => {
console.log(data)
})
#### connect()
// Listen for users and guests disconnecting from the network
unifi.on('disconnected', (data) => {
console.log(data)
})
Connect to the UniFi controller. Is called in the constructor, so normally you don't need to call it (except if you want
to re-establish a connection that was closed before).
// Listen for any event
unifi.on('event', (data) => {
console.log(data)
})
#### close()
Closes the connection to the UniFi controller
### UniFi API Methods
Following methods operate on the configured site. The path gets prefixed with
`https://<host>:<port>/api/s/<site>/` if it does not start with a slash, otherwise it gets prefixed with
`https://<host>:<port>`. To explore available API endpoints you can use the
[UniFi-API-browser](https://github.com/Art-of-WiFi/UniFi-API-browser).
These methods are returning a promise.
#### get(path)
Do a HTTP GET on the API.
**Examples:**
* Get a list of all clients
```javascript
unifi.get('stat/sta').then(console.log);
```
## Events
* Get infos of a specific client
```javascript
unifi.get('stat/user/<mac>').then(console.log);
```
In addition to the ```connect```, ```disconnect``` and ```event``` event types, other UniFi event types are emitted using the UniFi Event Key ID.
* Get alarms
```javascript
unifi.get('list/alarm').then(console.log);
```
This JSON file shows all possible events: https://demo.ubnt.com/manage/locales/en/eventStrings.json?v=5.4.11.2
* Get wireless network IDs
```javascript
unifi.get('rest/wlanconf').then(res => {
res.data.forEach(wlan => {
console.log(wlan.name, wlan._id);
});
});
```
Some events such as ```EVT_AD_LOGIN``` (Admin Login) are not emitted by the UniFi Controller.
* Get device IDs
```javascript
unifi.get('stat/device').then(res => {
res.data.forEach(dev => {
console.log(dev.name, dev._id);
});
});
```
Wireless User Events:
#### del(path)
* ```EVT_WU_Connected``` - Wireless User connected
* ```EVT_WU_Disconnected``` - Wireless User disconnected
* ```EVT_WU_ROAM``` - Wireless User roamed from one AP to another
* ```EVT_WU_ROAM_RADIO``` - Wireless User changed channel on the same AP
Do a HTTP DELETE on the API.
Wireless Guest Events:
#### post(path, body)
* ```EVT_WG_Connected``` - Wireless Guest connected
* ```EVT_WG_Disconnected``` - Wireless Guest disconnected
* ```EVT_WG_ROAM``` - Wireless Guest roamed from one AP to another
* ```EVT_WG_ROAM_RADIO``` - Wireless Guest changed channel on the same AP
* ```EVT_WG_AUTHORIZATION_ENDED``` - Wireless Guest became unauthorised
Do a HTTP POST on the API.
LAN User Events:
**Examples:**
* ```EVT_LU_CONNECTED``` - LAN User connected to the network
* ```EVT_LU_DISCONNECTED``` - LAN User disconnected from the network
* Enable all LEDs of all APs
```javascript
unifi.post('set/setting/mgmt', {led_enabled: true}).then(console.log);
```
LAN Guest Events:
* Disable a WLAN
```javascript
unifi.post('upd/wlanconf/<wlan_id>', {enabled: false}).then(console.log);
```
* ```EVT_LG_CONNECTED``` - LAN Guest connected to the network
* ```EVT_LG_DISCONNECTED``` - LAN Guest disconnected from the network
#### put(path, body)
Example listing for connections made to Guest Wireless networks only:
Do a HTTP PUT on the API.
**Examples:**
* Enable LED of AP
```javascript
unifi.on('EVT_WG_Connected', (data) => {
console.log(data)
})
unifi.put('rest/device/<device_id>', {led_override: 'on'}).then(console.log);
```
## License
MIT © 2018 [Sebastian Raff](https://github.com/hobbyquaker)
MIT © 2017-2018 [oznu](https://github.com/oznu)
[mit-badge]: https://img.shields.io/badge/License-MIT-blue.svg?style=flat
[mit-url]: LICENSE
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc