-
Notifications
You must be signed in to change notification settings - Fork 6
feat: add path-based sharing for kasm #115
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
8d83749
b89bb08
bb711d0
ccd4b0c
0f41a42
bec8d0b
e3840c4
64b282f
db65a2b
4fd38f3
b0cfe51
e9fac91
1969cfb
6fae365
30b7c65
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Don't understand, but probably it's needed for the path-based service to work. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Exactly, this leverages javascript as a fast path rewrite to provide the configuration in a way that the vnc.html page can parse as a valid configuration, thus setting the websocket address to the proper path. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
<!DOCTYPE html> | ||
<html> | ||
<head> | ||
<title>Path-Sharing Bounce Page</title> | ||
<style type="text/css"> | ||
:root { | ||
color-scheme: light dark; | ||
--dark: #121212; | ||
--header-bg: rgba(127,127,127,0.2); | ||
--light: white; | ||
--rule-color: light-dark(rgba(0,0,0,0.8), rgba(255,255,255,0.8)); | ||
background-color: light-dark(var(--light), var(--dark)); | ||
color: light-dark(var(--dark), var(--light)); | ||
} | ||
body, h1, p { | ||
box-sizing: border-box; | ||
margin:0; padding:0; | ||
} | ||
body{ | ||
font-family:Inter, system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif; | ||
} | ||
h1{ | ||
width: 100%; | ||
padding: 1rem; | ||
letter-spacing: -1.5pt; | ||
padding-bottom:10px; | ||
border-bottom: 1px solid var(--rule-color); | ||
background-color: var(--header-bg); | ||
} | ||
p { | ||
padding: 1rem; letter-spacing: -0.5pt;} | ||
a.indent { display:inline-block; padding-top:0.5rem; padding-left: 2rem; font-size:0.8rem } | ||
</style> | ||
<meta charset="UTF-8" /> | ||
</head> | ||
<body> | ||
<h1>Path-Sharing Bounce Page</h1> | ||
<p> | ||
This application is being served via path sharing. | ||
If you are not redirected, <span id="help">check the | ||
Javascript console in your browser's developer tools | ||
for more information.</span> | ||
</p> | ||
</body> | ||
<script language="javascript"> | ||
// This page exists to satisfy the querystring driven client API | ||
// specified here - https://raw.githubusercontent.com/kasmtech/noVNC/bce2d6a7048025c6e6c05df9d98b206c23f6dbab/docs/EMBEDDING.md | ||
// tl;dr: | ||
// * `host` - The WebSocket host to connect to. | ||
// This is just the hostname component of the original URL | ||
// * `port` - The WebSocket port to connect to. | ||
// It doesn't look like we need to set this unless it's different | ||
// than the incoming http request. | ||
// * `encrypt` - If TLS should be used for the WebSocket connection. | ||
// we base this on whether or not the protocol is `https`, seems | ||
// reasonable for now. | ||
// * `path` - The WebSocket path to use. | ||
// This apparently doesn't tolerate a leading `/` so we use a | ||
// function to tidy that up. | ||
function trimFirstCharIf(str, char) { | ||
return str.charAt(0) === char ? str.slice(1) : str; | ||
} | ||
function trimLastCharIf(str, char) { | ||
return str.endsWith("/") ? str.slice(0,str.length-1) : str; | ||
} | ||
const newloc = new URL(window.location); | ||
const h = document.getElementById("help") | ||
|
||
// Building the websockify path must happen before we append the filename to newloc.pathname | ||
newloc.searchParams.append("path", | ||
trimLastCharIf(trimFirstCharIf(newloc.pathname,"/"),"/")+"/websockify"); | ||
newloc.searchParams.append("encrypted", newloc.protocol==="https:"? true : false); | ||
|
||
newloc.pathname += "vnc.html" | ||
console.log(newloc); | ||
|
||
h.innerHTML = `click <a id="link" href="${newloc.toString()}">here</a> to go to the application. | ||
<br/><br/>The rewritten URL is:<br/><a id="link" class="indent" href="${newloc.toString()}">${newloc.toString()}</a>` | ||
window.location = newloc.href; | ||
</script> | ||
</html> |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,6 +3,8 @@ | |
# Exit on error, undefined variables, and pipe failures | ||
set -euo pipefail | ||
|
||
error() { printf "💀 ERROR: %s\n" "$@"; exit 1; } | ||
|
||
# Function to check if vncserver is already installed | ||
check_installed() { | ||
if command -v vncserver &> /dev/null; then | ||
|
@@ -188,7 +190,7 @@ if command -v sudo &> /dev/null && sudo -n true 2> /dev/null; then | |
SUDO=sudo | ||
else | ||
kasm_config_file="$HOME/.vnc/kasmvnc.yaml" | ||
SUDO= | ||
SUDO="" | ||
|
||
echo "WARNING: Sudo access not available, using user config dir!" | ||
|
||
|
@@ -206,6 +208,7 @@ echo "Writing KasmVNC config to $kasm_config_file" | |
$SUDO tee "$kasm_config_file" > /dev/null << EOF | ||
network: | ||
protocol: http | ||
interface: 127.0.0.1 | ||
websocket_port: ${PORT} | ||
ssl: | ||
require_ssl: false | ||
|
@@ -220,16 +223,82 @@ EOF | |
# and does not listen publicly | ||
echo -e "password\npassword\n" | vncpasswd -wo -u "$USER" | ||
|
||
get_http_dir() { | ||
# determine the served file path | ||
# Start with the default | ||
httpd_directory="/usr/share/kasmvnc/www" | ||
|
||
# Check the system configuration path | ||
if [[ -e /etc/kasmvnc/kasmvnc.yaml ]]; then | ||
d=($(grep -E "^\s*httpd_directory:.*$" /etc/kasmvnc/kasmvnc.yaml)) | ||
# If this grep is successful, it will return: | ||
# httpd_directory: /usr/share/kasmvnc/www | ||
if [[ $${#d[@]} -eq 2 && -d "$${d[1]}" ]]; then | ||
httpd_directory="$${d[1]}" | ||
fi | ||
fi | ||
|
||
# Check the home directory for overriding values | ||
if [[ -e "$HOME/.vnc/kasmvnc.yaml" ]]; then | ||
d=($(grep -E "^\s*httpd_directory:.*$" /etc/kasmvnc/kasmvnc.yaml)) | ||
if [[ $${#d[@]} -eq 2 && -d "$${d[1]}" ]]; then | ||
httpd_directory="$${d[1]}" | ||
fi | ||
fi | ||
echo $httpd_directory | ||
} | ||
|
||
fix_server_index_file(){ | ||
local fname=$${FUNCNAME[0]} # gets current function name | ||
if [[ $# -ne 1 ]]; then | ||
error "$fname requires exactly 1 parameter:\n\tpath to KasmVNC httpd_directory" | ||
fi | ||
local httpdir="$1" | ||
if [[ ! -d "$httpdir" ]]; then | ||
error "$fname: $httpdir is not a directory" | ||
fi | ||
pushd "$httpdir" > /dev/null | ||
|
||
cat <<'EOH' > /tmp/path_vnc.html | ||
${PATH_VNC_HTML} | ||
EOH | ||
$SUDO mv /tmp/path_vnc.html . | ||
# check for the switcheroo | ||
if [[ -f "index.html" && -L "vnc.html" ]]; then | ||
$SUDO mv $httpdir/index.html $httpdir/vnc.html | ||
fi | ||
$SUDO ln -s -f path_vnc.html index.html | ||
popd > /dev/null | ||
} | ||
|
||
patch_kasm_http_files(){ | ||
homedir=$(get_http_dir) | ||
fix_server_index_file "$homedir" | ||
} | ||
|
||
if [[ "${SUBDOMAIN}" == "false" ]]; then | ||
echo "🩹 Patching up webserver files to support path-sharing..." | ||
patch_kasm_http_files | ||
fi | ||
|
||
VNC_LOG="/tmp/kasmvncserver.log" | ||
# Start the server | ||
printf "🚀 Starting KasmVNC server...\n" | ||
vncserver -select-de "${DESKTOP_ENVIRONMENT}" -disableBasicAuth > /tmp/kasmvncserver.log 2>&1 & | ||
pid=$! | ||
|
||
# Wait for server to start | ||
sleep 5 | ||
grep -v '^[[:space:]]*$' /tmp/kasmvncserver.log | tail -n 10 | ||
if ps -p $pid | grep -q "^$pid"; then | ||
echo "ERROR: Failed to start KasmVNC server. Check full logs at /tmp/kasmvncserver.log" | ||
|
||
set +e | ||
vncserver -select-de "${DESKTOP_ENVIRONMENT}" -disableBasicAuth > "$VNC_LOG" 2>&1 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is dropping There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, vncserver forks all by itself if it successfully launches. |
||
RETVAL=$? | ||
set -e | ||
|
||
if [[ $RETVAL -ne 0 ]]; then | ||
echo "ERROR: Failed to start KasmVNC server. Return code: $RETVAL" | ||
if [[ -f "$VNC_LOG" ]]; then | ||
echo "Full logs:" | ||
cat "$VNC_LOG" | ||
else | ||
echo "ERROR: Log file not found: $VNC_LOG" | ||
fi | ||
exit 1 | ||
fi | ||
|
||
printf "🚀 KasmVNC server started successfully!\n" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can drop as it's the default value.
Add a new example below with
subdomain = false
to share how they can use it without a subdomain.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It looked like we were using that to show all of the values. I can do a follow-up PR if that is "minimum config to start" and make a section for "Using the module with path-based sharing"