- Provider-controlled strings (channel names, groups, file names, log lines, in-place mapping edits, client info) are rendered with textContent instead of innerHTML. PopupContent.description() takes an explicit isHTML flag that only the static help texts pass. - Websocket: drop the always-true CheckOrigin so gorilla's same-origin check applies; read the session token from the HttpOnly cookie sent with the handshake (the ?Token= query parameter is still accepted for older clients); the client no longer puts the token in the URL, rewrites the cookie, or console-logs request/response payloads. - Session cookie is HttpOnly, SameSite=Strict, Path=/, session-scoped (expiry stays server side) and is cleared on logout. - Serving the first-run wizard no longer sets Settings.AuthenticationWEB to false; the wizard page simply bypasses login while it is active. - Upgrade failures no longer write a second error response. - Tests: src/websocket_test.go covers cross-origin refusal, same-origin and no-Origin clients, missing/unknown/legacy tokens, and cookie flags.
This commit is contained in:
+25
-34
@@ -7,7 +7,6 @@ class Server {
|
||||
return;
|
||||
}
|
||||
SERVER_CONNECTION = true;
|
||||
console.log(data);
|
||||
if (this.cmd != "updateLog") {
|
||||
showElement("loading", true);
|
||||
UNDO = new Object();
|
||||
@@ -25,7 +24,8 @@ class Server {
|
||||
if (wsHost == undefined || wsHost.length < 1) {
|
||||
wsHost = window.location.hostname;
|
||||
}
|
||||
var url = this.protocol + wsHost + "/data/" + "?Token=" + getCookie("Token");
|
||||
// The session cookie (HttpOnly) is sent with the websocket handshake.
|
||||
var url = this.protocol + wsHost + "/data/";
|
||||
data["cmd"] = this.cmd;
|
||||
var requestCmd = data["cmd"];
|
||||
var ws = new WebSocket(url);
|
||||
@@ -75,10 +75,6 @@ class Server {
|
||||
if (data["cmd"] != "updateLog") {
|
||||
setConnectionState("busy");
|
||||
}
|
||||
console.log("REQUEST (JS):");
|
||||
console.log(data);
|
||||
console.log("REQUEST: (JSON)");
|
||||
console.log(JSON.stringify(data));
|
||||
this.send(JSON.stringify(data));
|
||||
};
|
||||
ws.onerror = function (e) {
|
||||
@@ -95,12 +91,7 @@ class Server {
|
||||
ws.onmessage = function (e) {
|
||||
responseReceived = true;
|
||||
finishRequest("online", true);
|
||||
console.log("RESPONSE:");
|
||||
var response = JSON.parse(e.data);
|
||||
console.log(response);
|
||||
if (response.hasOwnProperty("token")) {
|
||||
document.cookie = "Token=" + response["token"];
|
||||
}
|
||||
if (response["status"] == false) {
|
||||
setConnectionState("offline");
|
||||
alert(response["err"]);
|
||||
@@ -162,12 +153,6 @@ class Server {
|
||||
}
|
||||
}
|
||||
var WS_FAILURE_COUNT = 0;
|
||||
function getCookie(name) {
|
||||
var value = "; " + document.cookie;
|
||||
var parts = value.split("; " + name + "=");
|
||||
if (parts.length == 2)
|
||||
return parts.pop().split(";").shift();
|
||||
}
|
||||
class MainMenu {
|
||||
constructor() {
|
||||
this.DocumentID = "main-menu";
|
||||
@@ -181,7 +166,7 @@ class MainMenu {
|
||||
}
|
||||
createValue(value) {
|
||||
var element = document.createElement("P");
|
||||
element.innerHTML = value;
|
||||
element.textContent = value;
|
||||
return element;
|
||||
}
|
||||
}
|
||||
@@ -233,7 +218,7 @@ class Content {
|
||||
}
|
||||
createHeadline(value) {
|
||||
var element = document.createElement("H3");
|
||||
element.innerHTML = value;
|
||||
element.textContent = value;
|
||||
return element;
|
||||
}
|
||||
createHR() {
|
||||
@@ -584,7 +569,7 @@ class Cell {
|
||||
switch (this.childType) {
|
||||
case "P":
|
||||
element = document.createElement(this.childType);
|
||||
element.innerHTML = this.value;
|
||||
element.textContent = this.value;
|
||||
element.className = this.className;
|
||||
break;
|
||||
case "INPUT":
|
||||
@@ -632,7 +617,7 @@ class Cell {
|
||||
td.appendChild(element);
|
||||
}
|
||||
else {
|
||||
td.innerHTML = this.value;
|
||||
td.textContent = this.value;
|
||||
}
|
||||
if (this.onclick == true) {
|
||||
td.setAttribute("onclick", this.onclickFunktion);
|
||||
@@ -1022,7 +1007,7 @@ function setClientInfoValue(key, value) {
|
||||
element.appendChild(anchor);
|
||||
return;
|
||||
}
|
||||
element.innerHTML = textValue;
|
||||
element.textContent = textValue;
|
||||
}
|
||||
function createLayout() {
|
||||
// Client Info
|
||||
@@ -1168,11 +1153,17 @@ class PopupContent extends PopupWindow {
|
||||
s.options[s.selectedIndex].value = value;
|
||||
return select;
|
||||
}
|
||||
description(value) {
|
||||
// isHTML must only be true for static text written in the source; never for data.
|
||||
description(value, isHTML = false) {
|
||||
var tr = document.createElement("TR");
|
||||
var td = document.createElement("TD");
|
||||
var span = document.createElement("PRE");
|
||||
span.innerHTML = value;
|
||||
if (isHTML) {
|
||||
span.innerHTML = value;
|
||||
}
|
||||
else {
|
||||
span.textContent = value;
|
||||
}
|
||||
tr.appendChild(td);
|
||||
tr.appendChild(this.createContent(span));
|
||||
this.table.appendChild(tr);
|
||||
@@ -1278,7 +1269,7 @@ function openPopUp(dataType, element) {
|
||||
input.className = "notAvailable";
|
||||
content.appendRow("Tuner / Streams", input);
|
||||
}
|
||||
content.description("Number of parallel connections that can be established to the provider. <br>Only available with activated buffer.<br>New settings will only be applied after quitting all streams.");
|
||||
content.description("Number of parallel connections that can be established to the provider. <br>Only available with activated buffer.<br>New settings will only be applied after quitting all streams.", true);
|
||||
// Interaktion
|
||||
content.createInteraction();
|
||||
// Löschen
|
||||
@@ -1348,7 +1339,7 @@ function openPopUp(dataType, element) {
|
||||
input.className = "notAvailable";
|
||||
content.appendRow("Tuner / Streams", input);
|
||||
}
|
||||
content.description("Number of parallel connections that can be established to the provider. <br>Only available with activated buffer.<br>New settings will only be applied after quitting all streams.");
|
||||
content.description("Number of parallel connections that can be established to the provider. <br>Only available with activated buffer.<br>New settings will only be applied after quitting all streams.", true);
|
||||
// Interaktion
|
||||
content.createInteraction();
|
||||
// Löschen
|
||||
@@ -1448,7 +1439,7 @@ function openPopUp(dataType, element) {
|
||||
var select = content.createSelect(text, values, data[dbKey], dbKey);
|
||||
select.setAttribute("onchange", "javascript: this.className = 'changed'");
|
||||
content.appendRow("Group Title", select);
|
||||
content.description("Select a M3U group. (Counter)<br>Changing the group title in the M3U invalidates the filter.");
|
||||
content.description("Select a M3U group. (Counter)<br>Changing the group title in the M3U invalidates the filter.", true);
|
||||
// Groß- Kleinschreibung beachten
|
||||
var dbKey = "caseSensitive";
|
||||
var input = content.createCheckbox(dbKey);
|
||||
@@ -1458,12 +1449,12 @@ function openPopUp(dataType, element) {
|
||||
var input = content.createInput("text", dbKey, data[dbKey]);
|
||||
input.setAttribute("placeholder", "FHD,UHD");
|
||||
content.appendRow("Include", input);
|
||||
content.description("Channel name must include.<br>(Comma separated) Comma means or");
|
||||
content.description("Channel name must include.<br>(Comma separated) Comma means or", true);
|
||||
var dbKey = "exclude";
|
||||
var input = content.createInput("text", dbKey, data[dbKey]);
|
||||
input.setAttribute("placeholder", "ES,IT");
|
||||
content.appendRow("Exclude", input);
|
||||
content.description("Channel name must not contain.<br>(Comma separated) Comma means or");
|
||||
content.description("Channel name must not contain.<br>(Comma separated) Comma means or", true);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@@ -2030,13 +2021,13 @@ function donePopupData(dataType, idsStr) {
|
||||
//(document.getElementById(id).childNodes[2].firstChild as HTMLElement).setAttribute("src", value)
|
||||
break;
|
||||
case "x-name":
|
||||
document.getElementById(id).childNodes[3].firstChild.innerHTML = value;
|
||||
document.getElementById(id).childNodes[3].firstChild.textContent = value;
|
||||
break;
|
||||
case "x-category":
|
||||
document.getElementById(id).childNodes[3].firstChild.className = value;
|
||||
break;
|
||||
case "x-group-title":
|
||||
document.getElementById(id).childNodes[5].firstChild.innerHTML = value;
|
||||
document.getElementById(id).childNodes[5].firstChild.textContent = value;
|
||||
break;
|
||||
case "x-xmltv-file":
|
||||
if (value != "xTeVe Dummy" && value != "-") {
|
||||
@@ -2045,13 +2036,13 @@ function donePopupData(dataType, idsStr) {
|
||||
if (value == "-") {
|
||||
input["x-active"] = false;
|
||||
}
|
||||
document.getElementById(id).childNodes[6].firstChild.innerHTML = value;
|
||||
document.getElementById(id).childNodes[6].firstChild.textContent = value;
|
||||
break;
|
||||
case "x-mapping":
|
||||
if (value == "-") {
|
||||
input["x-active"] = false;
|
||||
}
|
||||
document.getElementById(id).childNodes[7].firstChild.innerHTML = value;
|
||||
document.getElementById(id).childNodes[7].firstChild.textContent = value;
|
||||
break;
|
||||
default:
|
||||
}
|
||||
@@ -2658,7 +2649,7 @@ class Log {
|
||||
if (entry.indexOf("DEBUG") != -1) {
|
||||
element.className = "debugMsg";
|
||||
}
|
||||
element.innerHTML = entry;
|
||||
element.textContent = entry;
|
||||
return element;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user