From f244ae412f48e1cf490ba152943c25449b9b42bf Mon Sep 17 00:00:00 2001 From: Elijah R Date: Thu, 1 Feb 2024 17:53:44 -0500 Subject: [PATCH] Set up the source tree for the typescript rewrite. Nothing really here just yet, just filler --- .gitignore | 4 +- babel.config.json | 17 - package.json | 19 +- {dist => src/assets}/desktop.png | Bin {dist => src/assets}/favicon.ico | Bin src/captcha.js | 13 - src/common.js | 21 - {dist => src/css}/style.css | 0 {dist => src/html}/index.html | 29 +- src/index.js | 908 ------------------------------ src/keyboard.js | 280 --------- src/permissions.js | 25 - src/protocol.js | 45 -- src/ts/main.ts | 0 src/ts/protocol/CollabVMClient.ts | 3 + tsconfig.json | 109 ++++ webpack.config.js | 31 - 17 files changed, 129 insertions(+), 1375 deletions(-) delete mode 100644 babel.config.json rename {dist => src/assets}/desktop.png (100%) rename {dist => src/assets}/favicon.ico (100%) delete mode 100644 src/captcha.js delete mode 100644 src/common.js rename {dist => src/css}/style.css (100%) rename {dist => src/html}/index.html (84%) delete mode 100644 src/index.js delete mode 100644 src/keyboard.js delete mode 100644 src/permissions.js delete mode 100644 src/protocol.js create mode 100644 src/ts/main.ts create mode 100644 src/ts/protocol/CollabVMClient.ts create mode 100644 tsconfig.json delete mode 100644 webpack.config.js diff --git a/.gitignore b/.gitignore index 793a671..9287d0d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,3 @@ node_modules/ -dist/*.js -dist/*.js.LICENSE.txt +dist/ +.parcel-cache/ \ No newline at end of file diff --git a/babel.config.json b/babel.config.json deleted file mode 100644 index 3f5cbe2..0000000 --- a/babel.config.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "presets": [ - [ - "@babel/preset-env", - { - "targets": { - "edge": "17", - "firefox": "60", - "chrome": "67", - "safari": "11.1" - }, - "useBuiltIns": "usage", - "corejs": "3.6.5" - } - ] - ] -} diff --git a/package.json b/package.json index fcbabfd..9a3462f 100644 --- a/package.json +++ b/package.json @@ -4,21 +4,22 @@ "description": "kill me", "private": true, "scripts": { - "build": "webpack --config webpack.config.js", - "serve": "serve dist/" + "build": "parcel build --dist-dir dist src/html/index.html", + "serve": "parcel src/html/index.html" }, "author": "Elijah R", "license": "GPL-3.0", "dependencies": { "@hcaptcha/types": "^1.0.3", - "nanoevents": "^7.0.1", - "serve": "^14.2.0", - "webpack": "^5.75.0", - "webpack-cli": "^5.0.1" + "@popperjs/core": "^2.11.8", + "bootstrap": "^5.3.2", + "nanoevents": "^7.0.1" + }, + "overrides": { + "@parcel/watcher": "~2.1.0" }, "devDependencies": { - "@babel/core": "^7.20.12", - "@babel/preset-env": "^7.20.2", - "babel-loader": "^9.1.2" + "parcel": "^2.11.0", + "typescript": "^5.3.3" } } diff --git a/dist/desktop.png b/src/assets/desktop.png similarity index 100% rename from dist/desktop.png rename to src/assets/desktop.png diff --git a/dist/favicon.ico b/src/assets/favicon.ico similarity index 100% rename from dist/favicon.ico rename to src/assets/favicon.ico diff --git a/src/captcha.js b/src/captcha.js deleted file mode 100644 index c6c8c92..0000000 --- a/src/captcha.js +++ /dev/null @@ -1,13 +0,0 @@ -export default function doCaptcha(sitekey) { - return new Promise((res, rej) => { - const modal = new bootstrap.Modal(document.getElementById('hcaptchaModal')); - modal.show(); - hcaptcha.render("captcha-box", { - sitekey: sitekey, - callback: (c) => { - modal.hide(); - res(c); - }, - }); - }) -} diff --git a/src/common.js b/src/common.js deleted file mode 100644 index 033f8f8..0000000 --- a/src/common.js +++ /dev/null @@ -1,21 +0,0 @@ -export const config = { - serverAddresses: [ - "wss://computernewb.com/collab-vm/vm0", - "wss://computernewb.com/collab-vm/vm1", - "wss://computernewb.com/collab-vm/vm2", - "wss://computernewb.com/collab-vm/vm3", - "wss://computernewb.com/collab-vm/vm4", - "wss://computernewb.com/collab-vm/vm5", - "wss://computernewb.com/collab-vm/vm6", - "wss://computernewb.com/collab-vm/vm7", - "wss://computernewb.com/collab-vm/vm8", - "wss://computernewb.com/collab-vm/vm9", - "wss://computernewb.com/collab-vm/eventvm", - ], - chatSound: "https://computernewb.com/collab-vm/notify.ogg", - // What XSS implementation the server uses - // 0: No XSS (cvm1.2.11) - // 1: Internal fork style (cvm1.ts, global opcode 21) - // 2: yellows111/collab-vm-server style (per-user opcode 21) - xssImplementation: 1, -} diff --git a/dist/style.css b/src/css/style.css similarity index 100% rename from dist/style.css rename to src/css/style.css diff --git a/dist/index.html b/src/html/index.html similarity index 84% rename from dist/index.html rename to src/html/index.html index c939567..74963dc 100644 --- a/dist/index.html +++ b/src/html/index.html @@ -4,10 +4,10 @@ Control Collaborative Virtual Machines! - - + + - + @@ -109,25 +109,6 @@ - - - @@ -194,7 +175,7 @@ - - + + diff --git a/src/index.js b/src/index.js deleted file mode 100644 index e71a80e..0000000 --- a/src/index.js +++ /dev/null @@ -1,908 +0,0 @@ -import { guacutils } from "./protocol"; -import { config } from "./common"; -import { GetKeysym } from "./keyboard"; -import { createNanoEvents } from "nanoevents"; -import { makeperms } from "./permissions"; -import doCaptcha from "./captcha"; -// None = -1 -// Has turn = 0 -// In queue = -var turn = -1; -var perms = makeperms(0, config); -var rank = 0; -var connected = false; -const vms = []; -const users = []; -const buttons = { - home: window.document.getElementById("homeBtn"), - takeTurn: window.document.getElementById("takeTurnBtn"), - changeUsername: window.document.getElementById("changeUsernameBtn"), - voteReset: window.document.getElementById("voteResetButton"), - screenshot: window.document.getElementById("screenshotButton"), - // Staff - restore: window.document.getElementById("restoreBtn"), - reboot: window.document.getElementById("rebootBtn"), - clearQueue: window.document.getElementById("clearQueueBtn"), - bypassTurn: window.document.getElementById("bypassTurnBtn"), - endTurn: window.document.getElementById("endTurnBtn"), - qemuMonitor: window.document.getElementById("qemuMonitorBtn"), - qemuMonitorSend: window.document.getElementById("qemuMonitorSendBtn"), - sendChat: window.document.getElementById("sendChatBtn"), - ctrlAltDel: window.document.getElementById("ctrlAltDelBtn"), - forceVoteYes: window.document.getElementById("forceVoteYesBtn"), - forceVoteNo: window.document.getElementById("forceVoteNoBtn"), -} -var hasTurn = false; -var vm; -var voteinterval; -var turninterval; -const chatsound = new Audio(config.chatSound); -// Elements -const turnstatus = window.document.getElementById("turnstatus"); -const vmlist = window.document.getElementById("vmlist"); -const vmview = window.document.getElementById("vmview"); -const display = window.document.getElementById("display"); -const displayCtx = display.getContext("2d"); -const chatList = window.document.getElementById("chatList"); -const userlist = window.document.getElementById("userlist"); -const usernameSpan = window.document.getElementById("username"); -const onlineusercount = window.document.getElementById("onlineusercount"); -const chatinput = window.document.getElementById("chat-input"); -const voteresetpanel = document.getElementById("voteResetPanel"); -const voteyesbtn = document.getElementById("voteYesBtn"); -const votenobtn = document.getElementById("voteNoBtn"); -const voteyeslabel = document.getElementById("voteYesLabel"); -const votenolabel = document.getElementById("voteNoLabel"); -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"); -const forceVotePanel = document.getElementById("forceVotePanel"); -// needed to scroll to bottom -const chatListDiv = document.querySelector(".chat-table"); - -let events = new Map(); - -function addListener(element, event, id, callback) { - events.set(id, callback); - element.addEventListener(event, callback, {capture: true}); -} - -function removeListener(element, event, id) { - element.removeEventListener(event, events.get(id), true); - events.delete(id); -} - -class CollabVMClient { - eventemitter = createNanoEvents(); - socket; - node; - #url; - #captcha = false; - captchaToken; - isMainSocket; - shouldReconnect = true; - constructor(url, isMainSocket) { - this.#url = url; - this.isMainSocket = isMainSocket; - } - connect(hcaptchatoken) { - this.captchaToken = hcaptchatoken; - return new Promise((res, rej) => { - try { - this.socket = new WebSocket(this.#url, "guacamole"); - } catch (e) { - rej(e); - } - this.socket.addEventListener('message', (e) => this.#onMessage(e)); - this.socket.addEventListener('open', () => res(true), {once: true}); - this.socket.addEventListener('close', (e) => { if(!e.wasClean) res(false); }, {once: true}); - }) - - } - #onClose() { - cleanup(); - if(this.shouldReconnect) { - setTimeout(async () => { - try { - connected = await this.connect(this.captchaToken); - } catch { - this.#onClose(); - } - this.connectToVM(this.node); - }, 2000); - } - } - disconnect() { - this.socket.send(guacutils.encode(["disconnect"])); - this.socket.close(); - } - getUrl() { - return this.#url; - } - connectToVM(node) { - return new Promise(async (res, rej) => { - this.socket.addEventListener('close', () => this.#onClose()); - this.node = node; - if (this.captchaToken !== null) { - await new Promise((reso, reje) => { - var unbind = this.eventemitter.on('captcha', (result) => { - unbind(); - if (result === true) { - reso(); - return; - } - else { - reje(); - } - }); - this.socket.send(guacutils.encode(["captcha", this.captchaToken])); - }); - } - var savedUsername = window.localStorage.getItem("username"); - if (savedUsername === null) - this.socket.send(guacutils.encode(["rename"])); - else this.socket.send(guacutils.encode(["rename", savedUsername])); - var unbind = this.eventemitter.on('connect', () => { - unbind(); - res(); - }); - var failunbind = this.eventemitter.on('connectfail', () => { - failunbind(); - rej(); - }); - this.socket.send(guacutils.encode(["connect", node])); - var pass = window.localStorage.getItem("password_"+this.#url); - if (pass) - this.admin.login(pass); - }); - } - async #onMessage(event) { - var msgArr = guacutils.decode(event.data); - window.cvmEvents.emit(msgArr[0], msgArr.slice(1)); - switch (msgArr[0]) { - case "nop": - this.socket.send("3.nop;"); - break; - case "connect": - switch (msgArr[1]) { - case "0": - this.eventemitter.emit('connectfail'); - break; - case "1": - this.eventemitter.emit('connect'); - break; - } - break; - case "captcha": - switch (msgArr[1]) { - case "0": - this.#captcha = msgArr[2]; - console.log(this.#captcha); - break; - case "1": - this.eventemitter.emit('captcha', true); - break; - case "2": - this.eventemitter.emit('captcha', false); - } - case "chat": - if (!connected || !this.isMainSocket) return; - for (var i = 1; i < msgArr.length; i += 2) { - chatMessage(msgArr[i], msgArr[i+1]) - } - chatsound.play(); - chatListDiv.scrollTop = chatListDiv.scrollHeight; - break; - case "list": - var list = []; - for (var i = 1; i < msgArr.length; i+=3) { - list.push({ - url: this.#url, - id: msgArr[i], - name: msgArr[i+1], - thumb: msgArr[i+2], - captcha: this.#captcha, - - }); - } - this.eventemitter.emit('list', list); - break; - case "size": - if (!connected || msgArr[1] !== "0") return; - display.width = msgArr[2]; - display.height = msgArr[3]; - break; - case "png": - if (!connected || msgArr[2] !== "0") return; - var img = new Image(display.width, display.height); - img.addEventListener('load', () => { - displayCtx.drawImage(img, msgArr[3], msgArr[4]); - }); - img.src = "data:image/png;base64," + msgArr[5]; - break; - case "rename": - if (msgArr[1] === "0") { - switch (msgArr[2]) { - case "1": - alert("That username is already taken"); - break; - case "2": - alert("Usernames can contain only numbers, letters, spaces, dashes, underscores, and dots, and it must be between 3 and 20 characters."); - break; - case "3": - alert("That username has been blacklisted."); - break; - } - if (!connected || !this.isMainSocket) return; - var u = users.find(u => u.username === window.username); - if (u) { - u.username = msgArr[3]; - u.element.children[0].innerHTML = msgArr[3]; - } - window.username = msgArr[3]; - usernameSpan.innerText = msgArr[3]; - window.localStorage.setItem("username", msgArr[3]); - return; - } - var user = users.find(u => u.username == msgArr[2]); - if (user === undefined) break; - user.username = msgArr[3]; - user.element.children[0].innerHTML = msgArr[3]; - break; - case "adduser": - if (!connected || !this.isMainSocket) return; - for (var i = 2; i < msgArr.length; i += 2) { - this.addUser(msgArr[i], msgArr[i+1]); - } - onlineusercount.innerText = users.length; - break; - case "remuser": - if (!connected || !this.isMainSocket) return; - for (var i = 2; i < msgArr.length; i++) { - var user = users.find(u => u.username == msgArr[i]); - users.splice(users.indexOf(user), 1); - userlist.removeChild(user.element); - } - onlineusercount.innerText = users.length; - break; - - case "turn": - // Reset all turn data - users.forEach((curr) => { - curr.turn = -1; - curr.element.classList = ""; - }); - buttons.takeTurn.innerHTML = " Take Turn"; - turn = -1; - if (!msgArr.includes(username)) - turnstatus.innerText = ""; - display.className = ""; - clearInterval(turninterval); - // Get the number of users queued for a turn - var queuedUsers = Number(msgArr[2]); - if (queuedUsers === 0) return; - var currentTurnUsername = msgArr[3]; - // Get the user who has the turn and highlight them - var currentTurnUser = users.find(u => u.username === currentTurnUsername); - currentTurnUser.element.classList = "table-primary"; - currentTurnUser.turn = 0; - if (currentTurnUsername === window.username) { - turn = 0; - var secs = Math.floor(parseInt(msgArr[1]) / 1000); - var turnUpdate = () => { - secs--; - if (secs === 0) - clearInterval(turninterval); - turnstatus.innerText = `Turn expires in ${secs} seconds.`; - } - turnUpdate(); - turninterval = setInterval(turnUpdate, 1000); - display.className = "focused"; - } - // Highlight all waiting users and set their status - if (queuedUsers > 1) { - for (var i = 1; i < queuedUsers; i++) { - if (window.username === msgArr[i+3]) { - turn = i; - var secs = Math.floor(parseInt(msgArr[msgArr.length-1]) / 1000); - var turnUpdate = () => { - secs--; - if (secs === 0) - clearInterval(turninterval); - turnstatus.innerText = `Waiting for turn in ${secs} seconds.`; - } - turninterval = setInterval(turnUpdate, 1000); - turnUpdate(); - display.className = "waiting"; - }; - var user = users.find(u => u.username === msgArr[i+3]); - user.turn = i; - user.element.classList = "table-warning"; - } - } - if (turn === -1) { - buttons.takeTurn.innerHTML = " Take Turn"; - } else { - buttons.takeTurn.innerHTML = " End Turn"; - } - this.reloadUsers(); - break; - case "vote": - switch (msgArr[1]) { - case "0": - // Vote started - case "1": - // Vote updated - voteresetpanel.style.display = "block"; - voteyeslabel.innerText = msgArr[3]; - votenolabel.innerText = msgArr[4]; - if (voteinterval) - clearInterval(voteinterval); - var timeToEnd = Math.floor(parseInt(msgArr[2]) / 1000); - var updateVote = () => { - timeToEnd--; - if (timeToEnd === 0) - clearInterval(voteinterval); - votetime.innerText = timeToEnd; - } - voteinterval = setInterval(updateVote, 1000); - updateVote(); - break; - case "2": - // Vote ended - voteresetpanel.style.display = "none"; - break; - case "3": - // too soon dumbass - window.alert(`Please wait ${msgArr[2]} seconds before starting another vote.`); - break; - } - break; - case "admin": - switch (msgArr[1]) { - case "0": - // Login - switch (msgArr[2]) { - case "0": - this.eventemitter.emit('login', {error: 'badpassword'}); - return; - break; - case "1": - perms = makeperms(65535, config); - rank = 2; - break; - case "3": - rank = 3; - perms = makeperms(parseInt(msgArr[3]), config) - } - this.eventemitter.emit('login', {perms: perms, rank: rank}); - usernameSpan.classList.remove("text-light"); - switch (rank) { - case 2: - usernameSpan.classList.add("text-danger"); - break; - case 3: - usernameSpan.classList.add("text-success"); - break; - } - // Disabled for now until we figure out the issue of uservm - //window.localStorage.setItem("password_"+this.#url, password); - staffbtns.style.display = "block"; - if (perms.restore) buttons.restore.style.display = "inline-block"; - if (perms.reboot) buttons.reboot.style.display = "inline-block"; - if (perms.bypassturn) { - buttons.bypassTurn.style.display = "inline-block"; - buttons.clearQueue.style.display = "inline-block"; - 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"; - } - if (perms.forcevote) forceVotePanel.style.display = "block"; - users.forEach((u) => userModOptions(u.username, u.element, u.element.children[0])); - break; - case "19": - // Got IP - this.eventemitter.emit('ip', {username: msgArr[2], ip: msgArr[3]}); - break; - case "2": - // QEMU output - qemuMonitorOutput.innerHTML += `> ${msgArr[2]}\n`; - qemuMonitorOutput.scrollTop = qemuMonitorOutput.scrollHeight; - break; - } - break; - } - } - addUser(name, urank) { - var olduser = users.find(u => u.username === name); - if (olduser !== undefined) { - users.splice(users.indexOf(olduser), 1); - userlist.removeChild(olduser.element); - } - var user = { - username: name, - rank: Number(urank), - turn: -1 - }; - users.push(user); - var tr = document.createElement("tr"); - var td = document.createElement("td"); - td.innerHTML = name; - switch (user.rank) { - case 2: - td.style.color = "#FF0000"; - break; - case 3: - td.style.color = "#00FF00"; - break; - } - tr.appendChild(td); - user.element = tr; - if (rank !== 0) userModOptions(user.username, tr, td); - userlist.appendChild(tr); - } - reloadUsers() { - // Sort the user list by turn status - users.sort((a, b) => { - if (a.turn === b.turn) return 0; - if (a.turn === -1) return 1; - if (b.turn === -1) return -1; - if (a.turn < b.turn) return -1; - else return 1; - }); - users.forEach((u) => { - userlist.removeChild(u.element); - userlist.appendChild(u.element); - }); - } - async list() { - return new Promise((res, rej) => { - var unbind = this.eventemitter.on('list', (e) => { - unbind(); - res(e); - }) - this.socket.send("4.list;"); - }); - } - chat(msg) { - this.socket.send(guacutils.encode(["chat", msg])); - } - rename(username) { - this.socket.send(guacutils.encode(["rename", username])); - } - turn() { - if (turn === -1) { - this.socket.send(guacutils.encode(["turn", "1"])) - } else { - this.socket.send(guacutils.encode(["turn", "0"])); - } - } - mouse(x, y, mask) { - this.socket.send(guacutils.encode(["mouse", x, y, mask])); - } - key(keysym, down) { - this.socket.send(guacutils.encode(["key", keysym, down ? "1" : "0"])); - } - mousewheelhandler(e) { - // gutted from guac source code - var delta = e.deltaY || -e.wheelDeltaY || -e.wheelDelta; - if (!delta) return; - if (e.deltaMode === 1) - delta = e.deltaY * 40; - // Convert to pixels if delta was pages - else if (e.deltaMode === 2) - delta = e.deltaY * 640; - // Up - while (delta <= -120) { - this.mousestate.scrollup = true; - this.sendmouse(); - this.mousestate.scrollup = false; - this.sendmouse(); - delta += 120; - } - // Down - while (delta >= 120) { - this.mousestate.scrolldown = true; - this.sendmouse(); - this.mousestate.scrolldown = false; - this.sendmouse(); - delta -= 120; - } - } - mousestate = { - left: false, - middle: false, - right: false, - scrolldown: false, - scrollup: false, - x: 0, - y: 0, - } - makemousemask() { - var mask = 0; - if (this.mousestate.left) mask |= 1; - if (this.mousestate.middle) mask |= 2; - if (this.mousestate.right) mask |= 4; - if (this.mousestate.scrollup) mask |= 8; - if (this.mousestate.scrolldown) mask |= 16; - return mask; - } - mouseevent(e, down) { - if (down !== undefined) {switch (e.button) { - case 0: - this.mousestate.left = down; - break; - case 1: - this.mousestate.middle = down; - break; - case 2: - this.mousestate.right = down; - break; - }} - this.mousestate.x = e.offsetX; - this.mousestate.y = e.offsetY; - this.sendmouse(); - } - sendmouse() { - var mask = this.makemousemask(); - this.mouse(this.mousestate.x, this.mousestate.y, mask); - } - keyevent(e, down) { - e.preventDefault(); - var keysym = GetKeysym(e.keyCode, e.keyIdentifier, e.key, e.location); - if (keysym === undefined) return; - this.key(keysym, down); - } - voteReset(reset) { - this.socket.send(guacutils.encode(["vote", reset ? "1" : "0"])); - } - admin = { - login: (password) => { - return new Promise((res, rej) => { - var unbind = this.eventemitter.on('login', (args) => { - unbind(); - if (args.error) rej(error); - res(args); - }) - this.socket.send(guacutils.encode(["admin", "2", password])); - }); - }, - adminInstruction: (...args) => { // Compatibility - args.unshift("admin"); - this.socket.send(guacutils.encode(args)); - }, - restore: () => this.socket.send(guacutils.encode(["admin", "8", this.node])), - reboot: () => this.socket.send(guacutils.encode(["admin", "10", this.node])), - clearQueue: () => this.socket.send(guacutils.encode(["admin", "17", this.node])), - bypassTurn: () => this.socket.send(guacutils.encode(["admin", "20"])), - endTurn: (user) => this.socket.send(guacutils.encode(["admin", "16", user])), - ban: (user) => this.socket.send(guacutils.encode(["admin", "12", user])), - kick: (user) => this.socket.send(guacutils.encode(["admin", "15", user])), - renameUser: (user, newname) => this.socket.send(guacutils.encode(["admin", "18", user, newname])), - mute: (user, mutestate) => this.socket.send(guacutils.encode(["admin", "14", user, mutestate])), - getip: (user) => { - if (users.find(u => u.username === user) === undefined) return; - return new Promise((res, rej) => { - var unbind = this.eventemitter.on('ip', (args) => { - if (args.username !== user) return; - unbind(); - res(args.ip); - }); - this.socket.send(guacutils.encode(["admin", "19", user])); - }); - }, - 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])); - }, - forceVote: (result) => { - this.socket.send(guacutils.encode(["admin", "13", result ? "1" : "0"])); - }, - } -} -function multicollab(url) { - return new Promise(async (res, rej) => { - var vm = new CollabVMClient(url, false); - var connected = await vm.connect(); - if(!connected) return res(false); - var list = await vm.list(); - vm.disconnect(); - list.forEach((curr) => { - var id = curr.id; - var name = curr.name; - vms.push(curr); - var div = document.createElement("div"); - div.classList = "col-sm-5 col-md-3"; - var card = document.createElement("div"); - card.classList = "card bg-dark text-light"; - card.setAttribute("data-cvm-node", id); - card.addEventListener("click", () => openVM(url, id)); - var img = document.createElement("img"); - img.src = "data:image/png;base64," + curr.thumb; - img.classList = "card-img-top"; - var bdy = document.createElement("div"); - bdy.classList = "card-body"; - var desc = document.createElement("h5"); - desc.innerHTML = name; - bdy.appendChild(desc); - card.appendChild(img); - card.appendChild(bdy); - div.appendChild(card); - curr.element = div; - reloadVMList(); - }); - res(true); - }); -} -function reloadVMList() { - vms.sort(function(a, b) { - return a.id > b.id ? 1 : -1; - }); - vmlist.children[0].innerHTML = ""; - vms.forEach((v) => vmlist.children[0].appendChild(v.element)); -} -function chatMessage(user, msg) { - var tr = document.createElement("tr"); - var td = document.createElement("td"); - if (user == "" || user === undefined) - td.innerHTML = msg; - else { - var u = users.find(u => u.username === user); - var userclass; - if (u) switch (u.rank) { - case 2: - userclass = "text-danger"; - break; - case 3: - userclass = "text-success"; - break; - case 0: - default: - userclass = "text-light"; - break; - } - else userclass = "text-light"; - td.innerHTML = `${user}> ${msg}`; - } - // I really hate this but html5 cockblocks me every other way - Array.prototype.slice.call(td.children).forEach((curr) => { - if (curr.nodeName === "SCRIPT") { - eval(curr.text) - } - }); - tr.appendChild(td); - chatList.appendChild(tr); -} -function userModOptions(user, tr, td) { - tr.classList.add("dropdown"); - td.classList.add("dropdown-toggle"); - td.setAttribute("data-bs-toggle", "dropdown"); - td.setAttribute("role", "button"); - td.setAttribute("aria-expanded", "false"); - var ul = document.createElement("ul"); - ul.classList = "dropdown-menu dropdown-menu-dark table-dark text-light"; - - if (perms.bypassturn) addUserDropdownItem(ul, "End Turn", () => vm.admin.endTurn(user)); - if (perms.ban) addUserDropdownItem(ul, "Ban", () => vm.admin.ban(user)); - if (perms.kick) addUserDropdownItem(ul, "Kick", () => vm.admin.kick(user)); - if (perms.rename) addUserDropdownItem(ul, "Rename", () => { - var newname = window.prompt(`Enter new username for ${user}`); - if (newname == null) return; - vm.admin.renameUser(user, newname) - }); - if (perms.mute) { - addUserDropdownItem(ul, "Temporary Mute", () => vm.admin.mute(user, 0)); - addUserDropdownItem(ul, "Indefinite Mute", () => vm.admin.mute(user, 1)); - addUserDropdownItem(ul, "Unmute", () => vm.admin.mute(user, 2)); - } - if (perms.grabip) addUserDropdownItem(ul, "Get IP", async () => { - 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) { - var li = document.createElement("li"); - var a = document.createElement("a"); - a.href = "#"; - a.classList.add("dropdown-item"); - a.innerHTML = text; - a.addEventListener('click', func); - li.appendChild(a); - ul.appendChild(li); -} -function returnToVMList() { - if(!connected) return; - connected = false; - vm.disconnect(); - vm.shouldReconnect = false; - voteresetpanel.style.display = "none"; - vmview.style.display = "none"; - vmlist.style.display = "block"; -} - -async function openVM(url, node) { - if (connected) return; - connected = true; - var _vm = vms.find(v => v.url === url); - var token = null; - if (_vm.captcha !== false) { - token = await doCaptcha(vm.captcha); - } - window.location.href = "#" + node; - window.VMName = node; - vm = new CollabVMClient(url, true); - await vm.connect(token); - await vm.connectToVM(node); - vmlist.style.display = "none"; - vmview.style.display = "block"; - addListener(display, 'mousemove', 'displayMove', (e) => vm.mouseevent(e, undefined)); - addListener(display, 'mousedown', 'displayDown', (e) => vm.mouseevent(e, true)); - addListener(display, 'mouseup', 'displayUp', (e) => vm.mouseevent(e, false)); - addListener(display, 'wheel', 'displayWheel', (e) => {vm.mousewheelhandler(e);e.preventDefault();return false;}); // BUG: mousewheelhandler seems to be broken! - addListener(display, 'contextmenu', 'displayContextMenu', (e) => e.preventDefault()); - addListener(display, 'click', 'displayClick', () => { if (turn === -1) vm.turn(); }); - addListener(display, 'keydown', 'displayKeyDown', (e) => vm.keyevent(e, true)); - addListener(display, 'keyup', 'displayKeyUp', (e) => vm.keyevent(e, false)); -} -function screenshotVM() { - return new Promise((res, rej) => { - display.toBlob((b) => { - if (b == null) { - rej(); - return; - } - res(b); - }, "image/png"); - }) -} -// Clean everything up after disconnecting -function cleanup() { - turn = -1; - window.username = null; - rank = 0; - hasTurn = false; - if (turninterval) clearInterval(turninterval); - if (voteinterval) - clearInterval(voteinterval); - users.splice(0); - userlist.innerHTML = ""; - Array.prototype.slice.call(staffbtns.children).forEach((curr) => curr.style.display = "none"); - staffbtns.style.display = "none"; - usernameSpan.classList = "input-group-text bg-dark text-light"; - display.height = 0; - display.width = 0; - removeListener(display, 'mousemove', 'displayMove'); - removeListener(display, 'mousedown', 'displayDown'); - removeListener(display, 'mouseup', 'displayUp'); - removeListener(display, 'wheel', 'displayWheel'); - removeListener(display, 'contextmenu', 'displayContextMenu'); - removeListener(display, 'click', 'displayClick'); - removeListener(display, 'keydown', 'displayKeyDown'); - removeListener(display, 'keyup', 'displayKeyUp'); -} -buttons.home.addEventListener('click', async () => returnToVMList()); -buttons.screenshot.addEventListener('click', async () => { - var blob = await screenshotVM(); - var url = URL.createObjectURL(blob); - window.open(url, "_blank"); -}); -chatinput.addEventListener("keypress", (e) => { - 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.changeUsername.addEventListener('click', () => { - var newuser = window.prompt("Enter new username", window.username); - if (newuser == null) return; - vm.rename(newuser); -}); -buttons.takeTurn.addEventListener('click', () => vm.turn()); -buttons.voteReset.addEventListener('click', () => vm.voteReset(true)); -buttons.ctrlAltDel.addEventListener('click', () => { - // Ctrl - vm.key(0xffe3, true); - // Alt - vm.key(0xffe9, true); - // Del - vm.key(0xffff, true); - // Ctrl - vm.key(0xffe3, false); - // Alt - vm.key(0xffe9, false); - // Del - vm.key(0xffff, false); -}); -voteyesbtn.addEventListener('click', () => vm.voteReset(true)); -votenobtn.addEventListener('click', () => vm.voteReset(false)); -// Staff buttons -buttons.restore.addEventListener('click', () => {if (window.confirm("Do you really want to restore the VM?")) vm.admin.restore()}); -buttons.reboot.addEventListener('click', () => vm.admin.reboot()); -buttons.clearQueue.addEventListener('click', () => vm.admin.clearQueue()); -buttons.bypassTurn.addEventListener('click', () => vm.admin.bypassTurn()); -buttons.endTurn.addEventListener('click', () => vm.admin.endTurn(users[0])); -buttons.forceVoteYes.addEventListener('click', () => vm.admin.forceVote(true)); -buttons.forceVoteNo.addEventListener('click', () => vm.admin.forceVote(false)); -// QEMU Monitor Shit -function sendQEMUCommand() { - if (!qemuMonitorInput.value) return; - vm.admin.qemuMonitor(qemuMonitorInput.value); - qemuMonitorInput.value = ""; -} -qemuMonitorInput.addEventListener('keypress', (e) => { - if (e.key === "Enter") sendQEMUCommand(); -}); -buttons.qemuMonitorSend.addEventListener('click', () => sendQEMUCommand()); - -// Login -var usernameClick = false; -usernameSpan.addEventListener('click', () => { - if (!usernameClick) { - usernameClick = true; - setInterval(() => {usernameClick = false;}, 1000); - return; - } - var pass = window.prompt("🔑"); - if (!pass) return; - vm.admin.login(pass); -}); - -// Load all vms -(async () => { -var p = []; -config.serverAddresses.forEach(v => p.push(multicollab(v))); -await Promise.all(p); -var vm = vms.find(v => v.id === window.location.hash.substring(1)); -if (vm) - openVM(vm.url, vm.id); -})(); -// Export some stuff -window.screenshotVM = screenshotVM; -window.multicollab = multicollab; -window.getPerms = () => perms; -window.getRank = () => rank; -window.GetAdmin = () => vm.admin; -window.cvmEvents = createNanoEvents(); -window.VMName = null; - -// Welcome modal -var noWelcomeModal = window.localStorage.getItem("no-welcome-modal"); -if (noWelcomeModal !== "1") { - var welcomeModalDismissBtn = document.getElementById("welcomeModalDismiss"); - var welcomeModal = new bootstrap.Modal(document.getElementById("welcomeModal")); - welcomeModalDismissBtn.addEventListener("click", () => { - window.localStorage.setItem("no-welcome-modal", 1); - }); - welcomeModalDismissBtn.disabled = true; - welcomeModal.show(); - setTimeout(() => { - welcomeModalDismissBtn.disabled = false; - }, 5000); -} diff --git a/src/keyboard.js b/src/keyboard.js deleted file mode 100644 index b54a001..0000000 --- a/src/keyboard.js +++ /dev/null @@ -1,280 +0,0 @@ -// Pulled a bunch of functions out of the guac source code to get a keysym -// and then a wrapper -// shitty but it works so /shrug -export function GetKeysym(keyCode, keyIdentifier, key, location) { - var keysym = keysym_from_key_identifier(key, location) - || keysym_from_keycode(keyCode, location); - - if (!keysym && key_identifier_sane(keyCode, keyIdentifier)) - keysym = keysym_from_key_identifier(keyIdentifier, location); - - return keysym; -} - - -function keysym_from_key_identifier(identifier, location) { - - if (!identifier) - return null; - - var typedCharacter; - - // If identifier is U+xxxx, decode Unicode character - var unicodePrefixLocation = identifier.indexOf("U+"); - if (unicodePrefixLocation >= 0) { - var hex = identifier.substring(unicodePrefixLocation+2); - typedCharacter = String.fromCharCode(parseInt(hex, 16)); - } - - // If single character, use that as typed character - else if (identifier.length === 1) - typedCharacter = identifier; - - // Otherwise, look up corresponding keysym - else - return get_keysym(keyidentifier_keysym[identifier], location); - - // Get codepoint - var codepoint = typedCharacter.charCodeAt(0); - return keysym_from_charcode(codepoint); - -} - -function get_keysym(keysyms, location) { - - if (!keysyms) - return null; - - return keysyms[location] || keysyms[0]; -} - -function keysym_from_charcode(codepoint) { - - // Keysyms for control characters - if (isControlCharacter(codepoint)) return 0xFF00 | codepoint; - - // Keysyms for ASCII chars - if (codepoint >= 0x0000 && codepoint <= 0x00FF) - return codepoint; - - // Keysyms for Unicode - if (codepoint >= 0x0100 && codepoint <= 0x10FFFF) - return 0x01000000 | codepoint; - - return null; -} - - -function isControlCharacter(codepoint) { - return codepoint <= 0x1F || (codepoint >= 0x7F && codepoint <= 0x9F); -} - -function keysym_from_keycode(keyCode, location) { - return get_keysym(keycodeKeysyms[keyCode], location); -} - -function key_identifier_sane(keyCode, keyIdentifier) { - - // Missing identifier is not sane - if (!keyIdentifier) - return false; - - // Assume non-Unicode keyIdentifier values are sane - var unicodePrefixLocation = keyIdentifier.indexOf("U+"); - if (unicodePrefixLocation === -1) - return true; - - // If the Unicode codepoint isn't identical to the keyCode, - // then the identifier is likely correct - var codepoint = parseInt(keyIdentifier.substring(unicodePrefixLocation+2), 16); - if (keyCode !== codepoint) - return true; - - // The keyCodes for A-Z and 0-9 are actually identical to their - // Unicode codepoints - if ((keyCode >= 65 && keyCode <= 90) || (keyCode >= 48 && keyCode <= 57)) - return true; - - // The keyIdentifier does NOT appear sane - return false; - -} - -var keycodeKeysyms = { - 8: [0xFF08], // backspace - 9: [0xFF09], // tab - 12: [0xFF0B, 0xFF0B, 0xFF0B, 0xFFB5], // clear / KP 5 - 13: [0xFF0D], // enter - 16: [0xFFE1, 0xFFE1, 0xFFE2], // shift - 17: [0xFFE3, 0xFFE3, 0xFFE4], // ctrl - 18: [0xFFE9, 0xFFE9, 0xFE03], // alt - 19: [0xFF13], // pause/break - 20: [0xFFE5], // caps lock - 27: [0xFF1B], // escape - 32: [0x0020], // space - 33: [0xFF55, 0xFF55, 0xFF55, 0xFFB9], // page up / KP 9 - 34: [0xFF56, 0xFF56, 0xFF56, 0xFFB3], // page down / KP 3 - 35: [0xFF57, 0xFF57, 0xFF57, 0xFFB1], // end / KP 1 - 36: [0xFF50, 0xFF50, 0xFF50, 0xFFB7], // home / KP 7 - 37: [0xFF51, 0xFF51, 0xFF51, 0xFFB4], // left arrow / KP 4 - 38: [0xFF52, 0xFF52, 0xFF52, 0xFFB8], // up arrow / KP 8 - 39: [0xFF53, 0xFF53, 0xFF53, 0xFFB6], // right arrow / KP 6 - 40: [0xFF54, 0xFF54, 0xFF54, 0xFFB2], // down arrow / KP 2 - 45: [0xFF63, 0xFF63, 0xFF63, 0xFFB0], // insert / KP 0 - 46: [0xFFFF, 0xFFFF, 0xFFFF, 0xFFAE], // delete / KP decimal - 91: [0xFFEB], // left window key (hyper_l) - 92: [0xFF67], // right window key (menu key?) - 93: null, // select key - 96: [0xFFB0], // KP 0 - 97: [0xFFB1], // KP 1 - 98: [0xFFB2], // KP 2 - 99: [0xFFB3], // KP 3 - 100: [0xFFB4], // KP 4 - 101: [0xFFB5], // KP 5 - 102: [0xFFB6], // KP 6 - 103: [0xFFB7], // KP 7 - 104: [0xFFB8], // KP 8 - 105: [0xFFB9], // KP 9 - 106: [0xFFAA], // KP multiply - 107: [0xFFAB], // KP add - 109: [0xFFAD], // KP subtract - 110: [0xFFAE], // KP decimal - 111: [0xFFAF], // KP divide - 112: [0xFFBE], // f1 - 113: [0xFFBF], // f2 - 114: [0xFFC0], // f3 - 115: [0xFFC1], // f4 - 116: [0xFFC2], // f5 - 117: [0xFFC3], // f6 - 118: [0xFFC4], // f7 - 119: [0xFFC5], // f8 - 120: [0xFFC6], // f9 - 121: [0xFFC7], // f10 - 122: [0xFFC8], // f11 - 123: [0xFFC9], // f12 - 144: [0xFF7F], // num lock - 145: [0xFF14], // scroll lock - 225: [0xFE03] // altgraph (iso_level3_shift) -}; - -var keyidentifier_keysym = { - "Again": [0xFF66], - "AllCandidates": [0xFF3D], - "Alphanumeric": [0xFF30], - "Alt": [0xFFE9, 0xFFE9, 0xFE03], - "Attn": [0xFD0E], - "AltGraph": [0xFE03], - "ArrowDown": [0xFF54], - "ArrowLeft": [0xFF51], - "ArrowRight": [0xFF53], - "ArrowUp": [0xFF52], - "Backspace": [0xFF08], - "CapsLock": [0xFFE5], - "Cancel": [0xFF69], - "Clear": [0xFF0B], - "Convert": [0xFF21], - "Copy": [0xFD15], - "Crsel": [0xFD1C], - "CrSel": [0xFD1C], - "CodeInput": [0xFF37], - "Compose": [0xFF20], - "Control": [0xFFE3, 0xFFE3, 0xFFE4], - "ContextMenu": [0xFF67], - "DeadGrave": [0xFE50], - "DeadAcute": [0xFE51], - "DeadCircumflex": [0xFE52], - "DeadTilde": [0xFE53], - "DeadMacron": [0xFE54], - "DeadBreve": [0xFE55], - "DeadAboveDot": [0xFE56], - "DeadUmlaut": [0xFE57], - "DeadAboveRing": [0xFE58], - "DeadDoubleacute": [0xFE59], - "DeadCaron": [0xFE5A], - "DeadCedilla": [0xFE5B], - "DeadOgonek": [0xFE5C], - "DeadIota": [0xFE5D], - "DeadVoicedSound": [0xFE5E], - "DeadSemivoicedSound": [0xFE5F], - "Delete": [0xFFFF], - "Down": [0xFF54], - "End": [0xFF57], - "Enter": [0xFF0D], - "EraseEof": [0xFD06], - "Escape": [0xFF1B], - "Execute": [0xFF62], - "Exsel": [0xFD1D], - "ExSel": [0xFD1D], - "F1": [0xFFBE], - "F2": [0xFFBF], - "F3": [0xFFC0], - "F4": [0xFFC1], - "F5": [0xFFC2], - "F6": [0xFFC3], - "F7": [0xFFC4], - "F8": [0xFFC5], - "F9": [0xFFC6], - "F10": [0xFFC7], - "F11": [0xFFC8], - "F12": [0xFFC9], - "F13": [0xFFCA], - "F14": [0xFFCB], - "F15": [0xFFCC], - "F16": [0xFFCD], - "F17": [0xFFCE], - "F18": [0xFFCF], - "F19": [0xFFD0], - "F20": [0xFFD1], - "F21": [0xFFD2], - "F22": [0xFFD3], - "F23": [0xFFD4], - "F24": [0xFFD5], - "Find": [0xFF68], - "GroupFirst": [0xFE0C], - "GroupLast": [0xFE0E], - "GroupNext": [0xFE08], - "GroupPrevious": [0xFE0A], - "FullWidth": null, - "HalfWidth": null, - "HangulMode": [0xFF31], - "Hankaku": [0xFF29], - "HanjaMode": [0xFF34], - "Help": [0xFF6A], - "Hiragana": [0xFF25], - "HiraganaKatakana": [0xFF27], - "Home": [0xFF50], - "Hyper": [0xFFED, 0xFFED, 0xFFEE], - "Insert": [0xFF63], - "JapaneseHiragana": [0xFF25], - "JapaneseKatakana": [0xFF26], - "JapaneseRomaji": [0xFF24], - "JunjaMode": [0xFF38], - "KanaMode": [0xFF2D], - "KanjiMode": [0xFF21], - "Katakana": [0xFF26], - "Left": [0xFF51], - "Meta": [0xFFE7, 0xFFE7, 0xFFE8], - "ModeChange": [0xFF7E], - "NumLock": [0xFF7F], - "PageDown": [0xFF56], - "PageUp": [0xFF55], - "Pause": [0xFF13], - "Play": [0xFD16], - "PreviousCandidate": [0xFF3E], - "PrintScreen": [0xFD1D], - "Redo": [0xFF66], - "Right": [0xFF53], - "RomanCharacters": null, - "Scroll": [0xFF14], - "Select": [0xFF60], - "Separator": [0xFFAC], - "Shift": [0xFFE1, 0xFFE1, 0xFFE2], - "SingleCandidate": [0xFF3C], - "Super": [0xFFEB, 0xFFEB, 0xFFEC], - "Tab": [0xFF09], - "Up": [0xFF52], - "Undo": [0xFF65], - "Win": [0xFFEB], - "Zenkaku": [0xFF28], - "ZenkakuHankaku": [0xFF2A] -}; \ No newline at end of file diff --git a/src/permissions.js b/src/permissions.js deleted file mode 100644 index ca736ee..0000000 --- a/src/permissions.js +++ /dev/null @@ -1,25 +0,0 @@ -export function makeperms(mask, config) { - const perms = { - restore: false, - reboot: false, - ban: false, - forcevote: false, - mute: false, - kick: false, - bypassturn: false, - rename: false, - grabip: false, - xss: false - }; - if ((mask & 1) !== 0) perms.restore = true; - if ((mask & 2) !== 0) perms.reboot = true; - if ((mask & 4) !== 0) perms.ban = true; - if ((mask & 8) !== 0) perms.forcevote = true; - if ((mask & 16) !== 0) perms.mute = true; - if ((mask & 32) !== 0) perms.kick = true; - 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 diff --git a/src/protocol.js b/src/protocol.js deleted file mode 100644 index 430a1a2..0000000 --- a/src/protocol.js +++ /dev/null @@ -1,45 +0,0 @@ -export const guacutils = { - decode: (string) => { - let pos = -1; - let sections = []; - - for(;;) { - let len = string.indexOf('.', pos + 1); - - if(len === -1) - break; - - pos = parseInt(string.slice(pos + 1, len)) + len + 1; - - // don't allow funky protocol length - if(pos > string.length) - return []; - - sections.push(string.slice(len + 1, pos)); - - - const sep = string.slice(pos, pos + 1); - - if(sep === ',') - continue; - else if(sep === ';') - break; - else - // Invalid data. - return []; - } - - return sections; - }, - - encode: (string) => { - let command = ''; - - for(var i = 0; i < string.length; i++) { - let current = string[i]; - command += current.toString().length + '.' + current; - command += ( i < string.length - 1 ? ',' : ';'); - } - return command; - } -}; \ No newline at end of file diff --git a/src/ts/main.ts b/src/ts/main.ts new file mode 100644 index 0000000..e69de29 diff --git a/src/ts/protocol/CollabVMClient.ts b/src/ts/protocol/CollabVMClient.ts new file mode 100644 index 0000000..e84bd29 --- /dev/null +++ b/src/ts/protocol/CollabVMClient.ts @@ -0,0 +1,3 @@ +export default class CollabVMClient { + +} \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..c40a31e --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,109 @@ +{ + "compilerOptions": { + /* Visit https://aka.ms/tsconfig to read more about this file */ + + /* Projects */ + // "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */ + // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */ + // "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */ + // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */ + // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */ + // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ + + /* Language and Environment */ + "target": "es2022", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ + // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ + // "jsx": "preserve", /* Specify what JSX code is generated. */ + // "experimentalDecorators": true, /* Enable experimental support for legacy experimental decorators. */ + // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */ + // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */ + // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */ + // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */ + // "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */ + // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */ + // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */ + // "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */ + + /* Modules */ + "module": "ES2022", /* Specify what module code is generated. */ + // "rootDir": "./", /* Specify the root folder within your source files. */ + "moduleResolution": "node", /* Specify how TypeScript looks up a file from a given module specifier. */ + // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ + // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */ + // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ + // "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */ + // "types": [], /* Specify type package names to be included without being referenced in a source file. */ + // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ + // "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */ + // "allowImportingTsExtensions": true, /* Allow imports to include TypeScript file extensions. Requires '--moduleResolution bundler' and either '--noEmit' or '--emitDeclarationOnly' to be set. */ + // "resolvePackageJsonExports": true, /* Use the package.json 'exports' field when resolving package imports. */ + // "resolvePackageJsonImports": true, /* Use the package.json 'imports' field when resolving imports. */ + // "customConditions": [], /* Conditions to set in addition to the resolver-specific defaults when resolving imports. */ + // "resolveJsonModule": true, /* Enable importing .json files. */ + // "allowArbitraryExtensions": true, /* Enable importing files with any extension, provided a declaration file is present. */ + // "noResolve": true, /* Disallow 'import's, 'require's or ''s from expanding the number of files TypeScript should add to a project. */ + + /* JavaScript Support */ + // "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */ + // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */ + // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */ + + /* Emit */ + // "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ + // "declarationMap": true, /* Create sourcemaps for d.ts files. */ + // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ + // "sourceMap": true, /* Create source map files for emitted JavaScript files. */ + // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */ + // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */ + // "outDir": "./", /* Specify an output folder for all emitted files. */ + // "removeComments": true, /* Disable emitting comments. */ + // "noEmit": true, /* Disable emitting files from a compilation. */ + // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */ + // "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types. */ + // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */ + // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */ + // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ + // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */ + // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */ + // "newLine": "crlf", /* Set the newline character for emitting files. */ + // "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */ + // "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */ + // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */ + // "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */ + // "declarationDir": "./", /* Specify the output directory for generated declaration files. */ + // "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */ + + /* Interop Constraints */ + // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ + // "verbatimModuleSyntax": true, /* Do not transform or elide any imports or exports not marked as type-only, ensuring they are written in the output file's format based on the 'module' setting. */ + // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ + "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */ + // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ + "forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */ + + /* Type Checking */ + "strict": true, /* Enable all strict type-checking options. */ + // "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */ + // "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */ + // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */ + // "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */ + // "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */ + // "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */ + // "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */ + // "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */ + // "noUnusedLocals": true, /* Enable error reporting when local variables aren't read. */ + // "noUnusedParameters": true, /* Raise an error when a function parameter isn't read. */ + // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */ + // "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */ + // "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */ + // "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */ + // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */ + // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */ + // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */ + // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */ + + /* Completeness */ + // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ + "skipLibCheck": true /* Skip type checking all .d.ts files. */ + } +} diff --git a/webpack.config.js b/webpack.config.js deleted file mode 100644 index cb74887..0000000 --- a/webpack.config.js +++ /dev/null @@ -1,31 +0,0 @@ -const path = require("path"); - -module.exports = { - entry: "./src/index.js", - - output: { - filename: 'main.js', - path: path.resolve(__dirname, 'dist'), - }, - - module: { - rules: [ - { - test: /\.m?js$/, - exclude: /node_modules/, - use: { - loader: 'babel-loader', - options: { - presets: [ - [ - '@babel/preset-env' - ] - ] - } - } - } - ] - }, - - mode: "production" -}