Commit Graph
99 Commits
Author SHA1 Message Date
twothatIT 276f4214a7 chore(release): bump version to 1.4.2 2026-08-19 11:22:08 +02:00
twothatIT a8ed87faa9 feat(customer): show NetBird API token renewal/expiry date
Displays when the per-customer token was last (re-)issued and its
computed expiry (365 days from renewal) on the Auto-Updates card, so it's
visible at a glance without checking the database.
2026-08-19 11:21:55 +02:00
twothatIT 1bc768151a feat(customer): allow changing an already-registered NetBird API token
The per-customer Auto-Updates card only showed the token input when no
token was registered yet, so there was no way to replace one once set
(e.g. rotating it manually). Adds a "Change token" link that reveals the
same input/save flow at any time.
2026-08-19 11:21:10 +02:00
twothatIT 1e05ddfe69 chore(release): bump version to 1.4.1 2026-08-19 11:17:38 +02:00
twothatIT e9afdb226c feat(netbird): auto-renew NetBird client-update API tokens before expiry
The tokens captured for central update control expire (NetBird enforces a
365-day max on Personal Access Tokens), and nothing was renewing them —
discovered that the 47 tokens created via the browser-automation bulk
onboarding were actually only 30-day tokens (left the UI's default
expiration field untouched instead of setting 365), so they would have
silently broken automatic-update control next month with no warning.

- Bumped all existing tokens to fresh 365-day ones via the API (using the
  still-valid old token as bearer — no re-login needed)
- Added netbird_api_token_renewed_at per deployment
- Scheduler now checks daily and renews any token older than 300 days
  automatically, so this never needs to be done by hand again
2026-08-19 11:15:49 +02:00
twothatIT 8a84e60a27 fix(validators): restore SystemConfigUpdate validators broken by misplaced classes
The two new NetbirdClientAutoUpdatePayload/NetbirdApiTokenPayload classes
were accidentally inserted between two of SystemConfigUpdate's own
@field_validator methods, which closed that class early — the ssl_mode,
base_domain, npm_api_url, and admin_email validators ended up attached to
NetbirdApiTokenPayload instead, whose fields don't exist. Pydantic raised
PydanticUserError on import, crash-looping the whole appliance container.
Moved the two new classes after all of SystemConfigUpdate's validators.
2026-08-19 09:35:12 +02:00
twothatIT a91a95825a chore(release): bump version to 1.4.0 2026-08-19 09:29:47 +02:00
twothatIT 6d333223a8 feat(netbird): central control of client Automatic Updates across all customers
Lets the MSP admin control NetBird's own "Settings > Clients > Automatic
Updates" feature (client/peer auto-update, v0.61.0+) for every customer from
one place, instead of logging into each customer's dashboard individually.

- New deployments automatically capture a Personal Access Token during the
  existing /api/setup bootstrap call (create_pat=true), requiring
  NB_SETUP_PAT_ENABLED=true on the management container (now set by default
  in the compose template). Token is encrypted at rest per customer.
- Existing customers (deployed before this existed) can have a token pasted
  in manually from their own dashboard — verified before being stored.
- Settings > Docker Images: master default (version + force-update toggle)
  plus "Apply to All Customers" which pushes it to everyone with a token.
- Customer detail page: shows the customer's live current setting (read
  from their NetBird API, not cached) with per-customer override or
  "sync from default".
- New app/services/netbird_client_update_service.py wraps the customer's
  NetBird Management API (GET/PUT /api/accounts) for this.
2026-08-19 09:24:13 +02:00
twothatIT 51fbd44809 chore(release): bump version to 1.3.0 2026-08-19 09:12:08 +02:00
twothatIT e53539231e fix(monitoring): repair silent-false-positive update badge + auto-update scheduling
Customer container status checks looked up containers by an exact expected
name. When a docker compose recreate got interrupted (e.g. a hung command
previously killed the whole update-all batch on timeout), Compose could leave
the old container renamed with a random hash prefix instead of removed. The
exact-name lookup then found nothing, returned None, and that silently
counted as "up to date" (green "Aktuell") instead of surfacing as unknown —
affecting 5 customers on the appliance whose containers were actually still
running under orphaned names.

- _run_cmd no longer raises on subprocess timeout, so one stuck customer
  can't abort the rest of a batch update
- repair_container_naming() self-heals orphaned hash-renamed containers by
  renaming them back before every status check and before recreate
- update-all loop now catches per-customer exceptions instead of aborting
- status responses expose "unknown" separately from "needs_update" so the UI
  shows a distinct grey badge instead of a false-positive green one
- new settings: automatic daily update check (on/off + time), with an
  independent toggle for whether it also auto-recreates customer containers
2026-08-19 09:10:29 +02:00
twothatITandClaude Sonnet 5 0e38b8083c docs(readme): update Updates section and API reference to match current app
- Document the one-click background update with live progress as the
  recommended path (manual git pull/compose is now the fallback)
- Add sortable customer columns feature
- Add missing API endpoints (settings/version, settings/update, update/status,
  sort_by/sort_order on GET /customers)
- Add missing Performance Tuning entry to table of contents
- De-pin the "Built With AI" model name so it doesn't go stale

Co-Authored-By: Claude Sonnet 5 <[email protected]>
2026-07-23 15:32:54 +02:00
twothatITandClaude Sonnet 5 0e2b292408 feat(customers): sortable table columns + default ascending ID order
- Customer list now defaults to ascending ID order instead of newest-first,
  so the table starts at customer #1 instead of the highest ID
- Add sort_by/sort_order query params to GET /customers (whitelisted column
  map to prevent SQL injection via arbitrary column names)
- Make ID/Name/Subdomain/Status/Devices/Created column headers clickable,
  toggling asc/desc with a visual arrow indicator

Co-Authored-By: Claude Sonnet 5 <[email protected]>
2026-07-23 15:16:31 +02:00
twothatITandClaude Sonnet 5 a5988af6a3 fix(update): stop blocking event loop during rebuild + fix infinite spinner
The update endpoint ran the entire git pull + docker build (up to 10 min)
synchronously inside the request handler, blocking the whole server for
everyone while it ran. Separately, the frontend spinner was only hidden on
error, never on success, so it spun forever even when the update worked.

- Run the update in a background thread; the request returns immediately
- Add GET /settings/update/status for progress polling (backup/pull/build/restart)
- Frontend polls status, then waits for the app to come back after the
  container restart, and shows a clear done/timeout message instead of an
  endless spinner

Co-Authored-By: Claude Sonnet 5 <[email protected]>
2026-07-23 15:09:42 +02:00
twothatITandClaude Sonnet 5 c5189d88fe perf(npm): cache NPM JWT instead of re-authenticating on every API call
Every NPM helper (proxy host create/update/delete, streams, certs) did a
fresh POST /api/tokens login before its actual request, adding an avoidable
round-trip to every proxy/stream operation.

- Cache the JWT per (api_url, email), sized from its 'exp' claim
- Transparently re-authenticate and retry once on a 401 (e.g. after an NPM
  restart invalidates a cached token), so a stale cache entry can't cause a
  hard failure

Co-Authored-By: Claude Sonnet 5 <[email protected]>
2026-07-23 14:51:23 +02:00
twothatITandClaude Sonnet 5 ac843da4ca perf(monitoring): stop blocking event loop with synchronous Docker calls
Customer search and detail loads were intermittently slow because every
customer-table render (including each search keystroke) triggered
/monitoring/customers/local-update-status, which looped synchronously over
all customers doing blocking `docker inspect` subprocess calls on the event
loop — stalling all other in-flight requests, including search itself.

- Offload per-service image/container inspection to the thread pool and run
  checks concurrently instead of sequentially (image_service, docker_service)
- Reuse a single Docker SDK client instead of reconnecting per customer
- Cache local-update-status results for 20s since the underlying data only
  changes after an image pull, not on every keystroke
- Parallelize /monitoring/customers container status lookups

Co-Authored-By: Claude Sonnet 5 <[email protected]>
2026-07-23 14:44:56 +02:00
twothatITandClaude Sonnet 4.6 f6b7eb2dae fix(npm): add gRPC read/send timeouts to proxy host location blocks
Adds grpc_read_timeout 3600s and grpc_send_timeout 3600s to both
ManagementService and SignalExchange location blocks to prevent
long-lived gRPC connections from being dropped by Nginx.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
2026-05-06 12:01:14 +02:00
twothatITandClaude Sonnet 4.6 8ede0f0a3c fix(deploy): fix redeploy button broken by JSON.stringify double quotes
Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
2026-03-10 22:13:23 +01:00
twothatITandClaude Sonnet 4.6 8040973227 fix(deploy): fix redeploy button broken by JSON.stringify double quotes
JSON.stringify('Name') produces "Name" with double quotes which breaks
the onclick attribute. Use data-customer-name attribute instead and
read it via this.dataset.customerName to avoid quoting issues.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
2026-03-10 22:13:06 +01:00
twothatITandClaude Sonnet 4.6 3cdc82f919 fix(deploy): show customer name in redeploy modal instead of ID
Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
2026-03-10 22:08:35 +01:00
twothatITandClaude Sonnet 4.6 40595fc381 fix(deploy): show customer name in redeploy modal instead of ID
The modal was showing '#2' instead of the customer name when opened
from the customer detail view, because the dashboard table row was
not visible. Now the name is passed directly from the button's onclick
context where data.name is already available.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
2026-03-10 22:08:17 +01:00
twothatITandClaude Sonnet 4.6 9ace554427 fix(cache): bust browser cache for JS and i18n files after updates
Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
2026-03-10 21:57:36 +01:00
twothatITandClaude Sonnet 4.6 f48c851ef0 fix(cache): bust browser cache for JS and i18n files after updates
After a container update, browsers serve stale app.js and lang/*.json
from cache, causing old UI code and missing translations to appear.

- serve_index() now reads the git commit hash and injects ?v=COMMIT into
  all static asset URLs (app.js, i18n.js, styles.css) in index.html
- window.STATIC_VERSION is injected into the page so i18n.js can append
  the same version to lang/*.json fetch calls
- index.html itself is served with Cache-Control: no-cache so the browser
  always revalidates it and picks up new asset URLs on next load

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
2026-03-10 21:57:18 +01:00
twothatITandClaude Sonnet 4.6 7d694c62bd feat(deploy): redeploy dialog with keep-data or fresh-deploy option
Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
2026-03-10 21:34:26 +01:00
twothatITandClaude Sonnet 4.6 d1bb6a633e feat(deploy): redeploy dialog with keep-data or fresh-deploy option
Add a confirmation modal when clicking Redeploy that lets the user choose:
- Keep Data: containers are recreated without wiping the instance directory.
  NetBird database, peer configs, and encryption keys are preserved.
- Fresh Deploy: full undeploy (removes all data) then redeploy from scratch.

Backend changes:
- POST /customers/{id}/deploy accepts keep_data query param (default false)
- When keep_data=true, undeploy_customer is skipped entirely
- deploy_customer now reuses existing npm_proxy_id/stream_id when the
  deployment record is still present (avoids duplicate NPM proxy entries)
- DNS record creation is skipped on keep_data redeploy (already exists)

Frontend changes:
- customerAction('deploy') opens the redeploy modal instead of calling API
- showRedeployModal(id) shows the two-option confirmation card dialog
- confirmRedeploy(keepData) calls the API with the correct parameter
- i18n keys added in en.json and de.json

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
2026-03-10 21:34:12 +01:00
twothatITandClaude Sonnet 4.6 b39a502257 fix(images): use Docker Registry v2 API for correct digest comparison
Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
2026-03-02 15:15:22 +01:00
twothatITandClaude Sonnet 4.6 dee07d7b8e fix(images): use Docker Registry v2 API for correct digest comparison
The Docker Hub REST API returns per-platform manifest digests, while
docker image inspect RepoDigests stores the manifest list digest.
These two values never match, causing update_available to always be
True even after a fresh pull.

Fix: use registry-1.docker.io/v2/{name}/manifests/{tag} with anonymous
auth and read the Docker-Content-Digest response header, which is the
exact same digest that docker pull stores in RepoDigests.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
2026-03-02 15:15:05 +01:00
twothatITandClaude Sonnet 4.6 351caec893 docs: update README with all current features and correct settings
Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
2026-02-25 08:34:29 +01:00
twothatITandClaude Sonnet 4.6 dd04408dc2 docs: update README with all current features and correct settings
- Add NetBird Container Updates section (digest check, pull, bulk update)
- Add update indicators, dark mode, LDAP/AD, Windows DNS to features
- Correct Settings table: add all tabs, remove incorrect Monitoring entry
- Split Docker Images tab out of System tab
- Add sudo install note for fresh Debian minimal
- Rewrite Updating NetBird Images section with new UI-based workflow
- Add new monitoring/image API endpoints to API docs

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
2026-02-25 08:33:20 +01:00
twothatITandClaude Sonnet 4.6 6373722c2b chore(release): merge unstable → main for beta-1.0
Promotes alpha-1.25 to beta-1.0 (stable branch).

Highlights:
- NetBird container update management (check / pull / update per customer + bulk)
- Visual update badges on dashboard and customer detail
- Dark mode toggle with localStorage persistence
- User role management for Azure AD / LDAP users
- Branding logo persistence across updates (Docker volume)
- Favicon, NPM stream removal, MFA (TOTP)
- LDAP / Active Directory and Azure AD SSO
- Windows DNS integration
- Settings restructure and Git branch dropdown

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
2026-02-24 21:58:24 +01:00
twothatITandClaude Sonnet 4.6 27c8e4889c feat(updates): visual update indicators, progress feedback, settings pull
- Dashboard: update badge (orange) injected lazily into customer Status cell
  after table renders via GET /monitoring/customers/local-update-status
  (local-only Docker inspect, no Hub call on every page load)
- Customer detail Deployment tab: "Update Images" button with spinner,
  shows success/error inline without page reload
- Monitoring Update All: now synchronous + sequential (one customer at a
  time), shows live spinner + per-customer results table on completion
- Settings > Docker Images: "Pull from Docker Hub" button with spinner
  and inline status message
- /monitoring/customers/local-update-status: new lightweight endpoint
  (no network, pure local Docker inspect)
- /monitoring/customers/update-all: removed BackgroundTasks, now awaits
  each customer sequentially and returns detailed per-customer results

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
2026-02-24 21:25:33 +01:00
twothatITandClaude Sonnet 4.6 848ead0b2c feat(updates): NetBird container image update management
- New image_service.py: Docker Hub digest check (no pull), local digest/ID
  comparison, pull_all_images, per-customer container image status, and
  update_customer_containers (docker compose up -d, data-safe)
- Monitoring endpoints: GET /images/check (hub vs local + per-customer
  needs_update), POST /images/pull (background), POST /customers/update-all
- Deployment endpoint: POST /{id}/update-images (single-customer update)
- Monitoring page: "NetBird Container Updates" card with Check / Pull / Update
  All buttons; image status table and per-customer update table with inline
  update buttons
- i18n: added keys in en.json and de.json

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
2026-02-24 21:01:56 +01:00
twothatIT c3ab7a5a67 fix(api): correct extraction of commit date from gitea branches api 2026-02-22 22:57:07 +01:00
twothatIT b955e4f464 feat(ui): settings menu restructure, git branch dropdown, and repo cleanup 2026-02-22 21:29:30 +01:00
twothatIT 831564762b feat(ui): clean vertical settings menu and improved version formatting 2026-02-22 16:07:08 +01:00
twothatIT 3f177a6993 fix(updater): add --rm to helper container to remove it after use 2026-02-22 15:58:18 +01:00
twothatIT ea4afbd6ca alpha-1.8: final test with privileged 2026-02-22 15:49:44 +01:00
twothatIT 95ec6765c1 fix(updater): add --privileged to helper container to bypass user namespace restrictions 2026-02-22 15:46:09 +01:00
twothatIT c40b7d3bc6 alpha-1.7: final test 2026-02-22 15:39:18 +01:00
twothatIT 525b056b91 fix(updater): add :z flag to docker volumes for SELinux 2026-02-22 15:33:42 +01:00
twothatIT 6bc11d4c5e alpha-1.6: test final update 2026-02-22 15:25:50 +01:00
twothatIT e0aa51bac3 fix(updater): remove log redirection from helper to avoid nonexistent dir error 2026-02-22 15:22:43 +01:00
twothatIT 94d0b989d0 alpha-1.5: trigger update 2026-02-22 15:16:20 +01:00
twothatIT 2780b065d2 fix(updater): add force-recreate and logging to helper container 2026-02-22 15:14:23 +01:00
twothatIT ef691a4308 alpha-1.4: test helper-container update 2026-02-22 14:51:43 +01:00
twothatIT 0fe68cc6df fix: use helper container for self-update (survives container restart) 2026-02-22 14:50:00 +01:00
twothatIT 314393d61a alpha-1.3: update test 2026-02-22 14:42:53 +01:00
twothatIT a9fc549cec fix: correct docker compose project name and target only app service for update 2026-02-22 14:40:07 +01:00
twothatIT 41bbd6676b alpha-1.2: test update button 2026-02-22 14:34:46 +01:00
twothatIT fc9589b6f9 fix: trigger_update setzt GIT_TAG/GIT_COMMIT env vars für docker compose rebuild 2026-02-22 14:32:08 +01:00
twothatIT 6d2251bcf5 alpha-1.1: Login-Page Version-Marker hinzugefügt 2026-02-22 14:25:44 +01:00
twothatIT fd79065519 feat: Git-Tag-basierte Versionierung (Alpha/Beta/Release statt Commit-Hash) 2026-02-22 14:12:32 +01:00
twothatITandClaude Sonnet 4.6 e9e2e67991 feat: add Windows DNS, LDAP, and Update settings tabs to UI
- Settings page: 3 new tabs (Windows DNS, LDAP / AD, Updates)
- Windows DNS tab: enable toggle, server/zone/username/password/record-IP,
  save + test connection button
- LDAP tab: enable toggle, server/port/SSL/bind-DN/password/base-DN/
  user-filter/group-DN, save + test connection button
- Updates tab: current + latest version info card with update-available
  badge, one-click update button (git pull + rebuild), git repo/branch/
  token settings form
- Azure AD tab: added Allowed Group Object ID field
- app.js: settings-dns-form, settings-ldap-form, settings-git-form
  submit handlers; testDnsConnection(), testLdapConnection(),
  loadVersionInfo(), triggerUpdate() functions; loadSettings() extended
  for all new fields
- en.json: all new translation keys
- de.json: complete German translation (was mostly empty before)

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
2026-02-21 21:48:15 +01:00
twothatITandClaude Sonnet 4.6 f92cdfbbef feat: add update management system with version check and one-click update
- Bake version info (commit, branch, date) into /app/version.json at build time
  via Docker ARG GIT_COMMIT/GIT_BRANCH/GIT_COMMIT_DATE
- Mount source directory as /app-source for in-container git operations
- Add git config safe.directory for /app-source (ownership mismatch fix)
- Add SystemConfig fields: git_repo_url, git_branch, git_token_encrypted
- Add DB migrations for the three new columns
- Add git_token encryption in update_settings() handler
- New endpoints:
    GET  /api/settings/version  — current version + latest from Gitea API
    POST /api/settings/update   — DB backup + git pull + docker compose rebuild
- New service: app/services/update_service.py
    get_current_version()  — reads /app/version.json
    check_for_updates()    — queries Gitea API for latest commit on branch
    backup_database()      — timestamped SQLite copy to /app/backups/
    trigger_update()       — git pull + fire-and-forget compose rebuild
- New script: update.sh — SSH-based manual update with health check

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
2026-02-21 21:33:43 +01:00
twothatITandClaude Sonnet 4.6 7793ca3666 feat: add Windows DNS integration and LDAP/AD authentication
Windows DNS (WinRM):
- New dns_service.py: create/delete A-records via PowerShell over WinRM (NTLM)
- Idempotent create (removes existing record first), graceful delete
- DNS failures are non-fatal — deployment continues, error logged
- test-dns endpoint: GET /api/settings/test-dns
- Integrated into deploy_customer() and undeploy_customer()

LDAP / Active Directory auth:
- New ldap_service.py: service-account bind + user search + user bind (ldap3)
- Optional AD group restriction via ldap_group_dn
- Login flow: LDAP first → local fallback (prevents admin lockout)
- LDAP users auto-created with auth_provider="ldap" and role="viewer"
- test-ldap endpoint: GET /api/settings/test-ldap
- reset-password/reset-mfa guards extended to block LDAP users

All credentials (dns_password, ldap_bind_password) encrypted with Fernet.
New DB columns added via backwards-compatible migrations.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
2026-02-21 21:06:51 +01:00
twothatITandClaude Sonnet 4.6 bc9aa6624f security: fix CORS wildcard, add security headers, enforce role check, sanitize errors
- CORS: remove allow_origins=["*"]; restrict to ALLOWED_ORIGINS env var
  (comma-separated list); default is no cross-origin access. Removed
  allow_credentials=True and method/header wildcards.
- Security headers middleware: add X-Content-Type-Options, X-Frame-Options,
  X-XSS-Protection, Referrer-Policy, Strict-Transport-Security to all
  responses.
- users.py: guard POST /api/users so only users with role="admin" can
  create new accounts (prevents privilege escalation by non-admin roles).
- auth.py: remove raw exception detail from Azure AD 500 response to
  avoid leaking internal error messages / stack traces to clients.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
2026-02-19 00:39:43 +01:00
twothatITandClaude Sonnet 4.6 1bbe4904a7 fix: resolve circular import, async blocking, SELinux and delete timeout issues
- Extract shared SlowAPI limiter to app/limiter.py to break circular
  import between app.main and app.routers.auth
- Seed default SystemConfig row (id=1) on first DB init so settings
  page works out of the box
- Make all docker_service.compose_* functions async (run_in_executor)
  so long docker pulls/stops no longer block the async event loop
- Propagate async to netbird_service stop/start/restart and await
  callers in deployments router
- Move customer delete to BackgroundTasks so the HTTP response returns
  immediately and avoids frontend "Network error" on slow machines
- docker-compose: add :z SELinux labels, mount docker.sock directly,
  add security_opt label:disable for socket access, extra_hosts for
  host.docker.internal, enable DELETE/VOLUMES on socket proxy
- npm_service: auto-detect outbound host IP via UDP socket when
  HOST_IP env var is not set

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
2026-02-19 00:30:25 +01:00
twothatITandClaude Sonnet 4.6 0ac15e4db9 rename: CLAUDE_CODE_SPEC.md -> ProjectAISpec.md
Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
2026-02-18 22:39:39 +01:00
twothatIT c00b52df83 Add Project Spec for AI 2026-02-18 22:27:55 +01:00
twothatIT 72bad11129 security: apply four immediate security fixes
Fix #1 - SECRET_KEY startup validation (config.py, .env):
- App refuses to start if SECRET_KEY is missing, shorter than 32 chars,
  or matches a known insecure default value
- .env: replaced hardcoded test key with placeholder + generation hint

Fix #2 - Docker socket proxy (docker-compose.yml):
- Add tecnativa/docker-socket-proxy sidecar
- Only expose required Docker API endpoints (CONTAINERS, IMAGES,
  NETWORKS, POST, EXEC); dangerous endpoints explicitly blocked
- Remove direct /var/run/docker.sock mount from main container
- Route Docker API via DOCKER_HOST=tcp://docker-socket-proxy:2375

Fix #3 - Azure AD group whitelist (auth.py, models.py, validators.py):
- New azure_allowed_group_id field in SystemConfig
- After token exchange, verify group membership via Graph API /me/memberOf
- Deny login with HTTP 403 if user is not in the required group
- New Azure AD users now get role 'viewer' instead of 'admin'

Fix #4 - Rate limiting on login (main.py, auth.py, requirements.txt):
- Add slowapi==0.1.9 dependency
- Initialize SlowAPI limiter in main.py with 429 exception handler
- Apply 10 requests/minute limit per IP on /login and /mfa/verify
2026-02-18 21:28:49 +01:00
twothatIT 2713e67259 Deutsch korrektur 2026-02-09 15:55:01 +01:00
twothatIT 40456bfaba Deutsch korrigiert 2026-02-09 15:53:14 +01:00
twothatITandClaude Opus 4.6 c7fc4758e3 Add SSL certificate mode: Let's Encrypt or Wildcard per NPM
Settings > NPM Integration now allows choosing between per-customer
Let's Encrypt certificates (default) or a shared wildcard certificate
already uploaded in NPM. Includes backend, frontend UI, and i18n support.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
2026-02-09 00:01:28 +01:00
twothatITandClaude Opus 4.6 3d28f13054 Add TOTP-based Multi-Factor Authentication (MFA) for local users
Global MFA toggle in Security settings, QR code setup on first login,
6-digit TOTP verification on subsequent logins. Azure AD users exempt.
Admins can reset user MFA. TOTP secrets encrypted at rest with Fernet.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
2026-02-08 23:14:06 +01:00
twothatITandClaude Opus 4.6 647630ff19 Fix LE cert creation: use empty meta for NPM API compatibility
NPM's certificate creation endpoint rejects letsencrypt_agree and
letsencrypt_email in the meta field (schema validation error). The
LE email is configured globally in NPM settings. Empty meta works.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
2026-02-08 22:45:36 +01:00
twothatITandClaude Opus 4.6 78a07122be Fix NPM SSL: preserve existing cert on update, find cert by domain
Three fixes:
1. When updating existing proxy host, preserve its certificate_id
   and SSL settings instead of resetting to 0
2. Search NPM certificates by domain if proxy host has no cert
   assigned (handles manually created certs)
3. Remove invalid 'nice_name' and 'dns_challenge' from LE cert
   request payload (caused 400 error on newer NPM versions)

Co-Authored-By: Claude Opus 4.6 <[email protected]>
2026-02-08 22:38:31 +01:00
twothatITandClaude Opus 4.6 9bc48a3e94 Fix NPM: reuse existing proxy host and SSL cert on redeployment
When a proxy host already exists in NPM (domain "already in use"),
the code now finds the existing host, updates it, and requests SSL
instead of failing with an error. Also checks if the host already
has a valid certificate before requesting a new one from Let's Encrypt.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
2026-02-08 22:31:49 +01:00
twothatITandClaude Opus 4.6 27c91eee95 Fix deploy crash: use valid log status 'info' instead of 'warning'
The deployment_logs table has a CHECK constraint allowing only
'success', 'error', 'info'. Using 'warning' caused an IntegrityError
that crashed the entire deployment.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
2026-02-08 22:23:52 +01:00
twothatITandClaude Opus 4.6 6c33753ada Remove HTTP fallback that broke HTTPS deployments
The HTTP fallback (Step 9b) would rewrite all configs to HTTP when SSL
cert creation failed, but if the user then manually set up SSL in NPM
the dashboard would fail with "Unauthenticated" due to mixed content
(HTTPS page loading HTTP OAuth endpoints). Now keeps HTTPS configs and
logs a warning instead, so manual SSL setup works correctly.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
2026-02-08 22:08:08 +01:00
twothatITandClaude Opus 4.6 52e1d251b7 Fix redeployment: reuse encryption key, port, and deployment record
When redeploying a customer without undeploying first, the management
server would crash with FATAL because a new DataStoreEncryptionKey was
generated but the old database (encrypted with the old key) still
existed. Now:
- Reads existing key from management.json if present
- Reuses existing UDP port from deployment record
- Stops old containers before starting new ones
- Updates existing deployment record instead of creating duplicate

Co-Authored-By: Claude Opus 4.6 <[email protected]>
2026-02-08 21:54:53 +01:00
twothatIT c72a226a40 Lizenz Update 2026-02-08 21:35:56 +01:00
twothatITandClaude Opus 4.6 fbce6b95fd Fix Unauthenticated: use local OIDCConfigEndpoint for embedded IdP
The management container was trying to fetch its own OIDC config via
the external URL (https://domain/oauth2/.well-known/...), which creates
a circular dependency: management -> DNS -> NPM -> Caddy -> management.
This fails because the management container can't reach itself through
the external network during startup.

Changed OIDCConfigEndpoint to http://127.0.0.1:80/oauth2/... (same as
LocalAddress) so the management server accesses its own embedded IdP
directly without going through DNS/NPM/Caddy.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
2026-02-08 21:33:59 +01:00
twothatITandClaude Opus 4.6 8853087161 Fix SSL cert creation and HTTP fallback for Unauthenticated error
- Create NPM proxy host WITHOUT SSL initially (ssl_forced=False),
  then request Let's Encrypt cert, then enable SSL only after cert
  is assigned. Prevents broken proxy when cert fails.
- If SSL cert creation fails, automatically fall back to HTTP mode:
  re-render management.json, dashboard.env, relay.env with http://
  URLs and recreate containers so dashboard login works.
- Better error logging in _request_ssl with specific timeout hints.
- Use template variables for relay WebSocket protocol (rels/rel)
  instead of hardcoded rels:// in management.json.j2 and relay.env.j2.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
2026-02-08 21:18:37 +01:00
twothatITandClaude Opus 4.6 6d42e583d6 Fix NPM forwarding: use HOST_IP env var instead of socket detection
Socket detection inside Docker returns the container IP (172.18.0.x),
not the host IP. Now:
- install.sh detects host IP via hostname -I and stores in .env
- docker-compose.yml passes HOST_IP to the container
- npm_service.py reads HOST_IP from environment
- Increased SSL cert timeout to 120s (LE validation is slow)
- Added better logging for SSL cert creation/assignment
- README updated with HOST_IP in .env example

Co-Authored-By: Claude Opus 4.6 <[email protected]>
2026-02-08 21:00:29 +01:00
twothatITandClaude Opus 4.6 b56f0eb8a4 Fix NPM forward host: use real host IP instead of Docker gateway
- npm_service._get_forward_host() now detects the actual host IP via
  UDP socket (works inside Docker containers) instead of using
  172.17.0.1 Docker gateway which NPM can't reach
- install.sh uses hostname -I for NPM forward host
- Removed npm_api_url parameter from _get_forward_host()

Co-Authored-By: Claude Opus 4.6 <[email protected]>
2026-02-08 20:45:01 +01:00
twothatITandClaude Opus 4.6 55e2c3b80b Fix install.sh: copy .git directory for update support via git pull
Changed cp -r ./* to cp -a . so hidden files (.git) are included
when copying to the install directory. Without this, git pull fails
in /opt/netbird-msp because it's not a git repository.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
2026-02-08 20:21:33 +01:00
twothatITandClaude Opus 4.6 835f3ed40e Add MSP Appliance domain with NPM proxy host + Let's Encrypt during install
- New optional question in Step 4: MSP Appliance domain (e.g. msp.example.com)
- After app startup: auto-creates NPM proxy host forwarding to host IP:8000
- Requests Let's Encrypt SSL cert and assigns it to the proxy host
- Shows HTTPS URL in completion summary when domain is configured

Co-Authored-By: Claude Opus 4.6 <[email protected]>
2026-02-08 20:15:20 +01:00
twothatIT 9d7e12c9df install.sh fix 2026-02-08 20:04:45 +01:00
twothatITandClaude Opus 4.6 db878ff35d Fix NPM integration: correct forward host, SSL, and add UDP stream
- Forward proxy to host IP + dashboard_port instead of container name
- Remove redundant advanced_config (Caddy handles internal routing)
- Add provider: letsencrypt to SSL certificate request
- Add NPM UDP stream creation/deletion for STUN/TURN relay ports
- Add npm_stream_id to Deployment model with migration
- Fix API docs URL in README (/api/docs)

Co-Authored-By: Claude Opus 4.6 <[email protected]>
2026-02-08 19:51:32 +01:00
twothatITandClaude Opus 4.6 af5bec8e77 Add TCP 9000+ dashboard ports to firewall config and documentation
Each customer gets TCP 9000+ID (dashboard) and UDP 3478+ID (relay).
Updated install.sh firewall section, completion summary, and README.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
2026-02-08 17:42:49 +01:00
twothatITandClaude Opus 4.6 817cb7e9bb Remove tests directory — not needed for production
Co-Authored-By: Claude Opus 4.6 <[email protected]>
2026-02-08 17:36:14 +01:00
twothatITandClaude Opus 4.6 c78c733009 Simplify install.sh system checks: remove RAM check, lower disk threshold to 50GB
Co-Authored-By: Claude Opus 4.6 <[email protected]>
2026-02-08 17:34:05 +01:00
twothatITandClaude Opus 4.6 6859530e31 Remove dev docs from tracking and add to .gitignore
Co-Authored-By: Claude Opus 4.6 <[email protected]>
2026-02-08 17:32:57 +01:00
twothatITandClaude Opus 4.6 833450b865 Add AI attribution to README
Co-Authored-By: Claude Opus 4.6 <[email protected]>
2026-02-08 17:27:26 +01:00
twothatITandClaude Opus 4.6 41ba835a99 Add i18n, branding, user management, health checks, and cleanup for deployment
- Multi-language support (EN/DE) with i18n engine and language files
- Configurable branding (name, subtitle, logo) in Settings
- Global default language and per-user language preference
- User management router with CRUD endpoints
- Customer status sync on start/stop/restart
- Health check fixes: derive status from container state, remove broken wget healthcheck
- Caddy reverse proxy and dashboard env templates for customer stacks
- Updated README with real hardware specs, prerequisites, and new features
- Removed .claude settings (JWT tokens) and build artifacts from tracking
- Updated .gitignore for .claude/ and Windows artifacts

Co-Authored-By: Claude Opus 4.6 <[email protected]>
2026-02-08 17:24:05 +01:00
twothatIT c4d68db2f4 fix 2026-02-07 23:10:59 +01:00
twothatIT 06753bd69a gub 2026-02-07 23:05:05 +01:00
twothatIT a50db95dd8 bugfixing 2026-02-07 22:55:34 +01:00
twothatIT 6646adb4a4 bugfixing 2026-02-07 22:46:39 +01:00
twothatIT ae63817172 bugfix 2026-02-07 21:41:43 +01:00
twothatIT f17ea7ddc7 bugfix 2026-02-07 21:29:16 +01:00
twothatIT a18df0018c bugfix 2026-02-07 21:13:50 +01:00
twothatIT 3d8ab57f31 update readme 2026-02-07 20:47:35 +01:00
twothatIT b70c2d2df7 url update 2026-02-07 20:46:07 +01:00
twothatIT ba9132cb67 verlauf gespeichert 2026-02-07 12:21:23 +01:00
twothatIT 42a3cc9d9f First Build alpha 0.1 2026-02-07 12:18:20 +01:00
twothatIT 29e83436b2 Interactive Installer 2026-02-07 12:00:00 +01:00
twothatIT 322ffaea62 First Project description 2026-02-07 11:44:50 +01:00
twothatIT 4a05a3e9de delet file 2026-02-07 11:28:10 +01:00
twothatIT f079bf475d Commit 1 2026-02-07 11:26:58 +01:00