aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOsmium Sorcerer <os@sof.beauty>2026-03-22 17:57:13 +0000
committerOsmium Sorcerer <os@sof.beauty>2026-03-29 22:22:25 +0000
commit79c2262cae02b513aee70943f7e07a9205316bdf (patch)
tree02efb824bad180a11bd1b68c41508088c167434b
parent06f34c776972542222623ca4f91880de97993fbf (diff)
Support Secure WebSocket
Add full WSS support to public server list (using wss_port, overriding insecure port), favorite servers list, and direct connections, and show which servers are secure. Revert the upstream's removal of `legacy` ServerInfo field, as I use it to filter out legacy servers. To differentiate schemes, the `scheme` field is used, either "ws" or "wss". I don't see the reason to add "tcp" protocol when we don't even support it. For the UI, add icons for secure and insecure connections. Highlight secure servers with a green background. In the favorite server dialog, a checkbox was added to select whether the server is using WSS. In the direct connection dialog, support "wss" scheme and default ports: 80 for WS, 443 for WSS, as per the WebSocket specification.
-rw-r--r--data.qrc2
-rw-r--r--data/icons/https.svg1
-rw-r--r--data/icons/noencryption.svg1
-rw-r--r--data/ui/favorite_server_dialog.ui13
-rw-r--r--src/lobby.cpp39
-rw-r--r--src/network/serverinfo.h3
-rw-r--r--src/network/websocketconnection.cpp2
-rw-r--r--src/networkmanager.cpp6
-rw-r--r--src/options.cpp18
-rw-r--r--src/widgets/direct_connect_dialog.cpp15
-rw-r--r--src/widgets/server_editor_dialog.cpp3
-rw-r--r--src/widgets/server_editor_dialog.h2
12 files changed, 70 insertions, 35 deletions
diff --git a/data.qrc b/data.qrc
index d44218a5..bad64a50 100644
--- a/data.qrc
+++ b/data.qrc
@@ -16,5 +16,7 @@
<file>data/ui/lobby_assets/down-arrow.png</file>
<file>data/ui/lobby_assets/up-arrow.png</file>
<file>data/ui/moderator_action_dialog.ui</file>
+ <file>data/icons/https.svg</file>
+ <file>data/icons/noencryption.svg</file>
</qresource>
</RCC>
diff --git a/data/icons/https.svg b/data/icons/https.svg
new file mode 100644
index 00000000..87a3c2b9
--- /dev/null
+++ b/data/icons/https.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" height="20px" viewBox="0 -960 960 960" width="20px" fill="#F3F3F3"><path d="M263.72-96Q234-96 213-117.15T192-168v-384q0-29.7 21.15-50.85Q234.3-624 264-624h24v-96q0-79.68 56.23-135.84 56.22-56.16 136-56.16Q560-912 616-855.84q56 56.16 56 135.84v96h24q29.7 0 50.85 21.15Q768-581.7 768-552v384q0 29.7-21.16 50.85Q725.68-96 695.96-96H263.72Zm.28-72h432v-384H264v384Zm267-141.21q21-21.21 21-51T530.79-411q-21.21-21-51-21T429-410.79q-21 21.21-21 51T429.21-309q21.21 21 51 21T531-309.21ZM360-624h240v-96q0-50-35-85t-85-35q-50 0-85 35t-35 85v96Zm-96 456v-384 384Z"/></svg> \ No newline at end of file
diff --git a/data/icons/noencryption.svg b/data/icons/noencryption.svg
new file mode 100644
index 00000000..91524c5f
--- /dev/null
+++ b/data/icons/noencryption.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" height="20px" viewBox="0 -960 960 960" width="20px" fill="#F3F3F3"><path d="m768-294-72.13-72.13v-185.74H510.13L438-624h162v-96q0-50-34.79-85T480-840q-50 0-85 35t-35 85v18l-65-65q17-65 68-105t117-40q80.08 0 136.04 56.16Q672-799.68 672-720v96h24q29.7 0 50.85 21.19Q768-581.62 768-551.87V-294Zm34 238-58-59q-9 8-21.5 13.5T696-96H263.72Q234-96 212.5-117T192-168v-384q0-23 13.11-41.53Q218.21-612.06 239-620L56-803l51-51 746 747-51 51ZM690-168 538-320q-9 15-25 23.5t-33 8.5q-29.7 0-50.85-21.15Q408-330.3 408-360q0-17 7.5-32.5T439-419L306-552h-42v384h426ZM488-370Zm112-92Z"/></svg> \ No newline at end of file
diff --git a/data/ui/favorite_server_dialog.ui b/data/ui/favorite_server_dialog.ui
index b90514dc..1fda9229 100644
--- a/data/ui/favorite_server_dialog.ui
+++ b/data/ui/favorite_server_dialog.ui
@@ -78,13 +78,24 @@
</widget>
</item>
<item row="3" column="0">
+ <widget class="QLabel" name="label_6">
+ <property name="text">
+ <string>Secure:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="1">
+ <widget class="QCheckBox" name="secure_cb">
+ </widget>
+ </item>
+ <item row="4" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Description:</string>
</property>
</widget>
</item>
- <item row="3" column="1">
+ <item row="4" column="1">
<widget class="QPlainTextEdit" name="description">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
diff --git a/src/lobby.cpp b/src/lobby.cpp
index 424f634b..29101c6f 100644
--- a/src/lobby.cpp
+++ b/src/lobby.cpp
@@ -471,19 +471,21 @@ void Lobby::list_servers()
QTreeWidgetItem *treeItem = new QTreeWidgetItem(ui_serverlist_tree);
treeItem->setData(0, Qt::DisplayRole, i);
- if (i_server.protocol == "tcp")
+ QIcon insecureIcon(":/data/icons/noencryption.svg");
+ QIcon secureIcon(":/data/icons/https.svg");
+ QColor secureColor(80, 120, 80);
+ treeItem->setText(1, i_server.name);
+ if (i_server.scheme == "wss")
{
- treeItem->setText(1, "(Legacy) " + i_server.name);
- treeItem->setBackground(0, Qt::darkRed);
- treeItem->setBackground(1, Qt::darkRed);
-
- QString tooltip = tr("Unable to connect to server. Server is missing WebSocket support.");
- treeItem->setToolTip(0, tooltip);
- treeItem->setToolTip(1, tooltip);
+ treeItem->setIcon(1, secureIcon);
+ treeItem->setToolTip(1, "Connection is secure.");
+ treeItem->setBackground(0, secureColor);
+ treeItem->setBackground(1, secureColor);
}
- else
+ else if (i_server.scheme == "ws")
{
- treeItem->setText(1, i_server.name);
+ treeItem->setIcon(1, insecureIcon);
+ treeItem->setToolTip(1, "Insecure. Traffic can be intercepted or modified.");
}
i++;
@@ -504,7 +506,7 @@ void Lobby::list_favorites()
QTreeWidgetItem *treeItem = new QTreeWidgetItem(ui_favorites_tree);
treeItem->setData(0, Qt::DisplayRole, i);
- if (i_server.protocol == "tcp")
+ if (i_server.legacy)
{
treeItem->setText(1, "(Legacy) " + i_server.name);
treeItem->setBackground(0, Qt::darkRed);
@@ -516,7 +518,22 @@ void Lobby::list_favorites()
}
else
{
+ QIcon insecureIcon(":/data/icons/noencryption.svg");
+ QIcon secureIcon(":/data/icons/https.svg");
+ QColor secureColor(80, 120, 80);
treeItem->setText(1, i_server.name);
+ if (i_server.scheme == "wss")
+ {
+ treeItem->setIcon(1, secureIcon);
+ treeItem->setToolTip(1, "Connection is secure.");
+ treeItem->setBackground(0, secureColor);
+ treeItem->setBackground(1, secureColor);
+ }
+ else if (i_server.scheme == "ws")
+ {
+ treeItem->setIcon(1, insecureIcon);
+ treeItem->setToolTip(1, "Insecure. Traffic can be intercepted or modified.");
+ }
}
i++;
diff --git a/src/network/serverinfo.h b/src/network/serverinfo.h
index de91a011..b7e00697 100644
--- a/src/network/serverinfo.h
+++ b/src/network/serverinfo.h
@@ -9,7 +9,8 @@ public:
QString description;
QString address;
quint16 port = 0;
- QString protocol = "ws";
+ bool legacy = false;
+ QString scheme = "ws";
QString toString() const;
};
diff --git a/src/network/websocketconnection.cpp b/src/network/websocketconnection.cpp
index e9cc1ef9..d51cdcaf 100644
--- a/src/network/websocketconnection.cpp
+++ b/src/network/websocketconnection.cpp
@@ -32,7 +32,7 @@ void WebSocketConnection::connectToServer(const ServerInfo &server)
disconnectFromServer();
QUrl url;
- url.setScheme(server.protocol);
+ url.setScheme(server.scheme);
url.setHost(server.address);
url.setPort(server.port);
diff --git a/src/networkmanager.cpp b/src/networkmanager.cpp
index 02d5961e..a7bb54ef 100644
--- a/src/networkmanager.cpp
+++ b/src/networkmanager.cpp
@@ -63,17 +63,17 @@ void NetworkManager::ms_request_finished(QNetworkReply *reply)
if (entry.contains("wss_port"))
{
server.port = entry["wss_port"].toInt();
- server.protocol = "wss";
+ server.scheme = "wss";
}
else if (entry.contains("ws_port"))
{
server.port = entry["ws_port"].toInt();
- server.protocol = "ws";
+ server.scheme = "ws";
}
else
{
server.port = entry["port"].toInt();
- server.protocol = "tcp";
+ server.legacy = true;
}
if (server.port != 0)
diff --git a/src/options.cpp b/src/options.cpp
index d25eea09..3d400c25 100644
--- a/src/options.cpp
+++ b/src/options.cpp
@@ -678,14 +678,7 @@ QVector<ServerInfo> Options::favorites()
f_server.port = favorite.value("port", 27016).toInt();
f_server.name = favorite.value("name", "Missing Name").toString();
f_server.description = favorite.value("desc", "No description").toString();
- if (favorite.contains("protocol"))
- {
- f_server.protocol = favorite.value("protocol").toString();
- }
- else
- {
- f_server.protocol = "tcp";
- }
+ f_server.scheme = favorite.value("scheme", "ws").toString();
serverlist.append(std::move(f_server));
favorite.endGroup();
@@ -705,7 +698,8 @@ void Options::setFavorites(QVector<ServerInfo> value)
favorite.setValue("address", fav_server.address);
favorite.setValue("port", fav_server.port);
favorite.setValue("desc", fav_server.description);
- favorite.setValue("protocol", fav_server.protocol);
+ favorite.setValue("legacy", fav_server.legacy);
+ favorite.setValue("scheme", fav_server.scheme);
favorite.endGroup();
}
favorite.sync();
@@ -726,7 +720,8 @@ void Options::addFavorite(ServerInfo server)
favorite.setValue("address", server.address);
favorite.setValue("port", server.port);
favorite.setValue("desc", server.description);
- favorite.setValue("protocol", server.protocol);
+ favorite.setValue("legacy", server.legacy);
+ favorite.setValue("scheme", server.scheme);
favorite.endGroup();
favorite.sync();
}
@@ -738,7 +733,8 @@ void Options::updateFavorite(ServerInfo server, int index)
favorite.setValue("address", server.address);
favorite.setValue("port", server.port);
favorite.setValue("desc", server.description);
- favorite.setValue("protocol", server.protocol);
+ favorite.setValue("legacy", server.legacy);
+ favorite.setValue("scheme", server.scheme);
favorite.endGroup();
favorite.sync();
}
diff --git a/src/widgets/direct_connect_dialog.cpp b/src/widgets/direct_connect_dialog.cpp
index f8c77b85..9859889d 100644
--- a/src/widgets/direct_connect_dialog.cpp
+++ b/src/widgets/direct_connect_dialog.cpp
@@ -51,7 +51,7 @@ void DirectConnectDialog::onConnectPressed()
QString l_hostname = ui_direct_hostname_edit->text();
if (!SCHEME_PATTERN.match(l_hostname).hasMatch())
{
- l_hostname = "ws://" % l_hostname;
+ l_hostname = "wss://" % l_hostname;
}
QUrl l_url(l_hostname);
@@ -61,20 +61,21 @@ void DirectConnectDialog::onConnectPressed()
return;
}
- if (l_url.scheme() != "ws")
+ if (l_url.scheme() != "ws" && l_url.scheme() != "wss")
{
- call_error(tr("Invalid URL scheme. Only ws:// is supported."));
+ call_error(tr("Invalid URL scheme. Only ws: and wss: are supported."));
return;
}
- if (l_url.port() == -1)
+ int port = l_url.port();
+ if (port == -1)
{
- call_error(tr("Invalid server port."));
- return;
+ port = (l_url.scheme() == "wss") ? 443 : 80;
}
ServerInfo l_server;
l_server.address = l_url.host();
- l_server.port = l_url.port();
+ l_server.port = port;
+ l_server.scheme = l_url.scheme();
l_server.name = "Direct Connection";
net_manager->connect_to_server(l_server);
diff --git a/src/widgets/server_editor_dialog.cpp b/src/widgets/server_editor_dialog.cpp
index 03c8d6c6..8f987f6a 100644
--- a/src/widgets/server_editor_dialog.cpp
+++ b/src/widgets/server_editor_dialog.cpp
@@ -31,6 +31,7 @@ ServerEditorDialog::ServerEditorDialog(QWidget *parent)
FROM_UI(QLineEdit, name);
FROM_UI(QLineEdit, hostname);
FROM_UI(QSpinBox, port);
+ FROM_UI(QCheckBox, secure_cb);
FROM_UI(QPlainTextEdit, description);
FROM_UI(QDialogButtonBox, button_box);
@@ -49,6 +50,7 @@ ServerEditorDialog::ServerEditorDialog(const ServerInfo &server, QWidget *parent
ui_name->setText(server.name);
ui_hostname->setText(server.address);
ui_port->setValue(server.port);
+ ui_secure_cb->setChecked(server.scheme == "wss");
ui_description->setPlainText(server.description);
}
@@ -58,6 +60,7 @@ ServerInfo ServerEditorDialog::currentServerInfo() const
server.name = ui_name->text();
server.address = ui_hostname->text();
server.port = ui_port->value();
+ server.scheme = ui_secure_cb->isChecked() ? "wss" : "ws";
server.description = ui_description->toPlainText();
return server;
}
diff --git a/src/widgets/server_editor_dialog.h b/src/widgets/server_editor_dialog.h
index a8844d4b..7b0bb651 100644
--- a/src/widgets/server_editor_dialog.h
+++ b/src/widgets/server_editor_dialog.h
@@ -2,6 +2,7 @@
#include "network/serverinfo.h"
+#include <QCheckBox>
#include <QComboBox>
#include <QDialog>
#include <QDialogButtonBox>
@@ -29,6 +30,7 @@ private:
QLineEdit *ui_name;
QLineEdit *ui_hostname;
QSpinBox *ui_port;
+ QCheckBox *ui_secure_cb;
QPlainTextEdit *ui_description;
QDialogButtonBox *ui_button_box;