- Go stdlib-only gateway: serves noVNC client, password auth, WS<->TCP relay - auth: PBKDF2-HMAC-SHA256 password hash, HMAC session cookies, login rate limit - relay: hand-written RFC 6455 WebSocket + transparent RFB bridge - vncspawner: cross-OS VNC server detection/launch (Windows/Linux/macOS) - server: /login /logout /vnc /api/status routes, session middleware, embed.FS - scripts: get-novnc, get-vnc (zip-verified), list-ips, open-firewall - run.bat: one-click launcher (asks only password), lists access IPs - README/AGENTS.md (Russian), .gitignore (root-anchored binaries)
40 lines
1.8 KiB
Go
40 lines
1.8 KiB
Go
package server
|
|
|
|
import (
|
|
"html/template"
|
|
"net/http"
|
|
)
|
|
|
|
type htmlTemplate = template.Template
|
|
|
|
func mustParseLoginTemplate() *htmlTemplate {
|
|
return template.Must(template.New("login").Parse(loginPageHTML))
|
|
}
|
|
|
|
func (s *Server) renderLogin(w http.ResponseWriter, errMsg string) {
|
|
w.Header().Set("Content-Type", "text/html; charset=utf-8")
|
|
_ = s.cookies.Execute(w, map[string]string{"Error": errMsg})
|
|
}
|
|
|
|
const loginPageHTML = `<!doctype html>
|
|
<html lang="en"><head><meta charset="utf-8">
|
|
<meta name="viewport" content="width=device-width,initial-scale=1">
|
|
<title>Web VNC</title><style>
|
|
*{box-sizing:border-box}
|
|
body{font-family:system-ui,Segoe UI,sans-serif;background:#0f1720;color:#e2e8f0;display:flex;align-items:center;justify-content:center;height:100vh;margin:0}
|
|
.card{background:#111827;padding:2rem 2.25rem;border-radius:14px;box-shadow:0 10px 40px rgba(0,0,0,.5);width:320px}
|
|
h1{font-size:1.3rem;margin:0 0 .25rem;text-align:center}
|
|
.sub{color:#94a3b8;font-size:.8rem;text-align:center;margin:0 0 1.4rem}
|
|
label{display:block;font-size:.8rem;margin-bottom:.35rem;color:#cbd5e1}
|
|
input{width:100%;padding:.6rem .7rem;border-radius:8px;border:1px solid #334155;background:#0b1220;color:#e2e8f0;font-size:.95rem}
|
|
button{width:100%;margin-top:1.1rem;padding:.65rem;border:none;border-radius:8px;background:#2563eb;color:#fff;font-weight:600;font-size:.95rem;cursor:pointer}
|
|
button:hover{background:#1d4ed8}
|
|
.err{color:#f87171;font-size:.8rem;margin:.7rem 0 0;text-align:center;min-height:1em}
|
|
</style></head><body><form class="card" method="post" action="/login" autocomplete="off">
|
|
<h1>🖥️ Web VNC</h1><p class="sub">Enter the access password</p>
|
|
<label for="password">Password</label>
|
|
<input id="password" name="password" type="password" autofocus required>
|
|
<button type="submit">Connect</button>
|
|
<div class="err">{{.Error}}</div>
|
|
</form></body></html>`
|