1
0
Fork 0
mirror of https://github.com/retspen/webvirtcloud synced 2026-11-08 19:26:48 +00:00
Commit graph

56 commits

Author SHA1 Message Date
catborise
676bcfeb09 fix(templates): forms and detail lists fit a phone screen
Column offsets without a breakpoint applied below it, where the column
is already full width, so the change password, compute, user, VM
create and VM settings forms ran past the right edge on a phone. Each
offset now starts at its column's breakpoint. The interface and network
detail lists were rows directly inside rows and sit in a column now;
the compute form loses a Bootstrap 3 thumbnail padding that broke its
gutters, and the add-rule dialog's hint is no longer cut off. The page
test checks both grid rules on every page.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-21 13:19:14 +03:00
catborise
e324e79fcb fix(templates): a wide table scrolls in its own box on a narrow screen
Twenty tables had no .table-responsive wrapper, so on a phone the user
list, compute list, VM lists, network and network filter pages scrolled
sideways as a whole. Each table now scrolls inside its box, as the
other ten already did. The page test walks the network page too, and
checks that every table on every page has the wrapper.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-21 12:57:26 +03:00
catborise
64057f8d05 fix(templates): icon-only buttons, selects and delete pages have accessible names
An accessibility scan (axe-core, WCAG 2 A/AA) of every page found 87
elements without a name. Icon-only buttons and links (the navbar's
administration menu on every page, the add/create buttons, the flavor
delete and back buttons) get a title, which is also their tooltip; the
labels of the language, architecture, chipset and filter selects point
at them; the memory bar is named. The shared delete confirmation page
had an empty <title> and heading, as no view passes "title": it says
"Delete <object>". The power-off form's aria-label was misspelled.
2026-10-19 16:15:06 +03:00
catborise
3a4488d34f fix(templates): pages parse without markup errors, element IDs are unique
Rendered through every URL on libvirt's test driver, the pages had
duplicate IDs and markup browsers repaired silently:

- Each flavor modal's "Advanced" button toggled #flav-add-collapse, the
  first modal's section; every modal now has its own. The flavor and
  template copies of the custom tab's control IDs, and the template
  tab's unused images input, are gone.
- The VM page's action icons and the XML editors were styled by
  repeated IDs; they use classes.
- Modal forms opened inside modal-body and closed after modal-footer;
  they wrap both. Stray end tags and duplicate attributes are removed,
  paragraphs no longer hold modals or rows, table heads have a row, and
  the create page closes its row and column.
- html lang is the active language instead of "en".

A test walks every URL as a superuser and fails on a repeated ID. The
console page still has no doctype: its full-height layout relies on
quirks mode and needs its own check.
2026-10-19 07:49:25 +03:00
catborise
c55f52f025 test: each app keeps its tests in a tests package
131 test modules sat next to the code they test; instances alone had
51 of them beside views.py and utils.py. They move into a
tests/ package per app, and the JavaScript checks into
webvirtcloud/tests/js. Each non-empty tests.py becomes tests/test_views.py;
the empty generated stubs are removed.

Imports of the app's own modules become absolute, paths built from
__file__ go one level up, the live helper is instances.tests.livetest,
and coverage omits */tests/*. The suite discovers the same 960 tests as
before.
2026-10-12 15:17:30 +03:00
catborise
4ae3fb2d53 feat(admin): list and remove the owners kept for vanished VMs
A VM that disappears from its compute keeps its owners in a tombstone
until INSTANCE_OWNERSHIP_RETENTION_DAYS pass, but nothing showed them.
Superusers now see them on the "Removed VMs" admin page (name, UUID,
owners, removed, expires) and can remove one, so a VM deleted on
purpose no longer hands its owners to a later VM with the same UUID.
2026-10-08 19:07:02 +03:00
catborise
c2fea2aa39 feat(accounts): failed logins lock a user for the address they come from
Nothing limited failed logins: a password could be guessed at the speed
the server answers. django-axes (8.3.1, Django 5.2, Python 3.10-3.13)
now counts them.

- A user is locked for the address the failed logins come from
  (username and IP together), so an attacker cannot lock someone out
  from elsewhere and users behind one NAT address do not share a lock.
  A successful login resets the count. axes sits in front of every
  authentication: the login page with or without OTP, LDAP and the API.
- The number of failed logins (default 5) and the lock time in minutes
  (default 15) are on the Settings page (LOGIN_FAILURE_LIMIT,
  LOGIN_LOCKOUT_MINUTES, added by migration appsettings.0014) and apply
  at once; an invalid value falls back to the default. Unlock with
  "manage.py axes_reset_username <username>".
- Behind the bundled nginx every request comes from 127.0.0.1; the
  client address is read from X-Real-IP, which nginx sets, but only for
  requests from a loopback address or from LOGIN_TRUSTED_PROXIES, so a
  forged header does not escape a lock.

settings.py.template gets the app, middleware, backend and AXES_*
settings; README tells existing installations what to copy. Tests that
call client.login now pass a request, which the axes backend needs.
The new tests fail with axes disabled.
2026-10-06 11:05:03 +03:00
catborise
940545c2c4 fix(admin): saving a user returns to ?next= only on this site
The user edit page redirected to its ?next= parameter after saving,
whatever it held: a link to the edit page with next=https://other.site
sent the administrator who saved the form to that site (CodeQL
py/url-redirection). The account page links there with a next of this
site.

next is now followed only when url_has_allowed_host_and_scheme accepts
it for this host, as user_instance_delete already does; otherwise the
user list. The test fails on the previous code for an absolute URL, a
scheme-relative one and a backslash variant.
2026-10-06 08:00:13 +03:00
catborise
2295673203 fix: every icon of the templates comes from the local icon cache
django-bootstrap-icons serves icons from static/icon_cache and fetches a
missing one from the CDN while the page renders; a server without
internet access shows an error text instead of the icon.

- copy (Clone on the instance lists), envelope-open ("Lost OTP?" page)
  and save (VM settings, network page) were not cached; they are now,
  fetched with django-bootstrap-icons itself.
- The user and group lists asked for 'exclamation-triangle ' with a
  trailing space, an icon that does not exist; the warning icon never
  showed.

A test checks that every {% bs_icon %} in the templates has its cache
file; it fails on the previous files.
2026-10-05 20:20:57 +03:00
catborise
405e6f1445 fix(admin): a new user's password reaches the database only hashed
The admin page that creates a user saved the form first, which wrote
the user with the raw password in the password column, and hashed it
with a second save afterwards. The raw password was in the database,
and in its journal and any copy taken meanwhile, and stayed there if
anything failed between the two writes.

- UserCreateForm hashes the password before the first save; groups
  and permissions are saved as before.
- The form applies AUTH_PASSWORD_VALIDATORS, after the user fields are
  set (so the similarity check sees the new username), as the password
  change forms already did. The settings template configures no
  validators, so nothing changes unless an installation sets them.

The tests record the SQL parameters of the request: the previous code
wrote the raw password in the INSERT; it also accepted passwords that
configured validators reject.
2026-10-05 18:39:33 +03:00
catborise
99dabbdcec fix(accounts): migrate no longer overrides the change-password permission
SHOW_PROFILE_EDIT_PASSWORD was replaced in 2020 by the change_password
permission, settable per user or group. A post_migrate hook applied the
old setting to all users so existing installs kept their behavior, and
asked to remove the setting afterwards; but the settings template still
set it to True. Every migrate, so every upgrade, therefore granted the
permission to all users again and undid an admin's per-user or
per-group choice (with False it would have revoked it from everyone).

- Migration accounts.0008 applies the setting one last time, if a
  settings.py still has it; the post_migrate hook is gone.
- New users get the permission when they are created (any path,
  including LDAP); the admin user form ticks it and saves the admin's
  choice afterwards.
- The template no longer sets SHOW_PROFILE_EDIT_PASSWORD; a check
  (accounts.W001) asks to remove it from existing settings, and the
  README upgrade notes say so.

The test that removes the permission and runs migrate fails on the
previous code. An upgrade from master with users was simulated: the
setting is applied once, and a permission removed afterwards stays
removed through the next migrate.
2026-10-04 20:26:53 +03:00
catborise
b04f656d2b ci: replace super-linter with ruff
Super-linter ran from the unpinned :latest image and, because of
branches-ignore: [master], never on pull requests to master. Ruff now
checks syntax errors and pyflakes rules (E9, F) on every push and PR.

Fixes the existing findings: unused imports and variables, an unused
duplicate import in instances/tests.py, and the star import in
accounts/views.py. settings-dev.py keeps its star import of the base
settings.
2026-10-04 01:08:11 +03:00
catborise
6dabd69445 fix(accounts): first-login password change is stored, not in the session
The forced change of the generated admin password was a session flag
set at login when the password still matched data/admin_password. A
new session after the file was gone bypassed it.

- UserAttributes.must_change_password (migration 0007) holds it; the
  admin created with a generated password gets it, and a password
  change clears it. ForcePasswordChangeMiddleware reads it.
- A system check (accounts.E001) stops the server unless the middleware
  follows AuthenticationMiddleware; the README has the settings change.
- If the generated password cannot be stored privately, provisioning
  stops without printing it and without creating the admin (one
  transaction for the user and its attributes).
- The admin is provisioned on any real migrate run while no user
  exists, so running migrate again after a failure creates it; flush
  (plan=None) and rollbacks of accounts are skipped.
- The post_migrate receivers check the migration state for the models
  they use, so a targeted migrate on a fresh database (e.g. migrate
  appsettings) no longer fails with 'no such table'.
2026-10-04 01:08:11 +03:00
catborise
cf1cde376b fix: require POST for user block/unblock and OTP email, flag console cookie
- 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.
2026-10-02 22:44:00 +03:00
catborise
708b986e8e feat(security): apply Codex review hardening to console tokens and superuser authorization 2026-09-27 11:30:03 +03:00
catborise
c31ed28042 test: expand unit test coverage across admin, accounts, vrtManager, logs, appsettings, and datasource 2026-09-25 11:26:53 +03:00
catborise
58e215f755
Merge pull request #609 from catborise/master
show last login info for users
2023-10-06 16:31:10 +03:00
catborise
e47d909e41 show last login time of users 2023-10-06 16:15:35 +03:00
Amélie Krejčí
1b2b3a3bce
Get UserAttributes object using get_or_create
This is done to automatically create the UserAttributes object in case LDAP User Backend didn't create it.
2023-09-23 09:52:48 +02:00
catborise
b47ec2e8f9 bootstrap icon conversion fixes 2023-08-11 09:40:38 +03:00
Emre Serdengeçti
1cbdf76df6
logger updates (#31)
* Log for failed login attempts

* Logger configuration for logging to file

* interface fixes

* login log fix, added logged in too

* bootstrap icons setup

* font-awesome icons replaced with bootstrap icons

* replaced i-tags with django_bootstrap_icons

* removed icons library from project

* bug fix

---------

Co-authored-by: catborise <catborise@gmail.com>
2023-08-09 09:20:18 +03:00
cserma
ad9f1db643 added filter for logs 2023-04-13 12:25:42 +03:00
catborise
a1eab70e2d reorg imports and black format 2022-11-02 16:05:41 +03:00
catborise
217e106c8b format python code with black 2022-11-02 08:54:35 +03:00
catborise
97acbd9843 fix typo error 2022-09-05 15:36:37 +03:00
Info-IIG
de2dce7573 Added Technicians group 2022-06-14 15:10:33 +02:00
catborise
073b7b6717
Bootstrap5 (#17)
* Bootstrap5 migration
2021-07-07 14:12:38 +03:00
catborise
d9c23291de rearrange search functionality 2021-06-10 15:17:53 +03:00
catborise
610efd5520 add host name for logs beside others 2021-05-31 11:39:09 +03:00
catborise
508e3609be lint with black python. convert f style strings to old one. some small fixes 2020-11-05 12:34:31 +03:00
Real-Gecko
5a19f0c949 OTP improvements 2020-10-19 14:26:08 +06:00
Real-Gecko
01043ba8a8 Templates cleanup 2020-10-15 20:18:45 +06:00
Real-Gecko
1b3fd9d05e replaced ugettext_lazy with gettext_lazy 2020-10-14 18:27:57 +06:00
Real-Gecko
5172a9f619 Accounts app improvements and tests 2020-10-14 14:25:05 +03:00
catborise
922a8e62d1 fix some linter warnings 2020-09-25 15:57:17 +03:00
catborise
372ba5a0f2 fix create user error 2020-08-21 20:53:16 +03:00
catborise
de63d9746d add change other user password ability to superusers 2020-07-23 13:16:39 +03:00
Real-Gecko
1a3cc36ada Moved admin/common/form.html to project templates 2020-06-16 18:04:37 +06:00
Real-Gecko
2951d0b035 Cleaned up UserAttributes model 2020-06-16 11:26:58 +06:00
Real-Gecko
68f7376d15 Moved confirm_delete.html to project templates 2020-06-15 16:30:27 +06:00
Real-Gecko
354163fa1d Added pagination to logs list template 2020-06-15 15:48:32 +06:00
Real-Gecko
e4e86ed576 replaced django-fa with django-icons 2020-06-15 14:46:13 +06:00
catborise
b7fc8a5fea Language change activation. Fix typos and add new translations 2020-06-10 15:16:58 +03:00
catborise
7bb6bd310b update locale files and TR translations. 2020-06-10 11:15:14 +03:00
catborise
21fcb8cd64 workaround for django 2.2 bug related with '0011_update_proxy_permissions' migration 2020-06-09 11:44:29 +03:00
catborise
e46bb99b3b fix typos and rearrange imports & add new lines EOF 2020-06-04 15:22:55 +03:00
catborise
e21f423bcf Convert LOGS_PER_PAGE from static settings to appsettings 2020-06-04 14:35:34 +03:00
catborise
8bafaa8720 add scope to th tags for screen readers 2020-06-04 12:04:46 +03:00
catborise
0e5840498e bootstrap 4.5 & Bootswatch Themes 2020-06-04 11:33:25 +03:00
Real-Gecko
10b6f88dbb Added coverage.py support 2020-05-29 19:37:49 +06:00