Complete browser-based remote desktop client built from protocol analysis: - Protobuf message definitions (75+ message types, 10 enums) - NaCl encryption (Ed25519 + Curve25519 ECDH + XSalsa20-Poly1305) - WebSocket signaling (hbbs) + relay (hbbr) connection lifecycle - VP8/VP9/AV1 video decoding via ogvjs WASM + yuv-canvas WebGL - Opus audio decoding via libopus WASM + Web Audio API - Full mouse/keyboard input forwarding to protobuf events - Connection dialog, status bar, toolbar, log panel UI Also tracked web_deps (codec libraries) in rustdesk-as-ref/
153 lines
6.5 KiB
HTML
153 lines
6.5 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
|
|
<title>RustDesk - Remote Desktop</title>
|
|
<link rel="stylesheet" href="css/style.css">
|
|
<link rel="icon" type="image/svg+xml" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'><text y='.9em' font-size='90'>🖥️</text></svg>">
|
|
</head>
|
|
<body>
|
|
|
|
<!-- Connection Overlay -->
|
|
<div id="connection-overlay">
|
|
<div class="connection-card">
|
|
<h1>RustDesk</h1>
|
|
<p class="subtitle">Standalone Web Client — Remote Desktop</p>
|
|
|
|
<form id="connection-form" onsubmit="return false;">
|
|
<div class="form-group">
|
|
<label for="server-addr">Server Address</label>
|
|
<input type="text" id="server-addr" placeholder="hbbs.example.com or 192.168.1.100:21115"
|
|
value="" autocomplete="off" spellcheck="false">
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label for="peer-id">Remote Peer ID</label>
|
|
<input type="text" id="peer-id" placeholder="e.g. 9-digit peer ID"
|
|
autocomplete="off" spellcheck="false" style="font-family: monospace; font-size: 18px; letter-spacing: 2px;">
|
|
</div>
|
|
|
|
<div class="form-row">
|
|
<div class="form-group" style="flex: 2;">
|
|
<label for="server-key">Server Public Key (optional)</label>
|
|
<input type="text" id="server-key" placeholder="For encrypted connections"
|
|
autocomplete="off" spellcheck="false" style="font-family: monospace; font-size: 11px;">
|
|
</div>
|
|
<div class="form-group" style="flex: 0; display: flex; align-items: flex-end;">
|
|
<label style="display: flex; align-items: center; gap: 6px; cursor: pointer; margin-bottom: 2px;">
|
|
<input type="checkbox" id="tls-check" checked>
|
|
<span style="font-size: 12px; color: var(--text-secondary);">TLS</span>
|
|
</label>
|
|
</div>
|
|
</div>
|
|
|
|
<button type="button" id="btn-connect" class="btn btn-primary">Connect</button>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Password Dialog -->
|
|
<div id="password-overlay">
|
|
<div class="password-card">
|
|
<h2>🔐 Authentication Required</h2>
|
|
<p style="font-size: 13px; color: var(--text-secondary); margin-bottom: 16px;">
|
|
The remote peer requires a password to connect.
|
|
</p>
|
|
<div class="form-group">
|
|
<input type="password" id="password-input" placeholder="Enter password" autocomplete="off">
|
|
</div>
|
|
<div style="display: flex; gap: 8px;">
|
|
<button type="button" class="btn btn-primary" id="btn-password-submit">Connect</button>
|
|
<button type="button" class="btn btn-danger" id="btn-password-cancel">Cancel</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Status Bar -->
|
|
<div id="status-bar">
|
|
<span class="status-indicator" id="status-indicator"></span>
|
|
<span class="status-text" id="status-text">Disconnected</span>
|
|
<span class="status-text" style="margin-left: 16px;">
|
|
Peer: <strong id="peer-id-display">—</strong>
|
|
</span>
|
|
<span class="status-text" style="margin-left: 16px;">
|
|
Client: <strong id="client-id-display">—</strong>
|
|
</span>
|
|
<div class="status-right">
|
|
<span class="fps-display" id="fps-display">— FPS</span>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Remote Desktop Canvas -->
|
|
<div id="remote-canvas-wrapper">
|
|
<canvas id="remote-canvas" tabindex="0"></canvas>
|
|
</div>
|
|
|
|
<!-- Toolbar -->
|
|
<div id="toolbar">
|
|
<button class="btn-icon" id="btn-disconnect" title="Disconnect">
|
|
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
<path d="M18.36 6.64a9 9 0 11-12.73 0M12 2v10"/>
|
|
</svg>
|
|
</button>
|
|
<div class="toolbar-divider"></div>
|
|
<button class="btn-icon" id="btn-fullscreen" title="Fullscreen">
|
|
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
<path d="M8 3H5a2 2 0 00-2 2v3m18 0V5a2 2 0 00-2-2h-3m0 18h3a2 2 0 002-2v-3M3 16v3a2 2 0 002 2h3"/>
|
|
</svg>
|
|
</button>
|
|
<div class="toolbar-divider"></div>
|
|
<button class="btn-icon" id="btn-mute" title="Toggle Audio">
|
|
🔊
|
|
</button>
|
|
<button class="btn-icon" id="btn-ctrl-alt-del" title="Ctrl+Alt+Del">
|
|
⌨️
|
|
</button>
|
|
<button class="btn-icon" id="btn-keyboard" title="Toggle Keyboard Mode">
|
|
🔣
|
|
</button>
|
|
<div class="toolbar-divider"></div>
|
|
<button class="btn-icon" id="btn-log" title="Toggle Log">
|
|
📋
|
|
</button>
|
|
</div>
|
|
|
|
<!-- Log Panel -->
|
|
<div id="log-panel">
|
|
<div class="log-header">
|
|
<span>Connection Log</span>
|
|
<button class="btn-icon btn-sm" id="btn-log-close">✕</button>
|
|
</div>
|
|
<div class="log-content" id="log-content"></div>
|
|
</div>
|
|
|
|
<!-- Toast Container -->
|
|
<div id="toast-container"></div>
|
|
|
|
<!-- External Libraries -->
|
|
<script src="https://cdn.jsdelivr.net/npm/protobufjs@7/dist/protobuf.min.js"></script>
|
|
<script src="https://cdn.jsdelivr.net/npm/tweetnacl@1/nacl.min.js"></script>
|
|
|
|
<!-- Codec Libraries (from web_deps) -->
|
|
<script src="lib/ogvjs-1.8.6/ogv-support.js"></script>
|
|
<script src="lib/ogvjs-1.8.6/ogv-decoder-video-vp8-wasm.js"></script>
|
|
<script src="lib/ogvjs-1.8.6/ogv-decoder-video-vp9-wasm.js"></script>
|
|
<script src="lib/ogvjs-1.8.6/ogv-decoder-video-av1-wasm.js"></script>
|
|
<script src="lib/ogvjs-1.8.6/ogv-worker-video.js"></script>
|
|
<script src="lib/ogvjs-1.8.6/ogv.js"></script>
|
|
<script src="lib/yuv-canvas-1.2.6.js"></script>
|
|
<script src="lib/libopus.js"></script>
|
|
|
|
<!-- Application -->
|
|
<script src="js/proto.js"></script>
|
|
<script src="js/crypto.js"></script>
|
|
<script src="js/connection.js"></script>
|
|
<script src="js/video.js"></script>
|
|
<script src="js/audio.js"></script>
|
|
<script src="js/input.js"></script>
|
|
<script src="js/app.js"></script>
|
|
|
|
</body>
|
|
</html>
|