diff --git a/CHANGELOG.md b/CHANGELOG.md index 21e4e34..8740811 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,26 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). +## [0.27.5] - 2026-09-30 +### Security +- OTP codes (both customer login via `UserOtpService` and staff login via + `OtpService`) were stored in plaintext in `users.otp_code`/`lunar_staff.otp_code` + and compared against the plaintext guess. The staff path was additionally + weaker — a loose `!=` comparison with no timing-attack protection and no + attempt-limiting at all. Both columns are replaced with `otp_code_hash` + (bcrypt, via a `'hashed'` cast — same convention `password` already uses), + compared with `Hash::check()`. The cache-backed pending-signup OTP path + (an email with no `User` row yet) is hashed the same way. No backfill — + any code mid-flight when this deploys is invalidated (codes expire in 10 + minutes regardless, so the practical impact is limited to a re-request). +- `App\Models\User`'s (3dealer) and `Modules\Core\Auth\Models\Staff`'s + `$hidden` arrays didn't list `otp_code`/`otp_expires_at`/`otp_attempts`/ + `pending_email_code_hash`/etc. at all — any serialization of either model + (an API response, `Auth::user()` returned somewhere) would have leaked + those fields, including the (now-hashed, previously plaintext) OTP code + itself. `Staff` additionally never overrode Lunar's own base `$hidden`, so + it also lacked `password`/`remember_token` protection until now. + ## [0.27.4] - 2026-09-29 ### Added - Generic `.bbk-notice` / `.bbk-notice--info` message box and a diff --git a/composer.json b/composer.json index 3b28e84..c374fe5 100644 --- a/composer.json +++ b/composer.json @@ -2,7 +2,7 @@ "name": "boboko/core", "description": "Core module — authentication and shared panel behaviour", "type": "library", - "version": "0.27.4", + "version": "0.27.5", "autoload": { "psr-4": { "Modules\\Core\\": "src/" diff --git a/package.json b/package.json index d939f0c..42e91c1 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@boboko/core", - "version": "0.27.4", + "version": "0.27.5", "private": true, "type": "module", "description": "Portable Stimulus controllers and styles for boboko-core's cart + checkout module. Installed as a real npm dependency (file:../boboko-core in dev, a tagged git install in prod) so a consuming app's `npm install` resolves this package's own dependencies (leaflet, @hotwired/stimulus) transitively, the same way `composer update boboko/*` does for PHP. See CONTRIBUTE.md's \"JS/CSS: a real npm package\" section.",