Skip to content

Commit

Permalink
Merge pull/4477 Preserve client certificate
Browse files Browse the repository at this point in the history
  • Loading branch information
brunnre8 committed Apr 27, 2022
2 parents 3726a8d + ae7020f commit c9c8cad
Show file tree
Hide file tree
Showing 3 changed files with 169 additions and 64 deletions.
4 changes: 0 additions & 4 deletions src/models/network.js
Original file line number Diff line number Diff line change
Expand Up @@ -133,10 +133,6 @@ Network.prototype.validate = function (client) {
this.sasl = "";
}

if (!this.tls) {
ClientCertificate.remove(this.uuid);
}

if (Helper.config.lockNetwork) {
// This check is needed to prevent invalid user configurations
if (
Expand Down
9 changes: 9 additions & 0 deletions test/fixtures/env.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,13 @@
"use strict";

const fs = require("fs");

const home = require("path").join(__dirname, ".thelounge");
require("../../src/helper").setHome(home);

const STSPolicies = require("../../src/plugins/sts"); // Must be imported *after* setHome

exports.mochaGlobalTeardown = async function () {
STSPolicies.refresh.cancel(); // Cancel debounced function, so it does not write later
fs.unlinkSync(STSPolicies.stsFile);
};
220 changes: 160 additions & 60 deletions test/models/network.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,69 @@ const Msg = require("../../src/models/msg");
const User = require("../../src/models/user");
const Network = require("../../src/models/network");
const Helper = require("../../src/helper");
const STSPolicies = require("../../src/plugins/sts");
const ClientCertificate = require("../../src/plugins/clientCertificate");

describe("Network", function () {
describe("Network(attr)", function () {
it("should generate uuid (v4) for each network", function () {
const network1 = new Network();
const network2 = new Network();

expect(network1.uuid).to.have.lengthOf(36);
expect(network2.uuid).to.have.lengthOf(36);
expect(network1.uuid).to.not.equal(network2.uuid);
});

it("lobby should be at the top", function () {
const network = new Network({
name: "Super Nice Network",
channels: [
new Chan({name: "AAAA!", type: Chan.Type.QUERY}),
new Chan({name: "#thelounge"}),
new Chan({name: "&foobar"}),
],
});
network.channels.push(new Chan({name: "#swag"}));

expect(network.channels[0].name).to.equal("Super Nice Network");
expect(network.channels[0].type).to.equal(Chan.Type.LOBBY);
});

it("should maintain channel reference", function () {
const chan = new Chan({
name: "#506-bug-fix",
messages: [
new Msg({
text: "message in constructor",
}),
],
});

const network = new Network({
name: "networkName",
channels: [chan],
});

chan.messages.push(
new Msg({
text: "message in original instance",
})
);

network.channels[1].messages.push(
new Msg({
text: "message after network creation",
})
);

expect(network.channels[1].messages).to.have.lengthOf(3);
expect(network.channels[1].messages[0].text).to.equal("message in constructor");
expect(network.channels[1].messages[1].text).to.equal("message in original instance");
expect(network.channels[1].messages[2].text).to.equal("message after network creation");
});
});

describe("#export()", function () {
it("should produce an valid object", function () {
const network = new Network({
Expand Down Expand Up @@ -61,8 +122,10 @@ describe("Network", function () {
ignoreList: [],
});
});
});

it("validate should set correct defaults", function () {
describe("#validate()", function () {
it("should set correct defaults", function () {
Helper.config.defaults.nick = "";

const network = new Network({
Expand All @@ -83,7 +146,7 @@ describe("Network", function () {
expect(network2.username).to.equal("InvalidNick");
});

it("lockNetwork should be enforced when validating", function () {
it("should enforce lockNetwork", function () {
Helper.config.lockNetwork = true;

// Make sure we lock in private mode
Expand Down Expand Up @@ -113,7 +176,101 @@ describe("Network", function () {
Helper.config.lockNetwork = false;
});

it("editing a network should enforce correct types", function () {
it("should apply STS policies iff they match", function () {
const client = {idMsg: 1, emit() {}};
STSPolicies.update("irc.example.com", 7000, 3600);

let network = new Network({
host: "irc.example.com",
port: 1337,
tls: false,
});

expect(network.validate(client)).to.be.true;
expect(network.port).to.equal(7000);
expect(network.tls).to.be.true;

network = new Network({
host: "irc2.example.com",
port: 1337,
tls: false,
});

expect(network.validate(client)).to.be.true;
expect(network.port).to.equal(1337);
expect(network.tls).to.be.false;

STSPolicies.update("irc.example.com", 7000, 0); // Cleanup
});

it("should not remove client certs if TLS is disabled", function () {
Helper.config.public = false;

const client = {idMsg: 1, emit() {}, messageStorage: []};

const network = new Network({host: "irc.example.com", sasl: "external"});
network.createIrcFramework(client);
expect(network.irc).to.not.be.null;

const client_cert = network.irc.options.client_certificate;
expect(client_cert).to.not.be.null;
expect(ClientCertificate.get(network.uuid)).to.deep.equal(client_cert);

expect(network.validate(client)).to.be.true;

expect(ClientCertificate.get(network.uuid)).to.deep.equal(client_cert); // Should be unchanged

ClientCertificate.remove(network.uuid);
Helper.config.public = true;
});

it("should not remove client certs if there is a STS policy", function () {
Helper.config.public = false;

const client = {idMsg: 1, emit() {}, messageStorage: []};
STSPolicies.update("irc.example.com", 7000, 3600);

const network = new Network({host: "irc.example.com", sasl: "external"});
network.createIrcFramework(client);
expect(network.irc).to.not.be.null;

const client_cert = network.irc.options.client_certificate;
expect(client_cert).to.not.be.null;
expect(ClientCertificate.get(network.uuid)).to.deep.equal(client_cert);

expect(network.validate(client)).to.be.true;

expect(ClientCertificate.get(network.uuid)).to.deep.equal(client_cert); // Should be unchanged

ClientCertificate.remove(network.uuid);
Helper.config.public = true;
});
});

describe("#createIrcFramework(client)", function () {
it("should generate and use a client certificate when using SASL external", function () {
Helper.config.public = false;

const client = {idMsg: 1, emit() {}};
STSPolicies.update("irc.example.com", 7000, 3600);

let network = new Network({host: "irc.example.com"});
network.createIrcFramework(client);
expect(network.irc).to.not.be.null;
expect(network.irc.options.client_certificate).to.be.null;

network = new Network({host: "irc.example.com", sasl: "external"});
network.createIrcFramework(client);
expect(network.irc).to.not.be.null;
expect(network.irc.options.client_certificate).to.not.be.null;

ClientCertificate.remove(network.uuid);
Helper.config.public = true;
});
});

describe("#edit(client, args)", function () {
it("should enforce correct types", function () {
let saveCalled = false;
let nameEmitCalled = false;

Expand Down Expand Up @@ -177,63 +334,6 @@ describe("Network", function () {
"/whois test",
]);
});

it("should generate uuid (v4) for each network", function () {
const network1 = new Network();
const network2 = new Network();

expect(network1.uuid).to.have.lengthOf(36);
expect(network2.uuid).to.have.lengthOf(36);
expect(network1.uuid).to.not.equal(network2.uuid);
});

it("lobby should be at the top", function () {
const network = new Network({
name: "Super Nice Network",
channels: [
new Chan({name: "AAAA!", type: Chan.Type.QUERY}),
new Chan({name: "#thelounge"}),
new Chan({name: "&foobar"}),
],
});
network.channels.push(new Chan({name: "#swag"}));

expect(network.channels[0].name).to.equal("Super Nice Network");
expect(network.channels[0].type).to.equal(Chan.Type.LOBBY);
});

it("should maintain channel reference", function () {
const chan = new Chan({
name: "#506-bug-fix",
messages: [
new Msg({
text: "message in constructor",
}),
],
});

const network = new Network({
name: "networkName",
channels: [chan],
});

chan.messages.push(
new Msg({
text: "message in original instance",
})
);

network.channels[1].messages.push(
new Msg({
text: "message after network creation",
})
);

expect(network.channels[1].messages).to.have.lengthOf(3);
expect(network.channels[1].messages[0].text).to.equal("message in constructor");
expect(network.channels[1].messages[1].text).to.equal("message in original instance");
expect(network.channels[1].messages[2].text).to.equal("message after network creation");
});
});

describe("#getFilteredClone(lastActiveChannel, lastMessage)", function () {
Expand Down

0 comments on commit c9c8cad

Please sign in to comment.