[TikiWiki-commits] [Git][tikiwiki/tiki][29.x] [BP][FIX] Fix Unsubscribe get request with no hash
"Elifeleti Mukisa Dan \(@Danelif\) via TikiWiki-cvs" <[email protected]>
| Newsgroups | gmane.comp.cms.tiki.cvs |
|---|---|
| Message-ID | <6a10c013d9747_3819e22c300a5@gitlab-sidekiq-low-urgency-cpu-bound-v2-d7f87744c-2lcgs.mail> |
Elifeleti Mukisa Dan pushed to branch 29.x at Tiki Wiki CMS Groupware / Tiki Commits: d1a2bfd0 by Elifeleti Mukisa Dan at 2026-05-22T20:36:52+00:00 [BP][FIX] Fix Unsubscribe get request with no hash --- * [BP][FIX] Fix Unsubscribe get request with no hash --- * [FIX] Fix Unsubscribe get request with no hash --- * [FIX] Fix Unsubscribe get request with no hash (cherry picked from commit a713cc9ed70513e0b41345032c99dc21820f8399) a713cc9e [FIX] Fix Unsubscribe get request with no hash Co-authored-by: Danelif <[email protected]> See merge request tikiwiki/tiki!10300 (cherry picked from commit 4e52055842453481e06daf310baf98779f3ffca8) dace1151 [FIX] Fix Unsubscribe get request with no hash Co-authored-by: Elifeleti Mukisa Dan <[email protected]> See merge request tikiwiki/tiki!10320 See merge request tikiwiki/tiki!10330 - - - - - 10 changed files: - lib/notifications/notificationemaillib.php - lib/tikilib.php - templates/mail/user_watch_article_post.tpl - templates/mail/user_watch_blog_post.tpl - templates/mail/user_watch_comment.tpl - templates/mail/user_watch_map_changed.tpl - templates/mail/user_watch_wiki_new_attach.tpl - templates/mail/user_watch_wiki_page_changed.tpl - templates/mail/user_watch_wiki_page_renamed.tpl - tiki-user_watches.php Changes: ===================================== lib/notifications/notificationemaillib.php ===================================== @@ -399,7 +399,12 @@ function sendWikiEmailNotification( if (empty($not['email'])) { continue; } - $smarty->assign('watchId', isset($not['watchId']) ? $not['watchId'] : ''); + $smarty->assign('watchId', $not['watchId'] ?? ''); + $watchUnsubscribeHash = ''; + if (! empty($not['watchId']) && ! empty($not['user'])) { + $watchUnsubscribeHash = $tikilib->generateWatchUnsubscribeHash($not['watchId'], $not['user']); + } + $smarty->assign('watchUnsubscribeHash', $watchUnsubscribeHash); $mail_subject = $smarty->fetchLang($not['language'], "mail/user_watch_wiki_page_changed_subject.tpl"); $mail_data = $smarty->fetchLang($not['language'], "mail/user_watch_wiki_page_changed.tpl"); @@ -448,6 +453,11 @@ function sendEmailNotification($watches, $dummy, $subjectTpl, $subjectParam, $tx } $smarty->assign('watchId', $watch['watchId'] ?? null); + $watchUnsubscribeHash = ''; + if (! empty($watch['watchId']) && ! empty($watch['user'])) { + $watchUnsubscribeHash = $tikilib->generateWatchUnsubscribeHash($watch['watchId'], $watch['user']); + } + $smarty->assign('watchUnsubscribeHash', $watchUnsubscribeHash); if ($watch['user']) { $mail->setUser($watch['user']); } ===================================== lib/tikilib.php ===================================== @@ -914,6 +914,39 @@ class TikiLib extends TikiDb_Bridge return $this->table('tiki_user_watches')->fetchOne('user', ['watchId' => $id]); } + + /** + * Generate an HMAC hash for a watch unsubscribe link. + * + * The hash binds the watchId to its owner so that only someone who + * received the original email notification can use the link. + * + * @param int $watchId + * @param string $user Owner of the watch + * @return string Hex-encoded HMAC-SHA256 + */ + public function generateWatchUnsubscribeHash($watchId, $user) + { + $key = $this->get_site_hash(); + return hash_hmac('sha256', $watchId . ':' . $user, $key); + } + + /** + * Verify an HMAC hash for a watch unsubscribe link. + * + * @param int $watchId + * @param string $hash Hash received from the request + * @return bool True if the hash is valid for this watchId + */ + public function verifyWatchUnsubscribeHash($watchId, $hash) + { + $owner = $this->get_user_notification($watchId); + if (! $owner) { + return false; + } + $expected = $this->generateWatchUnsubscribeHash($watchId, $owner); + return hash_equals($expected, $hash); + } /*shared*/ /** * @param $id ===================================== templates/mail/user_watch_article_post.tpl ===================================== @@ -13,7 +13,7 @@ {tr}Publish Date:{/tr} {$mail_current_publish_date|tiki_short_datetime:"":"n"} {if !empty($watchId)}{tr}If you don't want to receive these notifications follow this link:{/tr} -{mailurl}tiki-user_watches.php?id={$watchId}{/mailurl}{/if} +{mailurl}tiki-user_watches.php?id={$watchId}&hash={$watchUnsubscribeHash}{/mailurl}{/if} {if isset($mail_old_data)} ===================================== templates/mail/user_watch_blog_post.tpl ===================================== @@ -7,4 +7,4 @@ {mailurl}{$mail_postid|sefurl:blogpost}{/mailurl} {tr}If you don't want to receive these notifications follow this link:{/tr} -{mailurl}tiki-user_watches.php?id={$watchId}{/mailurl} +{mailurl}tiki-user_watches.php?id={$watchId}&hash={$watchUnsubscribeHash}{/mailurl} ===================================== templates/mail/user_watch_comment.tpl ===================================== @@ -27,6 +27,6 @@ {if $watchId} {tr}If you don't want to receive these notifications follow this link:{/tr} -{mailurl}tiki-user_watches.php?id={$watchId}{/mailurl} +{mailurl}tiki-user_watches.php?id={$watchId}&hash={$watchUnsubscribeHash}{/mailurl} {/if} ===================================== templates/mail/user_watch_map_changed.tpl ===================================== @@ -7,4 +7,4 @@ {mailurl}{$mail_link}?mapfile={$mail_page}{/mailurl} {tr}If you don't want to receive these notifications follow this link:{/tr} -{mailurl}tiki-user_watches.php?id={$watchId}{/mailurl} +{mailurl}tiki-user_watches.php?id={$watchId}&hash={$watchUnsubscribeHash}{/mailurl} ===================================== templates/mail/user_watch_wiki_new_attach.tpl ===================================== @@ -9,4 +9,4 @@ {mailurl}{$mail_page|sefurl}{/mailurl} {tr}If you don't want to receive these notifications follow this link:{/tr} -{mailurl}tiki-user_watches.php?id={$watchId}{/mailurl} +{mailurl}tiki-user_watches.php?id={$watchId}&hash={$watchUnsubscribeHash}{/mailurl} ===================================== templates/mail/user_watch_wiki_page_changed.tpl ===================================== @@ -21,7 +21,7 @@ {if $watchId} {tr}If you don't want to receive these notifications follow this link:{/tr} - {mailurl}tiki-user_watches.php?id={$watchId}{/mailurl} + {mailurl}tiki-user_watches.php?id={$watchId}&hash={$watchUnsubscribeHash}{/mailurl} {/if} *********************************************************** ===================================== templates/mail/user_watch_wiki_page_renamed.tpl ===================================== @@ -6,4 +6,4 @@ {tr}New name:{/tr} {$mail_newname} {tr}If you don't want to receive these notifications follow this link:{/tr} -{mailurl}tiki-user_watches.php?id={$watchId}{/mailurl} +{mailurl}tiki-user_watches.php?id={$watchId}&hash={$watchUnsubscribeHash}{/mailurl} ===================================== tiki-user_watches.php ===================================== @@ -14,6 +14,7 @@ $inputConfiguration = [ 'staticKeyFilters' => [ 'categwatch' => 'int', //post 'id' => 'int', //post + 'hash' => 'word', //get - unsubscribe hash 'add' => 'bool', //post 'event' => 'string', //post 'delete' => 'bool', //post @@ -67,14 +68,20 @@ if (isset($_REQUEST['categwatch'])) { } } // request from unsubscribe email link, like in templates/mail/user_watch_map_changed.tpl -// TODO would be better to provide a token with the unsubscribe link that could be matched to the database -// TODO so that the user doesn't have to log in to unsubscribe - similar to unsubscribe in tiki-newsletter.php +// The link includes an HMAC hash so that only the recipient of the email can unsubscribe. if (isset($_REQUEST['id'])) { - if ($tiki_p_admin_notifications != 'y' && $user != $tikilib->get_user_notification($_REQUEST['id'])) { + $watchId = $_REQUEST['id']; + $hash = isset($_REQUEST['hash']) ? $_REQUEST['hash'] : ''; + + if (empty($hash) || ! $tikilib->verifyWatchUnsubscribeHash($watchId, $hash)) { + Feedback::errorPage(['mes' => tr('Invalid or missing unsubscribe token'), 'errortype' => 403]); + } + + if ($tiki_p_admin_notifications != 'y' && $user != $tikilib->get_user_notification($watchId)) { Feedback::errorPage(['mes' => tr('Permission denied'), 'errortype' => 401]); } if ($access->checkCsrf()) { - $result = $tikilib->remove_user_watch_by_id($_REQUEST['id']); + $result = $tikilib->remove_user_watch_by_id($watchId); } if ($result && $result->numRows()) { Feedback::success(tr('Unsubscribed from user watch email notification')); View it on GitLab: https://gitlab.com/tikiwiki/tiki/-/commit/d1a2bfd05f02759da1941c3c9f15636aafa591e8 -- View it on GitLab: https://gitlab.com/tikiwiki/tiki/-/commit/d1a2bfd05f02759da1941c3c9f15636aafa591e8 You're receiving this email because of your account on gitlab.com. Manage all notifications: https://gitlab.com/-/profile/notifications | Help: https://gitlab.com/help _______________________________________________ TikiWiki-cvs mailing list [email protected] https://lists.sourceforge.net/lists/listinfo/tikiwiki-cvs