mirror of
https://github.com/sol1/rustguac.git
synced 2026-09-10 09:35:45 +00:00
99d79fe05d
New features: - Native Chromium autofill: pre-populate Login Data SQLite before launch, zero external deps (no Node.js/Playwright needed for simple login flows) - Per-entry domain allowlisting: restrict which domains Chromium can reach via --host-rules (separate from server-side web_allowed_networks CIDR) - Per-entry clipboard control: disable-copy and disable-paste for all session types (SSH, RDP, VNC, Web) via guacd native parameters - Guacamole import: `rustguac import-guacamole` parses mysqldump SQL and writes entries to Vault address book Security hardening: - Comprehensive Chromium managed policy deployed via install.sh, Dockerfile, and debian/postinst (blocks DevTools, downloads, file dialogs, extensions, dangerous URL schemes) - Profile isolation: each web session gets a unique UUID-based profile dir - Autofill credentials encrypted with Chromium's native os_crypt (AES-128-CBC) Documentation: - Updated README, docs/api.md, docs/security.md, docs/configuration.md, docs/overview.md, docs/integrations.md with all new features - Clarified two-layer domain restriction (web_allowed_networks vs allowed_domains) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
107 lines
4.0 KiB
Bash
Executable File
107 lines
4.0 KiB
Bash
Executable File
#!/bin/sh
|
|
set -e
|
|
|
|
# Ensure data directories have correct ownership
|
|
chown -R rustguac:rustguac /opt/rustguac/data
|
|
chown -R rustguac:rustguac /opt/rustguac/recordings
|
|
|
|
# Chromium policy: block devtools, file dialogs, password import (web session hardening)
|
|
mkdir -p /etc/chromium/policies/managed
|
|
cat > /etc/chromium/policies/managed/rustguac.json <<'POLICY'
|
|
{"AllowFileSelectionDialogs": false, "PasswordManagerEnabled": true, "ImportSavedPasswords": false, "DeveloperToolsAvailability": 2, "DownloadRestrictions": 3, "PrintingEnabled": false, "EditBookmarksEnabled": false, "BrowserSignin": 0, "SyncDisabled": true, "ExtensionInstallBlocklist": ["*"], "URLBlocklist": ["file://*", "chrome://*", "chrome-extension://*", "view-source:*", "javascript:*"], "URLAllowlist": ["chrome://policy"]}
|
|
POLICY
|
|
|
|
# ── Config migration: fix keys accidentally nested inside [recording] ──
|
|
# Versions prior to 0.4.1 shipped a config.toml with db_path, static_path,
|
|
# and other top-level keys placed after the [recording] header, causing them
|
|
# to be silently ignored. Detect and fix this.
|
|
CONFIG="/opt/rustguac/config.toml"
|
|
if [ -f "$CONFIG" ]; then
|
|
# Check if db_path appears ONLY after a [recording] header (i.e. is missing
|
|
# from the top-level section). A quick heuristic: if "db_path" exists in
|
|
# the file but only after a line matching [recording], it's broken.
|
|
if grep -q '^db_path' "$CONFIG" && \
|
|
! awk '/^\[recording\]/{stop=1} !stop && /^db_path/{found=1} END{exit !found}' "$CONFIG"; then
|
|
echo "Migrating config.toml: moving misplaced keys out of [recording] section..."
|
|
cp "$CONFIG" "${CONFIG}.bak-$(date +%Y%m%d%H%M%S)"
|
|
|
|
# Extract the misplaced keys from inside [recording]
|
|
# Strategy: rewrite the file, pulling known top-level keys out of [recording]
|
|
python3 -c "
|
|
import re, sys
|
|
|
|
with open('$CONFIG') as f:
|
|
lines = f.readlines()
|
|
|
|
top_keys = {'db_path', 'static_path', 'session_pending_timeout_secs',
|
|
'xvnc_path', 'chromium_path', 'display_range_start',
|
|
'display_range_end'}
|
|
|
|
in_section = None
|
|
extracted = []
|
|
remaining = []
|
|
|
|
for line in lines:
|
|
stripped = line.strip()
|
|
# Track which TOML section we're in
|
|
m = re.match(r'^\[(\w+)\]', stripped)
|
|
if m:
|
|
in_section = m.group(1)
|
|
remaining.append(line)
|
|
continue
|
|
|
|
# If inside a non-top-level section, check if this key belongs at top level
|
|
if in_section and not stripped.startswith('#') and '=' in stripped:
|
|
key = stripped.split('=', 1)[0].strip()
|
|
if key in top_keys:
|
|
extracted.append(line)
|
|
continue
|
|
|
|
remaining.append(line)
|
|
|
|
if extracted:
|
|
# Insert extracted keys right after the last top-level key before any section
|
|
insert_at = 0
|
|
for i, line in enumerate(remaining):
|
|
if re.match(r'^\[\w+\]', line.strip()):
|
|
insert_at = i
|
|
break
|
|
# Back up past blank lines to keep formatting nice
|
|
while insert_at > 0 and remaining[insert_at - 1].strip() == '':
|
|
insert_at -= 1
|
|
|
|
result = remaining[:insert_at] + ['\n'] + extracted + ['\n'] + remaining[insert_at:]
|
|
|
|
with open('$CONFIG', 'w') as f:
|
|
f.writelines(result)
|
|
print(' Moved {} key(s) to top-level section.'.format(len(extracted)))
|
|
else:
|
|
print(' No migration needed.')
|
|
" 2>/dev/null || echo " Config migration skipped (python3 not available)."
|
|
fi
|
|
fi
|
|
|
|
# Generate self-signed TLS certificate if none exists
|
|
if [ ! -f /opt/rustguac/tls/cert.pem ] || [ ! -f /opt/rustguac/tls/key.pem ]; then
|
|
CERT_HOSTNAME=$(hostname -f 2>/dev/null || hostname)
|
|
echo "Generating self-signed TLS certificate for ${CERT_HOSTNAME}..."
|
|
/opt/rustguac/bin/rustguac generate-cert \
|
|
--hostname "$CERT_HOSTNAME" \
|
|
--out-dir /opt/rustguac/tls
|
|
chmod 600 /opt/rustguac/tls/key.pem
|
|
chmod 644 /opt/rustguac/tls/cert.pem
|
|
fi
|
|
chown -R rustguac:rustguac /opt/rustguac/tls
|
|
|
|
# Update shared library cache for guacd libs
|
|
ldconfig
|
|
|
|
echo ""
|
|
echo " To set up encrypted file transfer (LUKS drive), run:"
|
|
echo " sudo /opt/rustguac/bin/drive-setup.sh"
|
|
echo ""
|
|
|
|
#DEBHELPER#
|
|
|
|
exit 0
|