mirror of
https://github.com/thelounge/thelounge
synced 2024-11-26 14:00:21 +00:00
Enforce STS policies
This commit is contained in:
parent
9b9db35e3c
commit
d9985e7318
3 changed files with 110 additions and 3 deletions
|
@ -6,6 +6,7 @@ const IrcFramework = require("irc-framework");
|
|||
const Chan = require("./chan");
|
||||
const Msg = require("./msg");
|
||||
const Helper = require("../helper");
|
||||
const STSPolicies = require("../plugins/sts");
|
||||
|
||||
module.exports = Network;
|
||||
|
||||
|
@ -78,7 +79,7 @@ Network.prototype.validate = function(client) {
|
|||
this.username = cleanString(this.username) || "thelounge";
|
||||
this.realname = cleanString(this.realname) || "The Lounge User";
|
||||
this.password = cleanString(this.password);
|
||||
this.host = cleanString(this.host);
|
||||
this.host = cleanString(this.host).toLowerCase();
|
||||
this.name = cleanString(this.name);
|
||||
|
||||
if (!this.port) {
|
||||
|
@ -124,6 +125,23 @@ Network.prototype.validate = function(client) {
|
|||
return false;
|
||||
}
|
||||
|
||||
const stsPolicy = STSPolicies.get(this.host);
|
||||
|
||||
if (stsPolicy && !this.tls) {
|
||||
this.channels[0].pushMessage(
|
||||
client,
|
||||
new Msg({
|
||||
type: Msg.Type.ERROR,
|
||||
text: `${this.host} has an active strict transport security policy, will connect to port ${stsPolicy.port} over a secure connection.`,
|
||||
}),
|
||||
true
|
||||
);
|
||||
|
||||
this.port = stsPolicy.port;
|
||||
this.tls = true;
|
||||
this.rejectUnauthorized = true;
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
"use strict";
|
||||
|
||||
const Msg = require("../../models/msg");
|
||||
const STSPolicies = require("../sts");
|
||||
|
||||
module.exports = function(irc, network) {
|
||||
const client = this;
|
||||
|
@ -27,7 +28,13 @@ module.exports = function(irc, network) {
|
|||
});
|
||||
|
||||
if (isSecure) {
|
||||
// TODO: store and update duration
|
||||
const duration = parseInt(values.duration, 10);
|
||||
|
||||
if (isNaN(duration)) {
|
||||
return;
|
||||
}
|
||||
|
||||
STSPolicies.update(network.host, network.port, duration);
|
||||
} else {
|
||||
const port = parseInt(values.port, 10);
|
||||
|
||||
|
@ -38,7 +45,7 @@ module.exports = function(irc, network) {
|
|||
network.channels[0].pushMessage(
|
||||
client,
|
||||
new Msg({
|
||||
text: `Server sent a strict transport security policy, reconnecting to port ${port}…`,
|
||||
text: `Server sent a strict transport security policy, reconnecting to ${network.host}:${port}…`,
|
||||
}),
|
||||
true
|
||||
);
|
||||
|
|
82
src/plugins/sts.js
Normal file
82
src/plugins/sts.js
Normal file
|
@ -0,0 +1,82 @@
|
|||
"use strict";
|
||||
|
||||
const _ = require("lodash");
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
const log = require("../log");
|
||||
const Helper = require("../helper");
|
||||
|
||||
class STSPolicies {
|
||||
constructor() {
|
||||
this.stsFile = path.join(Helper.getHomePath(), "sts-policies.json");
|
||||
this.policies = new Map();
|
||||
this.refresh = _.debounce(this.saveFile, 10000, {maxWait: 60000});
|
||||
|
||||
if (!fs.existsSync(this.stsFile)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const storedPolicies = JSON.parse(fs.readFileSync(this.stsFile, "utf-8"));
|
||||
const now = Date.now();
|
||||
|
||||
storedPolicies.forEach((value) => {
|
||||
if (value.expires > now) {
|
||||
this.policies.set(value.host, {
|
||||
port: value.port,
|
||||
expires: value.expires,
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
get(host) {
|
||||
const policy = this.policies.get(host);
|
||||
|
||||
if (typeof policy === "undefined") {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (policy.expires <= Date.now()) {
|
||||
this.policies.delete(host);
|
||||
this.refresh();
|
||||
return null;
|
||||
}
|
||||
|
||||
return policy;
|
||||
}
|
||||
|
||||
update(host, port, duration) {
|
||||
if (duration > 0) {
|
||||
this.policies.set(host, {
|
||||
port: port,
|
||||
expires: Date.now() + duration * 1000,
|
||||
});
|
||||
} else {
|
||||
this.policies.delete(host);
|
||||
}
|
||||
|
||||
this.refresh();
|
||||
}
|
||||
|
||||
saveFile() {
|
||||
const policiesToStore = [];
|
||||
|
||||
this.policies.forEach((value, key) => {
|
||||
policiesToStore.push({
|
||||
host: key,
|
||||
port: value.port,
|
||||
expires: value.expires,
|
||||
});
|
||||
});
|
||||
|
||||
const file = JSON.stringify(policiesToStore, null, "\t");
|
||||
|
||||
fs.writeFile(this.stsFile, file, {flag: "w+"}, (err) => {
|
||||
if (err) {
|
||||
log.error("Failed to update STS policies file!", err);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = new STSPolicies();
|
Loading…
Reference in a new issue