@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.
- package/README.md +31 -7
- package/dist/defaults/config.js +31 -2
- package/dist/package.json +94 -91
- package/dist/server/client.js +188 -194
- package/dist/server/clientManager.js +75 -72
- package/dist/server/command-line/index.js +44 -43
- package/dist/server/command-line/install.js +37 -70
- package/dist/server/command-line/outdated.js +12 -17
- package/dist/server/command-line/start.js +25 -26
- package/dist/server/command-line/storage.js +26 -31
- package/dist/server/command-line/uninstall.js +16 -23
- package/dist/server/command-line/upgrade.js +20 -26
- package/dist/server/command-line/users/add.js +33 -40
- package/dist/server/command-line/users/edit.js +18 -24
- package/dist/server/command-line/users/index.js +12 -16
- package/dist/server/command-line/users/list.js +11 -39
- package/dist/server/command-line/users/remove.js +16 -22
- package/dist/server/command-line/users/reset.js +34 -35
- package/dist/server/command-line/utils.js +231 -87
- package/dist/server/config.js +61 -52
- package/dist/server/helper.js +29 -28
- package/dist/server/identification.js +39 -34
- package/dist/server/index.js +1 -3
- package/dist/server/log.js +19 -16
- package/dist/server/models/chan.js +36 -33
- package/dist/server/models/msg.js +15 -19
- package/dist/server/models/network.js +102 -104
- package/dist/server/models/prefix.js +4 -7
- package/dist/server/models/user.js +5 -10
- package/dist/server/path-helper.js +8 -0
- package/dist/server/plugins/auth/ldap.js +177 -112
- package/dist/server/plugins/auth/local.js +10 -15
- package/dist/server/plugins/auth.js +6 -35
- package/dist/server/plugins/changelog.js +30 -27
- package/dist/server/plugins/clientCertificate.js +33 -37
- package/dist/server/plugins/dev-server.js +15 -21
- package/dist/server/plugins/inputs/action.js +9 -14
- package/dist/server/plugins/inputs/away.js +1 -3
- package/dist/server/plugins/inputs/ban.js +9 -14
- package/dist/server/plugins/inputs/blow.js +9 -14
- package/dist/server/plugins/inputs/connect.js +5 -10
- package/dist/server/plugins/inputs/ctcp.js +7 -12
- package/dist/server/plugins/inputs/disconnect.js +1 -3
- package/dist/server/plugins/inputs/ignore.js +23 -29
- package/dist/server/plugins/inputs/ignorelist.js +12 -18
- package/dist/server/plugins/inputs/index.js +8 -34
- package/dist/server/plugins/inputs/invite.js +7 -12
- package/dist/server/plugins/inputs/kick.js +7 -12
- package/dist/server/plugins/inputs/kill.js +1 -3
- package/dist/server/plugins/inputs/list.js +1 -3
- package/dist/server/plugins/inputs/mode.js +10 -15
- package/dist/server/plugins/inputs/msg.js +13 -18
- package/dist/server/plugins/inputs/mute.js +9 -15
- package/dist/server/plugins/inputs/nick.js +9 -14
- package/dist/server/plugins/inputs/notice.js +5 -7
- package/dist/server/plugins/inputs/part.js +11 -16
- package/dist/server/plugins/inputs/quit.js +7 -13
- package/dist/server/plugins/inputs/rainbow.js +55 -0
- package/dist/server/plugins/inputs/raw.js +1 -3
- package/dist/server/plugins/inputs/rejoin.js +7 -12
- package/dist/server/plugins/inputs/topic.js +7 -12
- package/dist/server/plugins/inputs/whois.js +1 -3
- package/dist/server/plugins/irc-events/away.js +14 -20
- package/dist/server/plugins/irc-events/cap.js +16 -22
- package/dist/server/plugins/irc-events/chghost.js +14 -13
- package/dist/server/plugins/irc-events/connection.js +61 -63
- package/dist/server/plugins/irc-events/ctcp.js +22 -28
- package/dist/server/plugins/irc-events/error.js +20 -26
- package/dist/server/plugins/irc-events/help.js +7 -13
- package/dist/server/plugins/irc-events/info.js +7 -13
- package/dist/server/plugins/irc-events/invite.js +7 -13
- package/dist/server/plugins/irc-events/join.js +30 -27
- package/dist/server/plugins/irc-events/kick.js +21 -17
- package/dist/server/plugins/irc-events/link.js +122 -109
- package/dist/server/plugins/irc-events/list.js +23 -26
- package/dist/server/plugins/irc-events/message.js +46 -52
- package/dist/server/plugins/irc-events/mode.js +66 -63
- package/dist/server/plugins/irc-events/modelist.js +29 -35
- package/dist/server/plugins/irc-events/motd.js +10 -16
- package/dist/server/plugins/irc-events/names.js +3 -6
- package/dist/server/plugins/irc-events/nick.js +26 -23
- package/dist/server/plugins/irc-events/part.js +19 -15
- package/dist/server/plugins/irc-events/quit.js +17 -14
- package/dist/server/plugins/irc-events/sasl.js +9 -15
- package/dist/server/plugins/irc-events/spgroups.js +38 -0
- package/dist/server/plugins/irc-events/spjoin.js +52 -0
- package/dist/server/plugins/irc-events/topic.js +12 -18
- package/dist/server/plugins/irc-events/unhandled.js +12 -12
- package/dist/server/plugins/irc-events/welcome.js +7 -13
- package/dist/server/plugins/irc-events/whois.js +20 -24
- package/dist/server/plugins/massEventAggregator.js +214 -0
- package/dist/server/plugins/messageStorage/sqlite.js +322 -141
- package/dist/server/plugins/messageStorage/text.js +21 -26
- package/dist/server/plugins/packages/index.js +105 -74
- package/dist/server/plugins/packages/publicClient.js +7 -16
- package/dist/server/plugins/packages/themes.js +11 -16
- package/dist/server/plugins/storage.js +28 -33
- package/dist/server/plugins/sts.js +12 -17
- package/dist/server/plugins/uploader.js +40 -43
- package/dist/server/plugins/webpush.js +23 -51
- package/dist/server/server.js +318 -271
- package/dist/server/storageCleaner.js +29 -37
- package/dist/server/utils/fish.js +349 -389
- package/dist/shared/irc.js +3 -6
- package/dist/shared/linkify.js +7 -14
- package/dist/shared/types/chan.js +6 -9
- package/dist/shared/types/changelog.js +1 -2
- package/dist/shared/types/config.js +1 -2
- package/dist/shared/types/mention.js +1 -2
- package/dist/shared/types/msg.js +3 -5
- package/dist/shared/types/network.js +1 -2
- package/dist/shared/types/storage.js +1 -2
- package/dist/shared/types/user.js +1 -2
- package/index.js +14 -10
- package/package.json +94 -91
- package/public/css/style.css +9 -6
- package/public/css/style.css.map +1 -1
- package/public/fonts/font-awesome/fa-brands-400.ttf +0 -0
- package/public/fonts/font-awesome/fa-brands-400.woff2 +0 -0
- package/public/fonts/font-awesome/fa-duotone-900.ttf +0 -0
- package/public/fonts/font-awesome/fa-duotone-900.woff2 +0 -0
- package/public/fonts/font-awesome/fa-light-300.ttf +0 -0
- package/public/fonts/font-awesome/fa-light-300.woff2 +0 -0
- package/public/fonts/font-awesome/fa-regular-400.ttf +0 -0
- package/public/fonts/font-awesome/fa-regular-400.woff2 +0 -0
- package/public/fonts/font-awesome/fa-solid-900.ttf +0 -0
- package/public/fonts/font-awesome/fa-solid-900.woff2 +0 -0
- package/public/fonts/font-awesome/fa-thin-100.ttf +0 -0
- package/public/fonts/font-awesome/fa-thin-100.woff2 +0 -0
- package/public/fonts/font-awesome/fa-v4compatibility.ttf +0 -0
- package/public/fonts/font-awesome/fa-v4compatibility.woff2 +0 -0
- package/public/js/bundle.js +1 -1
- package/public/js/bundle.js.map +1 -1
- package/public/js/bundle.vendor.js +1 -1
- package/public/js/bundle.vendor.js.LICENSE.txt +24 -6
- package/public/js/bundle.vendor.js.map +1 -1
- package/public/js/loading-error-handlers.js +1 -1
- package/public/service-worker.js +1 -1
- package/public/themes/default.css +1 -1
- package/public/themes/morning.css +1 -1
- package/dist/webpack.config.js +0 -224
package/dist/server/config.js
CHANGED
|
@@ -1,49 +1,45 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
const chalk_1 = __importDefault(require("chalk"));
|
|
12
|
-
const log_1 = __importDefault(require("./log"));
|
|
13
|
-
const helper_1 = __importDefault(require("./helper"));
|
|
14
|
-
const utils_1 = __importDefault(require("./command-line/utils"));
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import fs from "node:fs";
|
|
3
|
+
import os from "node:os";
|
|
4
|
+
import _ from "lodash";
|
|
5
|
+
import colors from "chalk";
|
|
6
|
+
import { pathToFileURL } from "node:url";
|
|
7
|
+
import log from "./log.js";
|
|
8
|
+
import Helper from "./helper.js";
|
|
9
|
+
import Utils from "./command-line/utils.js";
|
|
10
|
+
import defaultConfig from "../defaults/config.js";
|
|
15
11
|
class Config {
|
|
16
|
-
values =
|
|
12
|
+
values = { ..._.cloneDeep(defaultConfig), themeColor: "" };
|
|
17
13
|
#homePath = "";
|
|
18
14
|
getHomePath() {
|
|
19
15
|
return this.#homePath;
|
|
20
16
|
}
|
|
21
17
|
getConfigPath() {
|
|
22
|
-
return
|
|
18
|
+
return path.join(this.#homePath, "config.js");
|
|
23
19
|
}
|
|
24
20
|
getUserLogsPath() {
|
|
25
|
-
return
|
|
21
|
+
return path.join(this.#homePath, "logs");
|
|
26
22
|
}
|
|
27
23
|
getStoragePath() {
|
|
28
|
-
return
|
|
24
|
+
return path.join(this.#homePath, "storage");
|
|
29
25
|
}
|
|
30
26
|
getFileUploadPath() {
|
|
31
|
-
return
|
|
27
|
+
return path.join(this.#homePath, "uploads");
|
|
32
28
|
}
|
|
33
29
|
getUsersPath() {
|
|
34
|
-
return
|
|
30
|
+
return path.join(this.#homePath, "users");
|
|
35
31
|
}
|
|
36
32
|
getUserConfigPath(name) {
|
|
37
|
-
return
|
|
33
|
+
return path.join(this.getUsersPath(), `${name}.json`);
|
|
38
34
|
}
|
|
39
35
|
getClientCertificatesPath() {
|
|
40
|
-
return
|
|
36
|
+
return path.join(this.#homePath, "certificates");
|
|
41
37
|
}
|
|
42
38
|
getPackagesPath() {
|
|
43
|
-
return
|
|
39
|
+
return path.join(this.#homePath, "packages");
|
|
44
40
|
}
|
|
45
41
|
getPackageModulePath(packageName) {
|
|
46
|
-
return
|
|
42
|
+
return path.join(this.getPackagesPath(), "node_modules", packageName);
|
|
47
43
|
}
|
|
48
44
|
getDefaultNick() {
|
|
49
45
|
if (!this.values.defaults.nick) {
|
|
@@ -59,37 +55,45 @@ class Config {
|
|
|
59
55
|
// it mutates the oldConfig, but returns it as a convenience for testing
|
|
60
56
|
for (const key in newConfig) {
|
|
61
57
|
if (!Object.prototype.hasOwnProperty.call(oldConfig, key)) {
|
|
62
|
-
|
|
58
|
+
log.warn(`Unknown key "${colors.bold(key)}", please verify your config.`);
|
|
63
59
|
}
|
|
64
60
|
}
|
|
65
|
-
return
|
|
61
|
+
return _.mergeWith(oldConfig, newConfig, (objValue, srcValue, key) => {
|
|
66
62
|
// Do not override config variables if the type is incorrect (e.g. object changed into a string)
|
|
67
63
|
if (typeof objValue !== "undefined" &&
|
|
68
64
|
objValue !== null &&
|
|
69
65
|
typeof objValue !== typeof srcValue) {
|
|
70
|
-
|
|
66
|
+
log.warn(`Incorrect type for "${colors.bold(key)}", please verify your config.`);
|
|
71
67
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
|
|
72
68
|
return objValue;
|
|
73
69
|
}
|
|
74
70
|
// For arrays, simply override the value with user provided one.
|
|
75
|
-
if (
|
|
71
|
+
if (_.isArray(objValue)) {
|
|
76
72
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
|
|
77
73
|
return srcValue;
|
|
78
74
|
}
|
|
79
75
|
});
|
|
80
76
|
}
|
|
81
|
-
setHome(newPath) {
|
|
82
|
-
this.#homePath =
|
|
77
|
+
async setHome(newPath) {
|
|
78
|
+
this.#homePath = Helper.expandHome(newPath);
|
|
83
79
|
// Reload config from new home location
|
|
84
80
|
const configPath = this.getConfigPath();
|
|
85
|
-
if (
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
81
|
+
if (fs.existsSync(configPath)) {
|
|
82
|
+
try {
|
|
83
|
+
const configUrl = pathToFileURL(configPath).href;
|
|
84
|
+
const userConfigModule = await import(configUrl);
|
|
85
|
+
const userConfig = userConfigModule.default || userConfigModule;
|
|
86
|
+
if (_.isEmpty(userConfig)) {
|
|
87
|
+
log.warn(`The file located at ${colors.green(configPath)} does not appear to expose anything.`);
|
|
88
|
+
log.warn(`Make sure it is non-empty and the configuration is exported using ${colors.bold("export default { ... }")}.`);
|
|
89
|
+
log.warn("Using default configuration...");
|
|
90
|
+
}
|
|
91
|
+
this.merge(userConfig);
|
|
92
|
+
}
|
|
93
|
+
catch (error) {
|
|
94
|
+
log.error(`Failed to load config from ${configPath}:`, String(error));
|
|
95
|
+
log.warn("Using default configuration...");
|
|
91
96
|
}
|
|
92
|
-
this.merge(userConfig);
|
|
93
97
|
}
|
|
94
98
|
if (this.values.fileUpload.baseUrl) {
|
|
95
99
|
try {
|
|
@@ -97,42 +101,47 @@ class Config {
|
|
|
97
101
|
}
|
|
98
102
|
catch (e) {
|
|
99
103
|
this.values.fileUpload.baseUrl = undefined;
|
|
100
|
-
|
|
104
|
+
log.warn(`The ${colors.bold("fileUpload.baseUrl")} you specified is invalid: ${String(e)}`);
|
|
101
105
|
}
|
|
102
106
|
}
|
|
103
|
-
const manifestPath =
|
|
107
|
+
const manifestPath = Utils.getFileFromRelativeToRoot("public", "thelounge.webmanifest");
|
|
104
108
|
// Check if manifest exists, if not, the app most likely was not built
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
process.
|
|
109
|
+
// Skip this check in test environment
|
|
110
|
+
if (!fs.existsSync(manifestPath)) {
|
|
111
|
+
if (process.env.NODE_ENV !== "test") {
|
|
112
|
+
log.error(`The client application was not built. Run ${colors.bold("NODE_ENV=production yarn build")} to resolve this.`);
|
|
113
|
+
process.exit(1);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
else {
|
|
117
|
+
// Load theme color from the web manifest
|
|
118
|
+
const manifest = JSON.parse(fs.readFileSync(manifestPath, "utf8"));
|
|
119
|
+
this.values.themeColor = manifest.theme_color;
|
|
108
120
|
}
|
|
109
|
-
// Load theme color from the web manifest
|
|
110
|
-
const manifest = JSON.parse(fs_1.default.readFileSync(manifestPath, "utf8"));
|
|
111
|
-
this.values.themeColor = manifest.theme_color;
|
|
112
121
|
// log dir probably shouldn't be world accessible.
|
|
113
122
|
// Create it with the desired permission bits if it doesn't exist yet.
|
|
114
123
|
let logsStat = undefined;
|
|
115
124
|
const userLogsPath = this.getUserLogsPath();
|
|
116
125
|
try {
|
|
117
|
-
logsStat =
|
|
126
|
+
logsStat = fs.statSync(userLogsPath);
|
|
118
127
|
}
|
|
119
128
|
catch {
|
|
120
129
|
// ignored on purpose, node v14.17.0 will give us {throwIfNoEntry: false}
|
|
121
130
|
}
|
|
122
131
|
if (!logsStat) {
|
|
123
132
|
try {
|
|
124
|
-
|
|
133
|
+
fs.mkdirSync(userLogsPath, { recursive: true, mode: 0o750 });
|
|
125
134
|
}
|
|
126
135
|
catch (e) {
|
|
127
|
-
|
|
136
|
+
log.error("Unable to create logs directory", String(e));
|
|
128
137
|
}
|
|
129
138
|
}
|
|
130
139
|
else if (logsStat && logsStat.mode & 0o001) {
|
|
131
|
-
|
|
132
|
-
if (
|
|
133
|
-
|
|
140
|
+
log.warn(userLogsPath, "is world readable.", "The log files may be exposed. Please fix the permissions.");
|
|
141
|
+
if (os.platform() !== "win32") {
|
|
142
|
+
log.warn(`run \`chmod o-x "${userLogsPath}"\` to correct it.`);
|
|
134
143
|
}
|
|
135
144
|
}
|
|
136
145
|
}
|
|
137
146
|
}
|
|
138
|
-
|
|
147
|
+
export default new Config();
|
package/dist/server/helper.js
CHANGED
|
@@ -1,15 +1,11 @@
|
|
|
1
|
-
"
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
const os_1 = __importDefault(require("os"));
|
|
10
|
-
const net_1 = __importDefault(require("net"));
|
|
11
|
-
const bcryptjs_1 = __importDefault(require("bcryptjs"));
|
|
12
|
-
const crypto_1 = __importDefault(require("crypto"));
|
|
1
|
+
import pkg from "../package.json" with { type: "json" };
|
|
2
|
+
import _ from "lodash";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import os from "node:os";
|
|
5
|
+
import net from "node:net";
|
|
6
|
+
import bcrypt from "bcryptjs";
|
|
7
|
+
import crypto from "node:crypto";
|
|
8
|
+
import { execSync } from "node:child_process";
|
|
13
9
|
const Helper = {
|
|
14
10
|
expandHome,
|
|
15
11
|
getVersion,
|
|
@@ -21,20 +17,21 @@ const Helper = {
|
|
|
21
17
|
compareHostmask,
|
|
22
18
|
compareWithWildcard,
|
|
23
19
|
catch_to_error,
|
|
20
|
+
toTrimmedString,
|
|
24
21
|
password: {
|
|
25
22
|
hash: passwordHash,
|
|
26
23
|
compare: passwordCompare,
|
|
27
24
|
requiresUpdate: passwordRequiresUpdate,
|
|
28
25
|
},
|
|
29
26
|
};
|
|
30
|
-
|
|
27
|
+
export default Helper;
|
|
31
28
|
function getVersion() {
|
|
32
29
|
const gitCommit = getGitCommit();
|
|
33
|
-
const version = `v${
|
|
30
|
+
const version = `v${pkg.version}`;
|
|
34
31
|
return gitCommit ? `source (${gitCommit} / ${version})` : version;
|
|
35
32
|
}
|
|
36
33
|
function getVersionNumber() {
|
|
37
|
-
return
|
|
34
|
+
return pkg.version;
|
|
38
35
|
}
|
|
39
36
|
let _fetchedGitCommit = false;
|
|
40
37
|
let _gitCommit = null;
|
|
@@ -46,27 +43,25 @@ function getGitCommit() {
|
|
|
46
43
|
// --git-dir ".git" makes git only check current directory for `.git`, and not travel upwards
|
|
47
44
|
// We set cwd to the location of `index.js` as soon as the process is started
|
|
48
45
|
try {
|
|
49
|
-
|
|
50
|
-
_gitCommit = require("child_process")
|
|
51
|
-
.execSync('git --git-dir ".git" rev-parse --short HEAD', // Returns hash of current commit
|
|
46
|
+
_gitCommit = execSync('git --git-dir ".git" rev-parse --short HEAD', // Returns hash of current commit
|
|
52
47
|
{ stdio: ["ignore", "pipe", "ignore"] })
|
|
53
48
|
.toString()
|
|
54
49
|
.trim();
|
|
55
50
|
return _gitCommit;
|
|
56
51
|
}
|
|
57
|
-
catch
|
|
52
|
+
catch {
|
|
58
53
|
// Not a git repository or git is not installed
|
|
59
54
|
_gitCommit = null;
|
|
60
55
|
return null;
|
|
61
56
|
}
|
|
62
57
|
}
|
|
63
58
|
function getVersionCacheBust() {
|
|
64
|
-
const hash =
|
|
59
|
+
const hash = crypto.createHash("sha256").update(Helper.getVersion()).digest("hex");
|
|
65
60
|
return hash.substring(0, 10);
|
|
66
61
|
}
|
|
67
62
|
function ip2hex(address) {
|
|
68
63
|
// no ipv6 support
|
|
69
|
-
if (!
|
|
64
|
+
if (!net.isIPv4(address)) {
|
|
70
65
|
return "00000000";
|
|
71
66
|
}
|
|
72
67
|
return address
|
|
@@ -86,17 +81,17 @@ function expandHome(shortenedPath) {
|
|
|
86
81
|
if (!shortenedPath) {
|
|
87
82
|
return "";
|
|
88
83
|
}
|
|
89
|
-
const home =
|
|
90
|
-
return
|
|
84
|
+
const home = os.homedir().replace("$", "$$$$");
|
|
85
|
+
return path.resolve(shortenedPath.replace(/^~($|\/|\\)/, home + "$1"));
|
|
91
86
|
}
|
|
92
87
|
function passwordRequiresUpdate(password) {
|
|
93
|
-
return
|
|
88
|
+
return bcrypt.getRounds(password) !== 11;
|
|
94
89
|
}
|
|
95
90
|
function passwordHash(password) {
|
|
96
|
-
return
|
|
91
|
+
return bcrypt.hashSync(password, bcrypt.genSaltSync(11));
|
|
97
92
|
}
|
|
98
93
|
function passwordCompare(password, expected) {
|
|
99
|
-
return
|
|
94
|
+
return bcrypt.compare(password, expected);
|
|
100
95
|
}
|
|
101
96
|
function parseHostmask(hostmask) {
|
|
102
97
|
let nick = "";
|
|
@@ -139,7 +134,7 @@ function compareWithWildcard(a, b) {
|
|
|
139
134
|
// so we tokenize and join with the proper char back together,
|
|
140
135
|
// escaping any other regex modifier
|
|
141
136
|
const wildmany_split = a.split("*").map((sub) => {
|
|
142
|
-
const wildone_split = sub.split("?").map((p) =>
|
|
137
|
+
const wildone_split = sub.split("?").map((p) => _.escapeRegExp(p));
|
|
143
138
|
return wildone_split.join(".");
|
|
144
139
|
});
|
|
145
140
|
const user_regex = wildmany_split.join(".*");
|
|
@@ -155,7 +150,13 @@ function catch_to_error(prefix, err) {
|
|
|
155
150
|
msg = err;
|
|
156
151
|
}
|
|
157
152
|
else {
|
|
158
|
-
msg = err
|
|
153
|
+
msg = String(err);
|
|
159
154
|
}
|
|
160
155
|
return new Error(`${prefix}: ${msg}`);
|
|
161
156
|
}
|
|
157
|
+
function toTrimmedString(value) {
|
|
158
|
+
if (typeof value !== "string") {
|
|
159
|
+
return "";
|
|
160
|
+
}
|
|
161
|
+
return String(value ?? "").trim();
|
|
162
|
+
}
|
|
@@ -1,44 +1,41 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
const net_1 = __importDefault(require("net"));
|
|
8
|
-
const chalk_1 = __importDefault(require("chalk"));
|
|
9
|
-
const helper_1 = __importDefault(require("./helper"));
|
|
10
|
-
const config_1 = __importDefault(require("./config"));
|
|
11
|
-
const log_1 = __importDefault(require("./log"));
|
|
1
|
+
import fs from "fs";
|
|
2
|
+
import net from "net";
|
|
3
|
+
import colors from "chalk";
|
|
4
|
+
import Helper from "./helper.js";
|
|
5
|
+
import Config from "./config.js";
|
|
6
|
+
import log from "./log.js";
|
|
12
7
|
class Identification {
|
|
13
8
|
connectionId;
|
|
14
9
|
connections;
|
|
15
10
|
oidentdFile;
|
|
11
|
+
identdServer;
|
|
16
12
|
constructor(startedCallback) {
|
|
17
13
|
this.connectionId = 0;
|
|
18
14
|
this.connections = new Map();
|
|
19
|
-
if (typeof
|
|
20
|
-
this.oidentdFile =
|
|
21
|
-
|
|
15
|
+
if (typeof Config.values.oidentd === "string") {
|
|
16
|
+
this.oidentdFile = Helper.expandHome(Config.values.oidentd);
|
|
17
|
+
log.info(`Oidentd file: ${colors.green(this.oidentdFile)}`);
|
|
22
18
|
this.refresh();
|
|
23
19
|
}
|
|
24
|
-
if (
|
|
20
|
+
if (Config.values.identd.enable) {
|
|
25
21
|
if (this.oidentdFile) {
|
|
26
|
-
|
|
22
|
+
log.warn("Using both identd and oidentd at the same time, this is most likely not intended.");
|
|
27
23
|
}
|
|
28
|
-
|
|
24
|
+
this.identdServer = net.createServer(this.serverConnection.bind(this));
|
|
25
|
+
const server = this.identdServer;
|
|
29
26
|
server.on("error", (err) => {
|
|
30
27
|
startedCallback(this, err);
|
|
31
28
|
});
|
|
32
29
|
server.listen({
|
|
33
|
-
port:
|
|
34
|
-
host:
|
|
30
|
+
port: Config.values.identd.port || 113,
|
|
31
|
+
host: Config.values.bind,
|
|
35
32
|
}, () => {
|
|
36
33
|
const address = server.address();
|
|
37
34
|
if (typeof address === "string") {
|
|
38
|
-
|
|
35
|
+
log.info(`Identd server available on ${colors.green(address)}`);
|
|
39
36
|
}
|
|
40
37
|
else if (address?.address) {
|
|
41
|
-
|
|
38
|
+
log.info(`Identd server available on ${colors.green(address.address + ":" + address.port.toString())}`);
|
|
42
39
|
}
|
|
43
40
|
startedCallback(this);
|
|
44
41
|
});
|
|
@@ -48,9 +45,9 @@ class Identification {
|
|
|
48
45
|
}
|
|
49
46
|
}
|
|
50
47
|
serverConnection(socket) {
|
|
51
|
-
socket.on("error", (err) =>
|
|
48
|
+
socket.on("error", (err) => log.error(`Identd socket error: ${err}`));
|
|
52
49
|
socket.setTimeout(5000, () => {
|
|
53
|
-
|
|
50
|
+
log.warn(`identd: no data received, closing connection to ${socket.remoteAddress || "undefined"}`);
|
|
54
51
|
socket.destroy();
|
|
55
52
|
});
|
|
56
53
|
socket.once("data", (data) => {
|
|
@@ -60,17 +57,17 @@ class Identification {
|
|
|
60
57
|
}
|
|
61
58
|
respondToIdent(socket, buffer) {
|
|
62
59
|
if (!socket.remoteAddress) {
|
|
63
|
-
|
|
60
|
+
log.warn("identd: no remote address");
|
|
64
61
|
return;
|
|
65
62
|
}
|
|
66
63
|
const data = buffer.toString().split(",");
|
|
67
64
|
const lport = parseInt(data[0], 10) || 0;
|
|
68
65
|
const fport = parseInt(data[1], 10) || 0;
|
|
69
66
|
if (lport < 1 || fport < 1 || lport > 65535 || fport > 65535) {
|
|
70
|
-
|
|
67
|
+
log.warn(`identd: bogus request from ${socket.remoteAddress}`);
|
|
71
68
|
return;
|
|
72
69
|
}
|
|
73
|
-
|
|
70
|
+
log.debug(`identd: remote ${socket.remoteAddress} query ${lport}, ${fport}`);
|
|
74
71
|
for (const connection of this.connections.values()) {
|
|
75
72
|
// we only want to respond if all the ip,port tuples match, to avoid user enumeration
|
|
76
73
|
if (connection.socket.remotePort === fport &&
|
|
@@ -78,13 +75,13 @@ class Identification {
|
|
|
78
75
|
socket.remoteAddress === connection.socket.remoteAddress &&
|
|
79
76
|
socket.localAddress === connection.socket.localAddress) {
|
|
80
77
|
const reply = `${lport}, ${fport} : USERID : TheLounge : ${connection.user}\r\n`;
|
|
81
|
-
|
|
78
|
+
log.debug(`identd: reply is ${reply.trimEnd()}`);
|
|
82
79
|
socket.write(reply);
|
|
83
80
|
return;
|
|
84
81
|
}
|
|
85
82
|
}
|
|
86
83
|
const reply = `${lport}, ${fport} : ERROR : NO-USER\r\n`;
|
|
87
|
-
|
|
84
|
+
log.debug(`identd: reply is ${reply.trimEnd()}`);
|
|
88
85
|
socket.write(reply);
|
|
89
86
|
}
|
|
90
87
|
addSocket(socket, user) {
|
|
@@ -108,15 +105,15 @@ class Identification {
|
|
|
108
105
|
// Race condition: this can happen when more than one socket gets disconnected at
|
|
109
106
|
// once, since we `refresh()` for each one being added/removed. This results
|
|
110
107
|
// in there possibly being one or more disconnected sockets remaining when we get here.
|
|
111
|
-
|
|
108
|
+
log.warn(`oidentd: socket has no remote or local port (id=${id}). See https://github.com/lordbex/thelounge/pull/4695.`);
|
|
112
109
|
return;
|
|
113
110
|
}
|
|
114
111
|
if (!connection.socket.remoteAddress) {
|
|
115
|
-
|
|
112
|
+
log.warn(`oidentd: socket has no remote address, will not respond to queries`);
|
|
116
113
|
return;
|
|
117
114
|
}
|
|
118
115
|
if (!connection.socket.localAddress) {
|
|
119
|
-
|
|
116
|
+
log.warn(`oidentd: socket has no local address, will not respond to queries`);
|
|
120
117
|
return;
|
|
121
118
|
}
|
|
122
119
|
// we only want to respond if all the ip,port tuples match, to avoid user enumeration
|
|
@@ -128,12 +125,20 @@ class Identification {
|
|
|
128
125
|
` { reply "${connection.user}" }\n`;
|
|
129
126
|
});
|
|
130
127
|
if (this.oidentdFile) {
|
|
131
|
-
|
|
128
|
+
fs.writeFile(this.oidentdFile, file, { flag: "w+" }, function (err) {
|
|
132
129
|
if (err) {
|
|
133
|
-
|
|
130
|
+
log.error("Failed to update oidentd file!", err.message);
|
|
134
131
|
}
|
|
135
132
|
});
|
|
136
133
|
}
|
|
137
134
|
}
|
|
135
|
+
close(callback) {
|
|
136
|
+
if (this.identdServer) {
|
|
137
|
+
this.identdServer.close(callback);
|
|
138
|
+
}
|
|
139
|
+
else {
|
|
140
|
+
callback();
|
|
141
|
+
}
|
|
142
|
+
}
|
|
138
143
|
}
|
|
139
|
-
|
|
144
|
+
export default Identification;
|
package/dist/server/index.js
CHANGED
package/dist/server/log.js
CHANGED
|
@@ -1,35 +1,38 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
const chalk_1 = __importDefault(require("chalk"));
|
|
7
|
-
const read_1 = __importDefault(require("read"));
|
|
1
|
+
import colors from "chalk";
|
|
2
|
+
import { read } from "read";
|
|
3
|
+
import Config from "./config.js";
|
|
8
4
|
function timestamp() {
|
|
9
5
|
const datetime = new Date().toISOString().split(".")[0].replace("T", " ");
|
|
10
|
-
return
|
|
6
|
+
return colors.dim(datetime);
|
|
11
7
|
}
|
|
12
8
|
const log = {
|
|
13
9
|
/* eslint-disable no-console */
|
|
14
10
|
error(...args) {
|
|
15
|
-
console.error(timestamp(),
|
|
11
|
+
console.error(timestamp(), colors.red("[ERROR]"), ...args);
|
|
16
12
|
},
|
|
17
13
|
warn(...args) {
|
|
18
|
-
console.error(timestamp(),
|
|
14
|
+
console.error(timestamp(), colors.yellow("[WARN]"), ...args);
|
|
19
15
|
},
|
|
20
16
|
info(...args) {
|
|
21
|
-
console.log(timestamp(),
|
|
17
|
+
console.log(timestamp(), colors.blue("[INFO]"), ...args);
|
|
22
18
|
},
|
|
23
19
|
debug(...args) {
|
|
24
|
-
|
|
20
|
+
if (!Config.values.debug.logs)
|
|
21
|
+
return;
|
|
22
|
+
console.log(timestamp(), colors.green("[DEBUG]"), ...args);
|
|
25
23
|
},
|
|
26
24
|
raw(...args) {
|
|
27
25
|
console.log(...args);
|
|
28
26
|
},
|
|
29
27
|
/* eslint-enable no-console */
|
|
30
|
-
prompt(options
|
|
31
|
-
|
|
32
|
-
|
|
28
|
+
async prompt(options) {
|
|
29
|
+
const promptText = [timestamp(), colors.cyan("[PROMPT]"), options.text].join(" ");
|
|
30
|
+
const result = await read({
|
|
31
|
+
default: options.default,
|
|
32
|
+
prompt: promptText,
|
|
33
|
+
silent: options.silent,
|
|
34
|
+
});
|
|
35
|
+
return String(result);
|
|
33
36
|
},
|
|
34
37
|
};
|
|
35
|
-
|
|
38
|
+
export default log;
|