CiviMail - Fixup edge-case chars. Use consistent function.
authorTim Otten <totten@civicrm.org>
Thu, 21 Sep 2023 01:08:16 +0000 (18:08 -0700)
committerTim Otten <totten@civicrm.org>
Thu, 21 Sep 2023 01:19:15 +0000 (18:19 -0700)
1. Base64 can output some funny chars that are awkward in VERP and URL contexts.
   Use strict lowercase alphanumeric.
2. The new code was being used for the test mailing - but not for real mailings. They should use same formula.

CRM/Mailing/Event/BAO/MailingEventQueue.php

index aa8e99d69db84f9cf51fef67d1111fa3c444581e..056e159db3969def3759cf09adf07bc6a91f5da0 100644 (file)
@@ -29,7 +29,7 @@ class CRM_Mailing_Event_BAO_MailingEventQueue extends CRM_Mailing_Event_DAO_Mail
     $eq = new CRM_Mailing_Event_BAO_MailingEventQueue();
     $eq->copyValues($params);
     if (empty($params['id']) && empty($params['hash'])) {
-      $eq->hash = self::hash($params);
+      $eq->hash = self::hash();
     }
     $eq->save();
     return $eq;
@@ -53,7 +53,9 @@ class CRM_Mailing_Event_BAO_MailingEventQueue extends CRM_Mailing_Event_DAO_Mail
    *   The hash
    */
   public static function hash() {
-    return base64_encode(random_bytes(16));
+    // Case-insensitive. Some b64 chars are awkward in VERP+URL contexts. Over-generate (24 bytes) and then cut-back (16 alphanums).
+    $random = random_bytes(24);
+    return strtolower(substr(str_replace(['+', '/', '='], ['', '', ''], base64_encode($random)), 0, 16));
   }
 
   /**
@@ -296,9 +298,9 @@ SELECT DISTINCT(civicrm_mailing_event_queue.contact_id) as contact_id,
     // construct a bulk insert statement
     $values = [];
     foreach ($params as $param) {
-      $values[] = "( {$param[0]}, {$param[1]}, {$param[2]}, {$param[3]}, '" . substr(sha1("{$param[0]}:{$param[1]}:{$param[2]}:{$param[3]}:{$now}"),
-          0, 16
-        ) . "' )";
+      $hash = static::hash();
+      $values[] = "( {$param[0]}, {$param[1]}, {$param[2]}, {$param[3]}, '" . $hash . "' )";
+      // FIXME: This (non)escaping is valid as currently used but is not robust to change. This should use CRM_Utils_SQL_Insert...
     }
 
     while (!empty($values)) {