|
| 1 | +# Web UI and security |
| 2 | + |
| 3 | +Fiscguy ships optional pages for device registration, certificate upload, fiscal day control, |
| 4 | +status polling and receipts. They are off by default. |
| 5 | + |
| 6 | +## Enable |
| 7 | + |
| 8 | +```python |
| 9 | +# settings.py |
| 10 | +INSTALLED_APPS += ["django.contrib.sessions", "django.contrib.messages", "fiscguy"] |
| 11 | +FISCGUY_UI_ENABLED = True |
| 12 | +FISCGUY_ENCRYPTION_KEY = "<Fernet key>" # python -c "from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())" |
| 13 | +SESSION_COOKIE_SECURE = True |
| 14 | +CSRF_COOKIE_SECURE = True |
| 15 | + |
| 16 | +# urls.py |
| 17 | +path("fiscal/", include("fiscguy.web.urls")), |
| 18 | +``` |
| 19 | + |
| 20 | +The pages use the host's `LOGIN_URL`. Templates live under `fiscguy/` and can be overridden by |
| 21 | +placing files with the same names in your own `templates/fiscguy/` directory. |
| 22 | + |
| 23 | +## Settings |
| 24 | + |
| 25 | +| Setting | Default | Purpose | |
| 26 | +|---|---|---| |
| 27 | +| `FISCGUY_UI_ENABLED` | `False` | Turns the pages on. When off they return 404. | |
| 28 | +| `FISCGUY_PERMISSION_CLASSES` | `["rest_framework.permissions.IsAdminUser"]` | DRF permissions for every JSON endpoint. | |
| 29 | +| `FISCGUY_ACCESS_CHECK` | none | `callable(request, action) -> bool` that replaces the page permission check. | |
| 30 | +| `FISCGUY_DEVICE_QUERYSET` | none | `callable(request) -> QuerySet[Device]` limiting which devices a request can see or act on. Use it to scope devices per customer, branch or user. | |
| 31 | +| `FISCGUY_CLOSE_POLL` | `"background"` | `"client"` stops the server thread; the page (or your frontend) polls `get-status` instead. | |
| 32 | +| `FISCGUY_LOG_FDMS_PAYLOADS` | `False` | Logs FDMS request and response bodies at DEBUG. They contain buyer TINs and receipt data. | |
| 33 | +| `FISCGUY_REAUTH_MAX_AGE` | `300` | Seconds a password confirmation stays valid. | |
| 34 | +| `FISCGUY_ENCRYPTION_KEY` | derived from `SECRET_KEY` | Fernet key for certificate keys and activation keys. | |
| 35 | + |
| 36 | +## Permissions |
| 37 | + |
| 38 | +| Permission | Allows | |
| 39 | +|---|---| |
| 40 | +| `fiscguy.view_receipts` | Dashboard, device pages, receipts, status and ping | |
| 41 | +| `fiscguy.close_day` | Open and close fiscal days | |
| 42 | +| `fiscguy.manage_device` | Register devices, upload certificates, renew, sync configuration, audit log | |
| 43 | + |
| 44 | +Superusers have all three. The JSON API is staff-only by default because it can submit receipts |
| 45 | +and close days; the old behaviour of open endpoints is gone. Set `FISCGUY_PERMISSION_CLASSES` to |
| 46 | +use your own classes. |
| 47 | + |
| 48 | +## What protects the pages |
| 49 | + |
| 50 | +- Feature flag, login and a specific permission on every view. Nothing is public. |
| 51 | +- Device lookups go through `FISCGUY_DEVICE_QUERYSET`, so a guessed device or receipt ID returns 404. |
| 52 | +- Every state change is POST-only with CSRF protection. |
| 53 | +- Registering, uploading certificates and renewing certificates need the user's password again |
| 54 | + (valid for `FISCGUY_REAUTH_MAX_AGE` seconds). Switching a device between test and production |
| 55 | + deletes its history and needs the device ID typed to confirm. |
| 56 | +- Per-user throttling on registration, actions, status, ping and password confirmation. |
| 57 | +- Responses carry `Cache-Control: no-store`, `X-Frame-Options: DENY`, `Referrer-Policy: no-referrer` |
| 58 | + and a CSP that allows only same-origin scripts and styles. The templates have no inline script or style. |
| 59 | +- Keys and activation keys are write-only: never rendered back (even on a failed form), never logged, |
| 60 | + encrypted at rest. Uploads are capped at 64 KB, read in memory, validated and never written to disk. |
| 61 | +- Passphrase-protected keys, expired certificates and key/certificate mismatches are rejected. |
| 62 | +- Every register, upload, renew, open day and close day is written to `AuditLog` (user, time, device, IP). |
| 63 | + The log is read-only in the Django admin. |
| 64 | + |
| 65 | +`manage.py check` warns when `FISCGUY_ENCRYPTION_KEY` is unset (`fiscguy.W001`) and when the UI is |
| 66 | +enabled without secure cookies (`fiscguy.W002`). |
| 67 | + |
| 68 | +## Close day without a background thread |
| 69 | + |
| 70 | +With `FISCGUY_CLOSE_POLL = "client"`, `POST close-day/` returns as soon as FDMS accepts the request. |
| 71 | +Poll `GET get-status/` (API) or `devices/<id>/status/` (UI) until the day is `closed` or `close_failed`. |
| 72 | +The device page does this automatically. |
0 commit comments