Add a hack to detect distrust of Let's Encrypt

Many older devices do not support the Let's Encrypt CA, for various
reasons.  This causes connection issues for sites using Let's Encrypt to
support HTTPS connections.  This commit adds a hack that can be enabled
with a switch in callbacks.js to try to detect when the user's browser
does not trust the certificate and permit the user to connect to an
insecure endpoint instead.

Unfortunately, the AJAX API does not allow to distinguish between *why*
a request fails, so the best we can do is detect that the HTTPS request
failed, try to make a request over plain HTTP, and if it works, assume
the HTTPS request failed due to a certificate error.  It's not 100%
foolproof since the HTTPS endpoint could just be down for some reason,
but it should work well enough in most cases.

Closes #602
This commit is contained in:
calzoneman 2016-07-17 16:30:35 -07:00
parent aaa21aad05
commit 6e416fea8a

View file

@ -35,7 +35,7 @@ Callbacks = {
return;
$("<div/>")
.addClass("server-msg-disconnect")
.text("Disconnected from server. Attempting reconnection...")
.text("Disconnected from server.")
.appendTo($("#messagebuffer"));
scrollChat();
},
@ -1123,7 +1123,18 @@ function ioServerConnect(socketConfig) {
window.socket = io(chosenServer.url, opts);
}
(function () {
var USING_LETS_ENCRYPT = false;
function initSocketIO(socketConfig) {
function genericConnectionError() {
var message = "The socket.io library could not be loaded from <code>" +
source + "</code>. Ensure that it is not being blocked " +
"by a script blocking extension or firewall and try again.";
makeAlert("Error", message, "alert-danger")
.appendTo($("#announcements"));
Callbacks.disconnect();
}
if (typeof io === "undefined") {
var script = document.getElementById("socketio-js");
var source = "unknown";
@ -1131,21 +1142,70 @@ function ioServerConnect(socketConfig) {
source = script.src;
}
var message = "The socket.io library could not be loaded from <code>" +
source + "</code>. Ensure that it is not being blocked " +
"by a script blocking extension or firewall and try again.";
makeAlert("Error", message, "alert-danger")
.appendTo($("#announcements"));
Callbacks.disconnect();
if (/^https/.test(source) && location.protocol === "http:"
&& USING_LETS_ENCRYPT) {
checkLetsEncrypt(socketConfig, genericConnectionError);
return;
}
genericConnectionError();
return;
}
ioServerConnect(socketConfig);
setupCallbacks();
}
function checkLetsEncrypt(socketConfig, nonLetsEncryptError) {
var servers = socketConfig.servers.filter(function (server) {
return !server.secure && !server.ipv6Only
});
if (servers.length === 0) {
nonLetsEncryptError();
return;
}
$.ajax({
url: servers[0].url + "/socket.io/socket.io.js",
dataType: "script",
timeout: 10000
}).done(function () {
var message = "Your browser cannot connect securely because it does " +
"not support the newer Let's Encrypt certificate " +
"authority. Click below to acknowledge and continue " +
"connecting over an unencrypted connection. See " +
"<a href=\"https://community.letsencrypt.org/t/which-browsers-and-operating-systems-support-lets-encrypt/4394\" target=\"_blank\">here</a> " +
"for more details.";
var connectionAlert = makeAlert("Error", message, "alert-danger")
.appendTo($("#announcements"));
var button = document.createElement("button");
button.className = "btn btn-default";
button.textContent = "Connect Anyways";
var alertBox = connectionAlert.find(".alert")[0];
alertBox.appendChild(document.createElement("hr"));
alertBox.appendChild(button);
button.onclick = function connectAnyways() {
ioServerConnect({
servers: servers
});
setupCallbacks();
};
}).error(function () {
nonLetsEncryptError();
});
}
(function () {
$.getJSON("/socketconfig/" + CHANNEL.name + ".json")
.done(function (socketConfig) {
ioServerConnect(socketConfig);
setupCallbacks();
initSocketIO(socketConfig);
}).fail(function () {
makeAlert("Error", "Failed to retrieve socket.io configuration",
makeAlert("Error", "Failed to retrieve socket.io configuration. " +
"Please try again in a few minutes.",
"alert-danger")
.appendTo($("#announcements"));
Callbacks.disconnect();