From 3e44ba0c55523e5aee8dc90f27379c674ce216e1 Mon Sep 17 00:00:00 2001 From: Arlen Johnson Date: Wed, 25 Jun 2025 09:43:57 -0400 Subject: [PATCH 1/8] Add CSP script-src directive and remove inline event handlers (CO-2720) --- .editorconfig | 23 +++++++++++++ app/src/Controller/AppController.php | 3 ++ app/templates/MatchgridSettings/fields.inc | 15 +++++---- app/templates/Matchgrids/reconcile.php | 8 ++--- app/templates/Permissions/fields.inc | 20 +++++++----- app/templates/RuleAttributes/fields.inc | 16 +++++---- app/templates/SystemsOfRecord/fields.inc | 17 ++++++---- app/templates/element/httpHeaders.php | 9 +++-- app/templates/element/javascript.php | 26 ++++++++++++--- app/templates/element/menuAction.php | 13 ++++++-- app/templates/element/pagination.php | 38 ++++++++-------------- app/templates/element/search.php | 5 ++- app/templates/layout/default.php | 8 +++-- app/webroot/css/co-base.css | 22 +++++-------- app/webroot/js/comanage.js | 22 ++----------- 15 files changed, 141 insertions(+), 104 deletions(-) create mode 100644 .editorconfig diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 000000000..2317d521b --- /dev/null +++ b/.editorconfig @@ -0,0 +1,23 @@ +; This file is for unifying the coding style for different editors and IDEs. +; More information at https://editorconfig.org + +root = true + +[*] +indent_style = space +indent_size = 2 +end_of_line = lf +insert_final_newline = false +trim_trailing_whitespace = false + +[*.bat] +end_of_line = crlf + +[*.yml] +indent_size = 2 + +[*.twig] +insert_final_newline = false + +[Makefile] +indent_style = tab diff --git a/app/src/Controller/AppController.php b/app/src/Controller/AppController.php index 340e090b3..ed331192f 100644 --- a/app/src/Controller/AppController.php +++ b/app/src/Controller/AppController.php @@ -135,6 +135,9 @@ public function beforeRender(EventInterface $event) { $this->set('vv_menu_permissions', $this->Authorization->menuPermissions($this->request->getSession()->read('Auth.User.username'), $mgid)); } + + // Generate a nonce for use in JavaScript tags with the Content-Security-Policy script-src directive + $this->set('vv_js_nonce', base64_encode(random_bytes(16))); } /** diff --git a/app/templates/MatchgridSettings/fields.inc b/app/templates/MatchgridSettings/fields.inc index 9ef13fa05..fb9542f24 100644 --- a/app/templates/MatchgridSettings/fields.inc +++ b/app/templates/MatchgridSettings/fields.inc @@ -27,7 +27,7 @@ use \App\Lib\Enum\ReferenceIdEnum; ?> - Field->control('referenceid_method', - ['empty' => true, - 'onChange' => 'fields_update_gadgets();']); + ['empty' => true]); print $this->Field->control('referenceid_start', ['default' => 1001]); diff --git a/app/templates/Matchgrids/reconcile.php b/app/templates/Matchgrids/reconcile.php index 03f09913f..75b6e3a3c 100644 --- a/app/templates/Matchgrids/reconcile.php +++ b/app/templates/Matchgrids/reconcile.php @@ -217,12 +217,12 @@ - \ No newline at end of file + }); + \ No newline at end of file diff --git a/app/templates/Permissions/fields.inc b/app/templates/Permissions/fields.inc index 04876de61..5e3795841 100644 --- a/app/templates/Permissions/fields.inc +++ b/app/templates/Permissions/fields.inc @@ -27,7 +27,7 @@ use \App\Lib\Enum\PermissionEnum; ?> - Field->control('username'); - - print $this->Field->control('permission', - ['empty' => true, - 'onChange' => 'fields_update_gadgets();']); - + + print $this->Field->control('permission', ['empty' => true]); + print $this->Field->control('matchgrid_id', ['empty' => true]); } \ No newline at end of file diff --git a/app/templates/RuleAttributes/fields.inc b/app/templates/RuleAttributes/fields.inc index 310dd9010..613be2e58 100644 --- a/app/templates/RuleAttributes/fields.inc +++ b/app/templates/RuleAttributes/fields.inc @@ -28,7 +28,7 @@ use \App\Lib\Enum\ConfidenceModeEnum; use \App\Lib\Enum\SearchTypeEnum; ?> - -Field->control('attribute_id', ['empty' => true]); print $this->Field->control('crosscheck_attribute_id', ['empty' => true], false, __('match.fd.RuleAttributes.crosscheck_attribute_id')); print $this->Field->control('search_type', ['empty' => true]); - print $this->Field->control('required', ['onChange'=>'fields_update_gadgets();'], false); + print $this->Field->control('required', [], false); print $this->Field->control('match_empty', [], false); } \ No newline at end of file diff --git a/app/templates/SystemsOfRecord/fields.inc b/app/templates/SystemsOfRecord/fields.inc index 202e41c38..c7c4d87b4 100644 --- a/app/templates/SystemsOfRecord/fields.inc +++ b/app/templates/SystemsOfRecord/fields.inc @@ -28,7 +28,7 @@ use \App\Lib\Enum\ResolutionModeEnum; use \App\Lib\Enum\TrustModeEnum; ?> - true, 'default' => TrustModeEnum::Standard ]); - print $this->Field->control('resolution_mode', - ['empty' => true, - 'onChange' => 'fields_update_gadgets();']); - + print $this->Field->control('resolution_mode', + ['empty' => true]); + print $this->Field->control('notification_email', [], false); } diff --git a/app/templates/element/httpHeaders.php b/app/templates/element/httpHeaders.php index bcf393a49..9a2ab9899 100644 --- a/app/templates/element/httpHeaders.php +++ b/app/templates/element/httpHeaders.php @@ -25,18 +25,21 @@ * @license Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) */ -// As a general rule, all Match pages are post-login and so shouldn't be cached + // As a general rule, all Match pages are post-login and so shouldn't be cached header("Expires: Thursday, 10-Jan-69 00:00:00 GMT"); header("Cache-Control: no-store, no-cache, max-age=0, must-revalidate"); header("Pragma: no-cache"); + + // CakePHP adds inline event handlers ("oninput" and "oninvalid") to fields as part of FormHelper. + // So as not to throw CSP errors, we must include "script-src-attr 'unsafe-inline'". + header("Content-Security-Policy: object-src 'none'; base-uri 'none'; frame-ancestors 'self'; script-src 'self' 'nonce-$vv_js_nonce'; script-src-attr 'unsafe-inline';"); - header("Content-Security-Policy: object-src 'none'; base-uri 'none'; frame-ancestors 'self'"); header("X-Content-Type-Options: nosniff"); header("Permissions-Policy: accelerometer=(),autoplay=(),camera=(),cross-origin-isolated=(),display-capture=(),encrypted-media=(),fullscreen=(),geolocation=(),gyroscope=(),keyboard-map=(),magnetometer=(),microphone=(),midi=(),payment=(),picture-in-picture=(),publickey-credentials-get=(),screen-wake-lock=(),sync-xhr=(self),usb=(),web-share=(),xr-spatial-tracking=(),gamepad=(),hid=(),idle-detection=(),interest-cohort=(),serial=()"); header("Cross-Origin-Opener-Policy: same-origin"); header("X-Permitted-Cross-Domain-Policies: none"); -// Add X-UA-Compatible header for IE + // Add X-UA-Compatible header for IE if (isset($_SERVER['HTTP_USER_AGENT']) && (strpos($_SERVER['HTTP_USER_AGENT'], 'MSIE') !== false)) { header('X-UA-Compatible: IE=edge,chrome=1'); } diff --git a/app/templates/element/javascript.php b/app/templates/element/javascript.php index 352f7b476..ad0f9197c 100644 --- a/app/templates/element/javascript.php +++ b/app/templates/element/javascript.php @@ -19,7 +19,7 @@ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. - * + * * @link http://www.internet2.edu/comanage COmanage Project * @package match * @since COmanage Match v1.0.0 @@ -27,7 +27,7 @@ */ ?> - Form->postButton($action['onclick']['dg_conf_btn'], $action['onclick']['dg_post_btn_array'],['id' => $actionUid, 'class' => 'hidden']); ?> diff --git a/app/templates/element/pagination.php b/app/templates/element/pagination.php index c83fab84c..2cdffb7ab 100644 --- a/app/templates/element/pagination.php +++ b/app/templates/element/pagination.php @@ -43,31 +43,21 @@ Paginator->hasPage(2)): ?> - - -