diff --git a/dist/index.html b/dist/index.html
index eca2d5d..090aa27 100644
--- a/dist/index.html
+++ b/dist/index.html
@@ -114,6 +114,10 @@
diff --git a/dist/style.css b/dist/style.css
index 9b893a6..1a4a8f5 100644
--- a/dist/style.css
+++ b/dist/style.css
@@ -77,4 +77,8 @@
#qemuMonitorOutput {
height: 180px;
+}
+
+#xssCheckboxContainer {
+ display: none;
}
\ No newline at end of file
diff --git a/src/common.js b/src/common.js
index 42fb202..feaabe8 100644
--- a/src/common.js
+++ b/src/common.js
@@ -10,5 +10,10 @@ export const config = {
"wss://computernewb.com/collab-vm/vm7",
"wss://computernewb.com/collab-vm/vm8",
],
- chatSound: "https://computernewb.com/collab-vm/notify.ogg"
+ chatSound: "https://computernewb.com/collab-vm/notify.ogg",
+ // What XSS implementation the server uses
+ // 0: No XSS (If you're using upstream it will be this)
+ // 1: Internal fork style (main vms only, global opcode 21)
+ // 2: yellows111/collab-vm-server style (per-user opcode 21)
+ xssImplementation: 1,
}
\ No newline at end of file
diff --git a/src/index.js b/src/index.js
index 004b58f..da0dd3c 100644
--- a/src/index.js
+++ b/src/index.js
@@ -7,7 +7,7 @@ import { makeperms } from "./permissions";
// Has turn = 0
// In queue =
var turn = -1;
-var perms = makeperms(0);
+var perms = makeperms(0, config);
var rank = 0;
var connected = false;
const vms = [];
@@ -53,6 +53,8 @@ const votetime = document.getElementById("votetime");
const staffbtns = document.getElementById("staffbtns");
const qemuMonitorInput = document.getElementById("qemuMonitorInput");
const qemuMonitorOutput = document.getElementById("qemuMonitorOutput");
+const xssCheckbox = document.getElementById("xssCheckbox");
+const xssCheckboxContainer = document.getElementById("xssCheckboxContainer");
// needed to scroll to bottom
const chatListDiv = document.querySelector(".chat-table");
@@ -319,12 +321,12 @@ class CollabVMClient {
return;
break;
case "1":
- perms = makeperms(65535);
+ perms = makeperms(65535, config);
rank = 2;
break;
case "3":
rank = 3;
- perms = makeperms(parseInt(msgArr[3]))
+ perms = makeperms(parseInt(msgArr[3]), config)
}
this.eventemitter.emit('login', {perms: perms, rank: rank});
usernameSpan.classList.remove("text-light");
@@ -347,6 +349,9 @@ class CollabVMClient {
buttons.endTurn.style.display = "inline-block";
}
if (rank === 2) buttons.qemuMonitor.style.display = "inline-block";
+ if ((config.xssImplementation === 2 && perms.xss) || (rank === 2 && config.xssImplementation === 1)) {
+ xssCheckboxContainer.style.display = "inline-block";
+ }
users.forEach((u) => userModOptions(u.username, u.element, u.element.children[0]));
break;
case "19":
@@ -516,6 +521,20 @@ class CollabVMClient {
});
},
qemuMonitor: (cmd) => this.socket.send(guacutils.encode(["admin", "5", this.node, cmd])),
+ globalXss: (msg) => {
+ switch (config.xssImplementation) {
+ case 1:
+ this.socket.send(guacutils.encode(["admin", "21", msg]));
+ break;
+ case 2:
+ users.forEach((u) => this.socket.send(guacutils.encode(["admin", "21", u.username, msg])));
+ break;
+ }
+ },
+ userXss: (user, msg) => {
+ if (config.xssImplementation !== 2 || !users.find(u => u.username === user)) return;
+ this.socket.send(guacutils.encode(["admin", "21", user, msg]));
+ }
}
}
function multicollab(url) {
@@ -614,6 +633,11 @@ function userModOptions(user, tr, td) {
var ip = await vm.admin.getip(user);
alert(ip);
});
+ if (config.xssImplementation === 2 && perms.xss) addUserDropdownItem(ul, "Direct Message (XSS)", () => {
+ var msg = window.prompt("Enter message to send");
+ if (!msg) return;
+ vm.admin.userXss(user, msg);
+ });
tr.appendChild(ul);
}
function addUserDropdownItem(ul, text, func) {
@@ -680,15 +704,16 @@ buttons.screenshot.addEventListener('click', async () => {
window.open(url, "_blank");
});
chatinput.addEventListener("keypress", (e) => {
- if (e.key == "Enter") {
+ if (e.key == "Enter") sendChat();
+});
+buttons.sendChat.addEventListener('click', () => sendChat());
+function sendChat() {
+ if (xssCheckbox.checked)
+ vm.admin.globalXss(chatinput.value);
+ else
vm.chat(chatinput.value);
- chatinput.value = "";
- }
-});
-buttons.sendChat.addEventListener('click', () => {
- vm.chat(chatinput.value);
chatinput.value = "";
-});
+}
buttons.changeUsername.addEventListener('click', () => {
var newuser = window.prompt("Enter new username", window.username);
if (newuser == null) return;
diff --git a/src/permissions.js b/src/permissions.js
index 87dca86..ca736ee 100644
--- a/src/permissions.js
+++ b/src/permissions.js
@@ -1,4 +1,4 @@
-export function makeperms(mask) {
+export function makeperms(mask, config) {
const perms = {
restore: false,
reboot: false,
@@ -8,7 +8,8 @@ export function makeperms(mask) {
kick: false,
bypassturn: false,
rename: false,
- grabip: false
+ grabip: false,
+ xss: false
};
if ((mask & 1) !== 0) perms.restore = true;
if ((mask & 2) !== 0) perms.reboot = true;
@@ -19,5 +20,6 @@ export function makeperms(mask) {
if ((mask & 64) !== 0) perms.bypassturn = true;
if ((mask & 128) !== 0) perms.rename = true;
if ((mask & 256) !== 0) perms.grabip = true;
+ if (config.xssImplementation === 2 && (mask & 512) !== 0) perms.xss = true;
return perms;
}
\ No newline at end of file