From bb41326880450dc47c118b2c49969a74d8c74d98 Mon Sep 17 00:00:00 2001 From: Nick Cervantes Date: Wed, 13 Sep 2023 16:07:41 +0800 Subject: [PATCH 01/13] [twgit] Init feature 'feature-PRESSYNCED-2435_text_is_not_visible_in_preside_admin_toolbar_when_viewing_a_frontend_page'. From 9b4a462dbad2b2c380f18f6ec1473204aa9414cb Mon Sep 17 00:00:00 2001 From: Nick Cervantes Date: Wed, 13 Sep 2023 16:17:11 +0800 Subject: [PATCH 02/13] PRESSYNCED-2435: Update preside admin toolbar dropdown menu text color. --- system/assets/css/admin/frontend/toolbar.less | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/system/assets/css/admin/frontend/toolbar.less b/system/assets/css/admin/frontend/toolbar.less index 415431e6e6..157b32724b 100644 --- a/system/assets/css/admin/frontend/toolbar.less +++ b/system/assets/css/admin/frontend/toolbar.less @@ -47,4 +47,8 @@ html { } } } + + .dropdown-menu { + color : @text-color; + } } \ No newline at end of file From 4e3783d548cfbb5052a0fb9dc93c547a95dadbfc Mon Sep 17 00:00:00 2001 From: Seb Duggan Date: Wed, 13 Sep 2023 10:28:16 +0100 Subject: [PATCH 03/13] [twgit] Init feature 'feature-PRESIDECMS-2705_exception-type-is-not-simple-value'. From 2f93e5ca2d31c3bf12300e83049f773337069bad Mon Sep 17 00:00:00 2001 From: Seb Duggan Date: Wed, 13 Sep 2023 10:28:41 +0100 Subject: [PATCH 04/13] PRESIDECMS-2705 Check exception type is simple value in main onError handling --- system/Bootstrap.cfc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/system/Bootstrap.cfc b/system/Bootstrap.cfc index 8f90d1f59c..07d55df9b5 100644 --- a/system/Bootstrap.cfc +++ b/system/Bootstrap.cfc @@ -423,7 +423,7 @@ component { private boolean function _dealWithSqlReloadProtectionErrors( required struct exception ) output=true { var exceptionType = ( arguments.exception.type ?: "" ); - if ( exceptionType == "presidecms.auto.schema.sync.disabled" ) { + if ( IsSimpleValue( exceptionType ) && exceptionType == "presidecms.auto.schema.sync.disabled" ) { thread name=CreateUUId() e=arguments.exception { new preside.system.services.errors.ErrorLogService( appMapping = request._presideMappings.appMapping ?: "/app" From 9efe8acc4782087bd48ea1993ccade9f2e5d3915 Mon Sep 17 00:00:00 2001 From: Seb Duggan Date: Wed, 13 Sep 2023 11:26:09 +0100 Subject: [PATCH 05/13] [twgit] Init feature 'feature-PRESIDECMS-2704_admin-toolbar-menu-text-colour-on-frontend'. From 4faef36b3333ffe31818f6bf69d1e8aac9872c61 Mon Sep 17 00:00:00 2001 From: Seb Duggan Date: Thu, 14 Sep 2023 15:05:42 +0100 Subject: [PATCH 06/13] [twgit] Init feature 'feature-PRESIDECMS-2707_next-scheduled-send-date-in-past-error'. From 818a2955e1be1c164b4f32e91170942d20dc1e7b Mon Sep 17 00:00:00 2001 From: Seb Duggan Date: Thu, 14 Sep 2023 15:06:13 +0100 Subject: [PATCH 07/13] PRESIDECMS-2707 Fix messaging error if next_scheduled_send_date is in the past --- system/handlers/admin/emailCenter/CustomTemplates.cfc | 11 ++++++++--- system/i18n/cms.properties | 1 + 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/system/handlers/admin/emailCenter/CustomTemplates.cfc b/system/handlers/admin/emailCenter/CustomTemplates.cfc index a0c6492016..c821dac4ee 100644 --- a/system/handlers/admin/emailCenter/CustomTemplates.cfc +++ b/system/handlers/admin/emailCenter/CustomTemplates.cfc @@ -804,22 +804,27 @@ component extends="preside.system.base.AdminHandler" { } if ( args.sendMethod == "scheduled" ){ + var nowish = Now(); args.sendDate = args.scheduleType == "repeat" ? ( template.schedule_next_send_date ?: "" ) : ( template.schedule_date ?: "" ); - if ( IsDate( args.sendDate ) && args.sendDate > Now() ) { + if ( IsDate( args.sendDate ) && args.sendDate > nowish ) { args.estimatedSendCount = emailMassSendingService.getTemplateRecipientCount( templateId ); } if ( args.scheduleType == "repeat" ) { if ( IsDate( args.sendDate ) ) { - defaultNotice.message = translateResource( uri="cms:emailcenter.next.send.date.alert", data=[ DateTimeFormat( args.sendDate, "d mmm, yyyy HH:nn"), NumberFormat( args.estimatedSendCount ) ] ); + if ( args.sendDate > nowish ) { + defaultNotice.message = translateResource( uri="cms:emailcenter.next.send.date.alert", data=[ DateTimeFormat( args.sendDate, "d mmm, yyyy HH:nn"), NumberFormat( args.estimatedSendCount ) ] ); + } else { + defaultNotice.message = translateResource( uri="cms:emailcenter.next.send.date.in.past.alert", data=[ DateTimeFormat( args.sendDate, "d mmm, yyyy HH:nn") ] ); + } } else { defaultNotice.message = translateResource( uri="cms:emailcenter.next.send.date.unknown.alert" ); defaultNotice.class = "warn"; defaultNotice.icon = "fa-exclamation-triangle"; } } else if ( IsDate( args.sendDate ) ) { - if ( args.sendDate > Now() ) { + if ( args.sendDate > nowish ) { defaultNotice.message = translateResource( uri="cms:emailcenter.send.date.alert", data=[ DateTimeFormat( args.sendDate, "d mmm, yyyy HH:nn"), NumberFormat( args.estimatedSendCount ) ]); } else if ( args.queued ) { defaultNotice.message = translateResource( uri="cms:emailcenter.sending.alert", data=[ NumberFormat( args.queued ), NumberFormat( args.sent ) ] ); diff --git a/system/i18n/cms.properties b/system/i18n/cms.properties index 0a944c9c46..3618eee30e 100644 --- a/system/i18n/cms.properties +++ b/system/i18n/cms.properties @@ -1882,6 +1882,7 @@ emailcenter.send.date.unknown.alert=This email has not been scheduled to send. E emailcenter.send.date.in.past.alert=This email has as scheduled send date in the past: {1}. However, no emails have been sent. You may wish to edit the email settings to schedule the send. emailcenter.next.send.date.alert=Next scheduled send: {1}. Estimated recipient count: {2}. emailcenter.next.send.date.unknown.alert=Next scheduled send: unknown +emailcenter.next.send.date.in.past.alert=This email has as scheduled send date in the past: {1}. However, this should be corrected by the background email sending task very soon. emailcenter.manual.send.alert=This email is set to send manually. Use the "Send" button at the top right of your screen to begin the sending process. emailcenter.blueprints.page.title=Manage Email blueprints From 8a67511d2c219b9a76ace84e4a756ce39f27ecc9 Mon Sep 17 00:00:00 2001 From: Dominic Watson Date: Thu, 14 Sep 2023 18:27:53 +0100 Subject: [PATCH 08/13] [twgit] Init feature 'feature-PRESIDECMS-2708_better-cache-headers-for-assets'. From 0f2094057e24ea16959da4ff0d9111ec65ef2aac Mon Sep 17 00:00:00 2001 From: Dominic Watson Date: Thu, 14 Sep 2023 18:29:12 +0100 Subject: [PATCH 09/13] PRESIDECMS-2708 add more nuanced cache-control headers with asset downloads. For restricted assets, we should use cache-control: private to avoid proxies or any other shared caches from caching the response. Public assets can explicitly be labelled as such. In addition, provide configurable timeouts for the caches. --- system/config/Config.cfc | 4 ++ system/handlers/core/AssetDownload.cfc | 81 ++++++++++++++------------ 2 files changed, 49 insertions(+), 36 deletions(-) diff --git a/system/config/Config.cfc b/system/config/Config.cfc index 1730676806..e75af021f9 100644 --- a/system/config/Config.cfc +++ b/system/config/Config.cfc @@ -791,6 +791,10 @@ component { , trash = ( settings.env[ "assetmanager.storage.trash" ] ?: settings.uploads_directory & "/.trash" ) , publicUrl = ( settings.env[ "assetmanager.storage.publicUrl" ] ?: "" ) } + , cacheExpiry = { + public = Val( settings.env.ASSET_CACHE_EXPIRY_PUBLIC ?: 31536000 ) // one year + , private = Val( settings.env.ASSET_CACHE_EXPIRY_PRIVATE ?: 86400 ) // one day + } }; settings.assetManager.allowedExtensions = _typesToExtensions( settings.assetManager.types ); settings.assetManager.types.document.append( { tiff = { serveAsAttachment = true, mimeType="image/tiff" } } ); diff --git a/system/handlers/core/AssetDownload.cfc b/system/handlers/core/AssetDownload.cfc index 4a6933a6d9..c1684fd136 100644 --- a/system/handlers/core/AssetDownload.cfc +++ b/system/handlers/core/AssetDownload.cfc @@ -5,12 +5,13 @@ component { property name="websiteUserActionService" inject="websiteUserActionService"; property name="rulesEngineWebRequestService" inject="rulesEngineWebRequestService"; property name="queueMaxWaitAttempts" inject="coldbox:setting:assetManager.queue.downloadWaitSeconds"; + property name="publicCacheAge" inject="coldbox:setting:assetManager.cacheExpiry.public"; + property name="privateCacheAge" inject="coldbox:setting:assetManager.cacheExpiry.private"; public function asset( event, rc, prc ) output=false { announceInterception( "preDownloadAsset" ); - _checkDownloadPermissions( argumentCollection=arguments ); - + var isRestricted = _checkDownloadPermissions( argumentCollection=arguments ); var assetId = rc.assetId ?: ""; var versionId = rc.versionId ?: ""; var derivativeName = rc.derivativeId ?: ""; @@ -137,8 +138,13 @@ component { ); } + header name="etag" value=etag; - header name="cache-control" value="max-age=31536000"; + if ( isRestricted ) { + header name="cache-control" value="private, max-age=#privateCacheAge#"; + } else { + header name="cache-control" value="public, max-age=#publicCacheAge#"; + } if ( IsBinary( assetFilePathOrBinary ) ) { content @@ -178,54 +184,55 @@ component { return ReReplace( arguments.assetTitle, "\.#arguments.extension#$", "" ) & "." & arguments.extension; } - private void function _checkDownloadPermissions( event, rc, prc ) output=false { + private boolean function _checkDownloadPermissions( event, rc, prc ) output=false { var assetId = rc.assetId ?: ""; var derivativeName = rc.derivativeId ?: ""; if ( Len( Trim( derivativeName ) ) && assetManagerService.isDerivativePubliclyAccessible( derivativeName ) ) { - return; + return false; } var permissionSettings = assetManagerService.getAssetPermissioningSettings( assetId ); + if ( !permissionSettings.restricted ) { + return false; + } + if ( !event.isAdminUser() ) { - if ( permissionSettings.restricted ) { - if ( Len( Trim( permissionSettings.conditionId ) ) ) { - var conditionIsTrue = rulesEngineWebRequestService.evaluateCondition( permissionSettings.conditionId ); - - if ( !conditionIsTrue ) { - if ( !isLoggedIn() || ( permissionSettings.fullLoginRequired && isAutoLoggedIn() ) ) { - event.accessDenied( reason="LOGIN_REQUIRED", postLoginUrl=( cgi.http_referer ?: "" ) ); - } else { - event.accessDenied( reason="INSUFFICIENT_PRIVILEGES" ); - } + if ( Len( Trim( permissionSettings.conditionId ) ) ) { + var conditionIsTrue = rulesEngineWebRequestService.evaluateCondition( permissionSettings.conditionId ); + + if ( !conditionIsTrue ) { + if ( !isLoggedIn() || ( permissionSettings.fullLoginRequired && isAutoLoggedIn() ) ) { + event.accessDenied( reason="LOGIN_REQUIRED", postLoginUrl=( cgi.http_referer ?: "" ) ); + } else { + event.accessDenied( reason="INSUFFICIENT_PRIVILEGES" ); } - return; } - var hasPerm = event.isAdminUser() && hasCmsPermission( - permissionKey = "assetmanager.assets.download" - , context = "assetmanagerfolder" - , contextKeys = permissionSettings.contextTree - , forceGrantByDefault = IsBoolean( permissionSettings.grantAcessToAllLoggedInUsers ) && permissionSettings.grantAcessToAllLoggedInUsers - ); - if ( hasPerm ) { return; } + return true; + } + var hasPerm = event.isAdminUser() && hasCmsPermission( + permissionKey = "assetmanager.assets.download" + , context = "assetmanagerfolder" + , contextKeys = permissionSettings.contextTree + , forceGrantByDefault = IsBoolean( permissionSettings.grantAcessToAllLoggedInUsers ) && permissionSettings.grantAcessToAllLoggedInUsers + ); + if ( hasPerm ) { return true; } - if ( !isLoggedIn() || ( permissionSettings.fullLoginRequired && isAutoLoggedIn() ) ) { - event.accessDenied( reason="LOGIN_REQUIRED", postLoginUrl=( cgi.http_referer ?: "" ) ); - } + if ( !isLoggedIn() || ( permissionSettings.fullLoginRequired && isAutoLoggedIn() ) ) { + event.accessDenied( reason="LOGIN_REQUIRED", postLoginUrl=( cgi.http_referer ?: "" ) ); + } - hasPerm = hasWebsitePermission( - permissionKey = "assets.access" - , context = "asset" - , contextKeys = permissionSettings.contextTree - , forceGrantByDefault = IsBoolean( permissionSettings.grantAcessToAllLoggedInUsers ) && permissionSettings.grantAcessToAllLoggedInUsers - ) - if ( !hasPerm ) { - event.accessDenied( reason="INSUFFICIENT_PRIVILEGES" ); - } + hasPerm = hasWebsitePermission( + permissionKey = "assets.access" + , context = "asset" + , contextKeys = permissionSettings.contextTree + , forceGrantByDefault = IsBoolean( permissionSettings.grantAcessToAllLoggedInUsers ) && permissionSettings.grantAcessToAllLoggedInUsers + ) + if ( !hasPerm ) { + event.accessDenied( reason="INSUFFICIENT_PRIVILEGES" ); } } else { - hasPerm = hasCmsPermission( permissionKey = "assetmanager.assets.download" , context = "assetmanagerfolder" @@ -235,5 +242,7 @@ component { event.accessDenied( reason="INSUFFICIENT_PRIVILEGES" ); } } + + return true; } } \ No newline at end of file From 73741cde919f89a626f5a7d49089aa23ce4a3a81 Mon Sep 17 00:00:00 2001 From: Dominic Watson Date: Fri, 15 Sep 2023 11:26:26 +0100 Subject: [PATCH 10/13] PRESIDECMS-2708 tidy up methods + fix lack of var on variable --- system/handlers/core/AssetDownload.cfc | 93 +++++++++++++------------- 1 file changed, 46 insertions(+), 47 deletions(-) diff --git a/system/handlers/core/AssetDownload.cfc b/system/handlers/core/AssetDownload.cfc index c1684fd136..5ac26b7b96 100644 --- a/system/handlers/core/AssetDownload.cfc +++ b/system/handlers/core/AssetDownload.cfc @@ -8,10 +8,14 @@ component { property name="publicCacheAge" inject="coldbox:setting:assetManager.cacheExpiry.public"; property name="privateCacheAge" inject="coldbox:setting:assetManager.cacheExpiry.private"; - public function asset( event, rc, prc ) output=false { + public function asset( event, rc, prc ) { announceInterception( "preDownloadAsset" ); - var isRestricted = _checkDownloadPermissions( argumentCollection=arguments ); + var permissionSettings = _getPermissionSettings( argumentCollection=arguments ); + if ( permissionSettings.restricted ) { + _checkDownloadPermissions( argumentCollection=arguments, permissionSettings=permissionSettings ); + } + var assetId = rc.assetId ?: ""; var versionId = rc.versionId ?: ""; var derivativeName = rc.derivativeId ?: ""; @@ -138,9 +142,8 @@ component { ); } - header name="etag" value=etag; - if ( isRestricted ) { + if ( permissionSettings.restricted ) { header name="cache-control" value="private, max-age=#privateCacheAge#"; } else { header name="cache-control" value="public, max-age=#publicCacheAge#"; @@ -173,7 +176,7 @@ component { } // private helpers - private string function _doBrowserEtagLookup( required string etag ) output=false { + private string function _doBrowserEtagLookup( required string etag ) { if ( ( cgi.http_if_none_match ?: "" ) == arguments.etag ) { announceInterception( "onReturnAsset304", { etag = arguments.etag } ); content reset=true;header statuscode=304 statustext="Not Modified";abort; @@ -184,7 +187,7 @@ component { return ReReplace( arguments.assetTitle, "\.#arguments.extension#$", "" ) & "." & arguments.extension; } - private boolean function _checkDownloadPermissions( event, rc, prc ) output=false { + private struct function _getPermissionSettings( event, rc, prc ) { var assetId = rc.assetId ?: ""; var derivativeName = rc.derivativeId ?: ""; @@ -192,57 +195,53 @@ component { return false; } - var permissionSettings = assetManagerService.getAssetPermissioningSettings( assetId ); - - if ( !permissionSettings.restricted ) { - return false; - } - - if ( !event.isAdminUser() ) { - if ( Len( Trim( permissionSettings.conditionId ) ) ) { - var conditionIsTrue = rulesEngineWebRequestService.evaluateCondition( permissionSettings.conditionId ); - - if ( !conditionIsTrue ) { - if ( !isLoggedIn() || ( permissionSettings.fullLoginRequired && isAutoLoggedIn() ) ) { - event.accessDenied( reason="LOGIN_REQUIRED", postLoginUrl=( cgi.http_referer ?: "" ) ); - } else { - event.accessDenied( reason="INSUFFICIENT_PRIVILEGES" ); - } - } - return true; - } - var hasPerm = event.isAdminUser() && hasCmsPermission( - permissionKey = "assetmanager.assets.download" - , context = "assetmanagerfolder" - , contextKeys = permissionSettings.contextTree - , forceGrantByDefault = IsBoolean( permissionSettings.grantAcessToAllLoggedInUsers ) && permissionSettings.grantAcessToAllLoggedInUsers - ); - if ( hasPerm ) { return true; } + return assetManagerService.getAssetPermissioningSettings( assetId ); + } - if ( !isLoggedIn() || ( permissionSettings.fullLoginRequired && isAutoLoggedIn() ) ) { - event.accessDenied( reason="LOGIN_REQUIRED", postLoginUrl=( cgi.http_referer ?: "" ) ); - } + private void function _checkDownloadPermissions( event, rc, prc, permissionSettings ) { + var assetId = rc.assetId ?: ""; + var derivativeName = rc.derivativeId ?: ""; + var hasPerm = false; - hasPerm = hasWebsitePermission( - permissionKey = "assets.access" - , context = "asset" - , contextKeys = permissionSettings.contextTree - , forceGrantByDefault = IsBoolean( permissionSettings.grantAcessToAllLoggedInUsers ) && permissionSettings.grantAcessToAllLoggedInUsers - ) - if ( !hasPerm ) { - event.accessDenied( reason="INSUFFICIENT_PRIVILEGES" ); - } - } else { + if ( event.isAdminUser() ) { hasPerm = hasCmsPermission( permissionKey = "assetmanager.assets.download" , context = "assetmanagerfolder" - , contextKeys = permissionSettings.contextTree ?: [] + , contextKeys = arguments.permissionSettings.contextTree ?: [] ); if ( !hasPerm ) { event.accessDenied( reason="INSUFFICIENT_PRIVILEGES" ); } + return; } - return true; + if ( Len( Trim( arguments.permissionSettings.conditionId ) ) ) { + var conditionIsTrue = rulesEngineWebRequestService.evaluateCondition( arguments.permissionSettings.conditionId ); + + if ( conditionIsTrue ) { + return; + } + + if ( !isLoggedIn() || ( arguments.permissionSettings.fullLoginRequired && isAutoLoggedIn() ) ) { + event.accessDenied( reason="LOGIN_REQUIRED", postLoginUrl=( cgi.http_referer ?: "" ) ); + } else { + event.accessDenied( reason="INSUFFICIENT_PRIVILEGES" ); + } + } + + if ( !isLoggedIn() || ( arguments.permissionSettings.fullLoginRequired && isAutoLoggedIn() ) ) { + event.accessDenied( reason="LOGIN_REQUIRED", postLoginUrl=( cgi.http_referer ?: "" ) ); + } + + hasPerm = hasWebsitePermission( + permissionKey = "assets.access" + , context = "asset" + , contextKeys = arguments.permissionSettings.contextTree + , forceGrantByDefault = IsBoolean( arguments.permissionSettings.grantAcessToAllLoggedInUsers ) && arguments.permissionSettings.grantAcessToAllLoggedInUsers + ); + + if ( !hasPerm ) { + event.accessDenied( reason="INSUFFICIENT_PRIVILEGES" ); + } } } \ No newline at end of file From be825f7549d3abe22a258ea693d75b069632ab69 Mon Sep 17 00:00:00 2001 From: Dominic Watson Date: Fri, 15 Sep 2023 11:31:48 +0100 Subject: [PATCH 11/13] PRESIDECMS-2708 ensure we return expected format in all scenarios here --- system/handlers/core/AssetDownload.cfc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/system/handlers/core/AssetDownload.cfc b/system/handlers/core/AssetDownload.cfc index 5ac26b7b96..06b7598e02 100644 --- a/system/handlers/core/AssetDownload.cfc +++ b/system/handlers/core/AssetDownload.cfc @@ -192,7 +192,7 @@ component { var derivativeName = rc.derivativeId ?: ""; if ( Len( Trim( derivativeName ) ) && assetManagerService.isDerivativePubliclyAccessible( derivativeName ) ) { - return false; + return { restricted=false }; } return assetManagerService.getAssetPermissioningSettings( assetId ); From ae4a143dad0b7ea57238ef1e7837b78d54cedd38 Mon Sep 17 00:00:00 2001 From: Dominic Watson Date: Fri, 15 Sep 2023 14:56:47 +0100 Subject: [PATCH 12/13] PRESIDECMS-2707 i18n tweak --- system/i18n/cms.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/system/i18n/cms.properties b/system/i18n/cms.properties index 3618eee30e..6090ddc3a3 100644 --- a/system/i18n/cms.properties +++ b/system/i18n/cms.properties @@ -1882,7 +1882,7 @@ emailcenter.send.date.unknown.alert=This email has not been scheduled to send. E emailcenter.send.date.in.past.alert=This email has as scheduled send date in the past: {1}. However, no emails have been sent. You may wish to edit the email settings to schedule the send. emailcenter.next.send.date.alert=Next scheduled send: {1}. Estimated recipient count: {2}. emailcenter.next.send.date.unknown.alert=Next scheduled send: unknown -emailcenter.next.send.date.in.past.alert=This email has as scheduled send date in the past: {1}. However, this should be corrected by the background email sending task very soon. +emailcenter.next.send.date.in.past.alert=This email has a scheduled send date in the past: {1}. This will self-correct shortly. emailcenter.manual.send.alert=This email is set to send manually. Use the "Send" button at the top right of your screen to begin the sending process. emailcenter.blueprints.page.title=Manage Email blueprints From 7f95cbe0770ef8684caad0fe9d38afa68f591286 Mon Sep 17 00:00:00 2001 From: Dominic Watson Date: Mon, 18 Sep 2023 10:57:07 +0100 Subject: [PATCH 13/13] [twgit] Init hotfix 'hotfix-10.24.17'.