# Changelog

All notable changes to BaseCloud Shield will be documented in this file.

## [1.4.5] - 2026-03-27

### 🔐 Webhook Security — HMAC Request Signing

Added cryptographic signature verification for webhooks to prevent unauthorized interception or spoofing.

**New Features:**

1. **HMAC-SHA256 Request Signing**
   - All webhook requests can now be cryptographically signed
   - Receiving server can verify requests actually came from your WordPress site
   - Prevents attackers from spoofing webhook requests

2. **New Settings**
   - `webhook_secret` — Shared secret key for HMAC signing
   - `webhook_sign_requests` — Enable/disable request signing

3. **New HTTP Headers (when signing enabled)**
   - `X-BCShield-Signature` — HMAC-SHA256 signature of timestamp + body
   - `X-BCShield-Timestamp` — Unix timestamp for replay attack prevention

4. **Verification Example (PHP)**
   ```php
   $timestamp = $_SERVER['HTTP_X_BCSHIELD_TIMESTAMP'];
   $signature = $_SERVER['HTTP_X_BCSHIELD_SIGNATURE'];
   $body = file_get_contents('php://input');
   $expected = hash_hmac('sha256', $timestamp . '.' . $body, $your_secret);
   if (!hash_equals($expected, $signature)) die('Invalid signature');
   if (abs(time() - $timestamp) > 300) die('Request expired');
   ```

**Security Recommendation:**
- If using webhook delivery, **enable HMAC signing** and update your receiving endpoint to verify signatures
- Consider switching to SendGrid for email delivery — it doesn't expose OTP codes to intermediary systems

---

## [1.4.4] - 2026-03-27

### 🚨 CRITICAL FIX — False Positive Alert Flooding

This release addresses a critical bug where legitimate users were receiving 100+ "Account May Be Compromised" emails due to overly aggressive security thresholds.

**Root Cause Analysis:**
- `is_user_being_targeted()` triggered at just **2 OTP requests** — normal users logging in twice in an hour were flagged as under attack
- `is_credential_stuffing_attack()` triggered when **2 users** logged in from the same IP — offices with multiple employees triggered alerts for everyone
- No rate limiting on security alert emails — same user could receive unlimited alerts
- OTP tracking window was **1 hour** — far too long for legitimate usage patterns

**Fixes Implemented:**

1. **Fixed `is_user_being_targeted()` False Positives**
   - Now requires **5+ OTP requests** from **3+ different IPs** (was: 2 requests, any IP)
   - Normal users logging in twice no longer trigger attack alerts
   - Only tracks unique IPs, not repeat logins from same device

2. **Fixed `is_credential_stuffing_attack()` Office IP False Positives**
   - Now requires **3+ different accounts** AND **5+ total attempts** (was: 2 accounts)
   - Multiple employees at the same office no longer trigger credential stuffing alerts
   - Still blocks true attacks: many accounts + rapid attempts

3. **Added Alert Rate Limiting (1-Hour Cooldown)**
   - `send_account_under_attack_alert()` — max 1 email per user per hour
   - `send_credential_stuffing_alert()` — max 1 email per attacking IP per hour, plus per-user cooldowns
   - `send_security_alert()` — max 1 alert per user per hour
   - Prevents email flooding even during active attacks

4. **Reduced OTP Tracking Window**
   - Reduced from **3600s (1 hour)** to **900s (15 minutes)**
   - More appropriate for detecting rapid attacks vs. punishing normal re-logins

5. **New Security Constants**
   - `BCSHIELD_ALERT_COOLDOWN` (3600s) — minimum time between alerts per user
   - `BCSHIELD_TARGETED_THRESHOLD` (5) — OTP requests needed to trigger alert
   - `BCSHIELD_CREDENTIAL_STUFFING_MIN_USERS` (3) — accounts needed from same IP
   - `BCSHIELD_OTP_TRACKING_WINDOW` (900s) — how long to track OTP requests

---

## [1.4.3] - 2026-03-23

### Version bump — unified all version references to 1.4.3

No functional changes. All version strings (plugin header, `BCSHIELD_VERSION` constant, `readme.txt` stable tag, `package.json`) set to 1.4.3 for consistency.

---

## [1.4.2] - 2026-03-23

### 🛡️ Critical Security Hardening — Credential Stuffing & OTP Abuse

This release addresses real-world credential stuffing attacks where attackers hold valid passwords for multiple accounts and use them to flood those users with unsolicited OTP emails (observed on monitornet.co.za, 2026-03-22).

**Security Fixes (2026-03-23):**

1. **Tighter Credential Stuffing Threshold**
   - Now blocks an IP after it successfully authenticates on **2+ distinct accounts** (previously 3)
   - Prevents attackers from triggering OTP emails across multiple compromised accounts
   - Blocked IP receives an immediate lockout; admin is notified with a full report

2. **Admin Credential Stuffing Alert Email**
   - When a credential stuffing attack is blocked, admin receives an urgent email listing:
     - The attacking IP address
     - All compromised account usernames
     - Timestamp and recommended actions
   - Each affected user also receives an individual compromise warning email

3. **IP Address Shown in Every OTP Email**
   - Every OTP email now displays the requesting IP address
   - Includes a clear warning: "If you did not initiate this login, change your password immediately"
   - Lets users instantly identify unsolicited OTP requests

4. **Account Targeting Alert Lowered to 2 Requests**
   - Previously required 5+ OTP requests AND 2+ unique IPs before alerting
   - Now triggers after just **2 OTP requests** for the same account (single or multi-IP)
   - Legitimate users log in once — any repeat is suspicious

5. **Eliminated Duplicate Log Spam on Locked IPs**
   - `track_failed_login` now skips early if the IP is already locked
   - Prevents hundreds of redundant `login_failed` + `auto_lockout` log entries per blocked IP (previously a locked IP still accumulated one of each event per attempt)

**Original 1.4.2 Features:**

6. **Pre-OTP Attack Detection**
   - Tracks login attempts BEFORE OTP generation
   - Detects credential stuffing (same IP attacking multiple accounts)
   - Progressive delay: 5s, 10s, 20s, 40s exponential backoff (caps at 2 min)

7. **Username Enumeration Protection**
   - Masks login error messages (no longer reveals if username exists)
   - Auto-locks IPs trying 5+ different usernames within 5 minutes

**Constants:**
- `BCSHIELD_PRE_OTP_MAX_ATTEMPTS` (3) - Attempts before progressive delay
- `BCSHIELD_PRE_OTP_WINDOW` (300) - 5-minute tracking window
- `BCSHIELD_PROGRESSIVE_DELAY_BASE` (5) - Base delay in seconds
- `BCSHIELD_SUSPICIOUS_OTP_THRESHOLD` (5) - OTP requests before alert (threshold now 2)
- `BCSHIELD_CREDENTIAL_ATTACK_THRESHOLD` (10) - Total attempts before IP block

---

## [1.6.9] - 2026-03-17

### Fix OTP Timing and Flow

**Issues Fixed:**

1. **OTP Timer Now Accurate**
   - Timer correctly calculates remaining time from OTP creation timestamp
   - No more "Expired" showing immediately on load

2. **Smart OTP Reuse**
   - If existing OTP has <2 minutes remaining, generates fresh OTP
   - Prevents users getting stuck with nearly-expired codes

3. **Expired Session Handling**
   - If OTP data is missing or expired, redirects to login page
   - Clears stale cookies to prevent loop

4. **Consistent 10-minute validity**
   - OTP validity defaults to 10 minutes throughout

---

## [1.6.8] - 2026-03-17

### 🐛 Bug Fixes: Timer and Delivery Method Configuration

**Issues Fixed:**

1. **OTP Timer Showing "Expired" Immediately**
   - Timer now defaults to full validity time if OTP data isn't immediately available
   - Prevents confusing "Expired" display on page load

2. **Missing Delivery Method Configuration Inputs**
   - Added configuration sections for: Email, SendGrid, Webhook, WhatsApp, SMS
   - Config sections auto-show/hide when delivery method is checked/unchecked
   - Webhook URL input now visible when Webhook is selected

---

## [1.6.7] - 2026-03-17

### 🔧 Rollback OTP Flow to Proven 1.3.9 Architecture

**Problem:** Version 1.6.6's complete OTP rewrite broke authentication — users couldn't reach the OTP verification page at all.

**Solution:** Restored the battle-tested 1.3.9 authentication flow while keeping the modern 1.6.6 UI and all post-1.3.9 features.

#### What Changed:

1. **Restored Working Session Flow**
   - Back to `?bcshield_action=verify_otp` URL parameter
   - Using `bcshield_pending_user` and `bcshield_session` cookies (proven approach)
   - OTP data stored in transient with user ID key: `bcshield_otp_{user_id}`

2. **Restored `generate_session_token()` Method**
   - Deterministic token using `wp_salt('nonce')` — stays valid during OTP entry
   - Session hijacking protection via hash comparison

3. **Restored OTP Lock Mechanism**
   - Prevents duplicate OTP sends within 60 seconds
   - Existing valid OTP redirects to verification page without resending

4. **Preserved Modern Features**
   - 1.6.6 dark theme UI (admin panel + OTP form)
   - Security audit logs with webhook support
   - Configurable thresholds (attempts, lockout, trust hours)
   - Extended attempts per-IP feature
   - All delivery methods (email, SendGrid, webhook, WhatsApp, SMS)

#### Technical Details:
- `intercept_login()` — restored from 1.3.9 with lock mechanism
- `render_otp_form()` — restored method with 1.6.6 styling
- `validate_otp()` — restored from 1.3.9 with modern features

---

## [1.6.6] - 2026-03-17

### 🔄 Complete OTP Flow Rebuild — Bulletproof Authentication

**Problem:** OTP verification was resetting back to the form instead of logging users in, despite multiple attempted fixes. The root cause was complex interdependencies between session tokens, cookies, output buffering, and redirect handling.

**Solution:** Complete rewrite of the authentication flow with simplified, robust architecture:

#### Key Changes:

1. **Simplified Session Management**
   - Single transient per OTP session with token as key
   - Token is a simple 32-char random string (no complex hashing)
   - All session data stored server-side — cookie only holds the lookup token

2. **New OTP Page URL**
   - Changed from `?bcshield_action=verify_otp` to `?bcshield_otp=1`
   - Cleaner, simpler URL structure

3. **Earlier Hook Priority**
   - OTP verification now runs on `init` at priority 1 (before any output)
   - Form processing happens BEFORE any HTML rendering
   - Success redirects ALWAYS exit immediately

4. **Removed Problematic Features**
   - No more output buffering tricks (`ob_start`/`ob_end_clean`)
   - No more complex SameSite cookie wrapper (use standard `setcookie`)
   - No more dual-cookie session validation
   - Removed resend rate limiting complexity (can add back later if needed)

5. **Cleaner Cookie Handling**
   - Single cookie: `bcshield_token` (session lookup)
   - Trust cookie: `bcshield_trusted` (device remember)
   - Both use standard PHP `setcookie()` with `is_ssl()` check

6. **Simplified Flow**
   ```
   Login → intercept_login() → create session transient → set token cookie → redirect to ?bcshield_otp=1
   ↓
   OTP Page → handle_otp_verification() → if POST: validate → if correct: complete_login() & exit
   ↓
   complete_login() → clear session → set auth cookie → redirect to admin → exit
   ```

7. **Inline Styles**
   - OTP form CSS is now inline in the page (no external dependencies)
   - Same visual design, more reliable rendering

---

## [1.6.5] - 2026-03-17

### 🐛 Critical Bug Fix — OTP verification "resets" instead of logging in

**Symptoms:** User enters the correct 6-digit OTP, the button shows "Verifying…", then the page refreshes back to the OTP form instead of logging in.

**Root causes identified and fixed:**

1. **Missing SameSite cookie attribute** — Modern browsers (Chrome 80+, Firefox 79+, Safari) increasingly require explicit `SameSite` attribute on cookies. Without it, browsers may silently reject cookies, causing the session verification to fail and redirect the user away.
   - **Fix:** New `set_cookie()` helper method sets `SameSite=Lax` on all cookies using PHP 7.3+ array syntax (with fallback for older PHP).

2. **No output buffering** — Any PHP notice/warning (e.g., from third-party plugins) would send output before headers, breaking the `wp_redirect()` call and causing unpredictable behavior.
   - **Fix:** Added `ob_start()` / `ob_end_clean()` around the validation logic to discard any stray output before rendering.

3. **Form missing explicit action URL** — The OTP form relied on browser default (current URL) for POST target. Some edge cases (CDN rewrites, caching plugins) could alter this.
   - **Fix:** Form now has explicit `action="<?php echo esc_url(site_url('?bcshield_action=verify_otp')); ?>"`.

4. **Input not fully sanitized** — Whitespace or invisible characters in the OTP input could cause `hash_equals()` to fail even with correct digits.
   - **Fix:** Added explicit `trim()` and `preg_replace('/[^0-9]/', '', $input)` to ensure only digits are compared.

5. **OTP lock transient not cleared on success** — The `bcshield_otp_lock_{uid}` transient was not deleted on successful verification, potentially causing issues on subsequent logins.
   - **Fix:** Now deleted alongside the OTP transient on successful login.

6. **Used `wp_redirect()` instead of `wp_safe_redirect()`** — Security best practice is to use `wp_safe_redirect()` which validates the redirect URL.
   - **Fix:** All redirects now use `wp_safe_redirect()`.

7. **Missing user validation** — If the `bcshield_pending_user` cookie contained an invalid user ID (0 or non-existent), subsequent operations could fail silently.
   - **Fix:** Added explicit check that `$uid > 0` and `get_userdata($uid)` returns a valid user.

8. **Auth cookie not passing remember flag** — `wp_set_auth_cookie($uid)` was called without the `$remember` parameter, so "Remember this device" checkbox only affected the trust cookie duration, not the WordPress login session.
   - **Fix:** Now passes `$remember` to `wp_set_auth_cookie()` and also calls `wp_set_current_user()` for immediate session setup.

---

## [1.6.4] - 2026-03-17

### 🐛 Bug Fix — Correct OTP rejected when attempts threshold was reached

**Root cause:** In `validate_otp()`, the `attempts >= max_attempts` check ran *before* the OTP comparison. This meant that after `max_attempts` wrong codes, the very next submission was immediately locked out — even if it contained the correct OTP. For example, with the default `max_attempts = 5`, entering 5 wrong codes and then the correct code on the 6th try would trigger an IP lockout instead of a successful login.

**Fix:** The OTP comparison now runs first. A correct code always succeeds and clears the session, regardless of how many prior failed attempts occurred. The attempts counter and IP lockout logic are only enforced after confirming the code is wrong — which is exactly what the "Max OTP Attempts" setting in the admin panel describes.

---

## [1.6.3] - 2026-03-17

### 🔧 OTP Input — Single Field (replaces 6-box split input)
- Replaced the 6 individual digit boxes with a single `<input name="otp_input">` that posts its value directly to PHP — no JavaScript sync layer, no hidden field, nothing that can go silently wrong
- `autocomplete="one-time-code"` lets browsers and password managers auto-fill SMS/email OTP codes in one tap
- Non-digit characters are stripped as the user types; auto-submits the form when exactly 6 digits are present (typed or pasted)
- Visual design unchanged: same dark card, aurora background, green accents, JetBrains Mono font — single wide input with matching focus glow
- Resend button and countdown timer work identically; on resend success the input is cleared and focused so the user can enter the new code immediately

## [1.6.2] - 2026-03-17

### 🚨 Critical Bug Fixes — OTP login was always failing

Three compounding bugs caused every OTP submission to silently redirect back to the login page ("reset") instead of completing the login:

**Bug 1 — Session token was IP + User-Agent bound (root cause)**
The `bcshield_session` cookie value was an HMAC computed from the client IP and User-Agent at login time, and re-computed at submission time. Any difference in how the server sees the IP between the two requests (CDN hops, proxy layers, dual-stack IPv4/IPv6 selection, load balancer variance) produced a mismatch, triggering `session_mismatch` → `wp_redirect(home_url())`.
**Fix:** Session token is now a cryptographically random 64-char hex string generated at login time and stored server-side in a transient. Only the cookie value is compared against the stored value — IP/UA are no longer part of the token.

**Bug 2 — All cookies used hard-coded `secure: true`**
Every `setcookie()` call had the `$secure` parameter hard-coded to `true`. On any non-HTTPS connection (HTTP dev environment, mixed-protocol proxy) the browser silently drops cookies with the `secure` flag, so `bcshield_pending_user` and `bcshield_session` were never returned to the server, causing an immediate redirect to `home_url()`.
**Fix:** All `setcookie()` calls now use `is_ssl()` so the secure flag is set only when the connection actually is HTTPS.

**Bug 3 — OTP data was IP-bound (deleted OTP on any IP change)**
The OTP transient stored the client IP at generation time and deleted the OTP + blocked the user if the submission IP differed. Combined with Bug 1, any IP variance broke the entire flow.
**Fix:** IP mismatch is now logged as informational only — the session token already proves the submitter is the same browser that received the form.

### 🔧 Technical
- New `make_session_token($uid, $validity_secs)` — generates random token, stores in `bcshield_sess_{uid}` transient
- New `verify_session_token($uid, $cookie_value)` — constant-time compare against stored transient
- New `delete_session_token($uid)` — cleans up on successful login
- Old `session_token($uid, $ip, $ua)` HMAC method removed from the critical auth path

## [1.6.1] - 2026-03-17

### 🔧 Fixed
- **Paste auto-submit**: Pasting a complete 6-digit OTP now automatically submits the form after 80ms — no need to click "Verify & Sign In" separately
- **Paste clears old digits**: The paste handler now clears all digit boxes before filling them; previously, if the user had partially typed digits and then pasted, the leftover values in un-overwritten boxes would silently corrupt the submitted code
- **Auto-submit on last digit**: Typing the final (6th) digit also triggers auto-submission, making both paste and manual entry equally seamless

## [1.6.0] - 2026-03-17

### ✨ New Features
- **OTP Resend Button**: Added a "Resend Code" button on the verification screen — users can request a fresh OTP up to **3 times per session** without having to navigate back to the login page
- **Session-scoped resend counter**: Resend count is tracked per login session and resets automatically when the OTP validity window expires; after 3 resends the button is permanently disabled for that session
- **30-second client-side cooldown**: After each resend the button shows a live countdown before re-enabling, preventing accidental double-sends
- **Auto-clear digit boxes**: When a resend is triggered the digit input fields are cleared automatically so the user can enter the fresh code straight away

### 🔧 Technical
- Extracted `deliver_otp()` private helper — OTP delivery logic is now shared between `intercept_login` and the new resend AJAX handler (no duplication)
- New `wp_ajax_nopriv_bcshield_resend_otp` / `wp_ajax_bcshield_resend_otp` AJAX endpoints with full HMAC session validation and nonce protection
- Resend counter stored as `bcshield_resend_{uid}` transient scoped to the OTP validity window; initialised to 0 on every fresh OTP generation

## [1.5.2] - 2026-03-17

### ✨ New Features
- **Extended Attempts IPs**: Added per-IP attempt limit overrides — list trusted IPs (office, home, admin) that get a configurable higher attempt count (default 10, range 3–20) before lockout, while the global setting stays strict
- **Current IP hint**: The Extended Attempts IPs admin panel shows your current IP inline so you can add it with one glance

### 🔧 Technical
- New `max_attempts_for_ip($ip)` method checks IP against extended list before falling back to global `max_attempts`
- Extended attempts IPs use the same flexible format as Whitelist/Blacklist: exact IPs, wildcards, and CIDR notation

## [1.5.1] - 2026-03-17

### 🎨 UI Refinements
- **OTP Screen — Aurora Background**: Added a slow-drifting animated aurora gradient behind the verification card for depth and motion
- **OTP Screen — Card Entrance**: Replaced static appearance with a smooth spring-eased scale-in animation on page load
- **OTP Screen — Top Accent Line**: Added a subtle green gradient glow line at the top of the verification card to frame the interface
- **OTP Screen — Digit Pop Animation**: Digit boxes now animate with a spring bounce when filled, giving tactile feedback
- **OTP Screen — Filled State**: Wired up `.filled` CSS class to digit boxes on input, backspace, and paste — green tint now correctly activates when a digit is entered
- **Admin Header — Scan Line**: Added a continuous sweeping horizontal green light line along the bottom of the admin header for a live-system aesthetic

## [1.3.9] - 2026-02-25

### 🔧 Fixed
- **Logo Display**: Fixed breathing logo display in admin settings header
- **Asset Deployment**: Ensured logo PNG properly deploys to WordPress.org

## [1.3.8] - 2026-02-25

### 🔧 Fixed
- **Config Labels Visibility**: Fixed "Webhook URL", "From Email Address" and other config section labels - now properly white and visible
- **Enhanced CSS Specificity**: Improved CSS rules to ensure all labels in configuration sections display correctly
- **Checkbox Labels**: Fixed delivery method checkbox labels to be white

## [1.3.7] - 2026-02-25

### 🔧 Fixed
- **Section Headers**: Fixed dark "Webhook Configuration", "Email Configuration" and other section headers - now white for visibility
- **Config Labels**: All configuration section labels now properly white colored
- **Breathing Logo**: Ensured breathing logo PNG displays correctly in admin header

## [1.3.6] - 2026-02-25

### ✨ New Features
- **Breathing Logo Animation**: Added animated breathing logo alongside the settings page heading for enhanced visual appeal
- **Premium Branding**: Integrated official BaseCloud Shield PNG logo with CSS pulse animation

### 🎨 UI Improvements
- **White Text Theme**: Fixed all dark text issues - all text now visible white for better contrast
- **Input Field Styling**: Updated all input fields with white text and proper placeholder colors
- **Enhanced Readability**: Improved visibility across all admin interface elements

## [1.3.5] - 2026-02-13

### 🔧 Fixed
- **Broken Logo Image**: Fixed broken logo image in settings page header by adding proper logo.png file from main assets
- **Menu Icon**: Replaced broken base64 PNG icon with clean SVG shield icon for WordPress admin menu
- **Asset Integration**: Integrated official BaseCloud Shield logo from main folder into plugin assets

### 🎨 Enhanced
- **Visual Consistency**: Improved brand consistency across WordPress admin interface with proper logo display

## [1.3.4] - 2026-02-12

### 🔧 Fixed
- **Logo Display**: Updated logo assets to ensure proper display in admin panel
- **Asset Sync**: Synchronized icon files with UTM Tracker branding

## [1.3.3] - 2026-02-12

### 🎨 UI/UX Revolution
- **Premium Glassmorphism Design**: Complete UI overhaul with stunning glass-morphic effects and backdrop blur
- **Advanced Animations**: Added shimmer, float, glow-pulse, and logo-pulse animations for modern feel
- **Enhanced Logo Display**: Upgraded to animated BaseCloud logo with glowing effects and floating animation
- **Futuristic Color Scheme**: Deep space blues with vibrant neon green accents
- **Interactive Elements**: Smooth hover effects, transform animations, and enhanced visual feedback
- **Professional Polish**: Refined typography, spacing, and visual hierarchy throughout admin interface
- **Consistent Branding**: Matches BaseCloud UTM Tracker's premium design language

## [1.3.2] - 2026-02-04

### 🎨 Branding Update
- Replaced Lottie animation with official BaseCloud SVG logo
- Removed Lottie player dependency for lighter plugin footprint
- Updated admin header to use static SVG logo from BaseCloud Global

## [1.3.1] - 2026-02-04

### 🎨 UI Improvements
- Removed placeholder text from IP Whitelist and IP Blacklist fields for cleaner interface
- Textareas now appear empty by default
- Current IP still displayed in info box below whitelist for easy reference

## [1.3.0] - 2026-02-04

### 🎯 New Features: Advanced IP Management
- **IP Whitelist**: Add trusted IPs that bypass all lockout and rate limiting
  - Support for exact IPs (e.g., `169.0.79.28`)
  - Support for wildcards (e.g., `192.168.*.*`)
  - Support for CIDR notation (e.g., `10.0.0.0/24`)
  - Current IP displayed for easy whitelisting
  - Multiple IPs supported (one per line)
- **IP Blacklist**: Permanently block malicious IPs from accessing your site
  - Immediate denial of access for blacklisted IPs
  - Same flexible format support as whitelist
- **Manual IP Unlock**: Real-time IP lockout management
  - View all currently locked IPs in admin panel
  - See time remaining until auto-unlock
  - One-click manual unlock button
  - Audit trail logging for all manual unlocks

### 🛡️ Security Improvements
- Whitelisted IPs now bypass both lockout checks and rate limiting
- Blacklist check occurs before any authentication processing
- Enhanced security event logging for whitelist/blacklist activities
- Admin AJAX endpoint with proper nonce verification for IP unlocking

### 🎨 UI/UX Enhancements
- New "Security Controls" section in admin settings
- Real-time display of locked IPs with countdown timers
- Improved admin interface with color-coded IP status indicators
- Current user IP prominently displayed for convenience

## [1.2.8] - 2026-02-03

### 🔥 Critical Hotfix
- **FIXED**: "Suspicious session detected" error blocking legitimate logins
- **FIXED**: Session token validation now works correctly
- Session token generation now uses consistent secret instead of time-based
- Users can successfully complete login flow without false security alerts

### ✨ Improvements
- Enhanced OTP lock mechanism to prevent unnecessary duplicate OTP generation
- Existing valid OTP is reused if user attempts login multiple times
- Better handling of page refreshes during OTP verification process
- Reduced false positive security alerts for legitimate users

### 🐛 Bug Fixes
- Session token mismatch that was flagging all logins as suspicious
- OTP lock mechanism now properly redirects to verification page

## [1.2.7] - 2026-02-03

### 🔐 Security Enhancements
- **CRITICAL FIX**: Resolved duplicate OTP email sending issue
- Implemented comprehensive duplicate prevention across all delivery methods
- Added email deduplication to prevent same address receiving multiple OTPs
- Added phone number deduplication for WhatsApp/SMS delivery methods
- Enhanced recipient list deduplication to prevent duplicate user entries

### 🛡️ Enterprise-Grade Security Features
- **Brute Force Protection**: Maximum 5 OTP attempts before 15-minute IP lockout
- **Rate Limiting**: Limit OTP generation to 3 requests per 10-minute window
- **Cryptographically Secure OTP**: Replaced rand() with random_bytes() for secure random generation
- **Session Binding & Anti-Hijacking**: 
  - IP address validation - OTP must be verified from same IP
  - User-Agent fingerprinting for browser consistency validation
  - HMAC-SHA256 session tokens to prevent session fixation
  - Secure HMAC-based trust cookies (replaced simple MD5)
- **CSRF Protection**: WordPress nonce validation on OTP submission
- **Enhanced Cookie Security**: All cookies now use httponly and secure flags
- **Security Event Logging**: Comprehensive logging of all security events (last 100 events)
- **Real-Time Security Alerts**: 
  - Automatic email alerts for suspicious activity
  - Webhook integration for enterprise monitoring
  - Detection of session hijacking, IP mismatches, failed attempts
- **Attack Detection & Prevention**:
  - Session fixation attempt detection
  - OTP interception prevention (IP binding)
  - CSRF attack protection
  - Brute force attack blocking
  - Rate limit violation detection
- **Timing Attack Protection**: Uses hash_equals() for constant-time comparisons

### 🔧 Technical Improvements
- Added 60-second OTP generation lock to prevent rapid duplicate sends
- Enhanced IP detection supporting proxies, CloudFlare, and load balancers
- Implemented proper IP validation before processing
- OTP data now includes metadata (IP, User-Agent, timestamp, attempt counter)
- Improved error messages with remaining attempt counter
- Added pattern validation for numeric OTP input (inputmode="numeric")

### 📊 Security Monitoring
- New security event types tracked:
  - `ip_lockout` - IP locked due to multiple failures
  - `rate_limited` - OTP generation rate limited
  - `trusted_login` - Login via trusted device
  - `invalid_trust_cookie` - Suspicious cookie detected
  - `otp_generated` - New OTP created
  - `otp_expired` - Expired OTP usage attempt
  - `max_attempts` - Maximum attempts exceeded
  - `ip_mismatch` - OTP verification from different IP
  - `session_mismatch` - Session token validation failed
  - `otp_success` - Successful OTP verification
  - `otp_failed` - Failed OTP attempt
  - `csrf_attempt` - CSRF token validation failed

### 🎯 What This Prevents
- OTP Interception (IP binding enforcement)
- Session Hijacking (multi-factor validation)
- CSRF Attacks (nonce protection)
- Replay Attacks (one-time codes with metadata)
- Rate Limit Abuse (throttling)
- Brute Force Attacks (auto-lockout)
- Timing Attacks (constant-time comparisons)

## [1.2.6] - Previous Release
- Initial stable release
- Multiple delivery method support
- Recipient routing options
- Basic 2FA functionality

