diff --git a/CRM/Contact/BAO/Contact/Utils.php b/CRM/Contact/BAO/Contact/Utils.php index 84aa8fb09d4a..170ddec5409e 100644 --- a/CRM/Contact/BAO/Contact/Utils.php +++ b/CRM/Contact/BAO/Contact/Utils.php @@ -202,6 +202,12 @@ public static function generateChecksum($entityId, $ts = NULL, $live = NULL, $ha * @throws \CRM_Core_Exception */ public static function validChecksum($contactID, $inputCheck) { + // Allow a hook to invalidate checksums + $invalid = FALSE; + CRM_Utils_Hook::invalidateChecksum($contactID, $inputCheck, $invalid); + if ($invalid) { + return FALSE; + } $input = CRM_Utils_System::explode('_', $inputCheck, 3); diff --git a/CRM/Utils/Hook.php b/CRM/Utils/Hook.php index 82877f3feb08..9d93fa822b0c 100644 --- a/CRM/Utils/Hook.php +++ b/CRM/Utils/Hook.php @@ -2835,4 +2835,23 @@ public static function alterApiRoutePermissions(&$permissions, $entity, $action) ); } + /** + * Allows an extension to override the checksum validation. + * For example you may want to invalidate checksums that were sent out/forwarded by mistake. You could also + * intercept and redirect to a different page in this case - eg. to say "sorry, you tried to use a compromised + * checksum". + * + * @param int $contactID + * @param string $checksum + * @param bool $invalid + * Leave this at FALSE to allow the core code to perform validation. Set to TRUE to invalidate + */ + public static function invalidateChecksum($contactID, $checksum, &$invalid) { + return self::singleton()->invoke( + ['contactID', 'checksum', 'invalid'], + $contactID, $checksum, $isValid, self::$_nullObject, self::$_nullObject, + self::$_nullObject, 'civicrm_invalidateChecksum' + ); + } + }