From c54d1956d3b98cdfeb7d6fa81acdcf2d5836e5e9 Mon Sep 17 00:00:00 2001 From: Bozhidar Date: Mon, 22 Apr 2024 14:15:52 +0300 Subject: [PATCH] update --- .gitignore | 2 - compilators/debian/web-terminal/.eslintrc.cjs | 9 ++ compilators/debian/web-terminal/control | 9 ++ compilators/debian/web-terminal/copyright | 29 +++++ compilators/debian/web-terminal/package.json | 17 +++ .../web-terminal/phyre-web-terminal.service | 16 +++ compilators/debian/web-terminal/postinst | 30 +++++ compilators/debian/web-terminal/postrm | 2 + compilators/debian/web-terminal/server.js | 121 ++++++++++++++++++ .../web-terminal/web-terminal-compile.sh | 50 ++++++++ 10 files changed, 283 insertions(+), 2 deletions(-) create mode 100644 compilators/debian/web-terminal/.eslintrc.cjs create mode 100644 compilators/debian/web-terminal/control create mode 100644 compilators/debian/web-terminal/copyright create mode 100644 compilators/debian/web-terminal/package.json create mode 100644 compilators/debian/web-terminal/phyre-web-terminal.service create mode 100644 compilators/debian/web-terminal/postinst create mode 100644 compilators/debian/web-terminal/postrm create mode 100644 compilators/debian/web-terminal/server.js create mode 100644 compilators/debian/web-terminal/web-terminal-compile.sh diff --git a/.gitignore b/.gitignore index ae6857a..3b04e72 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,2 @@ web/storage/installed /docker/e2e-tests/node_modules/ -compilators/ -web/thirdparty/ diff --git a/compilators/debian/web-terminal/.eslintrc.cjs b/compilators/debian/web-terminal/.eslintrc.cjs new file mode 100644 index 0000000..1f53577 --- /dev/null +++ b/compilators/debian/web-terminal/.eslintrc.cjs @@ -0,0 +1,9 @@ +module.exports = { + env: { + browser: false, + node: true, + }, + rules: { + 'no-console': 'off', + }, +}; diff --git a/compilators/debian/web-terminal/control b/compilators/debian/web-terminal/control new file mode 100644 index 0000000..96b4815 --- /dev/null +++ b/compilators/debian/web-terminal/control @@ -0,0 +1,9 @@ +Source: phyre-web-terminal +Package: phyre-web-terminal +Priority: optional +Version: 1.0.0 +Section: admin +Maintainer: PhyrePanel +Homepage: https://www.phyrepanel.com +Architecture: amd64 +Description: Phyre Web Terminal diff --git a/compilators/debian/web-terminal/copyright b/compilators/debian/web-terminal/copyright new file mode 100644 index 0000000..3d5d553 --- /dev/null +++ b/compilators/debian/web-terminal/copyright @@ -0,0 +1,29 @@ +Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ +Upstream-Name: phyre +Source: https://www.phyrepanel.com + +Files: * +Copyright: 2018-2023, Phyre Control Panel +License: GPL-3.0+ + +License: GPL-3.0+ + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + . + This package is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + . + You should have received a copy of the GNU General Public License + along with this program. If not, see . + . + On Debian systems, the complete text of the GNU General + Public License version 3 can be found in /usr/share/common-licenses/GPL-3. + +# Please also look if there are files or directories which have a +# different copyright/license attached and list them here. +# Please avoid to pick license terms that are more restrictive than the +# packaged work, as it may make Debian's contributions unacceptable upstream. diff --git a/compilators/debian/web-terminal/package.json b/compilators/debian/web-terminal/package.json new file mode 100644 index 0000000..d0e9a9c --- /dev/null +++ b/compilators/debian/web-terminal/package.json @@ -0,0 +1,17 @@ +{ + "name": "cloudvisionapps/phyre-web-terminal-ws", + "private": true, + "version": "1.0.0", + "type": "module", + "scripts": { + "start": "node server.js" + }, + "dependencies": { + "node-pty": "^1.0.0", + "ws": "^8.16.0" + }, + "devDependencies": { + "@types/ws": "^8.5.10", + "@types/node": "^20.12.5" + } +} diff --git a/compilators/debian/web-terminal/phyre-web-terminal.service b/compilators/debian/web-terminal/phyre-web-terminal.service new file mode 100644 index 0000000..ca536da --- /dev/null +++ b/compilators/debian/web-terminal/phyre-web-terminal.service @@ -0,0 +1,16 @@ +[Unit] +Description=Phyre Web Terminal +Documentation=https://phyrepanel.com/docs/ +After=network.target + +[Service] +User=root +Group=phyre-users +Environment=NODE_ENV=production +Environment=PHYRE=/usr/local/phyre +ExecStart=/usr/local/phyre/web-terminal/server.js +ExecStop=/bin/kill -s TERM $MAINPID +Restart=on-failure + +[Install] +WantedBy=multi-user.target diff --git a/compilators/debian/web-terminal/postinst b/compilators/debian/web-terminal/postinst new file mode 100644 index 0000000..4dc7687 --- /dev/null +++ b/compilators/debian/web-terminal/postinst @@ -0,0 +1,30 @@ +#!/bin/bash + +set -e + +if [ "$1" != "configure" ]; then + exit 0 +fi + +# Run triggers below only on updates +if [ ! -e "/usr/local/phyre/data/users/admin" ]; then + exit +fi + +############################################################### +# Initialize functions/variables # +############################################################### + +if [ -z "$PHYRE" ]; then + export PHYRE='/usr/local/phyre' + PATH=$PATH:/usr/local/phyre/bin + export PATH +fi + +# Restart hestia-web-terminal service if enabled +if [ -f "/etc/systemd/system/phyre-web-terminal.service" ]; then + systemctl daemon-reload > /dev/null 2>&1 + if systemctl is-enabled phyre-web-terminal > /dev/null 2>&1; then + systemctl restart phyre-web-terminal + fi +fi diff --git a/compilators/debian/web-terminal/postrm b/compilators/debian/web-terminal/postrm new file mode 100644 index 0000000..13f4793 --- /dev/null +++ b/compilators/debian/web-terminal/postrm @@ -0,0 +1,2 @@ +#!/bin/sh + diff --git a/compilators/debian/web-terminal/server.js b/compilators/debian/web-terminal/server.js new file mode 100644 index 0000000..a185340 --- /dev/null +++ b/compilators/debian/web-terminal/server.js @@ -0,0 +1,121 @@ +#!/usr/bin/env node + +import { execSync } from 'node:child_process'; +import { readFileSync } from 'node:fs'; +import { spawn } from 'node-pty'; +import { WebSocketServer } from 'ws'; + +const sessionName = 'PHYRESID'; +const hostname = execSync('hostname', { silent: true }).toString().trim(); +// const systemIPs = JSON.parse( +// execSync(`${process.env.PHYRE}/bin/v-list-sys-ips json`, { silent: true }).toString(), +// ); +const systemIPs = []; +// const { config } = JSON.parse( +// execSync(`${process.env.PHYRE}/bin/v-list-sys-config json`, { silent: true }).toString(), +// ); +const config = { + WEB_TERMINAL_PORT: 3000, + BACKEND_PORT: 8083, +}; + +const wss = new WebSocketServer({ + port: parseInt(config.WEB_TERMINAL_PORT, 10), + verifyClient: async (info, cb) => { + if (!info.req.headers.cookie.includes(sessionName)) { + cb(false, 401, 'Unauthorized'); + return; + } + + const origin = info.origin || info.req.headers.origin; + let matches = origin === `https://${hostname}:${config.BACKEND_PORT}`; + + if (!matches) { + for (const ip of Object.keys(systemIPs)) { + if (origin === `https://${ip}:${config.BACKEND_PORT}`) { + matches = true; + break; + } + } + } + + if (matches) { + cb(true); + return; + } + cb(false, 403, 'Forbidden'); + }, +}); + +wss.on('connection', (ws, req) => { + wss.clients.add(ws); + + const remoteIP = req.headers['x-real-ip'] || req.socket.remoteAddress; + + // Check if session is valid + const sessionID = req.headers.cookie.split(`${sessionName}=`)[1].split(';')[0]; + console.log(`New connection from ${remoteIP} (${sessionID})`); + + const file = readFileSync(`${process.env.HESTIA}/data/sessions/sess_${sessionID}`); + if (!file) { + console.error(`Invalid session ID ${sessionID}, refusing connection`); + ws.close(1000, 'Your session has expired.'); + return; + } + const session = file.toString(); + + // Get username + const login = session.split('user|s:')[1].split('"')[1]; + const impersonating = session.split('look|s:')[1].split('"')[1]; + const username = impersonating.length > 0 ? impersonating : login; + + // Get user info + const passwd = readFileSync('/etc/passwd').toString(); + const userline = passwd.split('\n').find((line) => line.startsWith(`${username}:`)); + if (!userline) { + console.error(`User ${username} not found, refusing connection`); + ws.close(1000, 'You are not allowed to access this server.'); + return; + } + const [, , uid, gid, , homedir, shell] = userline.split(':'); + + if (shell.endsWith('nologin')) { + console.error(`User ${username} has no shell, refusing connection`); + ws.close(1000, 'You have no shell access.'); + return; + } + + // Spawn shell as logged in user + const pty = spawn(shell, [], { + name: 'xterm-color', + uid: parseInt(uid, 10), + gid: parseInt(gid, 10), + cwd: homedir, + env: { + SHELL: shell, + TERM: 'xterm-color', + USER: username, + HOME: homedir, + PWD: homedir, + PHYRE: process.env.PHYRE, + }, + }); + console.log(`New pty (${pty.pid}): ${shell} as ${username} (${uid}:${gid}) in ${homedir}`); + + // Send/receive data from websocket/pty + pty.on('data', (data) => ws.send(data)); + ws.on('message', (data) => pty.write(data)); + + // Ensure pty is killed when websocket is closed and vice versa + pty.on('exit', () => { + console.log(`Ended pty (${pty.pid})`); + if (ws.OPEN) { + ws.close(); + } + }); + ws.on('close', () => { + console.log(`Ended connection from ${remoteIP} (${sessionID})`); + pty.kill(); + wss.clients.delete(ws); + }); +}); diff --git a/compilators/debian/web-terminal/web-terminal-compile.sh b/compilators/debian/web-terminal/web-terminal-compile.sh new file mode 100644 index 0000000..e7bc617 --- /dev/null +++ b/compilators/debian/web-terminal/web-terminal-compile.sh @@ -0,0 +1,50 @@ +#!/bin/bash + +MAIN_DIR=$(pwd) + +# Install dependencies +sudo apt-get update -y +sudo apt-get install -y build-essential dpkg-dev debhelper autotools-dev libgeoip-dev libssl-dev libpcre3-dev zlib1g-dev + +sudo apt-get install -y npm nodejs + +# Package main dir is the path of the clean debian package +# In PACKAGE_MAIN_DIR must exist only the directories that will be copied to the final debian package + +sudo mkdir $MAIN_DIR/phyre-web-terminal-0.0.1 +PACKAGE_MAIN_DIR=$MAIN_DIR/phyre-web-terminal-0.0.1 + +# Create debian package directories +sudo mkdir -p $PACKAGE_MAIN_DIR/DEBIAN +sudo mkdir -p $PACKAGE_MAIN_DIR/usr/local/phyre/web-terminal + +# Copy web-terminal files +sudo cp $MAIN_DIR/.eslintrc.cjs $PACKAGE_MAIN_DIR/usr/local/phyre/web-terminal +sudo cp $MAIN_DIR/server.js $PACKAGE_MAIN_DIR/usr/local/phyre/web-terminal +sudo cp $MAIN_DIR/package.json $PACKAGE_MAIN_DIR/usr/local/phyre/web-terminal + +cd $PACKAGE_MAIN_DIR/usr/local/phyre/web-terminal +sudo chmod +x $PACKAGE_MAIN_DIR/usr/local/phyre/web-terminal/server.js + +# Compile web-terminal +cd $PACKAGE_MAIN_DIR/usr/local/phyre/web-terminal +sudo npm install + +# Copy debian package META file +sudo cp $MAIN_DIR/control $PACKAGE_MAIN_DIR/DEBIAN +sudo cp $MAIN_DIR/postinst $PACKAGE_MAIN_DIR/DEBIAN +sudo cp $MAIN_DIR/postrm $PACKAGE_MAIN_DIR/DEBIAN + +# Set debian package post files permissions +sudo chmod +x $PACKAGE_MAIN_DIR/DEBIAN/postinst +sudo chmod +x $PACKAGE_MAIN_DIR/DEBIAN/postrm + + +# Make debian package +sudo dpkg-deb --build $PACKAGE_MAIN_DIR +sudo dpkg --info $MAIN_DIR/phyre-web-terminal-0.0.1.deb +sudo dpkg --contents $MAIN_DIR/phyre-web-terminal-0.0.1.deb + +# Move debian package to dist folder +sudo mkdir -p $MAIN_DIR/dist +sudo mv $MAIN_DIR/phyre-web-terminal-0.0.1.deb $MAIN_DIR/dist