From 889667e332fe76fc670cb1d4620c47525d9a70bf Mon Sep 17 00:00:00 2001 From: Stefan Kangas Date: Wed, 12 Oct 2022 17:29:04 +0200 Subject: [PATCH] Make `message-unique-id' less prone to collisions * lisp/gnus/message.el (message-unique-id): Make less prone to collisions. (Bug#58472) (message-unique-id-char): Make unused variable obsolete. * test/lisp/gnus/message-tests.el (message-unique-id-test) (message-number-base36-test): New tests. --- lisp/gnus/message.el | 43 ++++++++------------------------- test/lisp/gnus/message-tests.el | 9 +++++++ 2 files changed, 19 insertions(+), 33 deletions(-) diff --git a/lisp/gnus/message.el b/lisp/gnus/message.el index 67ec0531fa..9b85f1c5fd 100644 --- a/lisp/gnus/message.el +++ b/lisp/gnus/message.el @@ -47,7 +47,7 @@ (require 'rfc2047) (require 'puny) (require 'rmc) ; read-multiple-choice -(require 'subr-x) +(require 'subr-x) ; string-limit (require 'yank-media) (require 'mailcap) (require 'sendmail) @@ -5889,41 +5889,18 @@ message-make-message-id "_-_" "")) "@" (message-make-fqdn) ">")) +(make-obsolete-variable 'message-unique-id-char nil "29.1") (defvar message-unique-id-char nil) -;; If you ever change this function, make sure the new version -;; cannot generate IDs that the old version could. -;; You might for example insert a "." somewhere (not next to another dot -;; or string boundary), or modify the "fsf" string. (defun message-unique-id () - ;; Don't use fractional seconds from timestamp; they may be unsupported. - ;; Instead we use this randomly inited counter. - (setq message-unique-id-char - ;; 2^16 * 25 just fits into 4 digits i base 36. - (let ((base (* 25 25))) - (if message-unique-id-char - (% (1+ message-unique-id-char) base) - (random base)))) - (let ((tm (time-convert nil 'integer))) + (let* ((time (car (time-convert nil t))) + (time-string (string-limit (message-number-base36 time -1) 12)) + (len (- 21 (length time-string)))) (concat - (if (or (eq system-type 'ms-dos) - ;; message-number-base36 doesn't handle bigints. - (floatp (user-uid))) - (let ((user (downcase (user-login-name)))) - (while (string-match "[^a-z0-9_]" user) - (aset user (match-beginning 0) ?_)) - user) - (message-number-base36 (user-uid) -1)) - (message-number-base36 (+ (ash tm -16) - (ash (% message-unique-id-char 25) 16)) - 4) - (message-number-base36 (+ (logand tm #xffff) - (ash (/ message-unique-id-char 25) 16)) - 4) - ;; Append a given name, because while the generated ID is unique - ;; to this newsreader, other newsreaders might otherwise generate - ;; the same ID via another algorithm. - ".fsf"))) + time-string + (message-number-base36 (random (expt 36 len)) len) + ;; Append ".gnu" to advertise that we're GNU Emacs. + ".gnu"))) (defun message-number-base36 (num len) (if (if (< len 0) @@ -5931,7 +5908,7 @@ message-number-base36 (= len 0)) "" (concat (message-number-base36 (/ num 36) (1- len)) - (char-to-string (aref "zyxwvutsrqponmlkjihgfedcba9876543210" + (char-to-string (aref "0123456789abcdefghijklmnopqrstuvwxyz" (% num 36)))))) (defun message-make-organization () diff --git a/test/lisp/gnus/message-tests.el b/test/lisp/gnus/message-tests.el index a724428ecb..e8c0655543 100644 --- a/test/lisp/gnus/message-tests.el +++ b/test/lisp/gnus/message-tests.el @@ -31,6 +31,15 @@ (require 'cl-lib) +(ert-deftest message-unique-id-test () + (should (stringp (message-unique-id))) + (should (= (length (message-unique-id)) 25))) + +(ert-deftest message-number-base36-test () + (should (equal (message-number-base36 10 -1) "a")) + (should (equal (message-number-base36 1 -1) "1")) + (should (equal (message-number-base36 (expt 36 5) -1) "100000"))) + (ert-deftest message-mode-propertize () (with-temp-buffer (unwind-protect -- 2.35.1