The token now names the console type it was made for: novncd accepts only
a VNC page's token and socketiod only a serial page's, so a VNC page's
token no longer opens the serial console without the VNC password.
A VNC session re-checks every 10 s, as the serial one did, that its user
may still open the console; a deactivated user or a removed owner loses
it. The check (may_still_open) moves to console.tokens for both daemons.
"Type it" sent each character's keysym and let QEMU pick the key from
its own US map, with Shift added for the US shifted characters. A VM
on another layout got other characters: on Turkish Q, '"' typed 'İ',
'@' typed "'", and ğ, ü, ş, ı, ö, ç typed nothing.
The Clipboard dialog now asks for the VM's keyboard layout and
remembers it per browser. Each character is typed as the key that makes
it on that layout (its scancode), with Shift, AltGr or both (AltGr
first: pressed after Shift, the right Alt is Alt on the Linux console),
so the VM's own layout makes the character. The layout is fixed when
typing starts. Text with a character no key types on the layout is not
typed at all, and the dialog lists those characters: a password or a
command with a character left out would be a wrong one.
A layout is one file in console/layouts/: its name and, for each key,
the characters it types plainly, with Shift, with AltGr and with
Shift+AltGr. The view offers every file, US first. dev/console_layout.py
writes a file from the system's XKB data as libxkbcommon computes it
(through ctypes, no new dependency), mapping keys to DOM codes with
noVNC's table from QEMU's keycodemapdb; it lists the dead keys it leaves
out, and drops the keys the keyboard model lacks (the key left of Z on
US pc104 keyboards). English (US) and Turkish Q come with it; the
README says how to add one.
The VM page offered a lite and a full VNC console. Lite lacked a clipboard,
display settings and a way to reconnect; full put noVNC's own side bar under
the panel's bar, with a Fullscreen item that called a function noVNC does
not have, status messages hidden behind the bar, saved noVNC settings that
overrode the Access tab's, connection settings that cannot apply, and a
Connect button that reused the page's two-minute token and failed.
console-vnc.html and static/js/console_vnc.js replace both, on noVNC's RFB
with Bootstrap controls, and keep what the full view did:
- Status in the bar (Connecting, Connected, Disconnected, Connection lost,
Could not connect, Authentication failed with the server's reason on
hover); Disconnect, then Reconnect, which loads the page again for a new
token.
- The VNC password in a dialog (with a username when the server asks for
one), not a browser prompt; without passwordless console it is not in
the page.
- Send key(s) gains Hold Ctrl / Alt / Windows (noVNC's extra keys).
- Clipboard: what the VM copies, sending text to the VM's clipboard, and
typing it key by key (new: works in firmware, installers and login
prompts; Shift for the characters a US keyboard shifts, 25 ms a key as
firmware drops faster keys, verified in a UEFI shell).
- View: scaling (none, fit, resize the VM's screen), clip, drag a clipped
screen, view only, dot cursor, quality, compression; it starts as
Settings > Console says (a touch screen starts fitted).
- A Keyboard item on touch devices (noVNC's on-screen keyboard input,
key events and Android's text-only input), Fullscreen with keyboard
lock, the bell.
Dropped with the full view: noVNC's websocket host/port/path, repeater ID
and log level (the panel fixes them), automatic reconnect (the token is
single use in time), XVP power buttons (QEMU has no XVP) and shared-mode off.
The bar is compact (about 45 px in the 850x600 window). The Access tab has
one Console button instead of the Lite/Full split and four switches, and
it and the VM list open one window per VM (opening it again reloads it).
A stopped VM, an unreachable or unsupported console and a disabled serial
console rendered the lite VNC page under the error: it connected to novncd
anyway, showed "Something went wrong" and offered keys, Scale and Send
CtrlAltDel for a console that was not there. A refused console was a bare
text 403 inside the popup.
- console-error.html: the console shell with the VM's name and the reason,
no menu and no script; a refused or unknown VM gets it with 403 and
without the VM's name, as before for everyone (no superuser exception).
- The view signs the console token only for a page that connects.
- console-menu.html: the Send key(s) menu and Fullscreen, included by the
console pages; the serial page lists only the keys it sends (the VNC
groups did nothing there).
- Every console window is titled "<VM> - Console".
- The lite page no longer takes a VNC password from its link.
- The shell lost its 850px x 600px corner radius (a grey arc on the
serial and error pages) and spans the window (container-fluid).
The page's "listens only on its host" check read the VM's next-start
definition, while novncd connects to the running VM's listener: after a
listen address change on a running VM, the page refused a console novncd
could reach, or let through one it could not. The page now reads the
running VM's listener, as novncd does, with the same loopback test, which
moves to vrtManager.util.
A VM defined with QEMU's own VNC websocket (graphics websocket='...',
which the panel never sets) made the console page connect to that port on
the panel's host name: the port is on the compute, so the console did not
open unless the panel ran on that compute, and then it bypassed novncd and
the panel's console token. Such a VM has its ordinary VNC port too, and
novncd now reaches it there like any other VM.
The console page is /console/<compute>/<uuid>/ with the view and display
options in the query. It was /console/?token=<compute>-<uuid>, a "token"
that was only the VM's address, parsed alongside a signed token that no
link ever sent. The list's console button takes the VM's UUID from the
database instead of asking libvirt for each row, and no longer defines a
global function per row.
- A console listening on a given address is reached on that address;
the compute's host name is used only for a wildcard listener (0.0.0.0,
::, none). It was always the host name, which may resolve to another
interface.
- ::1 and localhost count as loopback like 127.0.0.0/8: such a console
on a TCP or TLS host is refused instead of being tried on the host's
name.
- The console page says why such a console cannot open and what to change
(listen on all interfaces, or add the host over SSH) instead of a
generic connection error.
The console pages connect to /novncd/ on the address, scheme and port the
page itself was loaded from; nginx proxies it to novncd, which listens on
the loopback only. There is nothing to configure: the console works on
HTTPS (wss), behind another proxy and on any published port.
Before, the page connected to WS_PUBLIC_HOST/PORT/PATH, port 6080 by
default: straight to novncd, past nginx and without TLS, so an HTTPS panel
and a Docker container published on another port had no console until the
public port was set by hand, and novncd listened on every interface.
Gone: WS_PUBLIC_PORT, WS_PUBLIC_HOST, WS_PUBLIC_PATH and WS_CERT, the
installer's two public console questions and its 6080 firewall rule, the
Docker image's WS_PUBLIC_PORT and its init script lines, the manual
install's firewall rule for 6080 and nginx's unused /websockify location.
WS_HOST defaults to 127.0.0.1. A VM with a QEMU websocket port is still
reached on that port of the panel's host name (left for a separate
decision).
- novncd takes the console token only from its websocket URL. The page
also put the token in a cookie, one for the whole browser, and novncd
preferred the cookie: with two consoles open, a tab that (re)connected
after another console was opened got that other VM.
- novncd opens the VM by its UUID, the VM the access check was made for,
not by its name, which another VM on the host may carry now.
- The lite VNC page took the proxy's host, port and path from its link. A
link naming another host made the page send that host a fresh signed
console token, which opened the VM's console for two minutes. The page
now uses only what the server gives it, like the full page.
- On a local-socket host, a VM whose console listens on 127.0.0.1 is
reached directly instead of being refused for want of an SSH tunnel.
- A shut-off VM's console says that the VM is not running instead of
failing with no reason.
The xterm console never connected: socketiod expected a different token
format, its worker had no compute credentials, one global console was
shared by every client and its output broadcast to all of them, and the
Docker image did not run socketiod at all.
- console/tokens.py: one authorize() for noVNC and socketiod; the signed
token is the only credential, checked at connect time.
- socketiod: one pty worker per client (consolecallback with the
instance id), one session per VM, a session cap, input and resize
checked; the parent never opens libvirt. The engine.io same-origin
check is on.
- consolecallback: opens the console with the compute's credentials and
exits with a message when it cannot.
- Docker runs socketiod as a runit service; nginx proxies /socket.io/
with Host and the scheme for the origin check. Supervisor and systemd
start it as well; WEBVIRTCLOUD_SERIAL_CONSOLE=1 enables it.
- Tests: token and session unit tests, socketiod as a process, and a
live test that reads SeaBIOS from a wvc-test VM on the TCP and SSH
hosts.
Comments, docstrings and live test names cited item IDs of a roadmap
that is not part of the repository. They now say what is meant, or
nothing where the sentence stands without them. Test assertions and
behavior are unchanged.
SPICE was removed earlier; its leftovers and the console type choice go
too:
- the console settings form, update_console and the backend no longer
offer or change the type; an invalid console form now shows its
errors instead of being ignored;
- the create form, the API serializer and create_instance no longer take
a graphics type, new VMs get VNC; get_graphics_types and the graphics
entries of the domain capabilities are gone;
- migration appsettings.0013 deletes QEMU_CONSOLE_DEFAULT_TYPE;
- a VM defined elsewhere with another graphics type gets "Console type
... is not supported".
The locale catalogs still reference the deleted SPICE templates in
source comments; regenerating them is left to the translation work.
Instance.proxy looked the domain up by its stored name. After a rename
or a name swap outside WebVirtCloud, an operation on one VM changed
another; after a VM was replaced under the same name, operations hit
the new VM.
wvmInstance takes the UUID and uses lookupByUUIDString, with no
fallback to the name: a missing UUID fails instead of picking another
domain. Every caller that has an Instance passes it: proxy, console,
quota, post-migration autostart and the VDI URL. Migration uses the
domain the proxy already resolved. getvvfile and the gstfsd requests
use the host's current name of that UUID.
Live tests cover a name swap and a VM replaced under the same name;
both fail on the previous code.
- user_block, user_unblock and admin_email_otp changed state on GET, so an
<img> tag could lock a user out or trigger OTP emails through an
admin's session. They now require POST; the buttons are CSRF forms.
- The console token cookie is set with httponly, SameSite=Lax and, on
HTTPS, secure. Only novncd reads it; the page gets the token directly.
Add webvirtcloud/test_authorization_matrix.py, which walks every named URL
and checks that a user without any VM/compute relation only reaches an
explicit allowlist, and that the global view_instances permission does not
open consoles. It found:
- /computes/<id>/... views without any check (compute_graph,
get_compute_*, get_dom_capabilities, storages.get_volumes): the whole
computes URL namespace is now wrapped with superuser_only, so a view
added there later cannot be exposed by a missing decorator.
- guess_mac_address (leaks dhcpd.conf host/MAC pairs), random_mac_address
and guess_clone_name: superuser-only, like the buttons that use them.
- check_instance: cross-tenant VM name lookup with no caller; removed.
- getvvfile and get_vdi_url: reachable with only view_instances, and the
.vv file contains the VNC password.
Console access now follows one rule, instances.utils.can_open_console:
an active superuser or an active owner of the VM. The global
view_instances permission is read-only. It is used by the console page,
novncd, getvvfile and get_vdi_url (getvvfile and the VDI tab are kept for
virt-viewer users). The console page answers 403 instead of 500 when
access is denied, with the same answer for a missing VM.
socketiod does not validate the console token, keeps a single global PTY
and broadcasts its output to every connected client, so anyone who can
reach port 6081 can read and write a serial console that someone opened.
It is also broken for legitimate users, since console/views.py now writes
signed tokens that socketiod cannot parse.
Until it is rewritten, turn the serial console off by default:
- Add SERIAL_CONSOLE_ENABLED = False to the settings template; installs
whose settings.py lacks it are treated as disabled.
- The console view shows an error instead of the xterm page for pty
consoles while the setting is off.
- socketiod refuses to start unless SERIAL_CONSOLE_ENABLED is True.
- Supervisor: autostart=false for socketiod; drop -d (debug) from the
supervisor and systemd definitions; fix the systemd unit description;
conf/systemd/install.sh no longer suggests enabling socketiod.
- README: stop opening port 6081 and document how to enable the serial
console on a trusted network.
- Computes API: mark password as write_only in ComputeSerializer, restrict ComputeViewSet and architectures to IsAdminUser.
- Instances API: enforce user ownership tenant isolation in InstanceViewSet.list, restrict MigrateViewSet and CreateInstanceViewSet to IsAdminUser, require IsAdminUser for mutating FlavorViewSet.
- Storage, Network, and Interface APIs: restrict StorageViewSet, VolumeViewSet, NetworkViewSet, InterfaceViewSet to IsAdminUser.
- AppSettings & NWFilters: protect appsettings and nwfilter views with @superuser_only (403 Forbidden for non-superusers).
- noVNC Console: sign tokens with TimestampSigner (salt='console.novnc', max_age=600), verify signature and user authorization in novncd with backward-compatible fallback for debug/test mode.
- Accounts: avoid hardcoded default admin password; generate cryptographically secure random password unless ADMIN_PASSWORD is set (preserve 'admin' in test runner).
- gstfsd daemon: bind to 127.0.0.1 by default instead of 0.0.0.0.
- Tests: added comprehensive test coverage for API security, token expiration/rejection, and view permissions (132 tests passing).
- Remove obsolete spice-html5 static assets and SPICE console templates
- Restrict default console types to VNC with migration 0012
- Filter out SPICE in VM creation form and backend capabilities
- Return friendly deprecation notice if legacy VM is opened with SPICE
- Clean up docs, architecture references, and libvirt-bootstrap scripts
- Validate and coerce console query parameters (view_only, scale, resize_session, clip_viewport) to strict booleans via to_bool in console/views.py
- Sanitize view parameter to strictly 'lite' or 'full'
- Apply escapejs filter to all JS string interpolations in console-vnc-full.html, console-vnc-lite.html, console-spice-lite.html, and console-xterm.html
- Replace unsafe '| safe' filter in console-spice-lite.html with escapejs
- Add unit tests for XSS query param mitigation and escapejs character encoding