feat(ui): separate the namespace from the server URL

This should help prevent people from connecting to the main namespace,
when they forget to include the namespace at the end of the server URL.

Related:

- https://github.com/socketio/socket.io-admin-ui/issues/26
- https://github.com/socketio/socket.io-admin-ui/issues/42
This commit is contained in:
Damien Arrachequesne 2022-06-23 14:50:00 +02:00
parent 8542601b55
commit 5a8a75edc0
No known key found for this signature in database
GPG Key ID: 544D14663E7F7CF0
5 changed files with 60 additions and 18 deletions

View File

@ -17,6 +17,7 @@
:initial-server-url="serverUrl"
:initial-ws-only="wsOnly"
:initial-path="path"
:initial-namespace="namespace"
:initial-parser="parser"
:is-connecting="isConnecting"
:error="connectionError"
@ -70,6 +71,7 @@ export default {
serverUrl: (state) => state.connection.serverUrl,
wsOnly: (state) => state.connection.wsOnly,
path: (state) => state.connection.path,
namespace: (state) => state.connection.namespace,
parser: (state) => state.connection.parser,
backgroundColor: (state) =>
state.config.darkTheme ? "" : "grey lighten-5",
@ -92,7 +94,7 @@ export default {
},
methods: {
tryConnect(serverUrl, auth, wsOnly, path, parser) {
tryConnect(serverUrl, namespace, auth, wsOnly, path, parser) {
this.isConnecting = true;
if (SocketHolder.socket) {
SocketHolder.socket.disconnect();
@ -100,7 +102,7 @@ export default {
SocketHolder.socket.off("connect_error");
SocketHolder.socket.off("disconnect");
}
const socket = io(serverUrl, {
const socket = io(serverUrl + namespace, {
forceNew: true,
reconnection: false,
withCredentials: true, // needed for cookie-based sticky-sessions
@ -119,6 +121,7 @@ export default {
serverUrl,
wsOnly,
path,
namespace,
parser,
});
SocketHolder.socket = socket;
@ -210,6 +213,7 @@ export default {
onSubmit(form) {
this.tryConnect(
form.serverUrl,
form.namespace,
{
username: form.username,
password: form.password,
@ -231,6 +235,7 @@ export default {
const sessionId = this.$store.state.connection.sessionId;
this.tryConnect(
this.serverUrl,
this.namespace,
{
sessionId,
},

View File

@ -12,7 +12,7 @@
<v-text-field
v-model="serverUrl"
:label="$t('connection.serverUrl')"
placeholder="https://example.com/admin"
placeholder="https://example.com"
required
></v-text-field>
<v-text-field
@ -26,22 +26,39 @@
></v-text-field>
<v-switch
v-model="wsOnly"
:label="$t('connection.websocket-only')"
v-model="showAdvancedOptions"
:label="$t('connection.advanced-options')"
inset
dense
/>
<v-text-field
v-model="path"
:label="$t('connection.path')"
></v-text-field>
<v-expand-transition>
<div v-if="showAdvancedOptions">
<v-switch
v-model="wsOnly"
:label="$t('connection.websocket-only')"
inset
dense
v-show="showAdvancedOptions"
/>
<v-select
v-model="parser"
:label="$t('connection.parser')"
:items="parserOptions"
/>
<v-text-field
v-model="namespace"
:label="$t('connection.namespace')"
></v-text-field>
<v-text-field
v-model="path"
:label="$t('connection.path')"
></v-text-field>
<v-select
v-model="parser"
:label="$t('connection.parser')"
:items="parserOptions"
/>
</div>
</v-expand-transition>
<v-btn
:loading="isConnecting"
@ -69,15 +86,18 @@ export default {
initialServerUrl: String,
initialWsOnly: Boolean,
initialPath: String,
initialNamespace: String,
initialParser: String,
error: String,
},
data() {
return {
showAdvancedOptions: false,
serverUrl: this.initialServerUrl,
wsOnly: this.initialWsOnly,
path: this.initialPath,
namespace: this.initialNamespace,
username: "",
password: "",
parser: this.initialParser,
@ -111,6 +131,7 @@ export default {
serverUrl: this.serverUrl,
wsOnly: this.wsOnly,
path: this.path,
namespace: this.namespace,
username: this.username,
password: this.password,
parser: this.parser,

View File

@ -29,7 +29,9 @@
"path": "Path",
"parser": "Parser",
"default-parser": "Built-in parser",
"msgpack-parser": "MessagePack parser"
"msgpack-parser": "MessagePack parser",
"namespace": "Admin namespace",
"advanced-options": "Advanced options"
},
"dashboard": {
"title": "Dashboard",

View File

@ -26,7 +26,12 @@
"invalid-credentials": "Identifiants invalides",
"error": "Erreur",
"websocket-only": "WebSocket uniquement ?",
"path": "Chemin HTTP"
"path": "Chemin HTTP",
"parser": "Encodeur",
"default-parser": "Encodeur par défaut",
"msgpack-parser": "Encodeur basé sur MessagePack",
"namespace": "Espace de nom d'administration",
"advanced-options": "Options avancées"
},
"dashboard": {
"title": "Accueil",

View File

@ -6,6 +6,7 @@ export default {
serverUrl: "",
wsOnly: false,
path: "/socket.io",
namespace: "/admin",
parser: "default",
sessionId: "",
connected: false,
@ -13,22 +14,30 @@ export default {
mutations: {
init(state) {
if (isLocalStorageAvailable) {
state.serverUrl = localStorage.getItem("server_url");
state.serverUrl = localStorage.getItem("server_url") || "";
if (state.serverUrl.endsWith("/admin")) {
// for backward compatibility
state.serverUrl = state.serverUrl.slice(0, -6);
} else {
state.namespace = localStorage.getItem("namespace") || "/admin";
}
state.wsOnly = localStorage.getItem("ws_only") === "true";
state.sessionId = localStorage.getItem("session_id");
state.path = localStorage.getItem("path") || "/socket.io";
state.parser = localStorage.getItem("parser") || "default";
}
},
saveConfig(state, { serverUrl, wsOnly, path, parser }) {
saveConfig(state, { serverUrl, wsOnly, path, namespace, parser }) {
state.serverUrl = serverUrl;
state.wsOnly = wsOnly;
state.path = path;
state.namespace = namespace;
state.parser = parser;
if (isLocalStorageAvailable) {
localStorage.setItem("server_url", serverUrl);
localStorage.setItem("ws_only", wsOnly);
localStorage.setItem("path", path);
localStorage.setItem("namespace", namespace);
localStorage.setItem("parser", parser);
}
},