Prevent crashing on rDNS failure
This commit is contained in:
parent
42e08dec93
commit
59cc53014d
173
server/server.ts
173
server/server.ts
@ -72,9 +72,9 @@ export default async function (
|
|||||||
}
|
}
|
||||||
) {
|
) {
|
||||||
log.info(`Hard Lounge ${colors.green(Helper.getVersion())} \
|
log.info(`Hard Lounge ${colors.green(Helper.getVersion())} \
|
||||||
(Node.js ${colors.green(process.versions.node)} on ${colors.green(process.platform)} ${
|
(Node.js ${colors.green(process.versions.node)} on ${colors.green(
|
||||||
process.arch
|
process.platform
|
||||||
})`);
|
)} ${process.arch})`);
|
||||||
log.info(`Configuration file: ${colors.green(Config.getConfigPath())}`);
|
log.info(`Configuration file: ${colors.green(Config.getConfigPath())}`);
|
||||||
|
|
||||||
const staticOptions = {
|
const staticOptions = {
|
||||||
@ -96,8 +96,16 @@ export default async function (
|
|||||||
.get("/service-worker.js", forceNoCacheRequest)
|
.get("/service-worker.js", forceNoCacheRequest)
|
||||||
.get("/js/bundle.js.map", forceNoCacheRequest)
|
.get("/js/bundle.js.map", forceNoCacheRequest)
|
||||||
.get("/css/style.css.map", forceNoCacheRequest)
|
.get("/css/style.css.map", forceNoCacheRequest)
|
||||||
.use(express.static(Utils.getFileFromRelativeToRoot("public"), staticOptions))
|
.use(
|
||||||
.use("/storage/", express.static(Config.getStoragePath(), staticOptions));
|
express.static(
|
||||||
|
Utils.getFileFromRelativeToRoot("public"),
|
||||||
|
staticOptions
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.use(
|
||||||
|
"/storage/",
|
||||||
|
express.static(Config.getStoragePath(), staticOptions)
|
||||||
|
);
|
||||||
|
|
||||||
if (Config.values.fileUpload.enable) {
|
if (Config.values.fileUpload.enable) {
|
||||||
Uploader.router(app);
|
Uploader.router(app);
|
||||||
@ -123,7 +131,10 @@ export default async function (
|
|||||||
const fileName = req.params.filename;
|
const fileName = req.params.filename;
|
||||||
const packageFile = packages.getPackage(packageName);
|
const packageFile = packages.getPackage(packageName);
|
||||||
|
|
||||||
if (!packageFile || !packages.getFiles().includes(`${packageName}/${fileName}`)) {
|
if (
|
||||||
|
!packageFile ||
|
||||||
|
!packages.getFiles().includes(`${packageName}/${fileName}`)
|
||||||
|
) {
|
||||||
return res.status(404).send("Not found");
|
return res.status(404).send("Not found");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -180,7 +191,10 @@ export default async function (
|
|||||||
host: string | undefined;
|
host: string | undefined;
|
||||||
};
|
};
|
||||||
|
|
||||||
if (typeof Config.values.host === "string" && Config.values.host.startsWith("unix:")) {
|
if (
|
||||||
|
typeof Config.values.host === "string" &&
|
||||||
|
Config.values.host.startsWith("unix:")
|
||||||
|
) {
|
||||||
listenParams = Config.values.host.replace(/^unix:/, "");
|
listenParams = Config.values.host.replace(/^unix:/, "");
|
||||||
} else {
|
} else {
|
||||||
listenParams = {
|
listenParams = {
|
||||||
@ -208,8 +222,12 @@ export default async function (
|
|||||||
|
|
||||||
log.info(
|
log.info(
|
||||||
"Available at " +
|
"Available at " +
|
||||||
colors.green(`${protocol}://${address.address}:${address.port}/`) +
|
colors.green(
|
||||||
` in ${colors.bold(Config.values.public ? "public" : "private")} mode`
|
`${protocol}://${address.address}:${address.port}/`
|
||||||
|
) +
|
||||||
|
` in ${colors.bold(
|
||||||
|
Config.values.public ? "public" : "private"
|
||||||
|
)} mode`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -267,7 +285,9 @@ export default async function (
|
|||||||
log.error(`Could not start identd server, ${err.message}`);
|
log.error(`Could not start identd server, ${err.message}`);
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
} else if (!manager) {
|
} else if (!manager) {
|
||||||
log.error("Could not start identd server, ClientManager is undefined");
|
log.error(
|
||||||
|
"Could not start identd server, ClientManager is undefined"
|
||||||
|
);
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -290,7 +310,9 @@ export default async function (
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (Config.values.prefetchStorage) {
|
if (Config.values.prefetchStorage) {
|
||||||
log.info("Clearing prefetch storage folder, this might take a while...");
|
log.info(
|
||||||
|
"Clearing prefetch storage folder, this might take a while..."
|
||||||
|
);
|
||||||
|
|
||||||
(await import("./plugins/storage")).default.emptyDir();
|
(await import("./plugins/storage")).default.emptyDir();
|
||||||
}
|
}
|
||||||
@ -333,7 +355,10 @@ export default async function (
|
|||||||
function getClientLanguage(socket: Socket): string | null {
|
function getClientLanguage(socket: Socket): string | null {
|
||||||
const acceptLanguage = socket.handshake.headers["accept-language"];
|
const acceptLanguage = socket.handshake.headers["accept-language"];
|
||||||
|
|
||||||
if (typeof acceptLanguage === "string" && /^[\x00-\x7F]{1,50}$/.test(acceptLanguage)) {
|
if (
|
||||||
|
typeof acceptLanguage === "string" &&
|
||||||
|
/^[\x00-\x7F]{1,50}$/.test(acceptLanguage)
|
||||||
|
) {
|
||||||
// only allow ASCII strings between 1-50 characters in length
|
// only allow ASCII strings between 1-50 characters in length
|
||||||
return acceptLanguage;
|
return acceptLanguage;
|
||||||
}
|
}
|
||||||
@ -360,7 +385,10 @@ function getClientIp(socket: Socket) {
|
|||||||
function getClientSecure(socket: Socket) {
|
function getClientSecure(socket: Socket) {
|
||||||
let secure = socket.handshake.secure;
|
let secure = socket.handshake.secure;
|
||||||
|
|
||||||
if (Config.values.reverseProxy && socket.handshake.headers["x-forwarded-proto"] === "https") {
|
if (
|
||||||
|
Config.values.reverseProxy &&
|
||||||
|
socket.handshake.headers["x-forwarded-proto"] === "https"
|
||||||
|
) {
|
||||||
secure = true;
|
secure = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -390,7 +418,9 @@ function addSecurityHeaders(req: Request, res: Response, next: NextFunction) {
|
|||||||
// - https://user-images.githubusercontent.com is where we currently push our changelog screenshots
|
// - https://user-images.githubusercontent.com is where we currently push our changelog screenshots
|
||||||
// - data: is required for the HTML5 video player
|
// - data: is required for the HTML5 video player
|
||||||
if (Config.values.prefetchStorage || !Config.values.prefetch) {
|
if (Config.values.prefetchStorage || !Config.values.prefetch) {
|
||||||
policies.push("img-src 'self' data: https://user-images.githubusercontent.com");
|
policies.push(
|
||||||
|
"img-src 'self' data: https://user-images.githubusercontent.com"
|
||||||
|
);
|
||||||
policies.unshift("block-all-mixed-content");
|
policies.unshift("block-all-mixed-content");
|
||||||
} else {
|
} else {
|
||||||
policies.push("img-src http: https: data:");
|
policies.push("img-src http: https: data:");
|
||||||
@ -449,7 +479,9 @@ function initializeClient(
|
|||||||
|
|
||||||
// If client provided channel passes checks, use it. if client has invalid
|
// If client provided channel passes checks, use it. if client has invalid
|
||||||
// channel open (or windows like settings) then use last known server active channel
|
// channel open (or windows like settings) then use last known server active channel
|
||||||
openChannel = client.attachedClients[socket.id].openChannel || client.lastActiveChannel;
|
openChannel =
|
||||||
|
client.attachedClients[socket.id].openChannel ||
|
||||||
|
client.lastActiveChannel;
|
||||||
} else {
|
} else {
|
||||||
openChannel = client.lastActiveChannel;
|
openChannel = client.lastActiveChannel;
|
||||||
}
|
}
|
||||||
@ -552,7 +584,10 @@ function initializeClient(
|
|||||||
const hash = Helper.password.hash(p1);
|
const hash = Helper.password.hash(p1);
|
||||||
|
|
||||||
client.setPassword(hash, (success: boolean) => {
|
client.setPassword(hash, (success: boolean) => {
|
||||||
const obj = {success: false, error: undefined} as {
|
const obj = {
|
||||||
|
success: false,
|
||||||
|
error: undefined,
|
||||||
|
} as {
|
||||||
success: boolean;
|
success: boolean;
|
||||||
error: string | undefined;
|
error: string | undefined;
|
||||||
};
|
};
|
||||||
@ -567,7 +602,9 @@ function initializeClient(
|
|||||||
});
|
});
|
||||||
})
|
})
|
||||||
.catch((error: Error) => {
|
.catch((error: Error) => {
|
||||||
log.error(`Error while checking users password. Error: ${error.message}`);
|
log.error(
|
||||||
|
`Error while checking users password. Error: ${error.message}`
|
||||||
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -596,7 +633,9 @@ function initializeClient(
|
|||||||
socket.emit("changelog", changelogData);
|
socket.emit("changelog", changelogData);
|
||||||
})
|
})
|
||||||
.catch((error: Error) => {
|
.catch((error: Error) => {
|
||||||
log.error(`Error while fetching changelog. Error: ${error.message}`);
|
log.error(
|
||||||
|
`Error while fetching changelog. Error: ${error.message}`
|
||||||
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -665,7 +704,12 @@ function initializeClient(
|
|||||||
|
|
||||||
if (!Config.values.public) {
|
if (!Config.values.public) {
|
||||||
socket.on("push:register", (subscription) => {
|
socket.on("push:register", (subscription) => {
|
||||||
if (!Object.prototype.hasOwnProperty.call(client.config.sessions, token)) {
|
if (
|
||||||
|
!Object.prototype.hasOwnProperty.call(
|
||||||
|
client.config.sessions,
|
||||||
|
token
|
||||||
|
)
|
||||||
|
) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -684,18 +728,23 @@ function initializeClient(
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
socket.on("push:unregister", () => client.unregisterPushSubscription(token));
|
socket.on("push:unregister", () =>
|
||||||
|
client.unregisterPushSubscription(token)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const sendSessionList = () => {
|
const sendSessionList = () => {
|
||||||
// TODO: this should use the ClientSession type currently in client
|
// TODO: this should use the ClientSession type currently in client
|
||||||
const sessions = _.map(client.config.sessions, (session, sessionToken) => {
|
const sessions = _.map(
|
||||||
|
client.config.sessions,
|
||||||
|
(session, sessionToken) => {
|
||||||
return {
|
return {
|
||||||
current: sessionToken === token,
|
current: sessionToken === token,
|
||||||
active: _.reduce(
|
active: _.reduce(
|
||||||
client.attachedClients,
|
client.attachedClients,
|
||||||
(count, attachedClient) =>
|
(count, attachedClient) =>
|
||||||
count + (attachedClient.token === sessionToken ? 1 : 0),
|
count +
|
||||||
|
(attachedClient.token === sessionToken ? 1 : 0),
|
||||||
0
|
0
|
||||||
),
|
),
|
||||||
lastUse: session.lastUse,
|
lastUse: session.lastUse,
|
||||||
@ -703,7 +752,8 @@ function initializeClient(
|
|||||||
agent: session.agent,
|
agent: session.agent,
|
||||||
token: sessionToken, // TODO: Ideally don't expose actual tokens to the client
|
token: sessionToken, // TODO: Ideally don't expose actual tokens to the client
|
||||||
};
|
};
|
||||||
});
|
}
|
||||||
|
);
|
||||||
|
|
||||||
socket.emit("sessions:list", sessions);
|
socket.emit("sessions:list", sessions);
|
||||||
};
|
};
|
||||||
@ -725,8 +775,12 @@ function initializeClient(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// We do not need to do write operations and emit events if nothing changed.
|
// We do not need to do write operations and emit events if nothing changed.
|
||||||
if (client.config.clientSettings[newSetting.name] !== newSetting.value) {
|
if (
|
||||||
client.config.clientSettings[newSetting.name] = newSetting.value;
|
client.config.clientSettings[newSetting.name] !==
|
||||||
|
newSetting.value
|
||||||
|
) {
|
||||||
|
client.config.clientSettings[newSetting.name] =
|
||||||
|
newSetting.value;
|
||||||
|
|
||||||
// Pass the setting to all clients.
|
// Pass the setting to all clients.
|
||||||
client.emit("setting:new", {
|
client.emit("setting:new", {
|
||||||
@ -736,7 +790,10 @@ function initializeClient(
|
|||||||
|
|
||||||
client.save();
|
client.save();
|
||||||
|
|
||||||
if (newSetting.name === "highlights" || newSetting.name === "highlightExceptions") {
|
if (
|
||||||
|
newSetting.name === "highlights" ||
|
||||||
|
newSetting.name === "highlightExceptions"
|
||||||
|
) {
|
||||||
client.compileCustomHighlights();
|
client.compileCustomHighlights();
|
||||||
} else if (newSetting.name === "awayMessage") {
|
} else if (newSetting.name === "awayMessage") {
|
||||||
if (typeof newSetting.value !== "string") {
|
if (typeof newSetting.value !== "string") {
|
||||||
@ -749,7 +806,12 @@ function initializeClient(
|
|||||||
});
|
});
|
||||||
|
|
||||||
socket.on("setting:get", () => {
|
socket.on("setting:get", () => {
|
||||||
if (!Object.prototype.hasOwnProperty.call(client.config, "clientSettings")) {
|
if (
|
||||||
|
!Object.prototype.hasOwnProperty.call(
|
||||||
|
client.config,
|
||||||
|
"clientSettings"
|
||||||
|
)
|
||||||
|
) {
|
||||||
socket.emit("setting:all", {});
|
socket.emit("setting:all", {});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -802,7 +864,12 @@ function initializeClient(
|
|||||||
tokenToSignOut = token;
|
tokenToSignOut = token;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!Object.prototype.hasOwnProperty.call(client.config.sessions, tokenToSignOut)) {
|
if (
|
||||||
|
!Object.prototype.hasOwnProperty.call(
|
||||||
|
client.config.sessions,
|
||||||
|
tokenToSignOut
|
||||||
|
)
|
||||||
|
) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -815,7 +882,9 @@ function initializeClient(
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const socketToRemove = manager!.sockets.of("/").sockets.get(socketId);
|
const socketToRemove = manager!.sockets
|
||||||
|
.of("/")
|
||||||
|
.sockets.get(socketId);
|
||||||
|
|
||||||
socketToRemove!.emit("sign-out");
|
socketToRemove!.emit("sign-out");
|
||||||
socketToRemove!.disconnect();
|
socketToRemove!.disconnect();
|
||||||
@ -914,7 +983,13 @@ function performAuthentication(this: Socket, data) {
|
|||||||
let token: string;
|
let token: string;
|
||||||
|
|
||||||
const finalInit = () =>
|
const finalInit = () =>
|
||||||
initializeClient(socket, client, token, data.lastMessage || -1, data.openChannel);
|
initializeClient(
|
||||||
|
socket,
|
||||||
|
client,
|
||||||
|
token,
|
||||||
|
data.lastMessage || -1,
|
||||||
|
data.openChannel
|
||||||
|
);
|
||||||
|
|
||||||
const initClient = () => {
|
const initClient = () => {
|
||||||
// Configuration does not change during runtime of TL,
|
// Configuration does not change during runtime of TL,
|
||||||
@ -924,7 +999,9 @@ function performAuthentication(this: Socket, data) {
|
|||||||
|
|
||||||
socket.emit(
|
socket.emit(
|
||||||
"push:issubscribed",
|
"push:issubscribed",
|
||||||
token && client.config.sessions[token].pushSubscription ? true : false
|
token && client.config.sessions[token].pushSubscription
|
||||||
|
? true
|
||||||
|
: false
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -976,9 +1053,9 @@ function performAuthentication(this: Socket, data) {
|
|||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
log.warn(
|
log.warn(
|
||||||
`Authentication failed for user ${colors.bold(data.user)} from ${colors.bold(
|
`Authentication failed for user ${colors.bold(
|
||||||
getClientIp(socket)
|
data.user
|
||||||
)}`
|
)} from ${colors.bold(getClientIp(socket))}`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1001,7 +1078,12 @@ function performAuthentication(this: Socket, data) {
|
|||||||
if (client && data.token) {
|
if (client && data.token) {
|
||||||
const providedToken = client.calculateTokenHash(data.token);
|
const providedToken = client.calculateTokenHash(data.token);
|
||||||
|
|
||||||
if (Object.prototype.hasOwnProperty.call(client.config.sessions, providedToken)) {
|
if (
|
||||||
|
Object.prototype.hasOwnProperty.call(
|
||||||
|
client.config.sessions,
|
||||||
|
providedToken
|
||||||
|
)
|
||||||
|
) {
|
||||||
token = providedToken;
|
token = providedToken;
|
||||||
|
|
||||||
return authCallback(true);
|
return authCallback(true);
|
||||||
@ -1015,12 +1097,19 @@ function performAuthentication(this: Socket, data) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function reverseDnsLookup(ip: string, callback: (hostname: string) => void) {
|
function reverseDnsLookup(ip: string, callback: (hostname: string) => void) {
|
||||||
|
// node can throw, even if we provide valid input based on the DNS server
|
||||||
|
// returning SERVFAIL it seems: https://github.com/thelounge/thelounge/issues/4768
|
||||||
|
// so we manually resolve with the ip as a fallback in case something fails
|
||||||
|
try {
|
||||||
dns.reverse(ip, (reverseErr, hostnames) => {
|
dns.reverse(ip, (reverseErr, hostnames) => {
|
||||||
if (reverseErr || hostnames.length < 1) {
|
if (reverseErr || hostnames.length < 1) {
|
||||||
return callback(ip);
|
return callback(ip);
|
||||||
}
|
}
|
||||||
|
|
||||||
dns.resolve(hostnames[0], net.isIP(ip) === 6 ? "AAAA" : "A", (resolveErr, resolvedIps) => {
|
dns.resolve(
|
||||||
|
hostnames[0],
|
||||||
|
net.isIP(ip) === 6 ? "AAAA" : "A",
|
||||||
|
(resolveErr, resolvedIps) => {
|
||||||
// TODO: investigate SoaRecord class
|
// TODO: investigate SoaRecord class
|
||||||
if (!Array.isArray(resolvedIps)) {
|
if (!Array.isArray(resolvedIps)) {
|
||||||
return callback(ip);
|
return callback(ip);
|
||||||
@ -1037,6 +1126,14 @@ function reverseDnsLookup(ip: string, callback: (hostname: string) => void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return callback(ip);
|
return callback(ip);
|
||||||
});
|
}
|
||||||
});
|
);
|
||||||
|
});
|
||||||
|
} catch (err) {
|
||||||
|
log.error(
|
||||||
|
`failed to resolve rDNS for ${ip}, using ip instead`,
|
||||||
|
(err as any).toString()
|
||||||
|
);
|
||||||
|
setImmediate(callback, ip); // makes sure we always behave asynchronously
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user