- WifiPanel: revert useEffect back to useState initializer (avoids
synchronous setState in effect)
- Device detail: avoid Date.now() during render for push alert check
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Remove 7 no-op exported stubs from toast.tsx (ToastProvider, ToastViewport,
Toast, ToastTitle, ToastDescription, ToastClose, useToasts) — nothing imports them
- Remove fwFailKey variable and its Set() call from worker.go — the
firmware:check-failed Redis key was never read anywhere
- Remove unused deviceStore and credCache fields from tunnel.Manager struct
and drop corresponding parameters from NewManager(); update call site in
main.go and all test usages
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Remove unused imports: Mock, VariableDef, within, Badge, deviceGroupsApi, devicesApi
- Fix Unexpected any in AlertRulesPage catch block (use unknown + type assertion)
- Suppress react-refresh/only-export-components for getPasswordScore helper
- Add Link mock to LoginPage test and useAuth.getState() stub for navigation test
- Fix DeviceList tests to use data-testid selectors and correct empty state text
(component renders dual mobile/desktop views causing multiple-element errors)
- Remove unused container destructuring from TemplatePushWizard test
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Fix _commit_and_sync infinite recursion
- Use admin session for subnet_index allocation (bypass RLS)
- Auto-set VPN endpoint from CORS_ORIGINS hostname
- Remove server address field from VPN setup UI
- Add DELETE endpoint and button for VPN config removal
- Add wg-reload watcher for reliable config hot-reload via wg syncconf
- Add wg_status.json writer for live peer handshake status in UI
- Per-tenant SNAT for poller-to-device routing through VPN
- Restrict VPN→eth0 forwarding to Docker networks only (block exit node abuse)
- Use 10.10.0.0/16 allowed-address in RouterOS commands
- Fix structlog event= conflict (use audit=True)
- Export backup_scheduler proxy for firmware/upgrade imports
- Add SnapshotResponse interface and getSnapshot API method
- Add deviceName prop to ConfigHistorySection
- Add download handler that fetches snapshot and triggers .rsc file download
- Add Download icon button on each timeline entry with stopPropagation
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add click handlers to timeline entries to open diff viewer
- Render DiffViewer inline above timeline when snapshot selected
- Add hover state and cursor-pointer to timeline entries
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add DiffResponse interface and getDiff method to configHistoryApi
- Create DiffViewer component with unified diff rendering
- Green highlighting for added lines, red for removed lines
- Blue styling for hunk headers, loading skeleton, error state
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add ConfigChangeEntry interface and configHistoryApi.list() to api.ts
- Create ConfigHistorySection with timeline, loading skeleton, and empty state
- Poll every 60s via TanStack Query refetchInterval
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The Secret Key encoder used 26 base-30 characters which can only
represent 30^26 ≈ 2^127.58 values. Since the key is 128 bits,
~25% of generated keys silently lost their high bits during
formatting, making the Emergency Kit key unable to reconstruct
the original bytes on a new browser.
Changed KEY_CHAR_LENGTH from 26 to 27 (30^27 > 2^128). Parser
accepts both old 26-char and new 27-char keys for backward
compatibility. Format: A3-XXXXXX-XXXXXX-XXXXXX-XXXXXX-XXX
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The target input showed "8.8.8.8" as placeholder text but the actual
value was empty. Clicking Ping/Traceroute silently returned because
the empty target guard fired. Users saw the placeholder and assumed
the tool was broken.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The server-generated PDF had a placeholder for the Secret Key that was
never filled in client-side, making the Emergency Kit useless. Users
who relied on it could not recover their Secret Key on new devices.
Now generates the PDF entirely client-side via browser print dialog,
with the real Secret Key embedded. No server round-trip, key never
leaves the browser.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>