thelounge/src/clientManager.js

175 lines
4.3 KiB
JavaScript
Raw Normal View History

"use strict";
2017-10-15 18:05:19 +02:00
const _ = require("lodash");
const colors = require("colors/safe");
const fs = require("fs");
const path = require("path");
const Client = require("./client");
const Helper = require("./helper");
2017-07-10 21:47:03 +02:00
const WebPush = require("./plugins/webpush");
2014-08-14 01:43:11 +02:00
module.exports = ClientManager;
function ClientManager() {
this.clients = [];
}
ClientManager.prototype.init = function(identHandler, sockets) {
this.sockets = sockets;
this.identHandler = identHandler;
2017-07-10 21:47:03 +02:00
this.webPush = new WebPush();
if (!Helper.config.public && !Helper.config.ldap.enable) {
2017-10-15 18:05:19 +02:00
// TODO: Remove deprecated warning in v3.0.0
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 22:41:08 +02:00
this.autoloadUsers();
2016-04-26 22:41:08 +02:00
}
};
2014-08-14 01:43:11 +02:00
ClientManager.prototype.findClient = function(name) {
return this.clients.find((u) => u.name === name);
};
ClientManager.prototype.autoloadUsers = function() {
const users = this.getUsers();
const noUsersWarning = `There are currently no users. Create one with ${colors.bold("thelounge add <name>")}.`;
if (users.length === 0) {
log.info(noUsersWarning);
}
users.forEach((name) => this.loadUser(name));
fs.watch(Helper.USERS_PATH, _.debounce(() => {
const loaded = this.clients.map((c) => c.name);
const updatedUsers = this.getUsers();
if (updatedUsers.length === 0) {
log.info(noUsersWarning);
}
// New users created since last time users were loaded
_.difference(updatedUsers, loaded).forEach((name) => this.loadUser(name));
// Existing users removed since last time users were loaded
_.difference(loaded, updatedUsers).forEach((name) => {
const client = _.find(this.clients, {name: name});
if (client) {
2017-08-30 19:26:45 +02:00
client.quit(true);
this.clients = _.without(this.clients, client);
2017-10-15 18:05:19 +02:00
log.info(`User ${colors.bold(name)} disconnected and removed.`);
}
});
}, 1000, {maxWait: 10000}));
2014-08-14 03:51:54 +02:00
};
ClientManager.prototype.loadUser = function(name) {
2017-10-15 18:05:19 +02:00
const user = readUserConfig(name);
if (!user) {
2014-08-14 03:51:54 +02:00
return;
}
2017-10-15 18:05:19 +02:00
let client = this.findClient(name);
if (client) {
log.warn(`Tried to load user ${colors.bold(name)}, which is already loaded.`);
return client;
2014-09-25 00:23:54 +02:00
}
2017-10-15 18:05:19 +02:00
client = new Client(this, name, user);
this.clients.push(client);
return client;
2014-08-14 01:43:11 +02:00
};
ClientManager.prototype.getUsers = function() {
2017-10-15 18:05:19 +02:00
return fs
.readdirSync(Helper.USERS_PATH)
.filter((file) => file.endsWith(".json"))
.map((file) => file.slice(0, -5));
2014-08-14 01:43:11 +02:00
};
ClientManager.prototype.addUser = function(name, password, enableLog) {
2017-10-15 18:05:19 +02:00
if (path.basename(name) !== name) {
throw new Error(`${name} is an invalid username.`);
}
const userPath = Helper.getUserConfigPath(name);
if (fs.existsSync(userPath)) {
log.error(`User ${colors.green(name)} already exists.`);
2014-08-14 19:25:22 +02:00
return false;
2014-08-14 01:43:11 +02:00
}
2017-10-15 18:05:19 +02:00
const user = {
password: password || "",
log: enableLog || false,
awayMessage: "",
networks: [],
sessions: {},
};
try {
fs.writeFileSync(userPath, JSON.stringify(user, null, "\t"));
2015-10-01 00:39:57 +02:00
} catch (e) {
2017-10-15 18:05:19 +02:00
log.error(`Failed to create user ${colors.green(name)} (${e})`);
2014-08-14 01:43:11 +02:00
throw e;
}
2017-10-15 18:05:19 +02:00
2014-08-14 19:25:22 +02:00
return true;
2014-08-14 01:43:11 +02:00
};
ClientManager.prototype.updateUser = function(name, opts, callback) {
2017-10-15 18:05:19 +02:00
const user = readUserConfig(name);
if (!user) {
log.error(`Tried to update invalid user ${colors.green(name)}. This is most likely a bug.`);
return false;
}
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;
}
try {
fs.writeFileSync(Helper.getUserConfigPath(name), newUser);
} catch (e) {
log.error(`Failed to update user ${colors.green(name)} (${e})`);
throw e;
}
};
2017-10-15 18:05:19 +02:00
ClientManager.prototype.removeUser = function(name) {
const userPath = Helper.getUserConfigPath(name);
if (!fs.existsSync(userPath)) {
log.error(`Tried to remove non-existing user ${colors.green(name)}.`);
return false;
}
2017-10-15 18:05:19 +02:00
fs.unlinkSync(userPath);
return true;
};
2017-10-15 18:05:19 +02:00
function readUserConfig(name) {
const userPath = Helper.getUserConfigPath(name);
if (!fs.existsSync(userPath)) {
log.error(`Tried to read non-existing user ${colors.green(name)}`);
2014-08-14 19:25:22 +02:00
return false;
2014-08-14 01:43:11 +02:00
}
2017-10-15 18:05:19 +02:00
const data = fs.readFileSync(userPath, "utf-8");
return JSON.parse(data);
}