diff --git a/.gitignore b/.gitignore
index 57914d1aa..dbb6d7a75 100644
--- a/.gitignore
+++ b/.gitignore
@@ -35,8 +35,8 @@ archive/
# Firmware cache (downloaded firmware files)
firmware/
-# Virtual printer (auto-generated certs and uploads)
-virtual_printer/
+# Virtual printer (auto-generated certs and uploads at repo root)
+/virtual_printer/
# IDE
.idea/
@@ -58,3 +58,6 @@ firmware/
node_modules/
data/
+
+# JWT secret file (should be in data dir, but protect project root too)
+.jwt_secret
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 80d4847ae..07719c84b 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,9 +2,116 @@
All notable changes to Bambuddy will be documented in this file.
-## [0.1.7b] - Not released
+
+## [0.1.8b] - Not released
+
+### Added
+- **Windows Portable Launcher** (contributed by nmori):
+ - New `start_bambuddy.bat` for Windows users - double-click to run, no installation required
+ - Automatically downloads Python 3.13 and Node.js 22 on first run (portable, no system changes)
+ - Everything stored in `.portable\` folder for easy cleanup
+ - Commands: `start_bambuddy.bat` (launch), `start_bambuddy.bat update` (update deps), `start_bambuddy.bat reset` (clean start)
+ - Custom port via `set PORT=9000 & start_bambuddy.bat`
+ - Verifies all downloads with SHA256 checksums for security
+ - Supports both x64 and ARM64 Windows systems
+
+## [0.1.7] - 2026-02-03
+
+### Security
+- **Critical: Missing API Endpoint Authentication** (CVE-2026-25505, CVSS 9.8):
+ - Added authentication to 200+ API endpoints that were previously unprotected
+ - All route files now use `RequirePermissionIfAuthEnabled()` for permission checks
+ - Protected endpoints: archives, projects, settings, API keys, groups, cloud, notifications, maintenance, filaments, external links, smart plugs, discovery, firmware, camera, k-profiles, AMS history, pending uploads, updates, spoolman, system, print queue, printers
+ - Image-serving endpoints (thumbnails, timelapse, photos, camera streams) remain public as they require knowing the resource ID and are loaded via `` tags which cannot send Authorization headers
+ - Backend integration tests added to verify endpoint authentication enforcement
### Enhancements
+- **TOTP Authenticator Support for Bambu Cloud** (Issue #182):
+ - Added support for TOTP-based two-factor authentication when connecting to Bambu Cloud
+ - Accounts with authenticator apps (Google Authenticator, Authy, etc.) now work correctly
+ - Proper detection of verification type: email code vs TOTP code
+ - Uses browser-like headers to bypass Cloudflare protection on TFA endpoint
+ - Frontend shows appropriate message for each verification type
+ - Added translations for TOTP UI in English, German, and Japanese
+- **Spoolman: Open in Spoolman Button** (Issue #210):
+ - FilamentHoverCard now shows "Open in Spoolman" button when spool is already linked in Spoolman
+ - Button links directly to the spool's page in Spoolman for quick editing
+ - "Link to Spoolman" button now only shows when spool is not yet linked
+ - Link button correctly disabled when no unlinked spools are available in Spoolman
+ - Toast notification shown on successful/failed spool linking
+ - Added `/api/v1/spoolman/spools/linked` endpoint returning map of linked spool tags to IDs
+- **Complete German Translations**:
+ - All UI strings now fully translated to German (1800+ translation keys)
+ - Pages translated: Settings, Archives, File Manager, Queue, Printers, Profiles, Projects, Stats, Maintenance, Camera, Groups, Users, Login, Setup, Stream Overlay
+ - Components translated: ConfirmModal, LinkSpoolModal, FilamentHoverCard, Layout
+ - Added locale parity test to ensure English and German stay in sync
+- **Virtual Printer Proxy Mode**:
+ - New "Proxy" mode allows remote printing over any network by relaying slicer traffic to a real printer
+ - Configure a target printer and Bambuddy acts as a TLS proxy between your slicer and the printer
+ - Supports both FTP (port 9990) and MQTT (port 8883) protocols with full TLS encryption
+ - Slicer connects to Bambuddy using the real printer's access code
+ - Real-time status display showing active FTP/MQTT connections
+ - Target printer selector with validation (must be configured in Bambuddy)
+ - Proxy mode bypasses the access code requirement (uses the real printer's credentials)
+ - Full i18n support for all proxy mode UI strings (English, German, Japanese)
+
+### Fixed
+- **Cannot Link Multiple HA Entities to Same Printer** (Issue #214):
+ - Fixed Home Assistant entities being limited to one per printer
+ - Both frontend and backend were blocking printers that already had any smart plug linked
+ - Now only Tasmota plugs are limited to one per printer (physical device constraint)
+ - Multiple HA entities (switches, scripts, lights, etc.) can be linked to the same printer
+ - Restored "Show on Printer Card" toggle for HA entities to control visibility on printer cards
+ - Fixed printer card only showing `script.*` entities; now shows all HA entities with toggle enabled
+ - HA entities now default to auto_on=False and auto_off=False (appropriate for automations)
+ - Printer cards now update immediately when HA entities are added/modified/deleted
+- **Monthly Comparison Calculation Off** (Issue #229):
+ - Fixed filament statistics not accounting for quantity multiplier
+ - Monthly comparison chart now correctly multiplies `filament_used_grams` by `quantity`
+ - Daily and weekly charts also now account for quantity
+ - Filament type breakdown includes quantity in calculations
+ - Backend stats endpoint (`/archives/stats`) and Prometheus metrics also fixed
+ - Prints count now shows total items (sum of quantities) instead of archive count
+- **Authentication Required for Downloads** (Issue #231):
+ - Fixed support bundle download returning 401 Unauthorized when auth is enabled
+ - Fixed archive export (CSV/XLSX) failing with authentication enabled
+ - Fixed statistics export failing with authentication enabled
+ - Fixed printer file ZIP download failing with authentication enabled
+ - Root cause: These endpoints used raw `fetch()` without Authorization header
+- **Queue Schedule Date Picker Ignores User Format Settings** (Issue #233):
+ - Replaced native datetime picker with custom date/time inputs respecting user settings
+ - Date input shows in user's format (DD/MM/YYYY for EU, MM/DD/YYYY for US, YYYY-MM-DD for ISO)
+ - Time input shows in user's format (24H or 12H with AM/PM)
+ - Calendar button opens native picker for convenience; selection is formatted to user's preference
+ - Placeholder text shows expected format (e.g., "DD/MM/YYYY" or "HH:MM AM/PM")
+ - Added date utilities: `formatDateInput`, `parseDateInput`, `getDatePlaceholder`
+ - Added time utilities: `formatTimeInput`, `parseTimeInput`, `getTimePlaceholder`
+- **500 Error on Archive Detail Page**:
+ - Fixed internal server error when viewing individual archive details
+ - Root cause: `project` relationship not eagerly loaded in `get_archive()` service method
+ - Async SQLAlchemy requires explicit eager loading; lazy loading is not supported
+
+## [0.1.6.2] - 2026-02-02
+
+> **Security Release**: This release addresses critical security vulnerabilities. Users running authentication-enabled instances should upgrade immediately.
+
+### Security
+- **Critical: Hardcoded JWT Secret Key** (GHSA-gc24-px2r-5qmf, CWE-321) - Fixed hardcoded JWT secret key that could allow attackers to forge authentication tokens:
+ - JWT secret now loaded from `JWT_SECRET_KEY` environment variable (recommended for production)
+ - Falls back to auto-generated `.jwt_secret` file in data directory with secure permissions (0600)
+ - Generates cryptographically secure 64-byte random secret if neither exists
+ - **Action Required**: Existing users will need to re-login after upgrading
+- **Critical: Missing API Authentication** (GHSA-gc24-px2r-5qmf, CWE-306) - Fixed 77+ API endpoints that lacked authentication checks:
+ - Added HTTP middleware enforcing authentication on ALL `/api/` routes when auth is enabled
+ - Only essential public endpoints are exempt (login, auth status, version check, WebSocket)
+ - All other API calls now require valid JWT token or API key
+
+### Enhancements
+- **Location Filter for Queue** (Issue #220):
+ - Filter queue jobs by printer location in the Queue page
+ - "Any {Model}" queue assignments can now specify a target location (e.g., "Any X1C in Workshop")
+ - Location filter dropdown shows all unique locations from printers and queue items
+ - Location is saved with queue items and displayed in the queue list
- **Ownership-Based Permissions** (Issue #205):
- Users can now only update/delete their own items unless they have elevated permissions
- Update/delete permissions split into `*_own` and `*_all` variants:
@@ -51,11 +158,28 @@ All notable changes to Bambuddy will be documented in this file.
- Removed ~2000 lines of legacy JSON-based backup/restore code
### Fixes
+- **File Manager permissions not enforced** (Issue #224) - Fixed backend not checking `library:read` permission for File Manager endpoints:
+ - Added `library:read` permission check to all list/view endpoints (files, folders, stats)
+ - Added `library:upload` permission check to upload and folder creation endpoints
+ - Added `queue:create` permission check to add-to-queue endpoint
+ - Added `printers:control` permission check to direct print endpoint
+ - Added ownership-based permission checks to file move operation
+ - Users without `library:read` permission can no longer view files in the File Manager
+ - Users can now only delete/update their own files unless they have `*_all` permissions
+- **JWT secret key not persistent across restarts** - Fixed JWT secret key generation to properly use data directory, ensuring tokens remain valid across container restarts
+- **Images/thumbnails returning 401 when auth enabled** - Fixed auth middleware to allow public access to image/media endpoints (thumbnails, photos, QR codes, timelapses, camera streams) since browser elements like `
` don't send Authorization headers
- **Library thumbnails missing after restore** - Fixed library files using absolute paths that break after restore on different systems:
- Library now stores relative paths in database for portability
- Automatic migration converts existing absolute paths to relative on startup
- Thumbnails and files now display correctly after restoring backups
- **File uploads failing with authentication enabled** - Fixed all file upload functions (archives, photos, timelapses, library files, etc.) not sending authentication headers when auth is enabled
+- **External spool AMS mapping causing "Failed to get AMS mapping table"** (Issue #213) - Fixed external spool `ams_mapping2` slot_id handling that caused AMS mapping failures
+- **Filename matching for files with spaces** (Issue #218) - Fixed file detection when filenames contain spaces
+- **P2S FTP upload failure** (Issue #218) - Fixed FTP uploads to P2S printers by passing `skip_session_reuse` to ImplicitFTP_TLS
+- **Printer deletion freeze** (Issue #214) - Fixed UI freeze when deleting printers, and now allows multiple smart plugs per printer
+- **Stack trace exposure in error responses** (CodeQL Alert #68) - Fixed stack traces being exposed in API error responses in archives.py
+- **Printer serial numbers exposed in support bundle** (Issue #216) - Sanitized printer serial numbers in support bundle logs for privacy
+- **Missing sliced_for_model migration** (Issue #211) - Fixed database migration for `sliced_for_model` column that was missing in some upgrade paths
## [0.1.6-final] - 2026-01-31
diff --git a/PLAN.md b/PLAN.md
deleted file mode 100644
index 27cb52dd9..000000000
--- a/PLAN.md
+++ /dev/null
@@ -1,247 +0,0 @@
-# Notification Templates Management System
-
-## Overview
-
-Replace hardcoded notification messages with a flexible template system that allows users to customize notification content per event type, with provider-specific formatting support.
-
----
-
-## Data Model
-
-### New Table: `notification_templates`
-
-```sql
-CREATE TABLE notification_templates (
- id INTEGER PRIMARY KEY,
- event_type VARCHAR(50) NOT NULL, -- print_start, print_complete, etc.
- name VARCHAR(100) NOT NULL, -- User-friendly name
- title_template TEXT NOT NULL, -- Template for notification title
- body_template TEXT NOT NULL, -- Template for notification body
- is_default BOOLEAN DEFAULT 0, -- System default (non-deletable)
- created_at DATETIME,
- updated_at DATETIME
-);
-```
-
-**Event Types:**
-- `print_start`
-- `print_complete`
-- `print_failed`
-- `print_stopped`
-- `print_progress`
-- `printer_offline`
-- `printer_error`
-- `filament_low`
-- `maintenance_due`
-- `test` (for test notifications)
-
----
-
-## Template Variables
-
-Variables use `{variable_name}` syntax (Python format strings).
-
-### Per-Event Variables:
-
-| Event | Variables |
-|-------|-----------|
-| `print_start` | `{printer}`, `{filename}`, `{estimated_time}` |
-| `print_complete` | `{printer}`, `{filename}`, `{duration}`, `{filament_grams}` |
-| `print_failed` | `{printer}`, `{filename}`, `{duration}`, `{reason}` |
-| `print_stopped` | `{printer}`, `{filename}`, `{duration}` |
-| `print_progress` | `{printer}`, `{filename}`, `{progress}`, `{remaining_time}` |
-| `printer_offline` | `{printer}` |
-| `printer_error` | `{printer}`, `{error_type}`, `{error_detail}` |
-| `filament_low` | `{printer}`, `{slot}`, `{remaining_percent}`, `{color}` |
-| `maintenance_due` | `{printer}`, `{items}` (formatted list) |
-| `test` | `{app_name}` |
-
-### Common Variables (all events):
-- `{timestamp}` - Current date/time
-- `{app_name}` - "Bambuddy"
-
----
-
-## Default Templates
-
-Pre-seeded templates for each event (marked `is_default=True`):
-
-```
-print_start:
- title: "Print Started"
- body: "{printer}: {filename}\nEstimated: {estimated_time}"
-
-print_complete:
- title: "Print Completed"
- body: "{printer}: {filename}\nTime: {duration}\nFilament: {filament_grams}g"
-
-print_failed:
- title: "Print Failed"
- body: "{printer}: {filename}\nTime: {duration}\nReason: {reason}"
-
-print_stopped:
- title: "Print Stopped"
- body: "{printer}: {filename}\nTime: {duration}"
-
-print_progress:
- title: "Print {progress}% Complete"
- body: "{printer}: {filename}\nRemaining: {remaining_time}"
-
-printer_offline:
- title: "Printer Offline"
- body: "{printer} has disconnected"
-
-printer_error:
- title: "Printer Error: {error_type}"
- body: "{printer}\n{error_detail}"
-
-filament_low:
- title: "Filament Low"
- body: "{printer}: Slot {slot} at {remaining_percent}%"
-
-maintenance_due:
- title: "Maintenance Due"
- body: "{printer}:\n{items}"
-
-test:
- title: "Bambuddy Test"
- body: "This is a test notification. If you see this, notifications are working!"
-```
-
----
-
-## Provider-Specific Formatting
-
-The template system supports provider-specific formatting via a simple approach:
-
-1. **Plain text** (default) - Used for CallMeBot, ntfy, Pushover, Email
-2. **Markdown** - Automatically applied for Telegram (wrap title in `*bold*`)
-
-The notification service will:
-- Render the template with variables
-- Apply provider-specific formatting when sending
-
----
-
-## Implementation Steps
-
-### Backend
-
-1. **Create model** `backend/app/models/notification_template.py`
- - NotificationTemplate SQLAlchemy model
-
-2. **Create schemas** `backend/app/schemas/notification_template.py`
- - NotificationTemplateCreate, Update, Response
- - TemplateVariables (documentation of available vars per event)
-
-3. **Add migration** in `backend/app/core/database.py`
- - Create table if not exists
- - Seed default templates
-
-4. **Create API routes** `backend/app/api/routes/notification_templates.py`
- - `GET /api/v1/notification-templates` - List all templates
- - `GET /api/v1/notification-templates/{id}` - Get single template
- - `PUT /api/v1/notification-templates/{id}` - Update template
- - `POST /api/v1/notification-templates/{id}/reset` - Reset to default
- - `GET /api/v1/notification-templates/variables` - List available variables per event
- - `POST /api/v1/notification-templates/preview` - Preview template with sample data
-
-5. **Update notification service** `backend/app/services/notification_service.py`
- - Load templates from database
- - Render templates with variables
- - Remove hardcoded message builders
-
-6. **Register routes** in `backend/app/main.py`
-
-### Frontend
-
-7. **Add API client methods** `frontend/src/api/client.ts`
- - getNotificationTemplates, updateNotificationTemplate, etc.
-
-8. **Create template editor component** `frontend/src/components/NotificationTemplateEditor.tsx`
- - Template editing UI with variable insertion buttons
- - Live preview with sample data
- - Reset to default button
-
-9. **Update SettingsPage** `frontend/src/pages/SettingsPage.tsx`
- - Add "Templates" sub-section in Notifications tab
- - List all templates with edit capability
-
----
-
-## UI Design
-
-### Templates Section (in Settings > Notifications)
-
-```
-+--------------------------------------------------+
-| Message Templates |
-| Customize notification messages for each event |
-+--------------------------------------------------+
-| |
-| +----------------+ +----------------+ |
-| | Print Started | | Print Complete | ... |
-| | "Print Started"| | "Print Compl..." | |
-| | [Edit] | | [Edit] | |
-| +----------------+ +----------------+ |
-| |
-+--------------------------------------------------+
-```
-
-### Template Editor Modal
-
-```
-+--------------------------------------------------+
-| Edit Template: Print Complete [X] |
-+--------------------------------------------------+
-| Title: |
-| [Print Completed_________________________] |
-| |
-| Body: |
-| +----------------------------------------------+ |
-| | {printer}: {filename} | |
-| | Time: {duration} | |
-| | Filament: {filament_grams}g | |
-| +----------------------------------------------+ |
-| |
-| Available Variables: |
-| [+printer] [+filename] [+duration] [+filament] |
-| |
-| Preview: |
-| +----------------------------------------------+ |
-| | Title: Print Completed | |
-| | Body: Bambu X1C: Benchy.3mf | |
-| | Time: 1h 23m | |
-| | Filament: 15.2g | |
-| +----------------------------------------------+ |
-| |
-| [Reset to Default] [Cancel] [Save] |
-+--------------------------------------------------+
-```
-
----
-
-## File Changes Summary
-
-| File | Action |
-|------|--------|
-| `backend/app/models/notification_template.py` | Create |
-| `backend/app/schemas/notification_template.py` | Create |
-| `backend/app/api/routes/notification_templates.py` | Create |
-| `backend/app/core/database.py` | Modify (add migration + seeding) |
-| `backend/app/models/__init__.py` | Modify (export new model) |
-| `backend/app/services/notification_service.py` | Modify (use templates) |
-| `backend/app/main.py` | Modify (register routes) |
-| `frontend/src/api/client.ts` | Modify (add API methods + types) |
-| `frontend/src/components/NotificationTemplateEditor.tsx` | Create |
-| `frontend/src/pages/SettingsPage.tsx` | Modify (add templates section) |
-
----
-
-## Notes
-
-- Default templates cannot be deleted, only modified and reset
-- Templates are language-agnostic (user writes in their preferred language)
-- The existing `notification_language` setting can be removed later (templates replace i18n)
-- Variables that are unavailable for an event will render as empty string
-- Template rendering uses safe formatting (missing vars don't crash)
diff --git a/README.md b/README.md
index f305c2971..655ef8e4e 100644
--- a/README.md
+++ b/README.md
@@ -10,6 +10,7 @@
+
@@ -28,6 +29,25 @@
---
+## 🌐 NEW: Remote Printing with Proxy Mode
+
+
+
+