You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1720 lines
75 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

/* jshint -W097 */
/* jshint strict: false */
/* jslint node: true */
/* jshint -W061 */
'use strict';
const socketio = require('socket.io');
const path = require('path');
const fs = require('fs');
const cookieParser = require('cookie-parser');
const EventEmitter = require('events');
const util = require('util');
let request = null;
// From settings used only secure, auth and crossDomain
function IOSocket(server, settings, adapter) {
if (!(this instanceof IOSocket)) return new IOSocket(server, settings, adapter);
this.settings = settings || {};
this.adapter = adapter;
this.webServer = server;
this.subscribes = {};
let that = this;
// do not send too many state updates
let eventsThreshold = {
count: 0,
timeActivated: 0,
active: false,
accidents: 0,
repeatSeconds: 3, // how many seconds continuously must be number of events > value
value: 200, // how many events allowed in one check interval
checkInterval: 1000 // duration of one check interval
};
// Extract user name from socket
function getUserFromSocket(socket, callback) {
let wait = false;
try {
if (socket.handshake.headers.cookie && (!socket.request || !socket.request._query || !socket.request._query.user)) {
let cookie = decodeURIComponent(socket.handshake.headers.cookie);
let m = cookie.match(/connect\.sid=(.+)/);
if (m) {
// If session cookie exists
let c = m[1].split(';')[0];
let sessionID = cookieParser.signedCookie(c, that.settings.secret);
if (sessionID) {
// Get user for session
wait = true;
that.settings.store.get(sessionID, function (err, obj) {
if (obj && obj.passport && obj.passport.user) {
socket._sessionID = sessionID;
if (typeof callback === 'function') {
callback(null, obj.passport.user);
} else {
that.adapter.log.warn('[getUserFromSocket] Invalid callback')
}
} else {
if (typeof callback === 'function') {
callback('unknown user');
} else {
that.adapter.log.warn('[getUserFromSocket] Invalid callback')
}
}
});
}
}
}
if (!wait) {
let user = socket.request._query.user;
let pass = socket.request._query.pass;
if (user && pass) {
wait = true;
that.adapter.checkPassword(user, pass, function (res) {
if (res) {
that.adapter.log.debug('Logged in: ' + user);
if (typeof callback === 'function') {
callback(null, user);
} else {
that.adapter.log.warn('[getUserFromSocket] Invalid callback')
}
} else {
that.adapter.log.warn('Invalid password or user name: ' + user + ', ' + pass[0] + '***(' + pass.length + ')');
if (typeof callback === 'function') {
callback('unknown user');
} else {
that.adapter.log.warn('[getUserFromSocket] Invalid callback')
}
}
});
}
}
} catch (e) {
that.adapter.log.error(e);
wait = false;
}
if (!wait && typeof callback === 'function') {
callback('Cannot detect user');
}
}
function disableEventThreshold(readAll) {
if (eventsThreshold.active) {
eventsThreshold.accidents = 0;
eventsThreshold.count = 0;
eventsThreshold.active = false;
eventsThreshold.timeActivated = 0;
that.adapter.log.info('Subscribe on all states again');
setTimeout(function () {
if (readAll) {
that.adapter.getForeignStates('*', function (err, res) {
that.adapter.log.info('received all states');
for (let id in res) {
if (res.hasOwnProperty(id) && JSON.stringify(states[id]) !== JSON.stringify(res[id])) {
that.server.sockets.emit('stateChange', id, res[id]);
states[id] = res[id];
}
}
});
}
that.server.sockets.emit('eventsThreshold', false);
that.adapter.unsubscribeForeignStates('system.adapter.*');
that.adapter.subscribeForeignStates('*');
}, 50);
}
}
function enableEventThreshold() {
if (!eventsThreshold.active) {
eventsThreshold.active = true;
setTimeout(function () {
that.adapter.log.info('Unsubscribe from all states, except system\'s, because over ' + eventsThreshold.repeatSeconds + ' seconds the number of events is over ' + eventsThreshold.value + ' (in last second ' + eventsThreshold.count + ')');
eventsThreshold.timeActivated = new Date().getTime();
that.server.sockets.emit('eventsThreshold', true);
that.adapter.unsubscribeForeignStates('*');
that.adapter.subscribeForeignStates('system.adapter.*');
}, 100);
}
}
function getClientAddress(socket) {
let address;
if (socket.handshake) {
address = socket.handshake.address;
}
if (!address && socket.request && socket.request.connection) {
address = socket.request.connection.remoteAddress;
}
return address;
}
this.initSocket = function (socket) {
if (!socket._acl) {
if (that.settings.auth) {
getUserFromSocket(socket, function (err, user) {
if (err || !user) {
socket.emit('reauthenticate');
that.adapter.log.error('socket.io ' + (err || 'No user found in cookies'));
socket.disconnect();
} else {
socket._secure = true;
that.adapter.log.debug('socket.io client ' + user + ' connected');
that.adapter.calculatePermissions('system.user.' + user, commandsPermissions, function (acl) {
let address = getClientAddress(socket);
// socket._acl = acl;
socket._acl = mergeACLs(address, acl, that.settings.whiteListSettings);
socketEvents(socket, address);
});
}
});
} else {
that.adapter.calculatePermissions(that.settings.defaultUser, commandsPermissions, function (acl) {
let address = getClientAddress(socket);
// socket._acl = acl;
socket._acl = mergeACLs(address, acl, that.settings.whiteListSettings);
socketEvents(socket, address);
});
}
} else {
let address = getClientAddress(socket);
socketEvents(socket, address);
}
};
this.getWhiteListIpForAddress = function (address, whiteList){
return getWhiteListIpForAddress(address, whiteList);
};
function getWhiteListIpForAddress(address, whiteList) {
if (!whiteList) return null;
// check IPv6 or IPv4 direct match
if (whiteList.hasOwnProperty(address)) {
return address;
}
// check if address is IPv4
let addressParts = address.split('.');
if (addressParts.length !== 4) {
return null;
}
// do we have settings for wild carded ips?
let wildCardIps = Object.keys(whiteList).filter(function (key) {
return key.indexOf('*') !== -1;
});
if (wildCardIps.length === 0) {
// no wild carded ips => no ip configured
return null;
}
wildCardIps.forEach(function (ip) {
let ipParts = ip.split('.');
if (ipParts.length === 4) {
for (let i = 0; i < 4; i++) {
if (ipParts[i] === '*' && i === 3) {
// match
return ip;
}
if (ipParts[i] !== addressParts[i]) break;
}
}
});
return null;
}
function getPermissionsForIp(address, whiteList) {
return whiteList[getWhiteListIpForAddress(address, whiteList) || 'default'];
}
function mergeACLs(address, acl, whiteList) {
if (whiteList && address) {
let whiteListAcl = getPermissionsForIp(address, whiteList);
if (whiteListAcl) {
['object', 'state', 'file'].forEach(function (key) {
if (acl.hasOwnProperty(key) && whiteListAcl.hasOwnProperty(key)) {
Object.keys(acl[key]).forEach(function (permission) {
if (whiteListAcl[key].hasOwnProperty(permission)) {
acl[key][permission] = acl[key][permission] && whiteListAcl[key][permission];
}
})
}
});
if (whiteListAcl.user !== 'auth') {
acl.user = 'system.user.' + whiteListAcl.user;
}
}
}
return acl;
}
function pattern2RegEx(pattern) {
if (!pattern) {
return null;
}
if (pattern !== '*') {
if (pattern[0] === '*' && pattern[pattern.length - 1] !== '*') pattern += '$';
if (pattern[0] !== '*' && pattern[pattern.length - 1] === '*') pattern = '^' + pattern;
}
pattern = pattern.replace(/\./g, '\\.');
pattern = pattern.replace(/\*/g, '.*');
pattern = pattern.replace(/\[/g, '\\[');
pattern = pattern.replace(/]/g, '\\]');
pattern = pattern.replace(/\(/g, '\\(');
pattern = pattern.replace(/\)/g, '\\)');
return pattern;
}
this.subscribe = function (socket, type, pattern) {
//console.log((socket._name || socket.id) + ' subscribe ' + pattern);
if (socket) {
socket._subscribe = socket._subscribe || {};
}
if (!this.subscribes[type]) this.subscribes[type] = {};
let s;
if (socket) {
s = socket._subscribe[type] = socket._subscribe[type] || [];
for (let i = 0; i < s.length; i++) {
if (s[i].pattern === pattern) return;
}
}
let p = pattern2RegEx(pattern);
if (p === null) {
this.adapter.log.warn('Empty pattern!');
return;
}
if (socket) {
s.push({pattern: pattern, regex: new RegExp(p)});
}
if (this.subscribes[type][pattern] === undefined) {
this.subscribes[type][pattern] = 1;
if (type === 'stateChange') {
this.adapter.subscribeForeignStates(pattern);
} else if (type === 'objectChange') {
if (this.adapter.subscribeForeignObjects) {
this.adapter.subscribeForeignObjects(pattern);
}
} else if (type === 'log') {
if (this.adapter.requireLog) this.adapter.requireLog(true);
}
} else {
this.subscribes[type][pattern]++;
}
};
function showSubscribes(socket, type) {
if (socket && socket._subscribe) {
let s = socket._subscribe[type] || [];
let ids = [];
for (let i = 0; i < s.length; i++) {
ids.push(s[i].pattern);
}
that.adapter.log.debug('Subscribes: ' + ids.join(', '));
} else {
that.adapter.log.debug('Subscribes: no subscribes');
}
}
this.unsubscribe = function (socket, type, pattern) {
//console.log((socket._name || socket.id) + ' unsubscribe ' + pattern);
if (!this.subscribes[type]) this.subscribes[type] = {};
if (socket) {
if (!socket._subscribe || !socket._subscribe[type]) return;
for (let i = socket._subscribe[type].length - 1; i >= 0; i--) {
if (socket._subscribe[type][i].pattern === pattern) {
// Remove pattern from global list
if (this.subscribes[type][pattern] !== undefined) {
this.subscribes[type][pattern]--;
if (this.subscribes[type][pattern] <= 0) {
if (type === 'stateChange') {
//console.log((socket._name || socket.id) + ' unsubscribeForeignStates ' + pattern);
this.adapter.unsubscribeForeignStates(pattern);
} else if (type === 'objectChange') {
//console.log((socket._name || socket.id) + ' unsubscribeForeignObjects ' + pattern);
if (this.adapter.unsubscribeForeignObjects) this.adapter.unsubscribeForeignObjects(pattern);
} else if (type === 'log') {
//console.log((socket._name || socket.id) + ' requireLog false');
if (this.adapter.requireLog) this.adapter.requireLog(false);
}
delete this.subscribes[type][pattern];
}
}
delete socket._subscribe[type][i];
socket._subscribe[type].splice(i, 1);
return;
}
}
} else if (pattern) {
// Remove pattern from global list
if (this.subscribes[type][pattern] !== undefined) {
this.subscribes[type][pattern]--;
if (this.subscribes[type][pattern] <= 0) {
if (type === 'stateChange') {
//console.log((socket._name || socket.id) + ' unsubscribeForeignStates ' + pattern);
this.adapter.unsubscribeForeignStates(pattern);
} else if (type === 'objectChange') {
//console.log((socket._name || socket.id) + ' unsubscribeForeignObjects ' + pattern);
if (this.adapter.unsubscribeForeignObjects) this.adapter.unsubscribeForeignObjects(pattern);
} else if (type === 'log') {
//console.log((socket._name || socket.id) + ' requireLog false');
if (this.adapter.requireLog) this.adapter.requireLog(false);
}
delete this.subscribes[type][pattern];
}
}
} else {
for (pattern in this.subscribes[type]) {
if (!this.subscribes[type].hasOwnProperty(pattern)) continue;
if (type === 'stateChange') {
//console.log((socket._name || socket.id) + ' unsubscribeForeignStates ' + pattern);
this.adapter.unsubscribeForeignStates(pattern);
} else if (type === 'objectChange') {
//console.log((socket._name || socket.id) + ' unsubscribeForeignObjects ' + pattern);
if (this.adapter.unsubscribeForeignObjects) this.adapter.unsubscribeForeignObjects(pattern);
} else if (type === 'log') {
//console.log((socket._name || socket.id) + ' requireLog false');
if (this.adapter.requireLog) this.adapter.requireLog(false);
}
delete this.subscribes[type][pattern];
}
}
};
this.unsubscribeAll = function () {
if (this.server && this.server.sockets) {
for (let s in this.server.sockets) {
if (this.server.sockets.hasOwnProperty(s)) {
unsubscribeSocket(s, 'stateChange');
unsubscribeSocket(s, 'objectChange');
unsubscribeSocket(s, 'log');
}
}
}
};
function unsubscribeSocket(socket, type) {
if (!socket._subscribe || !socket._subscribe[type]) return;
for (let i = 0; i < socket._subscribe[type].length; i++) {
let pattern = socket._subscribe[type][i].pattern;
if (that.subscribes[type][pattern] !== undefined) {
that.subscribes[type][pattern]--;
if (that.subscribes[type][pattern] <= 0) {
if (type === 'stateChange') {
that.adapter.unsubscribeForeignStates(pattern);
} else if (type === 'objectChange') {
if (that.adapter.unsubscribeForeignObjects) that.adapter.unsubscribeForeignObjects(pattern);
} else if (type === 'log') {
if (that.adapter.requireLog) that.adapter.requireLog(false);
}
delete that.subscribes[type][pattern];
}
}
}
}
function subscribeSocket(socket, type) {
//console.log((socket._name || socket.id) + ' subscribeSocket');
if (!socket._subscribe || !socket._subscribe[type]) return;
for (let i = 0; i < socket._subscribe[type].length; i++) {
let pattern = socket._subscribe[type][i].pattern;
if (that.subscribes[type][pattern] === undefined) {
that.subscribes[type][pattern] = 1;
if (type === 'stateChange') {
that.adapter.subscribeForeignStates(pattern);
} else if (type === 'objectChange') {
if (that.adapter.subscribeForeignObjects) that.adapter.subscribeForeignObjects(pattern);
} else if (type === 'log') {
if (that.adapter.requireLog) that.adapter.requireLog(true);
}
} else {
that.subscribes[type][pattern]++;
}
}
}
function publish(socket, type, id, obj) {
if (!socket._subscribe || !socket._subscribe[type]) return;
let s = socket._subscribe[type];
for (let i = 0; i < s.length; i++) {
if (s[i].regex.test(id)) {
updateSession(socket);
socket.emit(type, id, obj);
return;
}
}
}
// update session ID, but not offter than 60 seconds
function updateSession(socket) {
if (socket._sessionID) {
let time = (new Date()).getTime();
if (socket._lastActivity && time - socket._lastActivity > settings.ttl * 1000) {
socket.emit('reauthenticate');
socket.disconnect();
return false;
}
socket._lastActivity = time;
if (!socket._sessionTimer) {
socket._sessionTimer = setTimeout(function () {
socket._sessionTimer = null;
that.settings.store.get(socket._sessionID, function (err, obj) {
if (obj) {
that.adapter.setSession(socket._sessionID, settings.ttl, obj);
} else {
socket.emit('reauthenticate');
socket.disconnect();
}
});
}, 60000);
}
}
return true;
}
// static information
let commandsPermissions = {
getObject: {type: 'object', operation: 'read'},
getObjects: {type: 'object', operation: 'list'},
getObjectView: {type: 'object', operation: 'list'},
setObject: {type: 'object', operation: 'write'},
requireLog: {type: 'object', operation: 'write'}, // just mapping to some command
delObject: {type: 'object', operation: 'delete'},
extendObject: {type: 'object', operation: 'write'},
getHostByIp: {type: 'object', operation: 'list'},
subscribeObjects: {type: 'object', operation: 'read'},
unsubscribeObjects: {type: 'object', operation: 'read'},
getStates: {type: 'state', operation: 'list'},
getState: {type: 'state', operation: 'read'},
setState: {type: 'state', operation: 'write'},
delState: {type: 'state', operation: 'delete'},
createState: {type: 'state', operation: 'create'},
subscribe: {type: 'state', operation: 'read'},
unsubscribe: {type: 'state', operation: 'read'},
getStateHistory: {type: 'state', operation: 'read'},
getVersion: {type: '', operation: ''},
addUser: {type: 'users', operation: 'create'},
delUser: {type: 'users', operation: 'delete'},
addGroup: {type: 'users', operation: 'create'},
delGroup: {type: 'users', operation: 'delete'},
changePassword: {type: 'users', operation: 'write'},
httpGet: {type: 'other', operation: 'http'},
cmdExec: {type: 'other', operation: 'execute'},
sendTo: {type: 'other', operation: 'sendto'},
sendToHost: {type: 'other', operation: 'sendto'},
readLogs: {type: 'other', operation: 'execute'},
readDir: {type: 'file', operation: 'list'},
createFile: {type: 'file', operation: 'create'},
writeFile: {type: 'file', operation: 'write'},
readFile: {type: 'file', operation: 'read'},
deleteFile: {type: 'file', operation: 'delete'},
readFile64: {type: 'file', operation: 'read'},
writeFile64: {type: 'file', operation: 'write'},
unlink: {type: 'file', operation: 'delete'},
rename: {type: 'file', operation: 'write'},
mkdir: {type: 'file', operation: 'write'},
chmodFile: {type: 'file', operation: 'write'},
authEnabled: {type: '', operation: ''},
disconnect: {type: '', operation: ''},
listPermissions: {type: '', operation: ''},
getUserPermissions: {type: 'object', operation: 'read'}
};
function addUser(user, pw, options, callback) {
if (typeof options === 'function') {
callback = options;
options = null;
}
if (!user.match(/^[-.A-Za-züäößÖÄÜа-яА-Я@+$§0-9=?!&# ]+$/)) {
if (typeof callback === 'function') {
callback('Invalid characters in the name. Only following special characters are allowed: -@+$§=?!&# and letters');
}
return;
}
that.adapter.getForeignObject('system.user.' + user, options, (err, obj) => {
if (obj) {
if (typeof callback === 'function') {
callback('User yet exists');
}
} else {
that.adapter.setForeignObject('system.user.' + user, {
type: 'user',
common: {
name: user,
enabled: true,
groups: []
}
}, options, () => {
that.adapter.setPassword(user, pw, options, callback);
});
}
});
}
function delUser(user, options, callback) {
that.adapter.getForeignObject('system.user.' + user, options, (err, obj) => {
if (err || !obj) {
if (typeof callback === 'function') {
callback('User does not exist');
}
} else {
if (obj.common.dontDelete) {
if (typeof callback === 'function') {
callback('Cannot delete user, while is system user');
}
} else {
that.adapter.delForeignObject('system.user.' + user, options, err => {
// Remove this user from all groups in web client
if (typeof callback === 'function') {
callback(err);
}
});
}
}
});
}
function addGroup(group, desc, acl, options, callback) {
let name = group;
if (typeof acl === 'function') {
callback = acl;
acl = null;
}
if (typeof desc === 'function') {
callback = desc;
desc = null;
}
if (typeof options === 'function') {
callback = options;
options = null;
}
if (name && name.substring(0, 1) !== name.substring(0, 1).toUpperCase()) {
name = name.substring(0, 1).toUpperCase() + name.substring(1);
}
group = group.substring(0, 1).toLowerCase() + group.substring(1);
if (!group.match(/^[-.A-Za-züäößÖÄÜа-яА-Я@+$§0-9=?!&#_ ]+$/)) {
if (typeof callback === 'function') {
callback('Invalid characters in the group name. Only following special characters are allowed: -@+$§=?!&# and letters');
}
return;
}
that.adapter.getForeignObject('system.group.' + group, options, (err, obj) => {
if (obj) {
if (typeof callback === 'function') {
callback('Group yet exists');
}
} else {
obj = {
_id: 'system.group.' + group,
type: 'group',
common: {
name: name,
desc: desc,
members: [],
acl: acl
}
};
that.adapter.setForeignObject('system.group.' + group, obj, options, err => {
if (typeof callback === 'function') {
callback(err, obj);
}
});
}
});
}
function delGroup(group, options, callback) {
that.adapter.getForeignObject('system.group.' + group, options, (err, obj) => {
if (err || !obj) {
if (typeof callback === 'function') {
callback('Group does not exist');
}
} else {
if (obj.common.dontDelete) {
if (typeof callback === 'function') {
callback('Cannot delete group, while is system group');
}
} else {
that.adapter.delForeignObject('system.group.' + group, options, err => {
// Remove this group from all users in web client
if (typeof callback === 'function') {
callback(err);
}
});
}
}
});
}
function checkPermissions(socket, command, callback, arg) {
if (socket._acl.user !== 'system.user.admin') {
// type: file, object, state, other
// operation: create, read, write, list, delete, sendto, execute, sendToHost, readLogs
if (commandsPermissions[command]) {
// If permission required
if (commandsPermissions[command].type) {
if (socket._acl[commandsPermissions[command].type] &&
socket._acl[commandsPermissions[command].type][commandsPermissions[command].operation]) {
return true;
} else {
that.adapter.log.warn('No permission for "' + socket._acl.user + '" to call ' + command + '. Need "' + commandsPermissions[command].type + '"."' + commandsPermissions[command].operation + '"');
}
} else {
return true;
}
} else {
that.adapter.log.warn('No rule for command: ' + command);
}
if (typeof callback === 'function') {
callback('permissionError');
} else {
if (commandsPermissions[command]) {
socket.emit('permissionError', {
command: command,
type: commandsPermissions[command].type,
operation: commandsPermissions[command].operation,
arg: arg
});
} else {
socket.emit('permissionError', {
command: command,
arg: arg
});
}
}
return false;
} else {
return true;
}
}
function checkObject(obj, options, flag) {
// read rights of object
if (!obj || !obj.common || !obj.acl || flag === 'list') {
return true;
}
if (options.user !== 'system.user.admin' &&
options.groups.indexOf('system.group.administrator') === -1) {
if (obj.acl.owner !== options.user) {
// Check if the user is in the group
if (options.groups.indexOf(obj.acl.ownerGroup) !== -1) {
// Check group rights
if (!(obj.acl.object & (flag << 4))) {
return false
}
} else {
// everybody
if (!(obj.acl.object & flag)) {
return false
}
}
} else {
// Check group rights
if (!(obj.acl.object & (flag << 8))) {
return false
}
}
}
return true;
}
this.send = function (socket, cmd, id, data) {
if (socket._apiKeyOk) {
socket.emit(cmd, id, data);
}
};
function stopAdapter(reason, callback) {
reason && that.adapter.log.warn('Adapter stopped. Reason: ' + reason);
that.adapter.getForeignObject('system.adapter.' + that.adapter.namespace, function (err, obj) {
if (err) that.adapter.log.error('[getForeignObject]: ' + err);
if (obj) {
obj.common.enabled = false;
setTimeout(function () {
that.adapter.setForeignObject(obj._id, obj, function (err) {
if (err) that.adapter.log.error('[setForeignObject]: ' + err);
callback && callback();
});
}, 5000);
} else {
callback && callback();
}
});
}
function redirectAdapter(url, callback) {
if (!url) {
that.adapter.log.warn('Received redirect command, but no URL');
} else {
that.adapter.getForeignObject('system.adapter.' + that.adapter.namespace, function (err, obj) {
if (err) that.adapter.log.error('redirectAdapter [getForeignObject]: ' + err);
if (obj) {
obj.native.cloudUrl = url;
setTimeout(function () {
that.adapter.setForeignObject(obj._id, obj, function (err) {
if (err) that.adapter.log.error('redirectAdapter [setForeignObject]: ' + err);
callback && callback();
});
}, 3000);
} else {
callback && callback();
}
});
}
}
function waitForConnect(delaySeconds) {
that.emit && that.emit('connectWait', delaySeconds);
}
function socketEvents(socket, address) {
if (socket.conn) {
that.adapter.log.info('==>Connected ' + socket._acl.user + ' from ' + address);
} else {
that.adapter.log.info('Trying to connect as ' + socket._acl.user + ' from ' + address);
}
if (!that.infoTimeout) {
that.infoTimeout = setTimeout(updateConnectedInfo, 1000);
}
socket.on('authenticate', function (user, pass, callback) {
that.adapter.log.debug((new Date()).toISOString() + ' Request authenticate [' + socket._acl.user + ']');
if (typeof user === 'function') {
callback = user;
user = undefined;
}
if (socket._acl.user !== null) {
if (typeof callback === 'function') {
callback(socket._acl.user !== null, socket._secure);
}
} else {
that.adapter.log.debug((new Date()).toISOString() + ' Request authenticate [' + socket._acl.user + ']');
socket._authPending = callback;
}
});
socket.on('name', function (name, cb) {
that.adapter.log.debug('Connection from ' + name);
updateSession(socket);
if (this._name === undefined) {
this._name = name;
if (!that.infoTimeout) that.infoTimeout = setTimeout(updateConnectedInfo, 1000);
} else if (this._name !== name) {
that.adapter.log.warn('socket ' + this.id + ' changed socket name from ' + this._name + ' to ' + name);
this._name = name;
}
if (typeof cb === 'function') {
cb();
}
});
/*
* objects
*/
socket.on('getObject', function (id, callback) {
if (updateSession(socket) && checkPermissions(socket, 'getObject', callback, id)) {
that.adapter.getForeignObject(id, {user: socket._acl.user}, callback);
}
});
socket.on('getObjects', function (callback) {
if (updateSession(socket) && checkPermissions(socket, 'getObjects', callback)) {
that.adapter.getForeignObjects('*', 'state', 'rooms', {user: socket._acl.user}, function (err, objs) {
if (typeof callback === 'function') {
callback(err, objs);
} else {
that.adapter.log.warn('[getObjects] Invalid callback')
}
});
}
});
socket.on('subscribeObjects', function (pattern, callback) {
if (updateSession(socket) && checkPermissions(socket, 'subscribeObjects', callback, pattern)) {
if (pattern && typeof pattern === 'object' && pattern instanceof Array) {
for (let p = 0; p < pattern.length; p++) {
that.subscribe(this, 'objectChange', pattern[p]);
}
} else {
that.subscribe(this, 'objectChange', pattern);
}
if (typeof callback === 'function') {
setImmediate(callback, null);
}
}
});
socket.on('unsubscribeObjects', function (pattern, callback) {
if (updateSession(socket) && checkPermissions(socket, 'unsubscribeObjects', callback, pattern)) {
if (pattern && typeof pattern === 'object' && pattern instanceof Array) {
for (let p = 0; p < pattern.length; p++) {
that.unsubscribe(this, 'objectChange', pattern[p]);
}
} else {
that.unsubscribe(this, 'objectChange', pattern);
}
if (typeof callback === 'function') {
setImmediate(callback, null);
}
}
});
socket.on('getObjectView', function (design, search, params, callback) {
if (updateSession(socket) && checkPermissions(socket, 'getObjectView', callback, search)) {
that.adapter.objects.getObjectView(design, search, params, {user: socket._acl.user}, callback);
}
});
socket.on('setObject', function (id, obj, callback) {
if (updateSession(socket) && checkPermissions(socket, 'setObject', callback, id)) {
that.adapter.setForeignObject(id, obj, {user: socket._acl.user}, callback);
}
});
/*
* states
*/
socket.on('getStates', function (pattern, callback) {
if (updateSession(socket) && checkPermissions(socket, 'getStates', callback, pattern)) {
if (typeof pattern === 'function') {
callback = pattern;
pattern = null;
}
that.adapter.getForeignStates(pattern || '*', {user: socket._acl.user}, callback);
}
});
socket.on('error', function (err) {
that.adapter.log.error('Socket error: ' + err);
});
// allow admin access
if (that.settings.allowAdmin) {
socket.on('getAllObjects', function (callback) {
if (updateSession(socket) && checkPermissions(socket, 'getObjects', callback)) {
that.adapter.objects.getObjectList({include_docs: true}, function (err, res) {
that.adapter.log.info('received all objects');
res = res.rows;
let objects = {};
if (socket._acl &&
socket._acl.user !== 'system.user.admin' &&
socket._acl.groups.indexOf('system.group.administrator') === -1) {
for (let i = 0; i < res.length; i++) {
if (checkObject(res[i].doc, socket._acl, 4 /* 'read' */)) {
objects[res[i].doc._id] = res[i].doc;
}
}
if (typeof callback === 'function') {
callback(null, objects);
} else {
that.adapter.log.warn('[getAllObjects] Invalid callback')
}
} else {
for (let j = 0; j < res.length; j++) {
objects[res[j].doc._id] = res[j].doc;
}
if (typeof callback === 'function') {
callback(null, objects);
} else {
that.adapter.log.warn('[getAllObjects] Invalid callback')
}
}
});
}
});
socket.on('delObject', function (id, callback) {
if (updateSession(socket) && checkPermissions(socket, 'delObject', callback, id)) {
that.adapter.delForeignObject(id, {user: socket._acl.user}, callback);
}
});
socket.on('extendObject', function (id, obj, callback) {
if (updateSession(socket) && checkPermissions(socket, 'extendObject', callback, id)) {
that.adapter.extendForeignObject(id, obj, {user: socket._acl.user}, callback);
}
});
socket.on('getHostByIp', function (ip, callback) {
if (updateSession(socket) && checkPermissions(socket, 'getHostByIp', ip)) {
that.adapter.objects.getObjectView('system', 'host', {}, {user: socket._acl.user}, function (err, data) {
if (data.rows.length) {
for (let i = 0; i < data.rows.length; i++) {
if (data.rows[i].value.common.hostname === ip) {
if (typeof callback === 'function') {
callback(ip, data.rows[i].value);
} else {
that.adapter.log.warn('[getHostByIp] Invalid callback')
}
return;
}
if (data.rows[i].value.native.hardware && data.rows[i].value.native.hardware.networkInterfaces) {
let net = data.rows[i].value.native.hardware.networkInterfaces;
for (let eth in net) {
if (!net.hasOwnProperty(eth)) continue;
for (let j = 0; j < net[eth].length; j++) {
if (net[eth][j].address === ip) {
if (typeof callback === 'function') {
callback(ip, data.rows[i].value);
} else {
that.adapter.log.warn('[getHostByIp] Invalid callback')
}
return;
}
}
}
}
}
}
if (typeof callback === 'function') {
callback(ip, null);
} else {
that.adapter.log.warn('[getHostByIp] Invalid callback')
}
});
}
});
socket.on('getForeignObjects', function (pattern, type, callback) {
if (updateSession(socket) && checkPermissions(socket, 'getObjects', callback)) {
if (typeof type === 'function') {
callback = type;
type = undefined;
}
that.adapter.getForeignObjects(pattern, type, {user: socket._acl.user}, function (err, objs) {
if (typeof callback === 'function') {
callback(err, objs);
} else {
that.adapter.log.warn('[getObjects] Invalid callback')
}
});
}
});
socket.on('getForeignStates', function (pattern, callback) {
if (updateSession(socket) && checkPermissions(socket, 'getStates', callback)) {
that.adapter.getForeignStates(pattern, {user: socket._acl.user}, function (err, objs) {
if (typeof callback === 'function') {
callback(err, objs);
} else {
that.adapter.log.warn('[getObjects] Invalid callback')
}
});
}
});
socket.on('requireLog', function (isEnabled, callback) {
if (updateSession(socket) && checkPermissions(socket, 'setObject', callback)) {
if (isEnabled) {
that.subscribe(this, 'log', 'dummy')
} else {
that.unsubscribe(this, 'log', 'dummy')
}
if (that.adapter.log.level === 'debug') showSubscribes(socket, 'log');
if (typeof callback === 'function') {
setImmediate(callback, null);
}
}
});
socket.on('readLogs', function (callback) {
if (updateSession(socket) && checkPermissions(socket, 'readLogs', callback)) {
let result = {list: []};
// deliver file list
try {
let config = adapter.systemConfig;
// detect file log
if (config && config.log && config.log.transport) {
for (let transport in config.log.transport) {
if (config.log.transport.hasOwnProperty(transport) && config.log.transport[transport].type === 'file') {
let filename = config.log.transport[transport].filename || 'log/';
let parts = filename.replace(/\\/g, '/').split('/');
parts.pop();
filename = parts.join('/');
if (filename[0] === '.') {
filename = path.normalize(__dirname + '/../../../') + filename;
}
if (fs.existsSync(filename)) {
let files = fs.readdirSync(filename);
for (let f = 0; f < files.length; f++) {
try {
if (!fs.lstatSync(filename + '/' + files[f]).isDirectory()) {
result.list.push('log/' + transport + '/' + files[f]);
}
} catch (e) {
// push unchecked
// result.list.push('log/' + transport + '/' + files[f]);
adapter.log.error('Cannot check file: ' + filename + '/' + files[f]);
}
}
}
}
}
} else {
result.error = 'no file loggers';
result.list = undefined;
}
} catch (e) {
adapter.log.error(e);
result.error = e;
result.list = undefined;
}
if (typeof callback === 'function') {
callback(result.error, result.list);
}
}
});
} else {
// only flot allowed
socket.on('delObject', function (id, callback) {
if (id.match(/^flot\./)) {
if (updateSession(socket) && checkPermissions(socket, 'delObject', callback, id)) {
that.adapter.delForeignObject(id, {user: socket._acl.user}, callback);
}
} else {
if (typeof callback === 'function') {
callback('permissionError');
}
}
});
}
socket.on('getState', function (id, callback) {
if (updateSession(socket) && checkPermissions(socket, 'getState', callback, id)) {
that.adapter.getForeignState(id, {user: socket._acl.user}, callback);
}
});
socket.on('setState', function (id, state, callback) {
if (updateSession(socket) && checkPermissions(socket, 'setState', callback, id)) {
if (typeof state !== 'object') state = {val: state};
that.adapter.setForeignState(id, state, {user: socket._acl.user}, function (err, res) {
if (typeof callback === 'function') {
callback(err, res);
}
});
}
});
// allow admin access
if (that.settings.allowAdmin) {
socket.on('delState', function (id, callback) {
if (updateSession(socket) && checkPermissions(socket, 'delState', callback, id)) {
that.adapter.delForeignState(id, {user: socket._acl.user}, callback);
}
});
socket.on('addUser', function (user, pass, callback) {
if (updateSession(socket) && checkPermissions(socket, 'addUser', callback, user)) {
addUser(user, pass, {user: socket._acl.user}, callback);
}
});
socket.on('delUser', function (user, callback) {
if (updateSession(socket) && checkPermissions(socket, 'delUser', callback, user)) {
delUser(user, {user: socket._acl.user}, callback);
}
});
socket.on('addGroup', function (group, desc, acl, callback) {
if (updateSession(socket) && checkPermissions(socket, 'addGroup', callback, group)) {
addGroup(group, desc, acl, {user: socket._acl.user}, callback);
}
});
socket.on('delGroup', function (group, callback) {
if (updateSession(socket) && checkPermissions(socket, 'delGroup', callback, group)) {
delGroup(group, {user: socket._acl.user}, callback);
}
});
socket.on('changePassword', function (user, pass, callback) {
if (updateSession(socket)) {
if (user === socket._acl.user || checkPermissions(socket, 'changePassword', callback, user)) {
that.adapter.setPassword(user, pass, {user: socket._acl.user}, callback);
}
}
});
// commands will be executed on host/controller
// following response commands are expected: cmdStdout, cmdStderr, cmdExit
socket.on('cmdExec', function (host, id, cmd, callback) {
if (updateSession(socket) && checkPermissions(socket, 'cmdExec', callback, cmd)) {
that.adapter.log.debug('cmdExec on ' + host + '(' + id + '): ' + cmd);
that.adapter.sendToHost(host, 'cmdExec', {data: cmd, id: id});
}
});
socket.on('eventsThreshold', function (isActive) {
if (!isActive) {
disableEventThreshold(true);
} else {
enableEventThreshold();
}
});
}
socket.on('getVersion', function (callback) {
if (updateSession(socket) && checkPermissions(socket, 'getVersion', callback)) {
if (typeof callback === 'function') {
callback(that.adapter.version);
} else {
that.adapter.log.warn('[getVersion] Invalid callback')
}
}
});
socket.on('subscribe', function (pattern, callback) {
if (updateSession(socket) && checkPermissions(socket, 'subscribe', callback, pattern)) {
if (pattern && typeof pattern === 'object' && pattern instanceof Array) {
for (let p = 0; p < pattern.length; p++) {
that.subscribe(this, 'stateChange', pattern[p]);
}
} else {
that.subscribe(this, 'stateChange', pattern);
}
if (that.adapter.log.level === 'debug') showSubscribes(socket, 'stateChange');
if (typeof callback === 'function') {
setImmediate(callback, null);
}
}
});
socket.on('unsubscribe', function (pattern, callback) {
if (updateSession(socket) && checkPermissions(socket, 'unsubscribe', callback, pattern)) {
if (pattern && typeof pattern === 'object' && pattern instanceof Array) {
for (let p = 0; p < pattern.length; p++) {
that.unsubscribe(this, 'stateChange', pattern[p]);
}
} else {
that.unsubscribe(this, 'stateChange', pattern);
}
if (that.adapter.log.level === 'debug') showSubscribes(socket, 'stateChange');
if (typeof callback === 'function') {
setImmediate(callback, null);
}
}
});
// new History
socket.on('getHistory', function (id, options, callback) {
if (updateSession(socket) && checkPermissions(socket, 'getStateHistory', callback, id)) {
options = options || {};
options.user = socket._acl.user;
that.adapter.getHistory(id, options, function (err, data, step, sessionId) {
if (typeof callback === 'function') {
callback(err, data, step, sessionId);
} else {
that.adapter.log.warn('[getHistory] Invalid callback')
}
});
}
});
// HTTP
socket.on('httpGet', function (url, callback) {
if (updateSession(socket) && checkPermissions(socket, 'httpGet', callback, url)) {
if (!request) request = require('request');
that.adapter.log.debug('httpGet: ' + url);
request(url, callback);
}
});
// commands
socket.on('sendTo', function (adapterInstance, command, message, callback) {
if (updateSession(socket) && checkPermissions(socket, 'sendTo', callback, command)) {
that.adapter.sendTo(adapterInstance, command, message, callback);
}
});
// following commands are protected and require the extra permissions
const protectedCommands = ['cmdExec', 'getLocationOnDisk', 'getDiagData', 'getDevList', 'delLogs', 'writeDirAsZip', 'writeObjectsAsZip', 'readObjectsAsZip', 'checkLogging', 'updateMultihost'];
socket.on('sendToHost', function (host, command, message, callback) {
// host can answer following commands: cmdExec, getRepository, getInstalled, getInstalledAdapter, getVersion, getDiagData, getLocationOnDisk, getDevList, getLogs, getHostInfo,
// delLogs, readDirAsZip, writeDirAsZip, readObjectsAsZip, writeObjectsAsZip, checkLogging, updateMultihost
if (updateSession(socket) && checkPermissions(socket, protectedCommands.indexOf(command) !== -1 ? 'cmdExec' : 'sendToHost', callback, command)) {
that.adapter.sendToHost(host, command, message, callback);
}
});
socket.on('authEnabled', callback => {
if (updateSession(socket) && checkPermissions(socket, 'authEnabled', callback)) {
if (typeof callback === 'function') {
callback(that.settings.auth, socket._acl.user.replace(/^system\.user\./, ''));
} else {
that.adapter.log.warn('[authEnabled] Invalid callback')
}
}
});
// file operations
socket.on('readFile', function (_adapter, fileName, callback) {
if (updateSession(socket) && checkPermissions(socket, 'readFile', callback, fileName)) {
that.adapter.readFile(_adapter, fileName, {user: socket._acl.user}, callback);
}
});
socket.on('readFile64', function (_adapter, fileName, callback) {
if (updateSession(socket) && checkPermissions(socket, 'readFile64', callback, fileName)) {
that.adapter.readFile(_adapter, fileName, {user: socket._acl.user}, function (err, buffer, type) {
let data64;
if (buffer) {
if (type === 'application/json') {
data64 = new Buffer(encodeURIComponent(buffer)).toString('base64');
} else {
if (typeof buffer === 'string') {
data64 = new Buffer(buffer).toString('base64');
} else {
data64 = buffer.toString('base64');
}
}
}
//Convert buffer to base 64
if (typeof callback === 'function') {
callback(err, data64 || '', type);
} else {
that.adapter.log.warn('[readFile64] Invalid callback')
}
});
}
});
socket.on('writeFile64', function (_adapter, fileName, data64, options, callback) {
if (typeof options === 'function') {
callback = options;
options = {user: socket._acl.user};
}
if (!options) options = {};
options.user = socket._acl.user;
if (updateSession(socket) && checkPermissions(socket, 'writeFile64', callback, fileName)) {
//Convert base 64 to buffer
let buffer = new Buffer(data64, 'base64');
that.adapter.writeFile(_adapter, fileName, buffer, options, function (err) {
if (typeof callback === 'function') {
callback(err);
}
});
}
});
socket.on('writeFile', function (_adapter, fileName, data, options, callback) {
if (typeof options === 'function') {
callback = options;
options = {user: socket._acl.user};
}
if (!options) options = {};
options.user = socket._acl.user;
if (updateSession(socket) && checkPermissions(socket, 'writeFile', callback, fileName)) {
that.adapter.writeFile(_adapter, fileName, data, options, callback);
}
});
socket.on('unlink', function (_adapter, name, callback) {
if (updateSession(socket) && checkPermissions(socket, 'unlink', callback, name)) {
that.adapter.unlink(_adapter, name, {user: socket._acl.user}, callback);
}
});
socket.on('rename', function (_adapter, oldName, newName, callback) {
if (updateSession(socket) && checkPermissions(socket, 'rename', callback, oldName)) {
that.adapter.rename(_adapter, oldName, newName, {user: socket._acl.user}, callback);
}
});
socket.on('mkdir', function (_adapter, dirName, callback) {
if (updateSession(socket) && checkPermissions(socket, 'mkdir', callback, dirName)) {
that.adapter.mkdir(_adapter, dirName, {user: socket._acl.user}, callback);
}
});
socket.on('readDir', function (_adapter, dirName, options, callback) {
if (typeof options === 'function') {
callback = options;
options = {};
}
options = options || {};
options.user = socket._acl.user;
if (options.filter === undefined) options.filter = true;
if (updateSession(socket) && checkPermissions(socket, 'readDir', callback, dirName)) {
that.adapter.readDir(_adapter, dirName, options, callback);
}
});
socket.on('chmodFile', function (_adapter, dirName, options, callback) {
if (typeof options === 'function') {
callback = options;
options = {};
}
options = options || {};
options.user = socket._acl.user;
if (options.filter === undefined) options.filter = true;
if (updateSession(socket) && checkPermissions(socket, 'chmodFile', callback, dirName)) {
that.adapter.chmodFile(_adapter, dirName, options, callback);
}
});
// connect/disconnect
socket.on('disconnect', function (error) {
that.adapter.log.info('<==Disconnect ' + socket._acl.user + ' from ' + getClientAddress(socket) + ' ' + (socket._name || ''));
unsubscribeSocket(this, 'stateChange');
unsubscribeSocket(this, 'objectChange');
unsubscribeSocket(this, 'log');
if (!that.infoTimeout) that.infoTimeout = setTimeout(updateConnectedInfo, 1000);
// if client mode
if (!socket.conn) {
socket._apiKeyOk = false;
that.emit && that.emit('disconnect', error);
}
});
socket.on('logout', function (callback) {
that.adapter.destroySession(socket._sessionID, callback);
});
socket.on('listPermissions', function (callback) {
if (updateSession(socket)) {
if (typeof callback === 'function') {
callback(commandsPermissions);
} else {
that.adapter.log.warn('[listPermissions] Invalid callback');
}
}
});
socket.on('getUserPermissions', function (callback) {
if (updateSession(socket) && checkPermissions(socket, 'getUserPermissions', callback)) {
if (typeof callback === 'function') {
callback(null, socket._acl);
} else {
that.adapter.log.warn('[getUserPermissions] Invalid callback')
}
}
});
if (typeof that.settings.extensions === 'function') {
that.settings.extensions(socket);
}
// if client mode
if (!socket.conn) {
socket._apiKeyOk = false;
socket.on('cloudDisconnect', function (err) {
err && that.adapter.log.warn('User disconnected from cloud: ' + err);
unsubscribeSocket(socket, 'stateChange');
unsubscribeSocket(socket, 'objectChange');
unsubscribeSocket(socket, 'log');
that.emit('cloudDisconnect');
});
socket.on('cloudConnect', function () {
// do not autosubscribe. The client must resubscribe all states anew
// subscribeSocket(socket, 'stateChange');
// subscribeSocket(socket, 'objectChange');
// subscribeSocket(socket, 'log');
that.emit('cloudConnect');
});
socket.on('cloudCommand', function (cmd, data) {
if (cmd === 'stop') {
stopAdapter(data);
} else if (cmd === 'redirect') {
redirectAdapter(data);
} else if (cmd === 'wait') {
waitForConnect(data || 30);
}
});
// only active in client mode
socket.on('connect', function () {
that.adapter.log.debug('Connected. Check api key...');
socket._apiKeyOk = false;
// 2018_01_20 workaround for pro: Remove it after next pro maintenance
if (that.settings.apikey.indexOf('@pro_') !== -1) {
socket._apiKeyOk = true;
that.emit && that.emit('connect');
}
// send api key if exists
this.emit('apikey', that.settings.apikey, that.settings.version, that.settings.uuid, function (err, instructions) {
// instructions = {
// validTill: '2018-03-14T01:01:01.567Z',
// command: 'wait' | 'stop' | 'redirect'
// data: some data for command (URL for redirect or seconds for wait'
if (instructions) {
if (typeof instructions !== 'object') {
that.adapter.setState('info.remoteTill', new Date(instructions).toISOString(), true);
} else {
if (instructions.validTill) {
that.adapter.setState('info.remoteTill', new Date(instructions.validTill).toISOString(), true);
}
if (instructions.command === 'stop') {
stopAdapter(instructions.data);
} else if (instructions.command === 'redirect') {
redirectAdapter(instructions.data);
} else if (instructions.command === 'wait') {
waitForConnect(instructions.data || 30);
}
}
}
if (!err) {
that.adapter.log.debug('API KEY OK');
socket._apiKeyOk = true;
that.emit && that.emit('connect');
} else {
if (err.indexOf('Please buy remote access to use pro.') !== -1) {
stopAdapter('Please buy remote access to use pro.');
}
that.adapter.log.error(err);
this.close(); // disconnect
}
});
if (socket._sessionID) {
that.adapter.getSession(socket._sessionID, function (obj) {
if (obj && obj.passport) {
socket._acl.user = obj.passport.user;
} else {
socket._acl.user = '';
socket.emit('reauthenticate');
socket.disconnect();
}
if (socket._authPending) {
socket._authPending(!!socket._acl.user, true);
delete socket._authPending;
}
});
}
subscribeSocket(this, 'stateChange');
subscribeSocket(this, 'objectChange');
subscribeSocket(this, 'log');
});
/*socket.on('reconnect', function (attempt) {
that.adapter.log.debug('Connected after attempt ' + attempt);
});
socket.on('reconnect_attempt', function (attempt) {
that.adapter.log.debug('reconnect_attempt');
});
socket.on('connect_error', function (error) {
that.adapter.log.debug('connect_error: ' + error);
});
socket.on('connect_timeout', function (error) {
that.adapter.log.debug('connect_timeout');
});
socket.on('reconnect_failed', function (error) {
that.adapter.log.debug('reconnect_failed');
});*/
} else {
// if server mode
if (socket.conn.request.sessionID) {
socket._secure = true;
socket._sessionID = socket.conn.request.sessionID;
// Get user for session
that.settings.store.get(socket.conn.request.sessionID, function (err, obj) {
if (!obj || !obj.passport) {
socket._acl.user = '';
socket.emit('reauthenticate');
socket.disconnect();
}
if (socket._authPending) {
socket._authPending(!!socket._acl.user, true);
delete socket._authPending;
}
});
}
subscribeSocket(socket, 'stateChange');
subscribeSocket(socket, 'objectChange');
subscribeSocket(socket, 'log');
}
}
function updateConnectedInfo() {
if (that.infoTimeout) {
clearTimeout(that.infoTimeout);
that.infoTimeout = null;
}
if (that.server.sockets) {
let text = '';
let cnt = 0;
if (that.server) {
let clients = that.server.sockets.connected;
for (let i in clients) {
if (clients.hasOwnProperty(i)) {
text += (text ? ', ' : '') + (clients[i]._name || 'noname');
cnt++;
}
}
}
text = '[' + cnt + ']' + text;
that.adapter.setState('connected', text, true);
}
}
this.publishAll = function (type, id, obj) {
if (id === undefined) {
console.log('Problem');
}
let clients = this.server.sockets.connected;
for (let i in clients) {
if (clients.hasOwnProperty(i)) {
publish(clients[i], type, id, obj);
}
}
};
this.sendLog = function (obj) {
// TODO Build in some threshold
if (this.server && this.server.sockets) {
this.server.sockets.emit('log', obj);
}
};
(function __constructor() {
if (that.settings.allowAdmin) {
// detect event bursts
setInterval(function () {
if (!eventsThreshold.active) {
if (eventsThreshold.count > eventsThreshold.value) {
eventsThreshold.accidents++;
if (eventsThreshold.accidents >= eventsThreshold.repeatSeconds) {
enableEventThreshold();
}
} else {
eventsThreshold.accidents = 0;
}
eventsThreshold.count = 0;
} else if (new Date().getTime() - eventsThreshold.timeActivated > 60000) {
disableEventThreshold();
}
}, eventsThreshold.checkInterval);
}
// it can be used as client too for cloud
if (!that.settings.apikey) {
if (!that.webServer.__inited) {
that.server = socketio.listen(that.webServer);
that.webServer.__inited = true;
}
// force using only websockets
if (that.settings.forceWebSockets) that.server.set('transports', ['websocket']);
} else {
that.server = server;
}
// socket = socketio.listen(settings.port, (settings.bind && settings.bind !== "0.0.0.0") ? settings.bind : undefined);
that.settings.defaultUser = that.settings.defaultUser || 'system.user.admin';
if (!that.settings.defaultUser.match(/^system\.user\./)) that.settings.defaultUser = 'system.user.' + that.settings.defaultUser;
if (that.settings.auth && that.server) {
that.server.use(function (socket, next) {
if (!socket.request._query.user || !socket.request._query.pass) {
getUserFromSocket(socket, function (err, user) {
if (err || !user) {
socket.emit('reauthenticate');
that.adapter.log.error('socket.io ' + (err || 'User not found'));
socket.disconnect();
} else {
socket._secure = true;
that.adapter.calculatePermissions('system.user.' + user, commandsPermissions, function (acl) {
let address = getClientAddress(socket);
// socket._acl = acl;
socket._acl = mergeACLs(address, acl, that.settings.whiteListSettings);
next();
});
}
});
} else {
that.adapter.checkPassword(socket.request._query.user, socket.request._query.pass, function (res) {
if (res) {
that.adapter.log.debug('Logged in: ' + socket.request._query.user + ', ' + socket.request._query.pass);
next();
} else {
that.adapter.log.warn('Invalid password or user name: ' + socket.request._query.user + ', ' + socket.request._query.pass);
socket.emit('reauthenticate');
next(new Error('Invalid password or user name'));
}
});
}
});
}
// Enable cross domain access
if (that.settings.crossDomain && that.server.set) {
that.server.set('origins', '*:*');
}
that.settings.ttl = that.settings.ttl || 3600;
that.server.on('connection', that.initSocket);
if (settings.port) {
that.adapter.log.info((settings.secure ? 'Secure ' : '') + 'socket.io server listening on port ' + settings.port);
}
if (!that.infoTimeout) that.infoTimeout = setTimeout(updateConnectedInfo, 1000);
// if client mode => add event handlers
if (that.settings.apikey) {
that.initSocket(that.server);
}
})();
}
util.inherits(IOSocket, EventEmitter);
module.exports = IOSocket;