完善虚拟机连接

This commit is contained in:
2024-07-31 20:45:38 +08:00
parent 9b51368f9c
commit b491db6b60
213 changed files with 43580 additions and 6 deletions

14
VM/novnc/utils/README.md Normal file
View File

@@ -0,0 +1,14 @@
## WebSockets Proxy/Bridge
Websockify has been forked out into its own project. `novnc_proxy` will
automatically download it here if it is not already present and not
installed as system-wide.
For more detailed description and usage information please refer to
the [websockify README](https://github.com/novnc/websockify/blob/master/README.md).
The other versions of websockify (C, Node.js) and the associated test
programs have been moved to
[websockify](https://github.com/novnc/websockify). Websockify was
formerly named wsproxy.

17
VM/novnc/utils/b64-to-binary.pl Executable file
View File

@@ -0,0 +1,17 @@
#!/usr/bin/env perl
use MIME::Base64;
for (<>) {
unless (/^'([{}])(\d+)\1(.+?)',$/) {
print;
next;
}
my ($dir, $amt, $b64) = ($1, $2, $3);
my $decoded = MIME::Base64::decode($b64) or die "Could not base64-decode line `$_`";
my $decoded_escaped = join "", map { "\\x$_" } unpack("(H2)*", $decoded);
print "'${dir}${amt}${dir}${decoded_escaped}',\n";
}

140
VM/novnc/utils/convert.js Executable file
View File

@@ -0,0 +1,140 @@
#!/usr/bin/env node
const path = require('path');
const { program } = require('commander');
const fs = require('fs');
const fse = require('fs-extra');
const babel = require('@babel/core');
program
.option('-m, --with-source-maps [type]', 'output source maps when not generating a bundled app (type may be empty for external source maps, inline for inline source maps, or both) ')
.option('--clean', 'clear the lib folder before building')
.parse(process.argv);
// the various important paths
const paths = {
main: path.resolve(__dirname, '..'),
core: path.resolve(__dirname, '..', 'core'),
vendor: path.resolve(__dirname, '..', 'vendor'),
libDirBase: path.resolve(__dirname, '..', 'lib'),
};
// util.promisify requires Node.js 8.x, so we have our own
function promisify(original) {
return function promiseWrap() {
const args = Array.prototype.slice.call(arguments);
return new Promise((resolve, reject) => {
original.apply(this, args.concat((err, value) => {
if (err) return reject(err);
resolve(value);
}));
});
};
}
const writeFile = promisify(fs.writeFile);
const readdir = promisify(fs.readdir);
const lstat = promisify(fs.lstat);
const ensureDir = promisify(fse.ensureDir);
const babelTransformFile = promisify(babel.transformFile);
// walkDir *recursively* walks directories trees,
// calling the callback for all normal files found.
function walkDir(basePath, cb, filter) {
return readdir(basePath)
.then((files) => {
const paths = files.map(filename => path.join(basePath, filename));
return Promise.all(paths.map(filepath => lstat(filepath)
.then((stats) => {
if (filter !== undefined && !filter(filepath, stats)) return;
if (stats.isSymbolicLink()) return;
if (stats.isFile()) return cb(filepath);
if (stats.isDirectory()) return walkDir(filepath, cb, filter);
})));
});
}
function makeLibFiles(sourceMaps) {
// NB: we need to make a copy of babelOpts, since babel sets some defaults on it
const babelOpts = () => ({
plugins: [],
presets: [
[ '@babel/preset-env',
{ modules: 'commonjs' } ]
],
ast: false,
sourceMaps: sourceMaps,
});
fse.ensureDirSync(paths.libDirBase);
const outFiles = [];
const handleDir = (vendorRewrite, inPathBase, filename) => Promise.resolve()
.then(() => {
const outPath = path.join(paths.libDirBase, path.relative(inPathBase, filename));
if (path.extname(filename) !== '.js') {
return; // skip non-javascript files
}
return Promise.resolve()
.then(() => ensureDir(path.dirname(outPath)))
.then(() => {
const opts = babelOpts();
// Adjust for the fact that we move the core files relative
// to the vendor directory
if (vendorRewrite) {
opts.plugins.push(["import-redirect",
{"root": paths.libDirBase,
"redirect": { "vendor/(.+)": "./vendor/$1"}}]);
}
return babelTransformFile(filename, opts)
.then((res) => {
console.log(`Writing ${outPath}`);
const {map} = res;
let {code} = res;
if (sourceMaps === true) {
// append URL for external source map
code += `\n//# sourceMappingURL=${path.basename(outPath)}.map\n`;
}
outFiles.push(`${outPath}`);
return writeFile(outPath, code)
.then(() => {
if (sourceMaps === true || sourceMaps === 'both') {
console.log(` and ${outPath}.map`);
outFiles.push(`${outPath}.map`);
return writeFile(`${outPath}.map`, JSON.stringify(map));
}
});
});
});
});
Promise.resolve()
.then(() => {
const handler = handleDir.bind(null, false, paths.main);
return walkDir(paths.vendor, handler);
})
.then(() => {
const handler = handleDir.bind(null, true, paths.core);
return walkDir(paths.core, handler);
})
.catch((err) => {
console.error(`Failure converting modules: ${err}`);
process.exit(1);
});
}
let options = program.opts();
if (options.clean) {
console.log(`Removing ${paths.libDirBase}`);
fse.removeSync(paths.libDirBase);
}
makeLibFiles(options.withSourceMaps);

127
VM/novnc/utils/genkeysymdef.js Executable file
View File

@@ -0,0 +1,127 @@
#!/usr/bin/env node
/*
* genkeysymdef: X11 keysymdef.h to JavaScript converter
* Copyright (C) 2018 The noVNC Authors
* Licensed under MPL 2.0 (see LICENSE.txt)
*/
"use strict";
const fs = require('fs');
let showHelp = process.argv.length === 2;
let filename;
for (let i = 2; i < process.argv.length; ++i) {
switch (process.argv[i]) {
case "--help":
case "-h":
showHelp = true;
break;
case "--file":
case "-f":
default:
filename = process.argv[i];
}
}
if (!filename) {
showHelp = true;
console.log("Error: No filename specified\n");
}
if (showHelp) {
console.log("Parses a *nix keysymdef.h to generate Unicode code point mappings");
console.log("Usage: node parse.js [options] filename:");
console.log(" -h [ --help ] Produce this help message");
console.log(" filename The keysymdef.h file to parse");
process.exit(0);
}
const buf = fs.readFileSync(filename);
const str = buf.toString('utf8');
const re = /^#define XK_([a-zA-Z_0-9]+)\s+0x([0-9a-fA-F]+)\s*(\/\*\s*(.*)\s*\*\/)?\s*$/m;
const arr = str.split('\n');
const codepoints = {};
for (let i = 0; i < arr.length; ++i) {
const result = re.exec(arr[i]);
if (result) {
const keyname = result[1];
const keysym = parseInt(result[2], 16);
const remainder = result[3];
const unicodeRes = /U\+([0-9a-fA-F]+)/.exec(remainder);
if (unicodeRes) {
const unicode = parseInt(unicodeRes[1], 16);
// The first entry is the preferred one
if (!codepoints[unicode]) {
codepoints[unicode] = { keysym: keysym, name: keyname };
}
}
}
}
let out =
"/*\n" +
" * Mapping from Unicode codepoints to X11/RFB keysyms\n" +
" *\n" +
" * This file was automatically generated from keysymdef.h\n" +
" * DO NOT EDIT!\n" +
" */\n" +
"\n" +
"/* Functions at the bottom */\n" +
"\n" +
"const codepoints = {\n";
function toHex(num) {
let s = num.toString(16);
if (s.length < 4) {
s = ("0000" + s).slice(-4);
}
return "0x" + s;
}
for (let codepoint in codepoints) {
codepoint = parseInt(codepoint);
// Latin-1?
if ((codepoint >= 0x20) && (codepoint <= 0xff)) {
continue;
}
// Handled by the general Unicode mapping?
if ((codepoint | 0x01000000) === codepoints[codepoint].keysym) {
continue;
}
out += " " + toHex(codepoint) + ": " +
toHex(codepoints[codepoint].keysym) +
", // XK_" + codepoints[codepoint].name + "\n";
}
out +=
"};\n" +
"\n" +
"export default {\n" +
" lookup(u) {\n" +
" // Latin-1 is one-to-one mapping\n" +
" if ((u >= 0x20) && (u <= 0xff)) {\n" +
" return u;\n" +
" }\n" +
"\n" +
" // Lookup table (fairly random)\n" +
" const keysym = codepoints[u];\n" +
" if (keysym !== undefined) {\n" +
" return keysym;\n" +
" }\n" +
"\n" +
" // General mapping as final fallback\n" +
" return 0x01000000 | u;\n" +
" },\n" +
"};";
console.log(out);

234
VM/novnc/utils/novnc_proxy Executable file
View File

@@ -0,0 +1,234 @@
#!/usr/bin/env bash
# Copyright (C) 2018 The noVNC Authors
# Licensed under MPL 2.0 or any later version (see LICENSE.txt)
usage() {
if [ "$*" ]; then
echo "$*"
echo
fi
echo "Usage: ${NAME} [--listen [HOST:]PORT] [--vnc VNC_HOST:PORT] [--cert CERT] [--ssl-only]"
echo
echo "Starts the WebSockets proxy and a mini-webserver and "
echo "provides a cut-and-paste URL to go to."
echo
echo " --listen [HOST:]PORT Port for proxy/webserver to listen on"
echo " Default: 6080 (on all interfaces)"
echo " --vnc VNC_HOST:PORT VNC server host:port proxy target"
echo " Default: localhost:5900"
echo " --cert CERT Path to combined cert/key file, or just"
echo " the cert file if used with --key"
echo " Default: self.pem"
echo " --key KEY Path to key file, when not combined with cert"
echo " --web WEB Path to web files (e.g. vnc.html)"
echo " Default: ./"
echo " --ssl-only Disable non-https connections."
echo " "
echo " --file-only Disable directory listing in web server."
echo " "
echo " --record FILE Record traffic to FILE.session.js"
echo " "
echo " --syslog SERVER Can be local socket such as /dev/log, or a UDP host:port pair."
echo " "
echo " --heartbeat SEC send a ping to the client every SEC seconds"
echo " --timeout SEC after SEC seconds exit when not connected"
echo " --idle-timeout SEC server exits after SEC seconds if there are no"
echo " "
echo " --web-auth enable authentication"
echo " --auth-plugin CLASS authentication plugin to use"
echo " --auth-source ARG plugin configuration"
echo " "
echo " active connections"
echo " "
exit 2
}
NAME="$(basename $0)"
REAL_NAME="$(readlink -f $0)"
HERE="$(cd "$(dirname "$REAL_NAME")" && pwd)"
HOST=""
PORT="6080"
LISTEN="$PORT"
VNC_DEST="localhost:5900"
CERT=""
KEY=""
WEB=""
proxy_pid=""
SSLONLY=""
RECORD=""
SYSLOG_ARG=""
HEARTBEAT_ARG=""
IDLETIMEOUT_ARG=""
TIMEOUT_ARG=""
WEBAUTH_ARG=""
AUTHPLUGIN_ARG=""
AUTHSOURCE_ARG=""
FILEONLY_ARG=""
die() {
echo "$*"
exit 1
}
cleanup() {
trap - TERM QUIT INT EXIT
trap "true" CHLD # Ignore cleanup messages
echo
if [ -n "${proxy_pid}" ]; then
echo "Terminating WebSockets proxy (${proxy_pid})"
kill ${proxy_pid}
fi
}
# Process Arguments
# Arguments that only apply to chrooter itself
while [ "$*" ]; do
param=$1; shift; OPTARG=$1
case $param in
--listen) LISTEN="${OPTARG}"; shift ;;
--vnc) VNC_DEST="${OPTARG}"; shift ;;
--cert) CERT="${OPTARG}"; shift ;;
--key) KEY="${OPTARG}"; shift ;;
--web) WEB="${OPTARG}"; shift ;;
--ssl-only) SSLONLY="--ssl-only" ;;
--file-only) FILEONLY_ARG="--file-only" ;;
--record) RECORD="${OPTARG}"; shift ;;
--syslog) SYSLOG_ARG="--syslog ${OPTARG}"; shift ;;
--heartbeat) HEARTBEAT_ARG="--heartbeat ${OPTARG}"; shift ;;
--idle-timeout) IDLETIMEOUT_ARG="--idle-timeout ${OPTARG}"; shift ;;
--timeout) TIMEOUT_ARG="--timeout ${OPTARG}"; shift ;;
--web-auth) WEBAUTH_ARG="--web-auth" ;;
--auth-plugin) AUTHPLUGIN_ARG="--auth-plugin ${OPTARG}"; shift ;;
--auth-source) AUTHSOURCE_ARG="--auth-source ${OPTARG}"; shift ;;
-h|--help) usage ;;
-*) usage "Unknown chrooter option: ${param}" ;;
*) break ;;
esac
done
if [ "$LISTEN" != "$PORT" ]; then
HOST=${LISTEN%:*}
PORT=${LISTEN##*:}
# if no host was given, restore
[ "$HOST" = "$PORT" ] && HOST=""
fi
# Sanity checks
if [ -z "${HOST}" ]; then
if bash -c "exec 7<>/dev/tcp/localhost/${PORT}" &> /dev/null; then
exec 7<&-
exec 7>&-
die "Port ${PORT} in use. Try --listen PORT"
else
exec 7<&-
exec 7>&-
fi
fi
trap "cleanup" TERM QUIT INT EXIT
# Find vnc.html
if [ -n "${WEB}" ]; then
if [ ! -e "${WEB}/vnc.html" ]; then
die "Could not find ${WEB}/vnc.html"
fi
elif [ -e "$(pwd)/vnc.html" ]; then
WEB=$(pwd)
elif [ -e "${HERE}/../vnc.html" ]; then
WEB=${HERE}/../
elif [ -e "${HERE}/vnc.html" ]; then
WEB=${HERE}
elif [ -e "${HERE}/../share/novnc/vnc.html" ]; then
WEB=${HERE}/../share/novnc/
else
die "Could not find vnc.html"
fi
# Find self.pem
if [ -n "${CERT}" ]; then
if [ ! -e "${CERT}" ]; then
die "Could not find ${CERT}"
fi
elif [ -e "$(pwd)/self.pem" ]; then
CERT="$(pwd)/self.pem"
elif [ -e "${HERE}/../self.pem" ]; then
CERT="${HERE}/../self.pem"
elif [ -e "${HERE}/self.pem" ]; then
CERT="${HERE}/self.pem"
else
echo "Warning: could not find self.pem"
fi
# Check key file
if [ -n "${KEY}" ]; then
if [ ! -e "${KEY}" ]; then
die "Could not find ${KEY}"
fi
fi
# try to find websockify (prefer local, try global, then download local)
if [[ -d ${HERE}/websockify ]]; then
WEBSOCKIFY=${HERE}/websockify/run
if [[ ! -x $WEBSOCKIFY ]]; then
echo "The path ${HERE}/websockify exists, but $WEBSOCKIFY either does not exist or is not executable."
echo "If you intended to use an installed websockify package, please remove ${HERE}/websockify."
exit 1
fi
echo "Using local websockify at $WEBSOCKIFY"
else
WEBSOCKIFY_FROMSYSTEM=$(which websockify 2>/dev/null)
WEBSOCKIFY_FROMSNAP=${HERE}/../usr/bin/python2-websockify
[ -f $WEBSOCKIFY_FROMSYSTEM ] && WEBSOCKIFY=$WEBSOCKIFY_FROMSYSTEM
[ -f $WEBSOCKIFY_FROMSNAP ] && WEBSOCKIFY=$WEBSOCKIFY_FROMSNAP
if [ ! -f "$WEBSOCKIFY" ]; then
echo "No installed websockify, attempting to clone websockify..."
WEBSOCKIFY=${HERE}/websockify/run
git clone https://github.com/novnc/websockify ${HERE}/websockify
if [[ ! -e $WEBSOCKIFY ]]; then
echo "Unable to locate ${HERE}/websockify/run after downloading"
exit 1
fi
echo "Using local websockify at $WEBSOCKIFY"
else
echo "Using installed websockify at $WEBSOCKIFY"
fi
fi
# Make all file paths absolute as websockify changes working directory
WEB=`realpath "${WEB}"`
[ -n "${CERT}" ] && CERT=`realpath "${CERT}"`
[ -n "${KEY}" ] && KEY=`realpath "${KEY}"`
[ -n "${RECORD}" ] && RECORD=`realpath "${RECORD}"`
echo "Starting webserver and WebSockets proxy on${HOST:+ host ${HOST}} port ${PORT}"
${WEBSOCKIFY} ${SYSLOG_ARG} ${SSLONLY} ${FILEONLY_ARG} --web ${WEB} ${CERT:+--cert ${CERT}} ${KEY:+--key ${KEY}} ${LISTEN} ${VNC_DEST} ${HEARTBEAT_ARG} ${IDLETIMEOUT_ARG} ${RECORD:+--record ${RECORD}} ${TIMEOUT_ARG} ${WEBAUTH_ARG} ${AUTHPLUGIN_ARG} ${AUTHSOURCE_ARG} &
proxy_pid="$!"
sleep 1
if [ -z "$proxy_pid" ] || ! ps -eo pid= | grep -w "$proxy_pid" > /dev/null; then
proxy_pid=
echo "Failed to start WebSockets proxy"
exit 1
fi
if [ -z "$HOST" ]; then
HOST=$(hostname)
fi
echo -e "\n\nNavigate to this URL:\n"
if [ "x$SSLONLY" == "x" ]; then
echo -e " http://${HOST}:${PORT}/vnc.html?host=${HOST}&port=${PORT}\n"
else
echo -e " https://${HOST}:${PORT}/vnc.html?host=${HOST}&port=${PORT}\n"
fi
echo -e "Press Ctrl-C to exit\n\n"
wait ${proxy_pid}

28
VM/novnc/utils/u2x11 Executable file
View File

@@ -0,0 +1,28 @@
#!/usr/bin/env bash
#
# Convert "U+..." commented entries in /usr/include/X11/keysymdef.h
# into JavaScript for use by noVNC. Note this is likely to produce
# a few duplicate properties with clashing values, that will need
# resolving manually.
#
# Colin Dean <colin@xvpsource.org>
#
regex="^#define[ \t]+XK_[A-Za-z0-9_]+[ \t]+0x([0-9a-fA-F]+)[ \t]+\/\*[ \t]+U\+([0-9a-fA-F]+)[ \t]+[^*]+.[ \t]+\*\/[ \t]*$"
echo "unicodeTable = {"
while read line; do
if echo "${line}" | egrep -qs "${regex}"; then
x11=$(echo "${line}" | sed -r "s/${regex}/\1/")
vnc=$(echo "${line}" | sed -r "s/${regex}/\2/")
if echo "${vnc}" | egrep -qs "^00[2-9A-F][0-9A-F]$"; then
: # skip ISO Latin-1 (U+0020 to U+00FF) as 1-to-1 mapping
else
# note 1-to-1 is possible (e.g. for Euro symbol, U+20AC)
echo " 0x${vnc} : 0x${x11},"
fi
fi
done < /usr/include/X11/keysymdef.h | uniq
echo "};"

45
VM/novnc/utils/validate Executable file
View File

@@ -0,0 +1,45 @@
#!/bin/bash
set -e
RET=0
OUT=`mktemp`
for fn in "$@"; do
echo "Validating $fn..."
echo
case $fn in
*.html)
type="text/html"
;;
*.css)
type="text/css"
;;
*)
echo "Unknown format!"
echo
RET=1
continue
;;
esac
curl --silent \
--header "Content-Type: ${type}; charset=utf-8" \
--data-binary @${fn} \
https://validator.w3.org/nu/?out=text > $OUT
cat $OUT
echo
# We don't fail the check for warnings as some warnings are
# not relevant for us, and we don't currently have a way to
# ignore just those
if grep -q -s -E "^Error:" $OUT; then
RET=1
fi
done
rm $OUT
exit $RET