- Dark mode — full automatic dark theme via
prefers-color-scheme: dark, covering keypad, battery widget, admin gear, PIN display, and all interactive states - Battery widget overhaul — fill bar now correctly clips to the reported percentage using
overflow: hidden+ childwidth: %; null and out-of-range values render as 0% with a grey fill instead of broken display; widget auto-polls every 60 seconds without page reload - Keypad disabled state — buttons grey out (
opacity: 0.35,pointer-events: none) and become non-interactive for the full duration of a brute-force block countdown - GPU-accelerated popup animation — access-granted/denied popups now animate with
transform: translateY()instead oftop, eliminating layout reflow on every frame - PIN placeholder — "Enter PIN" placeholder no longer inherits
letter-spacing: 8px; spacing is applied only to entered dot characters
- Atomic user store writes —
users.jsonis written viatempfile.mkstemp+os.replace, preventing file corruption if the process crashes mid-write - CSS consolidation — merged two duplicate
.containerblocks and two duplicate@media (max-width: 480px)blocks; all inline styles moved to named CSS classes - Popup deduplication —
showAccessDeniedPopupandshowAccessGrantedPopupunified into a singleshowAccessPopup(id)helper
- 13 new tests covering previously uncovered paths:
/admin/check-auth(authenticated and unauthenticated)/admin/logs/clear(all modes, missing file, invalid mode, unauthenticated)- PIN length boundaries (too short, too long, empty, non-JSON body)
UsersStore.effective_pinswith inactive users and invalid PINs in the store
- Python matrix expanded to 3.10 + 3.12
- Pip caching added to all jobs
banditnow fails the build on medium+ severity findings (removed|| true)rufflint job no longer usescontinue-on-error;ruff format --checkstep added- Docker login switched from
GHCR_PATsecret toGITHUB_TOKEN(no secret management needed) - All actions pinned to
@v4/setup-python@v5 - Redundant
pycodestyleworkflow removed (superseded by ruff)
- Added a fully responsive mobile view for the Users admin tab.
- Users are rendered as touch-friendly cards on small screens with status badges and action buttons.
- The desktop table remains unchanged; mobile now switches to cards for readability.
- Corrected CSS so only the logs table is hidden on phones (users table/cards remain visible).
- Minor README cleanup (removed outdated notice).
⚠️ BREAKING CHANGE: Starting with v1.10.0, user management has been completely redesigned with a new JSON-based user store. Existing users inconfig.ini[pins] section need to be migrated!
If you have users configured in config.ini [pins] section:
- Update to v1.10.0 (your existing users will continue to work temporarily)
- Access Admin Panel → Navigate to
http://your-dooropener:5000/admin - Go to Users Tab → Click on the "Users" tab in the admin interface
- Click "Migrate All" → This will move all your config.ini users to the new JSON store
- Verify Migration → Check that all users appear in the Users tab with "store" source
Benefits of Migration:
- ✅ Edit user PINs without restarting the container
- ✅ Activate/deactivate users instantly
- ✅ Track usage statistics ("Times Used" counter)
- ✅ Full user management via web interface
- ✅ No more manual config.ini editing
config.ini [pins] section will be deprecated in a future version. Migrate now to avoid disruption!
If you're upgrading from a previous version, follow these steps:
Add the new users.json volume bind and make config.ini read-write:
services:
dooropener:
image: ghcr.io/sloth-on-meth/dooropener:latest
volumes:
- ./config.ini:/app/config.ini:rw # ⚠️ Changed from :ro to :rw
- ./users.json:/app/users.json # 🆕 New volume for user data
- ./logs:/app/logs
# ... rest of your configNote: The app will automatically create users.json when needed - no manual file creation required!
# Start the updated container
docker-compose up -d
# Access admin panel
# Go to Users tab → Click "Migrate All" button- Check that all users appear in the Users tab with "store" source
- Test that PINs still work
- Your
config.ini[pins] section will be automatically cleaned up
Why these changes?
config.ini:rw- Allows automatic removal of migrated users from configusers.json- New persistent storage for user data with advanced features
- NEW: Complete admin UI for user management with tabbed interface (Logs/Users)
- NEW: JSON-based user store (
users.json) with atomic operations and host persistence - NEW: "Migrate All" functionality to bulk migrate config-only users from
config.inito JSON store - NEW: Full CRUD operations for JSON store users (Create, Edit, Delete, Activate/Deactivate)
- NEW: Toast notifications throughout admin UI replacing blocking alert dialogs
- NEW: Log management with "Clear All Logs" functionality
- NEW: Button busy states with inline progress indicators for long-running operations
- NEW: Usage tracking - "Times Used" counter for each user showing door access frequency
- IMPROVED: User PIN resolution now prioritizes JSON store over config.ini entries
- IMPROVED: Migration process removes users from config.ini after successful JSON store creation
- IMPROVED: Admin UI uses modern modals and responsive design patterns
- IMPROVED: "Migrate All" button intelligently shows/hides based on available config-only users
- BREAKING: Individual user migration removed - use "Migrate All" for bulk operations
- DEPRECATION: config.ini [pins] section will be removed in a future version - migrate to JSON store
- Added
users.jsonvolume bind in docker-compose.yml for data persistence - Simplified config.ini writing to avoid temporary file permission issues
- Enhanced error handling and logging for user management operations
- Added
user_exists()method to UsersStore class - Improved admin session authentication across all user management endpoints
- Added
times_usedcounter that increments on successful door access - Enhanced
touch_user()method with usage tracking and backward compatibility
- Existing config.ini [pins] users can be migrated via Admin → Users → "Migrate All"
- Migration preserves existing PINs and removes entries from config.ini
- JSON store users gain full management capabilities (edit PIN, activate/deactivate)
- Usage statistics are automatically tracked for all JSON store users
- No downtime required - config and JSON users work simultaneously during transition
- Added support for trusting a custom CA bundle for Home Assistant HTTPS requests.
- New
[HomeAssistant] ca_bundleoption inconfig.iniallows pointing to a PEM bundle. - When set and readable, all HA
requests.get/postcalls useverify=<ca_bundle>. - When not set, default system trust store is used (
verify=True). - README updated with Docker compose mount examples and env var alternatives (
REQUESTS_CA_BUNDLE,SSL_CERT_FILE).
- Introduced per‑request CSP nonce and applied it to inline scripts in
templates/index.htmlandtemplates/admin.html. - CSP tightened to rely on nonces for scripts, with a safe fallback when nonce generation fails.
- Restored 500 responses when the OIDC well‑known or
end_session_endpointis missing to align with tests/expectations.
- Added SSL tests to ensure
verify=Trueby default (no ca_bundle) andverify=<path>when a bundle is configured for both GET and POST HA calls. - Adjusted admin auth tests to accept non‑blocking delay responses (HTTP 429) for progressive delays before blocking.
- pycodestyle step is now non‑blocking in CI (
continue-on-error: true), emitting warnings instead of failing the job. - Fixed PEP 8 style (E203/E302) and Ruff issues (
Responsetyping, removed unused import).
- Bumped version to 1.9.0.
- Added Web App Manifest and Service Worker to enable install on mobile/desktop.
- Register Service Worker on load; added in-app "Install App" button (Android/Chrome).
- Manifest and icons wired; Apple touch icon supported via existing favicon.
- Auto-submit is now debounced: users can type 4–8 digits; submit fires after a short pause.
- Keyboard auto-repeat is ignored to prevent floods from held keys.
- Submission lock prevents concurrent requests.
- "ACCESS GRANTED / DENIED" popups now appear above the glass card.
- Enforce active blocks even when a correct PIN or valid OIDC session is used.
- Persist session block across workers via signed cookie (
blocked_until_ts). - All block responses now include
blocked_until(epoch seconds) for client countdowns. - Frontend shows a live countdown toast until the block expires.
- Added tests verifying:
- Correct PIN during active block still returns 429 and includes
blocked_until. - Persisted session block denies OIDC pinless open and includes
blocked_until.
- Correct PIN during active block still returns 429 and includes
- Removed Black from CI to avoid repo-vs-image formatting differences.
lintjob now runs Ruff only; separate pycodestyle workflow runs style checks without formatting.
- Bumped version to 1.8.0.
- OIDC now fully gated: all OIDC functionality is disabled unless the OAuth client is initialized and
enabled=truein[oidc]. - Added CSRF protection via
stateand replay protection vianoncein the OIDC flow. - Enabled PKCE (
S256). - Strict token validation: issuer (
iss) check, audience (aud) supports list or string, expiration (exp) and not‑before (nbf) with 60s leeway. - Session fixation protection: session is cleared after successful token validation before setting auth data.
- Pinless open only when: OIDC enabled, session valid (non‑expired), user in allowed group (if configured), and
require_pin_for_oidc=false. - Hardened security headers: strong CSP,
frame-ancestors 'none',object-src 'none',base-uri 'none',Permissions-Policy, strict referrer policy, and no‑cache on dynamic endpoints. - Admin login protected with progressive delays and temporary session blocking; all attempts are now audit‑logged.
- Expanded OIDC tests: state/nonce, expired session behavior, pinless success, invalid state rejection, login redirect behavior, and OIDC gating.
- CI pushes Docker image to GHCR on every push using
docker/login-actionwith PAT orGITHUB_TOKENfallback.
- Adopted linuxserver.io‑style
PUID/PGID/UMASKpattern for painless host permissions. - New
entrypoint.shaligns runtime user/group to host IDs, ensures/app/logsis writable, applies umask, then drops privileges viagosu. - Fixed Debian package availability in
python:3.9-slim(trixie) by installingpasswd(providesuseradd/groupadd) instead ofshadow. docker-compose.ymlupdated to includePUID,PGID,UMASKenvs;config.inistays read‑only;logs/is writeable.
- Switched to
RotatingFileHandlerfor both access and audit logs to prevent unbounded growth. - All logs centralized under
/app/logs/(mount./logs:/app/logs).
- Frontend SSO button visibility now strictly follows backend
oidc_enabledflag. - Added missing
openDoorWithSSO()function to make SSO button functional.
- README refreshed with compose example,
PUID/PGID/UMASK,SESSION_COOKIE_SECURE, and logging paths in linuxserver.io style. .env.exampleupdated with new envs.config.ini.examplegains optional[oidc] public_keyfor local token signature validation.
- Thanks to @hanneshier for the idea and contributions around the OIDC flow.
- Thanks to @remijn for fixing my docker build flow
- Configurable Security Parameters: All rate limiting and blocking thresholds are now settable in
[security]section ofconfig.ini. - Dynamic Security Settings: Security values (max attempts, block time, etc) are now loaded from config, not hardcoded.
- Improved Error Messaging: On door open failure, users are prompted with 'Please contact the administrator.'
- Documentation: README and config.ini.example updated for new security features.
- UI/JS Polish: Minor bugfixes and cleanup for keypad and error handling.
- Version bump to 1.6.0
- Removed deprecated
repository.jsonfile. - Moved
favicon-192.pnginto thestatic/directory for better asset organization. - Updated documentation and project structure to clarify Home Assistant add-on compatibility and standalone usage requirements.
- General code review and preparation for v1.5 release.
- Updated all core dependencies to latest stable versions (Flask 3.1.2, requests 2.32.5, Werkzeug 3.1.3, pytz 2025.2) for improved security and compatibility.
- General codebase maintenance and preparation for future features.
- Now you do not have to build anymore - ghcr setup!
- api error
- Multi-Layer Rate Limiting - Session-based (3 attempts), IP-based (5 attempts), and global (50/hour) protection
- Enhanced IP Detection - Uses
request.remote_addrinstead of spoofable client headers - Session Tracking - Unique session identifiers prevent easy bypass of rate limits
- Suspicious Request Detection - Blocks requests with missing/bot User-Agent headers
- Composite Identifiers - IP + User-Agent/language fingerprinting for better tracking
- Visual Keypad Interface - Replaced text input with responsive 3x4 grid keypad (0-9, backspace, enter)
- Auto-Submit PIN Entry - Door opens automatically when valid PIN length (4-8 digits) is entered
- Perfect Alignment - PIN display and keypad visually centered and width-matched
- Keyboard Support - Physical keyboard input (0-9, Backspace, Enter) works alongside touch
- Success Sound - Ascending chime sequence using Web Audio API
- Failure Sound - "Womp womp" descending trombone effect for invalid attempts
- Visual Feedback - Button animations, haptic vibration, toast notifications
- Responsive Design - Optimized for both desktop and mobile devices
- Test Mode - Safe testing without physical door operation (
test_mode = truein config.ini) - Simulated Success - Shows success messages and logs without Home Assistant API calls
- Full Feature Testing - All keypad, audio, and security features work in test mode
- Environment Variable - Set
TZenvironment variable for local timezone (default: UTC) - Consistent Logging - All timestamps in logs use the configured timezone
- Docker Integration - Timezone configuration through docker-compose environment
- Enhanced Logging - Session IDs, composite identifiers, and detailed status tracking
- Progressive Security - Multiple blocking mechanisms with different thresholds
- Dependency Updates - Added pytz for robust timezone handling
- Fixed variable reference errors in logging statements
- Resolved import conflicts with configparser
- Improved error handling in security functions
- Environment Variable Port Configuration - Port can now be configured via
DOOROPENER_PORTenvironment variable - Flexible Configuration Priority - Environment variables take precedence over config.ini settings
- Docker Environment Integration - Seamless port configuration through .env files and docker-compose
- Simplified Docker Setup - Removed complex startup scripts in favor of environment variable approach
- Better Configuration Management - Clear priority order: ENV var → config.ini → default fallback
- Enhanced Documentation - Updated README with environment variable best practices
DOOROPENER_PORTenvironment variable (highest priority)config.ini[server]portsetting- Default fallback: 6532
- Fixed Docker container not respecting config.ini port settings
- Improved port configuration consistency between host and container
- Modern Glass Morphism UI - Premium frosted glass interface with backdrop blur effects
- Per-User PIN Authentication - Individual PINs for each resident/user
- Zigbee Device Integration - Automatic device detection and real-time battery monitoring
- Admin Dashboard - Password-protected admin panel with audit logging
- Rate Limiting & Security - Per-IP progressive delays and brute-force protection
- Docker Containerization - Complete Docker setup with health checks and resource limits
- Responsive Design - Optimized for desktop, tablet, and mobile devices
- Per-IP rate limiting with progressive delays (1s, 2s, 4s, 8s, 16s)
- 5-minute IP lockout after 5 failed attempts
- Secure session management with HTTPOnly cookies
- Input validation and sanitization
- Comprehensive audit logging
- Home Assistant API integration
- MQTT battery level monitoring
- Real-time status updates
- Custom background image support
- Haptic feedback on mobile devices
- Toast notifications for user feedback
- Glass morphism design with backdrop filters
- Color-coded battery indicators
- Interactive button states with animations
- Mobile-optimized touch interface
- Admin access via floating gear icon
- Multi-stage Docker build
- Health checks and restart policies
- Resource limits (0.5 CPU cores, 256MB RAM)
- Log rotation and volume mounts
- Environment-based configuration
- Admin login persistence: Sessions don't persist across page refreshes
- SESSION_COOKIE_SECURE set to False for local HTTP development
- Supports any Home Assistant switch entity
- Configurable user PINs via config.ini
- Customizable admin password
- Environment variable support for secrets