@lordbex/thelounge 4.4.3-blowfish → 4.5.0-blowfish-pre

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (141) hide show
  1. package/README.md +31 -7
  2. package/dist/defaults/config.js +31 -2
  3. package/dist/package.json +94 -91
  4. package/dist/server/client.js +188 -194
  5. package/dist/server/clientManager.js +75 -72
  6. package/dist/server/command-line/index.js +44 -43
  7. package/dist/server/command-line/install.js +37 -70
  8. package/dist/server/command-line/outdated.js +12 -17
  9. package/dist/server/command-line/start.js +25 -26
  10. package/dist/server/command-line/storage.js +26 -31
  11. package/dist/server/command-line/uninstall.js +16 -23
  12. package/dist/server/command-line/upgrade.js +20 -26
  13. package/dist/server/command-line/users/add.js +33 -40
  14. package/dist/server/command-line/users/edit.js +18 -24
  15. package/dist/server/command-line/users/index.js +12 -16
  16. package/dist/server/command-line/users/list.js +11 -39
  17. package/dist/server/command-line/users/remove.js +16 -22
  18. package/dist/server/command-line/users/reset.js +34 -35
  19. package/dist/server/command-line/utils.js +231 -87
  20. package/dist/server/config.js +61 -52
  21. package/dist/server/helper.js +29 -28
  22. package/dist/server/identification.js +39 -34
  23. package/dist/server/index.js +1 -3
  24. package/dist/server/log.js +19 -16
  25. package/dist/server/models/chan.js +36 -33
  26. package/dist/server/models/msg.js +15 -19
  27. package/dist/server/models/network.js +102 -104
  28. package/dist/server/models/prefix.js +4 -7
  29. package/dist/server/models/user.js +5 -10
  30. package/dist/server/path-helper.js +8 -0
  31. package/dist/server/plugins/auth/ldap.js +177 -112
  32. package/dist/server/plugins/auth/local.js +10 -15
  33. package/dist/server/plugins/auth.js +6 -35
  34. package/dist/server/plugins/changelog.js +30 -27
  35. package/dist/server/plugins/clientCertificate.js +33 -37
  36. package/dist/server/plugins/dev-server.js +15 -21
  37. package/dist/server/plugins/inputs/action.js +9 -14
  38. package/dist/server/plugins/inputs/away.js +1 -3
  39. package/dist/server/plugins/inputs/ban.js +9 -14
  40. package/dist/server/plugins/inputs/blow.js +9 -14
  41. package/dist/server/plugins/inputs/connect.js +5 -10
  42. package/dist/server/plugins/inputs/ctcp.js +7 -12
  43. package/dist/server/plugins/inputs/disconnect.js +1 -3
  44. package/dist/server/plugins/inputs/ignore.js +23 -29
  45. package/dist/server/plugins/inputs/ignorelist.js +12 -18
  46. package/dist/server/plugins/inputs/index.js +8 -34
  47. package/dist/server/plugins/inputs/invite.js +7 -12
  48. package/dist/server/plugins/inputs/kick.js +7 -12
  49. package/dist/server/plugins/inputs/kill.js +1 -3
  50. package/dist/server/plugins/inputs/list.js +1 -3
  51. package/dist/server/plugins/inputs/mode.js +10 -15
  52. package/dist/server/plugins/inputs/msg.js +13 -18
  53. package/dist/server/plugins/inputs/mute.js +9 -15
  54. package/dist/server/plugins/inputs/nick.js +9 -14
  55. package/dist/server/plugins/inputs/notice.js +5 -7
  56. package/dist/server/plugins/inputs/part.js +11 -16
  57. package/dist/server/plugins/inputs/quit.js +7 -13
  58. package/dist/server/plugins/inputs/rainbow.js +55 -0
  59. package/dist/server/plugins/inputs/raw.js +1 -3
  60. package/dist/server/plugins/inputs/rejoin.js +7 -12
  61. package/dist/server/plugins/inputs/topic.js +7 -12
  62. package/dist/server/plugins/inputs/whois.js +1 -3
  63. package/dist/server/plugins/irc-events/away.js +14 -20
  64. package/dist/server/plugins/irc-events/cap.js +16 -22
  65. package/dist/server/plugins/irc-events/chghost.js +14 -13
  66. package/dist/server/plugins/irc-events/connection.js +61 -63
  67. package/dist/server/plugins/irc-events/ctcp.js +22 -28
  68. package/dist/server/plugins/irc-events/error.js +20 -26
  69. package/dist/server/plugins/irc-events/help.js +7 -13
  70. package/dist/server/plugins/irc-events/info.js +7 -13
  71. package/dist/server/plugins/irc-events/invite.js +7 -13
  72. package/dist/server/plugins/irc-events/join.js +30 -27
  73. package/dist/server/plugins/irc-events/kick.js +21 -17
  74. package/dist/server/plugins/irc-events/link.js +122 -109
  75. package/dist/server/plugins/irc-events/list.js +23 -26
  76. package/dist/server/plugins/irc-events/message.js +46 -52
  77. package/dist/server/plugins/irc-events/mode.js +66 -63
  78. package/dist/server/plugins/irc-events/modelist.js +29 -35
  79. package/dist/server/plugins/irc-events/motd.js +10 -16
  80. package/dist/server/plugins/irc-events/names.js +3 -6
  81. package/dist/server/plugins/irc-events/nick.js +26 -23
  82. package/dist/server/plugins/irc-events/part.js +19 -15
  83. package/dist/server/plugins/irc-events/quit.js +17 -14
  84. package/dist/server/plugins/irc-events/sasl.js +9 -15
  85. package/dist/server/plugins/irc-events/spgroups.js +38 -0
  86. package/dist/server/plugins/irc-events/spjoin.js +52 -0
  87. package/dist/server/plugins/irc-events/topic.js +12 -18
  88. package/dist/server/plugins/irc-events/unhandled.js +12 -12
  89. package/dist/server/plugins/irc-events/welcome.js +7 -13
  90. package/dist/server/plugins/irc-events/whois.js +20 -24
  91. package/dist/server/plugins/massEventAggregator.js +214 -0
  92. package/dist/server/plugins/messageStorage/sqlite.js +322 -141
  93. package/dist/server/plugins/messageStorage/text.js +21 -26
  94. package/dist/server/plugins/packages/index.js +105 -74
  95. package/dist/server/plugins/packages/publicClient.js +7 -16
  96. package/dist/server/plugins/packages/themes.js +11 -16
  97. package/dist/server/plugins/storage.js +28 -33
  98. package/dist/server/plugins/sts.js +12 -17
  99. package/dist/server/plugins/uploader.js +40 -43
  100. package/dist/server/plugins/webpush.js +23 -51
  101. package/dist/server/server.js +318 -271
  102. package/dist/server/storageCleaner.js +29 -37
  103. package/dist/server/utils/fish.js +349 -389
  104. package/dist/shared/irc.js +3 -6
  105. package/dist/shared/linkify.js +7 -14
  106. package/dist/shared/types/chan.js +6 -9
  107. package/dist/shared/types/changelog.js +1 -2
  108. package/dist/shared/types/config.js +1 -2
  109. package/dist/shared/types/mention.js +1 -2
  110. package/dist/shared/types/msg.js +3 -5
  111. package/dist/shared/types/network.js +1 -2
  112. package/dist/shared/types/storage.js +1 -2
  113. package/dist/shared/types/user.js +1 -2
  114. package/index.js +14 -10
  115. package/package.json +94 -91
  116. package/public/css/style.css +9 -6
  117. package/public/css/style.css.map +1 -1
  118. package/public/fonts/font-awesome/fa-brands-400.ttf +0 -0
  119. package/public/fonts/font-awesome/fa-brands-400.woff2 +0 -0
  120. package/public/fonts/font-awesome/fa-duotone-900.ttf +0 -0
  121. package/public/fonts/font-awesome/fa-duotone-900.woff2 +0 -0
  122. package/public/fonts/font-awesome/fa-light-300.ttf +0 -0
  123. package/public/fonts/font-awesome/fa-light-300.woff2 +0 -0
  124. package/public/fonts/font-awesome/fa-regular-400.ttf +0 -0
  125. package/public/fonts/font-awesome/fa-regular-400.woff2 +0 -0
  126. package/public/fonts/font-awesome/fa-solid-900.ttf +0 -0
  127. package/public/fonts/font-awesome/fa-solid-900.woff2 +0 -0
  128. package/public/fonts/font-awesome/fa-thin-100.ttf +0 -0
  129. package/public/fonts/font-awesome/fa-thin-100.woff2 +0 -0
  130. package/public/fonts/font-awesome/fa-v4compatibility.ttf +0 -0
  131. package/public/fonts/font-awesome/fa-v4compatibility.woff2 +0 -0
  132. package/public/js/bundle.js +1 -1
  133. package/public/js/bundle.js.map +1 -1
  134. package/public/js/bundle.vendor.js +1 -1
  135. package/public/js/bundle.vendor.js.LICENSE.txt +24 -6
  136. package/public/js/bundle.vendor.js.map +1 -1
  137. package/public/js/loading-error-handlers.js +1 -1
  138. package/public/service-worker.js +1 -1
  139. package/public/themes/default.css +1 -1
  140. package/public/themes/morning.css +1 -1
  141. package/dist/webpack.config.js +0 -224
@@ -1,71 +1,43 @@
1
- "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
- Object.defineProperty(o, "default", { enumerable: true, value: v });
15
- }) : function(o, v) {
16
- o["default"] = v;
17
- });
18
- var __importStar = (this && this.__importStar) || function (mod) {
19
- if (mod && mod.__esModule) return mod;
20
- var result = {};
21
- if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
- __setModuleDefault(result, mod);
23
- return result;
24
- };
25
- var __importDefault = (this && this.__importDefault) || function (mod) {
26
- return (mod && mod.__esModule) ? mod : { "default": mod };
27
- };
28
- Object.defineProperty(exports, "__esModule", { value: true });
29
- const lodash_1 = __importDefault(require("lodash"));
30
- const ws_1 = require("ws");
31
- const express_1 = __importDefault(require("express"));
32
- const fs_1 = __importDefault(require("fs"));
33
- const path_1 = __importDefault(require("path"));
34
- const socket_io_1 = require("socket.io");
35
- const dns_1 = __importDefault(require("dns"));
36
- const chalk_1 = __importDefault(require("chalk"));
37
- const net_1 = __importDefault(require("net"));
38
- const log_1 = __importDefault(require("./log"));
39
- const client_1 = __importDefault(require("./client"));
40
- const clientManager_1 = __importDefault(require("./clientManager"));
41
- const uploader_1 = __importDefault(require("./plugins/uploader"));
42
- const helper_1 = __importDefault(require("./helper"));
43
- const config_1 = __importDefault(require("./config"));
44
- const identification_1 = __importDefault(require("./identification"));
45
- const changelog_1 = __importDefault(require("./plugins/changelog"));
46
- const inputs_1 = __importDefault(require("./plugins/inputs"));
47
- const auth_1 = __importDefault(require("./plugins/auth"));
48
- const themes_1 = __importDefault(require("./plugins/packages/themes"));
49
- themes_1.default.loadLocalThemes();
50
- const index_1 = __importDefault(require("./plugins/packages/index"));
51
- const utils_1 = __importDefault(require("./command-line/utils"));
52
- const chan_1 = require("../shared/types/chan");
1
+ import _ from "lodash";
2
+ import { WebSocketServer as wsServer } from "ws";
3
+ import express from "express";
4
+ import fs from "fs";
5
+ import path from "path";
6
+ import { Server as ioServer } from "socket.io";
7
+ import dns from "dns";
8
+ import colors from "chalk";
9
+ import net from "net";
10
+ import log from "./log.js";
11
+ import Client from "./client.js";
12
+ import ClientManager from "./clientManager.js";
13
+ import Uploader from "./plugins/uploader.js";
14
+ import Helper from "./helper.js";
15
+ import Config from "./config.js";
16
+ import Identification from "./identification.js";
17
+ import changelog from "./plugins/changelog.js";
18
+ import inputs from "./plugins/inputs/index.js";
19
+ import Auth from "./plugins/auth.js";
20
+ import themes from "./plugins/packages/themes.js";
21
+ themes.loadLocalThemes();
22
+ import packages from "./plugins/packages/index.js";
23
+ import Utils from "./command-line/utils.js";
24
+ import { ChanType } from "../shared/types/chan.js";
53
25
  // A random number that will force clients to reload the page if it differs
54
26
  const serverHash = Math.floor(Date.now() * Math.random());
55
27
  let manager = null;
56
- async function default_1(options = {
28
+ export default async function (options = {
57
29
  dev: false,
58
30
  }) {
59
- log_1.default.info(`The Lounge ${chalk_1.default.green(helper_1.default.getVersion())} \
60
- (Node.js ${chalk_1.default.green(process.versions.node)} on ${chalk_1.default.green(process.platform)} ${process.arch})`);
61
- log_1.default.info(`Configuration file: ${chalk_1.default.green(config_1.default.getConfigPath())}`);
31
+ log.info(`The Lounge ${colors.green(Helper.getVersion())} \
32
+ (Node.js ${colors.green(process.versions.node)} on ${colors.green(process.platform)} ${process.arch})`);
33
+ log.info(`Configuration file: ${colors.green(Config.getConfigPath())}`);
62
34
  const staticOptions = {
63
35
  redirect: false,
64
36
  maxAge: 86400 * 1000,
65
37
  };
66
- const app = (0, express_1.default)();
38
+ const app = express();
67
39
  if (options.dev) {
68
- (await Promise.resolve().then(() => __importStar(require("./plugins/dev-server")))).default(app);
40
+ (await import("./plugins/dev-server.js")).default(app);
69
41
  }
70
42
  app.set("env", "production")
71
43
  .disable("x-powered-by")
@@ -75,10 +47,10 @@ async function default_1(options = {
75
47
  .get("/service-worker.js", forceNoCacheRequest)
76
48
  .get("/js/bundle.js.map", forceNoCacheRequest)
77
49
  .get("/css/style.css.map", forceNoCacheRequest)
78
- .use(express_1.default.static(utils_1.default.getFileFromRelativeToRoot("public"), staticOptions))
79
- .use("/storage/", express_1.default.static(config_1.default.getStoragePath(), staticOptions));
80
- if (config_1.default.values.fileUpload.enable) {
81
- uploader_1.default.router(app);
50
+ .use(express.static(Utils.getFileFromRelativeToRoot("public"), staticOptions))
51
+ .use("/storage/", express.static(Config.getStoragePath(), staticOptions));
52
+ if (Config.values.fileUpload.enable) {
53
+ Uploader.router(app);
82
54
  }
83
55
  // This route serves *installed themes only*. Local themes are served directly
84
56
  // from the `public/themes/` folder as static assets, without entering this
@@ -86,7 +58,7 @@ async function default_1(options = {
86
58
  // local themes will not get those changes.
87
59
  app.get("/themes/:theme.css", (req, res) => {
88
60
  const themeName = encodeURIComponent(req.params.theme);
89
- const theme = themes_1.default.getByName(themeName);
61
+ const theme = themes.getByName(themeName);
90
62
  if (theme === undefined || theme.filename === undefined) {
91
63
  return res.status(404).send("Not found");
92
64
  }
@@ -95,161 +67,196 @@ async function default_1(options = {
95
67
  app.get("/packages/:package/:filename", (req, res) => {
96
68
  const packageName = req.params.package;
97
69
  const fileName = req.params.filename;
98
- const packageFile = index_1.default.getPackage(packageName);
99
- if (!packageFile || !index_1.default.getFiles().includes(`${packageName}/${fileName}`)) {
70
+ const packageFile = packages.getPackage(packageName);
71
+ if (!packageFile || !packages.getFiles().includes(`${packageName}/${fileName}`)) {
100
72
  return res.status(404).send("Not found");
101
73
  }
102
- const packagePath = config_1.default.getPackageModulePath(packageName);
103
- return res.sendFile(path_1.default.join(packagePath, fileName));
74
+ const packagePath = Config.getPackageModulePath(packageName);
75
+ return res.sendFile(path.join(packagePath, fileName));
104
76
  });
105
- if (config_1.default.values.public && (config_1.default.values.ldap || {}).enable) {
106
- log_1.default.warn("Server is public and set to use LDAP. Set to private mode if trying to use LDAP authentication.");
77
+ if (Config.values.public && (Config.values.ldap || {}).enable) {
78
+ log.warn("Server is public and set to use LDAP. Set to private mode if trying to use LDAP authentication.");
107
79
  }
108
80
  let server;
109
- if (!config_1.default.values.https.enable) {
110
- const createServer = (await Promise.resolve().then(() => __importStar(require("http")))).createServer;
81
+ if (!Config.values.https.enable) {
82
+ const createServer = (await import("http")).createServer;
111
83
  server = createServer(app);
112
84
  }
113
85
  else {
114
- const keyPath = helper_1.default.expandHome(config_1.default.values.https.key);
115
- const certPath = helper_1.default.expandHome(config_1.default.values.https.certificate);
116
- const caPath = helper_1.default.expandHome(config_1.default.values.https.ca);
117
- if (!keyPath.length || !fs_1.default.existsSync(keyPath)) {
118
- log_1.default.error("Path to SSL key is invalid. Stopping server...");
86
+ const keyPath = Helper.expandHome(Config.values.https.key);
87
+ const certPath = Helper.expandHome(Config.values.https.certificate);
88
+ const caPath = Helper.expandHome(Config.values.https.ca);
89
+ if (!keyPath.length || !fs.existsSync(keyPath)) {
90
+ log.error("Path to SSL key is invalid. Stopping server...");
119
91
  process.exit(1);
120
92
  }
121
- if (!certPath.length || !fs_1.default.existsSync(certPath)) {
122
- log_1.default.error("Path to SSL certificate is invalid. Stopping server...");
93
+ if (!certPath.length || !fs.existsSync(certPath)) {
94
+ log.error("Path to SSL certificate is invalid. Stopping server...");
123
95
  process.exit(1);
124
96
  }
125
- if (caPath.length && !fs_1.default.existsSync(caPath)) {
126
- log_1.default.error("Path to SSL ca bundle is invalid. Stopping server...");
97
+ if (caPath.length && !fs.existsSync(caPath)) {
98
+ log.error("Path to SSL ca bundle is invalid. Stopping server...");
127
99
  process.exit(1);
128
100
  }
129
- const createServer = (await Promise.resolve().then(() => __importStar(require("https")))).createServer;
101
+ const createServer = (await import("https")).createServer;
130
102
  server = createServer({
131
- key: fs_1.default.readFileSync(keyPath),
132
- cert: fs_1.default.readFileSync(certPath),
133
- ca: caPath ? fs_1.default.readFileSync(caPath) : undefined,
103
+ key: fs.readFileSync(keyPath),
104
+ cert: fs.readFileSync(certPath),
105
+ ca: caPath ? fs.readFileSync(caPath) : undefined,
134
106
  }, app);
135
107
  }
136
108
  let listenParams;
137
- if (typeof config_1.default.values.host === "string" && config_1.default.values.host.startsWith("unix:")) {
138
- listenParams = config_1.default.values.host.replace(/^unix:/, "");
109
+ if (typeof Config.values.host === "string" && Config.values.host.startsWith("unix:")) {
110
+ listenParams = Config.values.host.replace(/^unix:/, "");
139
111
  }
140
112
  else {
141
113
  listenParams = {
142
- port: config_1.default.values.port,
143
- host: config_1.default.values.host,
114
+ port: Config.values.port,
115
+ host: Config.values.host,
144
116
  };
145
117
  }
146
- // eslint-disable-next-line @typescript-eslint/restrict-template-expressions
147
- server.on("error", (err) => log_1.default.error(`${err}`));
148
- server.listen(listenParams, () => {
149
- if (typeof listenParams === "string") {
150
- log_1.default.info("Available on socket " + chalk_1.default.green(listenParams));
151
- }
152
- else {
153
- const protocol = config_1.default.values.https.enable ? "https" : "http";
154
- const address = server?.address();
155
- if (address && typeof address !== "string") {
156
- // TODO: Node may revert the Node 18 family string --> number change
157
- // @ts-expect-error This condition will always return 'false' since the types 'string' and 'number' have no overlap.
158
- if (address.family === "IPv6" || address.family === 6) {
159
- address.address = "[" + address.address + "]";
118
+ server.on("error", (err) => log.error(`${err}`));
119
+ let sockets = null;
120
+ let identd = null;
121
+ return new Promise((resolve) => {
122
+ server.listen(listenParams, () => {
123
+ void (async () => {
124
+ if (typeof listenParams === "string") {
125
+ log.info("Available on socket " + colors.green(listenParams));
160
126
  }
161
- log_1.default.info("Available at " +
162
- chalk_1.default.green(`${protocol}://${address.address}:${address.port}/`) +
163
- ` in ${chalk_1.default.bold(config_1.default.values.public ? "public" : "private")} mode`);
164
- }
165
- }
166
- // This should never happen
167
- if (!server) {
168
- return;
169
- }
170
- const sockets = new socket_io_1.Server(server, {
171
- wsEngine: ws_1.Server,
172
- cookie: false,
173
- serveClient: false,
174
- // TODO: type as Server.Transport[]
175
- transports: config_1.default.values.transports,
176
- pingTimeout: 60000,
177
- });
178
- sockets.on("connect", (socket) => {
179
- // eslint-disable-next-line @typescript-eslint/restrict-template-expressions
180
- socket.on("error", (err) => log_1.default.error(`io socket error: ${err}`));
181
- if (config_1.default.values.public) {
182
- performAuthentication.call(socket, {});
183
- }
184
- else {
185
- socket.on("auth:perform", performAuthentication);
186
- socket.emit("auth:start", serverHash);
187
- }
188
- });
189
- manager = new clientManager_1.default();
190
- index_1.default.loadPackages();
191
- const defaultTheme = themes_1.default.getByName(config_1.default.values.theme);
192
- if (defaultTheme === undefined) {
193
- log_1.default.warn(`The specified default theme "${chalk_1.default.red(config_1.default.values.theme)}" does not exist, verify your config.`);
194
- config_1.default.values.theme = "default";
195
- }
196
- else if (defaultTheme.themeColor) {
197
- config_1.default.values.themeColor = defaultTheme.themeColor;
198
- }
199
- new identification_1.default((identHandler, err) => {
200
- if (err) {
201
- log_1.default.error(`Could not start identd server, ${err.message}`);
202
- process.exit(1);
203
- }
204
- else if (!manager) {
205
- log_1.default.error("Could not start identd server, ClientManager is undefined");
206
- process.exit(1);
207
- }
208
- manager.init(identHandler, sockets);
209
- });
210
- // Handle ctrl+c and kill gracefully
211
- let suicideTimeout = null;
212
- const exitGracefully = async function () {
213
- if (suicideTimeout !== null) {
214
- return;
215
- }
216
- log_1.default.info("Exiting...");
217
- // Close all client and IRC connections
218
- if (manager) {
219
- manager.clients.forEach((client) => client.quit());
220
- }
221
- if (config_1.default.values.prefetchStorage) {
222
- log_1.default.info("Clearing prefetch storage folder, this might take a while...");
223
- (await Promise.resolve().then(() => __importStar(require("./plugins/storage")))).default.emptyDir();
224
- }
225
- // Forcefully exit after 3 seconds
226
- suicideTimeout = setTimeout(() => process.exit(1), 3000);
227
- // Close http server
228
- server?.close(() => {
229
- if (suicideTimeout !== null) {
230
- clearTimeout(suicideTimeout);
127
+ else {
128
+ const protocol = Config.values.https.enable ? "https" : "http";
129
+ const address = server?.address();
130
+ if (address && typeof address !== "string") {
131
+ // Node.js changed address.family from number (4, 6) to string ("IPv4", "IPv6")
132
+ // in v18, but may revert this change. Support both formats for compatibility.
133
+ const family = address.family;
134
+ if (family === "IPv6" || family === 6) {
135
+ address.address = "[" + address.address + "]";
136
+ }
137
+ log.info("Available at " +
138
+ colors.green(`${protocol}://${address.address}:${address.port}/`) +
139
+ ` in ${colors.bold(Config.values.public ? "public" : "private")} mode`);
140
+ }
231
141
  }
232
- process.exit(0);
233
- });
234
- };
235
- /* eslint-disable @typescript-eslint/no-misused-promises */
236
- process.on("SIGINT", exitGracefully);
237
- process.on("SIGTERM", exitGracefully);
238
- /* eslint-enable @typescript-eslint/no-misused-promises */
239
- // Clear storage folder after server starts successfully
240
- if (config_1.default.values.prefetchStorage) {
241
- Promise.resolve().then(() => __importStar(require("./plugins/storage"))).then(({ default: storage }) => {
242
- storage.emptyDir();
243
- })
244
- .catch((err) => {
245
- log_1.default.error(`Could not clear storage folder, ${err.message}`);
246
- });
247
- }
248
- changelog_1.default.checkForUpdates(manager);
142
+ // This should never happen
143
+ if (!server) {
144
+ return;
145
+ }
146
+ sockets = new ioServer(server, {
147
+ wsEngine: wsServer,
148
+ cookie: false,
149
+ serveClient: false,
150
+ transports: Config.values.transports,
151
+ pingTimeout: 60000,
152
+ });
153
+ sockets.on("connect", (socket) => {
154
+ socket.on("error", (err) => log.error(`io socket error: ${err}`));
155
+ if (Config.values.public) {
156
+ performAuthentication.call(socket, {});
157
+ }
158
+ else {
159
+ socket.on("auth:perform", performAuthentication);
160
+ socket.emit("auth:start", serverHash);
161
+ }
162
+ });
163
+ manager = new ClientManager();
164
+ await packages.loadPackages();
165
+ const defaultTheme = themes.getByName(Config.values.theme);
166
+ if (defaultTheme === undefined) {
167
+ log.warn(`The specified default theme "${colors.red(Config.values.theme)}" does not exist, verify your config.`);
168
+ Config.values.theme = "default";
169
+ }
170
+ else if (defaultTheme.themeColor) {
171
+ Config.values.themeColor = defaultTheme.themeColor;
172
+ }
173
+ new Identification((identHandler, err) => {
174
+ if (err) {
175
+ log.error(`Could not start identd server, ${err.message}`);
176
+ process.exit(1);
177
+ }
178
+ else if (!manager) {
179
+ log.error("Could not start identd server, ClientManager is undefined");
180
+ process.exit(1);
181
+ }
182
+ identd = identHandler;
183
+ manager.init(identHandler, sockets);
184
+ });
185
+ // Handle ctrl+c and kill gracefully
186
+ let suicideTimeout = null;
187
+ const exitGracefully = function () {
188
+ if (suicideTimeout !== null) {
189
+ return;
190
+ }
191
+ log.info("Exiting...");
192
+ // Close all client and IRC connections
193
+ if (manager) {
194
+ manager.clients.forEach((client) => client.quit());
195
+ }
196
+ if (Config.values.prefetchStorage) {
197
+ log.info("Clearing prefetch storage folder, this might take a while...");
198
+ import("./plugins/storage.js")
199
+ .then(({ default: storage }) => {
200
+ storage.emptyDir();
201
+ })
202
+ .catch((err) => {
203
+ log.error(`Could not clear storage folder, ${err.message}`);
204
+ });
205
+ }
206
+ // Forcefully exit after 3 seconds
207
+ suicideTimeout = setTimeout(() => process.exit(1), 3000);
208
+ // Close http server
209
+ server?.close(() => {
210
+ if (suicideTimeout !== null) {
211
+ clearTimeout(suicideTimeout);
212
+ }
213
+ process.exit(0);
214
+ });
215
+ };
216
+ process.on("SIGINT", exitGracefully);
217
+ process.on("SIGTERM", exitGracefully);
218
+ // Clear storage folder after server starts successfully
219
+ if (Config.values.prefetchStorage) {
220
+ import("./plugins/storage.js")
221
+ .then(({ default: storage }) => {
222
+ storage.emptyDir();
223
+ })
224
+ .catch((err) => {
225
+ log.error(`Could not clear storage folder, ${err.message}`);
226
+ });
227
+ }
228
+ changelog.checkForUpdates(manager);
229
+ // Create stop method that properly closes everything
230
+ const stop = (callback) => {
231
+ // Stop changelog update checks to clear the 24-hour timeout
232
+ changelog.stopUpdateChecks();
233
+ // Stop file watchers
234
+ packages.stopWatching();
235
+ if (manager) {
236
+ manager.stopAutoloadUsers();
237
+ }
238
+ // Remove signal handlers to prevent double-close on SIGTERM/SIGINT
239
+ process.removeListener("SIGINT", exitGracefully);
240
+ process.removeListener("SIGTERM", exitGracefully);
241
+ // Close identd first, then HTTP server (which will auto-close Socket.IO)
242
+ if (identd) {
243
+ identd.close(() => {
244
+ server.close(callback);
245
+ });
246
+ }
247
+ else {
248
+ server.close(callback);
249
+ }
250
+ };
251
+ resolve({
252
+ httpServer: server,
253
+ io: sockets,
254
+ stop,
255
+ });
256
+ })();
257
+ });
249
258
  });
250
- return server;
251
259
  }
252
- exports.default = default_1;
253
260
  function getClientLanguage(socket) {
254
261
  const acceptLanguage = socket.handshake.headers["accept-language"];
255
262
  if (typeof acceptLanguage === "string" && /^[\x00-\x7F]{1,50}$/.test(acceptLanguage)) {
@@ -260,11 +267,11 @@ function getClientLanguage(socket) {
260
267
  }
261
268
  function getClientIp(socket) {
262
269
  let ip = socket.handshake.address || "127.0.0.1";
263
- if (config_1.default.values.reverseProxy) {
270
+ if (Config.values.reverseProxy) {
264
271
  const forwarded = String(socket.handshake.headers["x-forwarded-for"])
265
272
  .split(/\s*,\s*/)
266
273
  .filter(Boolean);
267
- if (forwarded.length && net_1.default.isIP(forwarded[0])) {
274
+ if (forwarded.length && net.isIP(forwarded[0])) {
268
275
  ip = forwarded[0];
269
276
  }
270
277
  }
@@ -272,7 +279,7 @@ function getClientIp(socket) {
272
279
  }
273
280
  function getClientSecure(socket) {
274
281
  let secure = socket.handshake.secure;
275
- if (config_1.default.values.reverseProxy && socket.handshake.headers["x-forwarded-proto"] === "https") {
282
+ if (Config.values.reverseProxy && socket.handshake.headers["x-forwarded-proto"] === "https") {
276
283
  secure = true;
277
284
  }
278
285
  return secure;
@@ -297,7 +304,7 @@ function addSecurityHeaders(_req, res, next) {
297
304
  // If prefetch is enabled, but storage is not, we have to allow mixed content
298
305
  // - https://user-images.githubusercontent.com is where we currently push our changelog screenshots
299
306
  // - data: is required for the HTML5 video player
300
- if (config_1.default.values.prefetchStorage || !config_1.default.values.prefetch) {
307
+ if (Config.values.prefetchStorage || !Config.values.prefetch) {
301
308
  policies.push("img-src 'self' data: https://user-images.githubusercontent.com");
302
309
  policies.unshift("block-all-mixed-content");
303
310
  }
@@ -316,17 +323,17 @@ function forceNoCacheRequest(_req, res, next) {
316
323
  }
317
324
  function indexRequest(_req, res) {
318
325
  res.setHeader("Content-Type", "text/html");
319
- fs_1.default.readFile(utils_1.default.getFileFromRelativeToRoot("client/index.html.tpl"), "utf-8", (err, file) => {
326
+ fs.readFile(Utils.getFileFromRelativeToRoot("client/index.html.tpl"), "utf-8", (err, file) => {
320
327
  if (err) {
321
- log_1.default.error(`failed to server index request: ${err.name}, ${err.message}`);
328
+ log.error(`failed to server index request: ${err.name}, ${err.message}`);
322
329
  res.sendStatus(500);
323
330
  return;
324
331
  }
325
332
  const config = {
326
333
  ...getServerConfiguration(),
327
- ...{ cacheBust: helper_1.default.getVersionCacheBust() },
334
+ ...{ cacheBust: Helper.getVersionCacheBust() },
328
335
  };
329
- res.send(lodash_1.default.template(file)(config));
336
+ res.send(_.template(file)(config));
330
337
  });
331
338
  }
332
339
  function initializeClient(socket, client, token, lastMessage, openChannel) {
@@ -344,27 +351,43 @@ function initializeClient(socket, client, token, lastMessage, openChannel) {
344
351
  else {
345
352
  openChannel = client.lastActiveChannel;
346
353
  }
347
- if (config_1.default.values.fileUpload.enable) {
348
- new uploader_1.default(socket);
354
+ // If no valid active channel, default to the first channel of the first network
355
+ if (!openChannel || openChannel < 0) {
356
+ const firstNetwork = client.networks[0];
357
+ if (firstNetwork && firstNetwork.channels.length > 0) {
358
+ openChannel = firstNetwork.channels[0].id;
359
+ }
360
+ }
361
+ if (Config.values.fileUpload.enable) {
362
+ new Uploader(socket);
349
363
  }
350
364
  socket.on("disconnect", function () {
351
365
  process.nextTick(() => client.clientDetach(socket.id));
352
366
  });
353
367
  socket.on("input", (data) => {
354
- if (lodash_1.default.isPlainObject(data)) {
368
+ if (_.isPlainObject(data)) {
355
369
  client.input(data);
356
370
  }
357
371
  });
358
372
  socket.on("more", (data) => {
359
- if (lodash_1.default.isPlainObject(data)) {
373
+ if (_.isPlainObject(data)) {
360
374
  const history = client.more(data);
361
375
  if (history !== null) {
362
376
  socket.emit("more", history);
363
377
  }
364
378
  }
365
379
  });
380
+ // Fetch messages around a specific time (for jumping to search results)
381
+ socket.on("messages:around", async (data) => {
382
+ if (_.isPlainObject(data)) {
383
+ const result = await client.getMessagesAround(data);
384
+ if (result !== null) {
385
+ socket.emit("messages:around", result);
386
+ }
387
+ }
388
+ });
366
389
  socket.on("network:new", (data) => {
367
- if (lodash_1.default.isPlainObject(data)) {
390
+ if (_.isPlainObject(data)) {
368
391
  // prevent people from overriding webirc settings
369
392
  data.uuid = null;
370
393
  data.commands = null;
@@ -376,30 +399,30 @@ function initializeClient(socket, client, token, lastMessage, openChannel) {
376
399
  if (typeof data !== "string") {
377
400
  return;
378
401
  }
379
- const network = lodash_1.default.find(client.networks, { uuid: data });
402
+ const network = _.find(client.networks, { uuid: data });
380
403
  if (!network) {
381
404
  return;
382
405
  }
383
406
  socket.emit("network:info", network.exportForEdit());
384
407
  });
385
408
  socket.on("network:edit", (data) => {
386
- if (!lodash_1.default.isPlainObject(data)) {
409
+ if (!_.isPlainObject(data)) {
387
410
  return;
388
411
  }
389
- const network = lodash_1.default.find(client.networks, { uuid: data.uuid });
412
+ const network = _.find(client.networks, { uuid: data.uuid });
390
413
  if (!network) {
391
414
  return;
392
415
  }
393
416
  network.edit(client, data);
394
417
  });
395
418
  socket.on("history:clear", (data) => {
396
- if (lodash_1.default.isPlainObject(data)) {
419
+ if (_.isPlainObject(data)) {
397
420
  client.clearHistory(data);
398
421
  }
399
422
  });
400
- if (!config_1.default.values.public && !config_1.default.values.ldap.enable) {
423
+ if (!Config.values.public && !Config.values.ldap.enable) {
401
424
  socket.on("change-password", (data) => {
402
- if (lodash_1.default.isPlainObject(data)) {
425
+ if (_.isPlainObject(data)) {
403
426
  const old = data.old_password;
404
427
  const p1 = data.new_password;
405
428
  const p2 = data.verify_password;
@@ -410,7 +433,7 @@ function initializeClient(socket, client, token, lastMessage, openChannel) {
410
433
  });
411
434
  return;
412
435
  }
413
- helper_1.default.password
436
+ Helper.password
414
437
  .compare(old || "", client.config.password)
415
438
  .then((matching) => {
416
439
  if (!matching) {
@@ -420,7 +443,7 @@ function initializeClient(socket, client, token, lastMessage, openChannel) {
420
443
  });
421
444
  return;
422
445
  }
423
- const hash = helper_1.default.password.hash(p1);
446
+ const hash = Helper.password.hash(p1);
424
447
  client.setPassword(hash, (success) => {
425
448
  socket.emit("change-password", {
426
449
  success: success,
@@ -429,7 +452,7 @@ function initializeClient(socket, client, token, lastMessage, openChannel) {
429
452
  });
430
453
  })
431
454
  .catch((error) => {
432
- log_1.default.error(`Error while checking users password. Error: ${error.message}`);
455
+ log.error(`Error while checking users password. Error: ${error.message}`);
433
456
  });
434
457
  }
435
458
  });
@@ -438,7 +461,7 @@ function initializeClient(socket, client, token, lastMessage, openChannel) {
438
461
  client.open(socket.id, data);
439
462
  });
440
463
  socket.on("sort:networks", (data) => {
441
- if (!lodash_1.default.isPlainObject(data)) {
464
+ if (!_.isPlainObject(data)) {
442
465
  return;
443
466
  }
444
467
  if (!Array.isArray(data.order)) {
@@ -447,7 +470,7 @@ function initializeClient(socket, client, token, lastMessage, openChannel) {
447
470
  client.sortNetworks(data.order);
448
471
  });
449
472
  socket.on("sort:channels", (data) => {
450
- if (!lodash_1.default.isPlainObject(data)) {
473
+ if (!_.isPlainObject(data)) {
451
474
  return;
452
475
  }
453
476
  if (!Array.isArray(data.order) || typeof data.network !== "string") {
@@ -456,25 +479,25 @@ function initializeClient(socket, client, token, lastMessage, openChannel) {
456
479
  client.sortChannels(data.network, data.order);
457
480
  });
458
481
  socket.on("names", (data) => {
459
- if (lodash_1.default.isPlainObject(data)) {
482
+ if (_.isPlainObject(data)) {
460
483
  client.names(data);
461
484
  }
462
485
  });
463
486
  socket.on("changelog", () => {
464
- Promise.all([changelog_1.default.fetch(), index_1.default.outdated()])
487
+ Promise.all([changelog.fetch(), packages.outdated()])
465
488
  .then(([changelogData, packageUpdate]) => {
466
489
  changelogData.packages = packageUpdate;
467
490
  socket.emit("changelog", changelogData);
468
491
  })
469
492
  .catch((error) => {
470
- log_1.default.error(`Error while fetching changelog. Error: ${error.message}`);
493
+ log.error(`Error while fetching changelog. Error: ${error.message}`);
471
494
  });
472
495
  });
473
496
  // In public mode only one client can be connected,
474
497
  // so there's no need to handle msg:preview:toggle
475
- if (!config_1.default.values.public) {
498
+ if (!Config.values.public) {
476
499
  socket.on("msg:preview:toggle", (data) => {
477
- if (lodash_1.default.isPlainObject(data)) {
500
+ if (_.isPlainObject(data)) {
478
501
  return;
479
502
  }
480
503
  const networkAndChan = client.find(data.target);
@@ -516,7 +539,7 @@ function initializeClient(socket, client, token, lastMessage, openChannel) {
516
539
  socket.on("mentions:dismiss_all", () => {
517
540
  client.mentions = [];
518
541
  });
519
- if (!config_1.default.values.public) {
542
+ if (!Config.values.public) {
520
543
  socket.on("push:register", (subscription) => {
521
544
  if (!Object.prototype.hasOwnProperty.call(client.config.sessions, token)) {
522
545
  return;
@@ -535,10 +558,10 @@ function initializeClient(socket, client, token, lastMessage, openChannel) {
535
558
  }
536
559
  const sendSessionList = () => {
537
560
  // TODO: this should use the ClientSession type currently in client
538
- const sessions = lodash_1.default.map(client.config.sessions, (session, sessionToken) => {
561
+ const sessions = _.map(client.config.sessions, (session, sessionToken) => {
539
562
  return {
540
563
  current: sessionToken === token,
541
- active: lodash_1.default.reduce(client.attachedClients, (count, attachedClient) => count + (attachedClient.token === sessionToken ? 1 : 0), 0),
564
+ active: _.reduce(client.attachedClients, (count, attachedClient) => count + (attachedClient.token === sessionToken ? 1 : 0), 0),
542
565
  lastUse: session.lastUse,
543
566
  ip: session.ip,
544
567
  agent: session.agent,
@@ -548,9 +571,9 @@ function initializeClient(socket, client, token, lastMessage, openChannel) {
548
571
  socket.emit("sessions:list", sessions);
549
572
  };
550
573
  socket.on("sessions:get", sendSessionList);
551
- if (!config_1.default.values.public) {
574
+ if (!Config.values.public) {
552
575
  socket.on("setting:set", (newSetting) => {
553
- if (!lodash_1.default.isPlainObject(newSetting)) {
576
+ if (!_.isPlainObject(newSetting)) {
554
577
  return;
555
578
  }
556
579
  if (typeof newSetting.value === "object" ||
@@ -597,15 +620,15 @@ function initializeClient(socket, client, token, lastMessage, openChannel) {
597
620
  }
598
621
  const { chan, network } = networkAndChan;
599
622
  // If the user mutes the lobby, we mute the entire network.
600
- if (chan.type === chan_1.ChanType.LOBBY) {
623
+ if (chan.type === ChanType.LOBBY) {
601
624
  for (const channel of network.channels) {
602
- if (channel.type !== chan_1.ChanType.SPECIAL) {
625
+ if (channel.type !== ChanType.SPECIAL) {
603
626
  channel.setMuteStatus(setMutedTo);
604
627
  }
605
628
  }
606
629
  }
607
630
  else {
608
- if (chan.type !== chan_1.ChanType.SPECIAL) {
631
+ if (chan.type !== ChanType.SPECIAL) {
609
632
  chan.setMuteStatus(setMutedTo);
610
633
  }
611
634
  }
@@ -617,6 +640,25 @@ function initializeClient(socket, client, token, lastMessage, openChannel) {
617
640
  }
618
641
  client.save();
619
642
  });
643
+ socket.on("pin:change", ({ target, setPinnedTo }) => {
644
+ const networkAndChan = client.find(target);
645
+ if (!networkAndChan) {
646
+ return;
647
+ }
648
+ const { chan } = networkAndChan;
649
+ // Only allow pinning queries
650
+ if (chan.type !== ChanType.QUERY) {
651
+ return;
652
+ }
653
+ chan.pinned = setPinnedTo;
654
+ for (const attachedClient of Object.keys(client.attachedClients)) {
655
+ manager.sockets.in(attachedClient).emit("pin:changed", {
656
+ target,
657
+ status: setPinnedTo,
658
+ });
659
+ }
660
+ client.save();
661
+ });
620
662
  }
621
663
  socket.on("sign-out", (tokenToSignOut) => {
622
664
  // If no token provided, sign same client out
@@ -628,7 +670,7 @@ function initializeClient(socket, client, token, lastMessage, openChannel) {
628
670
  }
629
671
  delete client.config.sessions[tokenToSignOut];
630
672
  client.save();
631
- lodash_1.default.map(client.attachedClients, (attachedClient, socketId) => {
673
+ _.map(client.attachedClients, (attachedClient, socketId) => {
632
674
  if (attachedClient.token !== tokenToSignOut) {
633
675
  return;
634
676
  }
@@ -649,9 +691,9 @@ function initializeClient(socket, client, token, lastMessage, openChannel) {
649
691
  networks: client.networks.map((network) => network.getFilteredClone(openChannel, lastMessage)),
650
692
  token: tokenToSend,
651
693
  });
652
- socket.emit("commands", inputs_1.default.getCommands());
694
+ socket.emit("commands", inputs.getCommands());
653
695
  };
654
- if (config_1.default.values.public) {
696
+ if (Config.values.public) {
655
697
  sendInitEvent();
656
698
  }
657
699
  else if (!token) {
@@ -669,59 +711,58 @@ function initializeClient(socket, client, token, lastMessage, openChannel) {
669
711
  }
670
712
  function getClientConfiguration() {
671
713
  const common = {
672
- fileUpload: config_1.default.values.fileUpload.enable,
673
- ldapEnabled: config_1.default.values.ldap.enable,
674
- isUpdateAvailable: changelog_1.default.isUpdateAvailable,
714
+ fileUpload: Config.values.fileUpload.enable,
715
+ ldapEnabled: Config.values.ldap.enable,
716
+ isUpdateAvailable: changelog.isUpdateAvailable,
675
717
  applicationServerKey: manager.webPush.vapidKeys.publicKey,
676
- version: helper_1.default.getVersionNumber(),
677
- gitCommit: helper_1.default.getGitCommit(),
678
- themes: themes_1.default.getAll(),
679
- defaultTheme: config_1.default.values.theme,
680
- public: config_1.default.values.public,
681
- useHexIp: config_1.default.values.useHexIp,
682
- prefetch: config_1.default.values.prefetch,
683
- fileUploadMaxFileSize: uploader_1.default ? uploader_1.default.getMaxFileSize() : undefined, // TODO can't be undefined?
718
+ version: Helper.getVersionNumber(),
719
+ gitCommit: Helper.getGitCommit(),
720
+ themes: themes.getAll(),
721
+ defaultTheme: Config.values.theme,
722
+ public: Config.values.public,
723
+ useHexIp: Config.values.useHexIp,
724
+ prefetch: Config.values.prefetch,
725
+ fileUploadMaxFileSize: Uploader ? Uploader.getMaxFileSize() : undefined, // TODO can't be undefined?
684
726
  };
685
727
  const defaultsOverride = {
686
- nick: config_1.default.getDefaultNick(), // expand the number part
728
+ nick: Config.getDefaultNick(), // expand the number part
687
729
  // TODO: this doesn't seem right, if the client needs this as a buffer
688
730
  // the client ought to add it on its own
689
731
  sasl: "",
690
732
  saslAccount: "",
691
733
  saslPassword: "",
692
734
  };
693
- if (!config_1.default.values.lockNetwork) {
735
+ if (!Config.values.lockNetwork) {
694
736
  const defaults = {
695
- ...lodash_1.default.clone(config_1.default.values.defaults),
737
+ ..._.clone(Config.values.defaults),
696
738
  ...defaultsOverride,
697
739
  };
698
740
  const result = {
699
741
  ...common,
700
742
  defaults: defaults,
701
- lockNetwork: config_1.default.values.lockNetwork,
743
+ lockNetwork: Config.values.lockNetwork,
702
744
  };
703
745
  return result;
704
746
  }
705
747
  // Only send defaults that are visible on the client
706
748
  const defaults = {
707
- ...lodash_1.default.pick(config_1.default.values.defaults, ["name", "username", "password", "realname", "join"]),
749
+ ..._.omit(Config.values.defaults, ["host", "name", "port", "tls", "rejectUnauthorized"]),
708
750
  ...defaultsOverride,
709
751
  };
710
752
  const result = {
711
753
  ...common,
712
- lockNetwork: config_1.default.values.lockNetwork,
754
+ lockNetwork: Config.values.lockNetwork,
713
755
  defaults: defaults,
714
756
  };
715
757
  return result;
716
758
  }
717
759
  function getServerConfiguration() {
718
- return { ...config_1.default.values, ...{ stylesheets: index_1.default.getStylesheets() } };
760
+ return { ...Config.values, ...{ stylesheets: packages.getStylesheets() } };
719
761
  }
720
762
  function performAuthentication(data) {
721
- if (!lodash_1.default.isPlainObject(data)) {
763
+ if (!_.isPlainObject(data)) {
722
764
  return;
723
765
  }
724
- const socket = this;
725
766
  let client;
726
767
  let token;
727
768
  const finalInit = () => {
@@ -739,7 +780,7 @@ function performAuthentication(data) {
739
780
  if (!client) {
740
781
  throw new Error("finalInit called with undefined client, this is a bug");
741
782
  }
742
- initializeClient(socket, client, token, lastMessage, openChannel);
783
+ initializeClient(this, client, token, lastMessage, openChannel);
743
784
  };
744
785
  const initClient = () => {
745
786
  if (!client) {
@@ -748,17 +789,17 @@ function performAuthentication(data) {
748
789
  // Configuration does not change during runtime of TL,
749
790
  // and the client listens to this event only once
750
791
  if (data && (!("hasConfig" in data) || !data.hasConfig)) {
751
- socket.emit("configuration", getClientConfiguration());
752
- socket.emit("push:issubscribed", token && client.config.sessions[token].pushSubscription ? true : false);
792
+ this.emit("configuration", getClientConfiguration());
793
+ this.emit("push:issubscribed", token && client.config.sessions[token].pushSubscription ? true : false);
753
794
  }
754
- const clientIP = getClientIp(socket);
795
+ const clientIP = getClientIp(this);
755
796
  client.config.browser = {
756
797
  ip: clientIP,
757
- isSecure: getClientSecure(socket),
758
- language: getClientLanguage(socket),
798
+ isSecure: getClientSecure(this),
799
+ language: getClientLanguage(this),
759
800
  };
760
801
  // If webirc is enabled perform reverse dns lookup
761
- if (config_1.default.values.webirc === null) {
802
+ if (Config.values.webirc === null) {
762
803
  return finalInit();
763
804
  }
764
805
  const cb_client = client; // ensure that TS figures out that client can't be nil
@@ -767,13 +808,13 @@ function performAuthentication(data) {
767
808
  finalInit();
768
809
  });
769
810
  };
770
- if (config_1.default.values.public) {
771
- client = new client_1.default(manager);
811
+ if (Config.values.public) {
812
+ client = new Client(manager);
772
813
  client.connect();
773
814
  manager.clients.push(client);
774
815
  const cb_client = client; // ensure TS can see we never have a nil client
775
- socket.on("disconnect", function () {
776
- manager.clients = lodash_1.default.without(manager.clients, cb_client);
816
+ this.on("disconnect", () => {
817
+ manager.clients = _.without(manager.clients, cb_client);
777
818
  cb_client.quit();
778
819
  });
779
820
  initClient();
@@ -786,12 +827,12 @@ function performAuthentication(data) {
786
827
  // Authorization failed
787
828
  if (!success) {
788
829
  if (!client) {
789
- log_1.default.warn(`Authentication for non existing user attempted from ${chalk_1.default.bold(getClientIp(socket))}`);
830
+ log.warn(`Authentication for non existing user attempted from ${colors.bold(getClientIp(this))}`);
790
831
  }
791
832
  else {
792
- log_1.default.warn(`Authentication failed for user ${chalk_1.default.bold(data.user)} from ${chalk_1.default.bold(getClientIp(socket))}`);
833
+ log.warn(`Authentication failed for user ${colors.bold(data.user)} from ${colors.bold(getClientIp(this))}`);
793
834
  }
794
- socket.emit("auth:failed");
835
+ this.emit("auth:failed");
795
836
  return;
796
837
  }
797
838
  // If authorization succeeded but there is no loaded user,
@@ -815,13 +856,19 @@ function performAuthentication(data) {
815
856
  }
816
857
  }
817
858
  if (!("user" in data && "password" in data)) {
818
- log_1.default.warn("performAuthentication: callback data has no user or no password");
859
+ log.warn("performAuthentication: callback data has no user or no password");
860
+ authCallback(false);
861
+ return;
862
+ }
863
+ if (!manager) {
864
+ log.error("performAuthentication: ClientManager not initialized");
819
865
  authCallback(false);
820
866
  return;
821
867
  }
822
- auth_1.default.initialize().then(() => {
868
+ const clientManager = manager;
869
+ void Auth.initialize().then(() => {
823
870
  // Perform password checking
824
- auth_1.default.auth(manager, client, data.user, data.password, authCallback);
871
+ Auth.auth(clientManager, client, data.user, data.password, authCallback);
825
872
  });
826
873
  }
827
874
  function reverseDnsLookup(ip, callback) {
@@ -829,11 +876,11 @@ function reverseDnsLookup(ip, callback) {
829
876
  // returning SERVFAIL it seems: https://github.com/thelounge/thelounge/issues/4768
830
877
  // so we manually resolve with the ip as a fallback in case something fails
831
878
  try {
832
- dns_1.default.reverse(ip, (reverseErr, hostnames) => {
879
+ dns.reverse(ip, (reverseErr, hostnames) => {
833
880
  if (reverseErr || hostnames.length < 1) {
834
881
  return callback(ip);
835
882
  }
836
- dns_1.default.resolve(hostnames[0], net_1.default.isIP(ip) === 6 ? "AAAA" : "A", (resolveErr, resolvedIps) => {
883
+ dns.resolve(hostnames[0], net.isIP(ip) === 6 ? "AAAA" : "A", (resolveErr, resolvedIps) => {
837
884
  // TODO: investigate SoaRecord class
838
885
  if (!Array.isArray(resolvedIps)) {
839
886
  return callback(ip);
@@ -851,7 +898,7 @@ function reverseDnsLookup(ip, callback) {
851
898
  });
852
899
  }
853
900
  catch (err) {
854
- log_1.default.error(`failed to resolve rDNS for ${ip}, using ip instead`, err.toString());
901
+ log.error(`failed to resolve rDNS for ${ip}, using ip instead`, String(err));
855
902
  setImmediate(callback, ip); // makes sure we always behave asynchronously
856
903
  }
857
904
  }