2016-10-09 15:14:02 -04:00
|
|
|
"use strict";
|
|
|
|
|
2014-08-14 13:25:22 -04:00
|
|
|
var _ = require("lodash");
|
2016-12-11 03:29:09 -05:00
|
|
|
var colors = require("colors/safe");
|
2014-08-13 19:43:11 -04:00
|
|
|
var fs = require("fs");
|
2014-08-13 21:51:54 -04:00
|
|
|
var Client = require("./client");
|
2014-09-13 08:23:17 -04:00
|
|
|
var Helper = require("./helper");
|
2017-07-10 15:47:03 -04:00
|
|
|
const WebPush = require("./plugins/webpush");
|
2014-08-13 19:43:11 -04:00
|
|
|
|
|
|
|
module.exports = ClientManager;
|
|
|
|
|
|
|
|
function ClientManager() {
|
2014-08-14 12:35:37 -04:00
|
|
|
this.clients = [];
|
2016-12-17 04:51:33 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
ClientManager.prototype.init = function(identHandler, sockets) {
|
|
|
|
this.sockets = sockets;
|
|
|
|
this.identHandler = identHandler;
|
2017-07-10 15:47:03 -04:00
|
|
|
this.webPush = new WebPush();
|
2016-12-17 04:51:33 -05:00
|
|
|
|
2017-08-23 01:11:28 -04:00
|
|
|
if (!Helper.config.public && !Helper.config.ldap.enable) {
|
2016-12-17 04:51:33 -05:00
|
|
|
if ("autoload" in Helper.config) {
|
|
|
|
log.warn(`Autoloading users is now always enabled. Please remove the ${colors.yellow("autoload")} option from your configuration file.`);
|
|
|
|
}
|
2016-04-26 16:41:08 -04:00
|
|
|
|
2016-12-17 04:51:33 -05:00
|
|
|
this.autoloadUsers();
|
2016-04-26 16:41:08 -04:00
|
|
|
}
|
2016-12-17 04:51:33 -05:00
|
|
|
};
|
2014-08-13 19:43:11 -04:00
|
|
|
|
2017-06-21 03:58:29 -04:00
|
|
|
ClientManager.prototype.findClient = function(name) {
|
|
|
|
return this.clients.find((u) => u.name === name);
|
2014-08-14 12:35:37 -04:00
|
|
|
};
|
|
|
|
|
2016-12-07 00:50:11 -05:00
|
|
|
ClientManager.prototype.autoloadUsers = function() {
|
2017-08-23 01:11:28 -04:00
|
|
|
const users = this.getUsers();
|
|
|
|
const noUsersWarning = `There are currently no users. Create one with ${colors.bold("lounge add <name>")}.`;
|
|
|
|
|
2017-08-23 01:42:59 -04:00
|
|
|
// There was an error, already logged, but we have to crash the server as
|
|
|
|
// user directory could not be accessed
|
|
|
|
if (users === undefined) {
|
|
|
|
process.exit(1);
|
|
|
|
}
|
|
|
|
|
2017-08-26 00:55:49 -04:00
|
|
|
if (users.length === 0) {
|
2017-08-23 01:11:28 -04:00
|
|
|
log.info(noUsersWarning);
|
|
|
|
}
|
|
|
|
|
|
|
|
users.forEach((name) => this.loadUser(name));
|
2016-12-07 00:50:11 -05:00
|
|
|
|
|
|
|
fs.watch(Helper.USERS_PATH, _.debounce(() => {
|
2017-04-08 08:34:31 -04:00
|
|
|
const loaded = this.clients.map((c) => c.name);
|
2016-12-07 00:50:11 -05:00
|
|
|
const updatedUsers = this.getUsers();
|
|
|
|
|
2017-08-26 00:55:49 -04:00
|
|
|
if (updatedUsers.length === 0) {
|
2017-08-23 01:11:28 -04:00
|
|
|
log.info(noUsersWarning);
|
|
|
|
}
|
|
|
|
|
2016-12-07 00:50:11 -05:00
|
|
|
// New users created since last time users were loaded
|
2017-04-08 08:34:31 -04:00
|
|
|
_.difference(updatedUsers, loaded).forEach((name) => this.loadUser(name));
|
2016-12-07 00:50:11 -05:00
|
|
|
|
|
|
|
// Existing users removed since last time users were loaded
|
2017-04-08 08:34:31 -04:00
|
|
|
_.difference(loaded, updatedUsers).forEach((name) => {
|
2016-12-07 00:50:11 -05:00
|
|
|
const client = _.find(this.clients, {name: name});
|
|
|
|
if (client) {
|
2017-08-30 13:26:45 -04:00
|
|
|
client.quit(true);
|
2016-12-07 00:50:11 -05:00
|
|
|
this.clients = _.without(this.clients, client);
|
2016-12-11 03:29:09 -05:00
|
|
|
log.info(`User ${colors.bold(name)} disconnected and removed`);
|
2016-12-07 00:50:11 -05:00
|
|
|
}
|
|
|
|
});
|
|
|
|
}, 1000, {maxWait: 10000}));
|
2014-08-13 21:51:54 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
ClientManager.prototype.loadUser = function(name) {
|
2016-10-09 04:54:44 -04:00
|
|
|
let json;
|
2014-08-13 21:51:54 -04:00
|
|
|
try {
|
2016-10-09 04:54:44 -04:00
|
|
|
json = this.readUserConfig(name);
|
2015-09-30 18:39:57 -04:00
|
|
|
} catch (e) {
|
2016-04-16 07:32:38 -04:00
|
|
|
log.error("Failed to read user config", e);
|
2014-08-13 21:51:54 -04:00
|
|
|
return;
|
|
|
|
}
|
2014-09-24 18:23:54 -04:00
|
|
|
if (!this.findClient(name)) {
|
|
|
|
this.clients.push(new Client(
|
2016-02-16 19:14:43 -05:00
|
|
|
this,
|
2014-09-24 18:23:54 -04:00
|
|
|
name,
|
|
|
|
json
|
|
|
|
));
|
|
|
|
}
|
2014-08-13 19:43:11 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
ClientManager.prototype.getUsers = function() {
|
|
|
|
var users = [];
|
|
|
|
try {
|
2016-05-08 02:21:31 -04:00
|
|
|
var files = fs.readdirSync(Helper.USERS_PATH);
|
2017-04-08 08:34:31 -04:00
|
|
|
files.forEach((file) => {
|
2014-10-14 18:24:15 -04:00
|
|
|
if (file.indexOf(".json") !== -1) {
|
|
|
|
users.push(file.replace(".json", ""));
|
|
|
|
}
|
2014-10-14 16:05:16 -04:00
|
|
|
});
|
2015-09-30 18:39:57 -04:00
|
|
|
} catch (e) {
|
2017-08-23 01:42:59 -04:00
|
|
|
log.error(`Failed to get users (${e})`);
|
2014-08-13 19:43:11 -04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
return users;
|
|
|
|
};
|
|
|
|
|
2017-01-29 14:33:57 -05:00
|
|
|
ClientManager.prototype.addUser = function(name, password, enableLog) {
|
2014-08-13 19:43:11 -04:00
|
|
|
var users = this.getUsers();
|
|
|
|
if (users.indexOf(name) !== -1) {
|
2014-08-14 13:25:22 -04:00
|
|
|
return false;
|
2014-08-13 19:43:11 -04:00
|
|
|
}
|
|
|
|
try {
|
2016-05-08 02:21:31 -04:00
|
|
|
if (require("path").basename(name) !== name) {
|
2016-04-02 17:19:57 -04:00
|
|
|
throw new Error(name + " is an invalid username.");
|
|
|
|
}
|
|
|
|
|
2014-08-13 21:51:54 -04:00
|
|
|
var user = {
|
|
|
|
user: name,
|
|
|
|
password: password || "",
|
2017-01-29 14:33:57 -05:00
|
|
|
log: enableLog,
|
2017-04-28 11:58:14 -04:00
|
|
|
awayMessage: "",
|
2017-06-21 03:58:29 -04:00
|
|
|
networks: [],
|
|
|
|
sessions: {},
|
2014-08-13 21:51:54 -04:00
|
|
|
};
|
|
|
|
fs.writeFileSync(
|
2016-05-08 02:21:31 -04:00
|
|
|
Helper.getUserConfigPath(name),
|
2016-06-19 13:16:50 -04:00
|
|
|
JSON.stringify(user, null, "\t")
|
2014-08-13 21:51:54 -04:00
|
|
|
);
|
2015-09-30 18:39:57 -04:00
|
|
|
} catch (e) {
|
2016-04-02 17:19:57 -04:00
|
|
|
log.error("Failed to add user " + name, e);
|
2014-08-13 19:43:11 -04:00
|
|
|
throw e;
|
|
|
|
}
|
2014-08-14 13:25:22 -04:00
|
|
|
return true;
|
2014-08-13 19:43:11 -04:00
|
|
|
};
|
|
|
|
|
2016-11-19 15:54:16 -05:00
|
|
|
ClientManager.prototype.updateUser = function(name, opts, callback) {
|
|
|
|
const users = this.getUsers();
|
2016-02-16 19:14:43 -05:00
|
|
|
if (users.indexOf(name) === -1) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (typeof opts === "undefined") {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2017-04-08 08:34:31 -04:00
|
|
|
const user = this.readUserConfig(name);
|
2016-11-19 15:54:16 -05:00
|
|
|
const currentUser = JSON.stringify(user, null, "\t");
|
|
|
|
_.assign(user, opts);
|
|
|
|
const newUser = JSON.stringify(user, null, "\t");
|
|
|
|
|
|
|
|
// Do not touch the disk if object has not changed
|
|
|
|
if (currentUser === newUser) {
|
|
|
|
return callback ? callback() : true;
|
2016-02-16 19:14:43 -05:00
|
|
|
}
|
2016-11-19 15:54:16 -05:00
|
|
|
|
|
|
|
fs.writeFile(Helper.getUserConfigPath(name), newUser, (err) => {
|
|
|
|
if (err) {
|
2017-09-17 04:09:19 -04:00
|
|
|
log.error(`Failed to update user ${colors.green(name)} (${err})`);
|
2016-11-19 15:54:16 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
if (callback) {
|
|
|
|
callback(err);
|
|
|
|
}
|
|
|
|
});
|
2016-02-16 19:14:43 -05:00
|
|
|
};
|
|
|
|
|
|
|
|
ClientManager.prototype.readUserConfig = function(name) {
|
|
|
|
var users = this.getUsers();
|
|
|
|
if (users.indexOf(name) === -1) {
|
|
|
|
return false;
|
|
|
|
}
|
2016-05-08 02:21:31 -04:00
|
|
|
var data = fs.readFileSync(Helper.getUserConfigPath(name), "utf-8");
|
2016-06-12 02:43:35 -04:00
|
|
|
return JSON.parse(data);
|
2016-02-16 19:14:43 -05:00
|
|
|
};
|
|
|
|
|
2014-08-13 19:43:11 -04:00
|
|
|
ClientManager.prototype.removeUser = function(name) {
|
|
|
|
var users = this.getUsers();
|
|
|
|
if (users.indexOf(name) === -1) {
|
2014-08-14 13:25:22 -04:00
|
|
|
return false;
|
2014-08-13 19:43:11 -04:00
|
|
|
}
|
|
|
|
try {
|
2016-05-08 02:21:31 -04:00
|
|
|
fs.unlinkSync(Helper.getUserConfigPath(name));
|
2015-09-30 18:39:57 -04:00
|
|
|
} catch (e) {
|
2014-08-13 19:43:11 -04:00
|
|
|
throw e;
|
|
|
|
}
|
2014-08-14 13:25:22 -04:00
|
|
|
return true;
|
2014-08-13 19:43:11 -04:00
|
|
|
};
|