From b9bbda4601b8c544e449e87bf52df5c758fa2873 Mon Sep 17 00:00:00 2001 From: Github Actions Date: Wed, 19 Feb 2025 20:56:46 +0000 Subject: [PATCH 1/4] Version bump --- box.json | 16 +++++------ changelog.md | 75 +++++++++++++++++++++++++++------------------------- 2 files changed, 47 insertions(+), 44 deletions(-) diff --git a/box.json b/box.json index a53f6fd..82100c5 100644 --- a/box.json +++ b/box.json @@ -1,6 +1,6 @@ { "name":"ColdBox Cross Site Request Forgery (CSRF)", - "version":"3.2.0", + "version":"3.3.0", "location":"https://downloads.ortussolutions.com/ortussolutions/coldbox-modules/cbcsrf/@build.version@/cbcsrf-@build.version@.zip", "author":"Ortus Solutions.com ", "slug":"cbcsrf", @@ -27,7 +27,7 @@ "cbstorages":"^3.0.0" }, "devDependencies":{ - "commandbox-boxlang":"*", + "commandbox-boxlang":"*", "commandbox-cfformat":"*", "commandbox-docbox":"*" }, @@ -47,11 +47,11 @@ "format:watch":"cfformat watch handlers/,interceptors/,models/,test-harness/tests/specs,ModuleConfig.cfc ./.cfformat.json", "format:check":"cfformat check handlers/,interceptors/,models/,test-harness/tests/specs,ModuleConfig.cfc", "install:dependencies":"install && cd test-harness && install", - "start:lucee" : "server start serverConfigFile=server-lucee@5.json", - "start:2021" : "server start serverConfigFile=server-adobe@2021.json", - "stop:lucee" : "server stop serverConfigFile=server-lucee@5.json", - "stop:2021" : "server stop serverConfigFile=server-adobe@2021.json", - "logs:lucee" : "server log serverConfigFile=server-lucee@5.json --follow", - "logs:2021" : "server log serverConfigFile=server-adobe@2021.json --follow" + "start:lucee":"server start serverConfigFile=server-lucee@5.json", + "start:2021":"server start serverConfigFile=server-adobe@2021.json", + "stop:lucee":"server stop serverConfigFile=server-lucee@5.json", + "stop:2021":"server stop serverConfigFile=server-adobe@2021.json", + "logs:lucee":"server log serverConfigFile=server-lucee@5.json --follow", + "logs:2021":"server log serverConfigFile=server-adobe@2021.json --follow" } } diff --git a/changelog.md b/changelog.md index a1a97bd..22a448d 100644 --- a/changelog.md +++ b/changelog.md @@ -5,10 +5,12 @@ 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.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ----- +* * * ## [Unreleased] +## [3.2.0] - 2025-02-19 + ### Added - BoxLang certification @@ -19,92 +21,93 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added -* New versions on all github actions -* Updates for Adobe 2021 server installations - +- New versions on all github actions +- Updates for Adobe 2021 server installations ## [3.0.0] => 2022-OCT-10 ### Added -* Updated to new module template updates +- Updated to new module template updates ### Changed -* Dropped ACF 2016 +- Dropped ACF 2016 ## [2.3.1] => 2021-NOV-10 ### Fixed -* Fixed cfformat locations on `box.json` +- Fixed cfformat locations on `box.json` ## [2.3.0] => 2021-SEP-02 ### Added/Compatiblity -* New setting: `enableAuthTokenRotator` which defaults to **false**, unlike previously which was **true**. This allows for rotation of keys for csrf tokens on login and logout if you are using cbauth via the new interceptor: `AuthRotator`. Make sure you turn this flag to **true** to keep the previous version functionality. +- New setting: `enableAuthTokenRotator` which defaults to **false**, unlike previously which was **true**. This allows for rotation of keys for csrf tokens on login and logout if you are using cbauth via the new interceptor: `AuthRotator`. Make sure you turn this flag to **true** to keep the previous version functionality. ## [2.2.0] => 2021-JUL-21 ### Added -* Github actions migration -* New setting to provide the ability to choose the storage interface for csrf tokens: `cacheStorage` -* Adobe 2021 support +- Github actions migration +- New setting to provide the ability to choose the storage interface for csrf tokens: `cacheStorage` +- Adobe 2021 support ### Fixed -* Build version replacement token -* ensure `actionMarkedToSkip()` returns `false` when the handler is empty - +- Build version replacement token +- ensure `actionMarkedToSkip()` returns `false` when the handler is empty ## [2.1.0] => 2020-SEP-09 ### Added -* Github changelog publishing -* More cfformating goodness -* Changelog standards -* New `csrfField()` to generate a self linking field and JS but forces a new token and adds a block of javascript to the document, synchronized with the `rotateTimeout` setting, that will reload the page if the token expires. +- Github changelog publishing +- More cfformating goodness +- Changelog standards +- New `csrfField()` to generate a self linking field and JS but forces a new token and adds a block of javascript to the document, synchronized with the `rotateTimeout` setting, that will reload the page if the token expires. ### Fixed -* Null checks on `defaultValue` in case it's passed as an empty string +- Null checks on `defaultValue` in case it's passed as an empty string ## [2.0.1] => 2020-APR-06 -* Deactivate the verifier by default +- Deactivate the verifier by default ## [2.0.0] => 2020-APR-02 ### Features -* Migrated to all new ColdBox 5/6 standards -* Added an auto-verifier interceptor (see readme) -* Added `cbStorages` dependency to allow for distributed caching of tokens -* Ability to auto expire tokens -* Ability to rotate tokens -* Ability to generate input fields -* Ability to verify tokens from headers -* Ability to have an endpoint for csfr generation for authenticated users -* Automatic listeners for `cbauth` to rotate tokens via login/logout methods +- Migrated to all new ColdBox 5/6 standards +- Added an auto-verifier interceptor (see readme) +- Added `cbStorages` dependency to allow for distributed caching of tokens +- Ability to auto expire tokens +- Ability to rotate tokens +- Ability to generate input fields +- Ability to verify tokens from headers +- Ability to have an endpoint for csfr generation for authenticated users +- Automatic listeners for `cbauth` to rotate tokens via login/logout methods ### Compat -* All methods signatures have changed, please see the readme for the updated methods +- All methods signatures have changed, please see the readme for the updated methods ## [1.1.0] -* Travis updates -* Build updates -* DocBox migration +- Travis updates +- Build updates +- DocBox migration ## [1.0.1] -* production ignore lists -* Unloading of helpers +- production ignore lists +- Unloading of helpers ## [1.0.0] -* Create first module version +- Create first module version + +[unreleased]: https://github.com/coldbox-modules/cbcsrf/compare/v3.2.0...HEAD +[3.2.0]: https://github.com/coldbox-modules/cbcsrf/compare/8fe273b1fc4adc4c29062bb34aa040de9da63177...v3.2.0 From 0dfb2a9637e3e46c66cda34889e21f868da95795 Mon Sep 17 00:00:00 2001 From: Jon Clausen Date: Wed, 14 Jan 2026 17:43:02 -0500 Subject: [PATCH 2/4] BOX-166 Resolve - implement timeout skew and range --- ModuleConfig.cfc | 2 ++ models/cbcsrf.cfc | 23 +++++++++++++++++------ readme.md | 2 ++ 3 files changed, 21 insertions(+), 6 deletions(-) diff --git a/ModuleConfig.cfc b/ModuleConfig.cfc index 61a6b78..0156632 100644 --- a/ModuleConfig.cfc +++ b/ModuleConfig.cfc @@ -36,6 +36,8 @@ component { // By default, all csrf tokens have a life-span of 30 minutes. After 30 minutes, they expire and we aut-generate new ones. // If you do not want expiring tokens, then set this value to 0 rotationTimeout : 30, + // The interval in seconds within which, if a token's expiration is impending, we force generate new token for the user. + timeoutSkew : 60, // Enable the /cbcsrf/generate endpoint to generate cbcsrf tokens for secured users. enableEndpoint : false, // The WireBox mapping to use for the CacheStorage diff --git a/models/cbcsrf.cfc b/models/cbcsrf.cfc index e08bffc..c93864d 100644 --- a/models/cbcsrf.cfc +++ b/models/cbcsrf.cfc @@ -60,12 +60,7 @@ component accessors="true" singleton { // Is it a new key? !csrfData.keyExists( arguments.key ) || // Has the token expired? - ( - csrfData[ arguments.key ].expires != "never" && dateCompare( - now(), - csrfData[ arguments.key ].expires - ) == 1 - ) + tokenInExpiryRange( csrfData[ arguments.key ] ) ) { // Generate a new token csrfData[ arguments.key ] = { @@ -87,6 +82,22 @@ component accessors="true" singleton { return csrfData[ arguments.key ].token; } + + /** + * Determines if the token is within the expiry range + * @tokenData The token data struct + * + * @return True if the token is within the expiry range + */ + private boolean function tokenInExpiryRange( required struct tokenData ) { + if ( tokenData.expires == "never" ) { + return false; + } + + var secondsToExpiry = dateDiff( "s", now(), tokenData.expires ); + return secondsToExpiry <= variables.settings.timeoutSkew; + } + /** * Validates the given token against the same stored in the session for a specific key. * diff --git a/readme.md b/readme.md index 9f22483..6084706 100644 --- a/readme.md +++ b/readme.md @@ -74,6 +74,8 @@ moduleSettings = { // By default, all csrf tokens have a life-span of 30 minutes. After 30 minutes, they expire and we aut-generate new ones. // If you do not want expiring tokens, then set this value to 0 rotationTimeout : 30, + // The interval in seconds within which, if a token's expiration is impending, we force generate new token for the user. + timeoutSkew : 120, // Enable the /cbcsrf/generate endpoint to generate cbcsrf tokens for secured users. enableEndpoint : false, // The WireBox mapping to use for the CacheStorage From a04db19d335f56797bae4903d3c2b1e860448d50 Mon Sep 17 00:00:00 2001 From: jclausen <5255645+jclausen@users.noreply.github.com> Date: Wed, 14 Jan 2026 22:50:08 +0000 Subject: [PATCH 3/4] Apply cfformat changes --- ModuleConfig.cfc | 2 +- models/cbcsrf.cfc | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/ModuleConfig.cfc b/ModuleConfig.cfc index 0156632..2fe55bb 100644 --- a/ModuleConfig.cfc +++ b/ModuleConfig.cfc @@ -37,7 +37,7 @@ component { // If you do not want expiring tokens, then set this value to 0 rotationTimeout : 30, // The interval in seconds within which, if a token's expiration is impending, we force generate new token for the user. - timeoutSkew : 60, + timeoutSkew : 60, // Enable the /cbcsrf/generate endpoint to generate cbcsrf tokens for secured users. enableEndpoint : false, // The WireBox mapping to use for the CacheStorage diff --git a/models/cbcsrf.cfc b/models/cbcsrf.cfc index c93864d..2d6e4e3 100644 --- a/models/cbcsrf.cfc +++ b/models/cbcsrf.cfc @@ -85,11 +85,12 @@ component accessors="true" singleton { /** * Determines if the token is within the expiry range + * * @tokenData The token data struct * * @return True if the token is within the expiry range */ - private boolean function tokenInExpiryRange( required struct tokenData ) { + private boolean function tokenInExpiryRange( required struct tokenData ){ if ( tokenData.expires == "never" ) { return false; } From 744315694ed5e13a5dcef0d2064851935f872114 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Sede=C3=B1o?= Date: Wed, 9 Sep 2026 17:25:36 +0200 Subject: [PATCH 4/4] Mark CBCsrf as threadSafe so the singleton is published after autowiring Without the annotation WireBox stores the singleton in its cache before autowiring it, and the first containsKey() check in coldbox/system/ioc/scopes/Singleton.cfc runs outside the lock. A concurrent request can therefore get the instance before cacheStorage is injected and fail with "variable [CACHESTORAGE] doesn't exist". CacheStorage@cbstorages already carries the annotation for the same reason. CBCsrf has no circular dependencies, so publishing after autowire is safe. --- changelog.md | 7 +++++++ models/cbcsrf.cfc | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/changelog.md b/changelog.md index 22a448d..a1abfef 100644 --- a/changelog.md +++ b/changelog.md @@ -9,6 +9,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Fixed + +- Marked `CBCsrf` as `threadSafe` so WireBox publishes the singleton only after + autowiring it. Concurrent requests hitting a cold singleton cache (right after a + framework reinit, for instance) could otherwise get a half-wired instance and fail + with `variable [CACHESTORAGE] doesn't exist`. + ## [3.2.0] - 2025-02-19 ### Added diff --git a/models/cbcsrf.cfc b/models/cbcsrf.cfc index 2d6e4e3..1f7e35f 100644 --- a/models/cbcsrf.cfc +++ b/models/cbcsrf.cfc @@ -4,7 +4,7 @@ * --- * Service that encapsulates token security against cross site request forgery (csrf) */ -component accessors="true" singleton { +component accessors="true" singleton threadSafe { /* ********************************************************************* ** DI