From dbec4982873410192f2584ec8aed087f81fb6d67 Mon Sep 17 00:00:00 2001 From: Linty Date: Thu, 4 Sep 2025 17:21:53 +0200 Subject: [PATCH] fixes #2404 notify users of impending API key expiration Adds logic to detect when an API key is about to expire and sends a notification email to the user if the key expires within 7 days and no recent notification was sent. Introduces a new 'last_notified_on' column to the user_auth_keys table to track notification timing. --- include/common.inc.php | 24 +++++++++++ include/functions_user.inc.php | 79 ++++++++++++++++++++++++++++------ install/db/179-database.php | 24 +++++++++++ language/en_UK/common.lang.php | 5 +++ language/fr_FR/common.lang.php | 5 +++ 5 files changed, 124 insertions(+), 13 deletions(-) create mode 100644 install/db/179-database.php diff --git a/include/common.inc.php b/include/common.inc.php index e40129c9f..d9b6f2420 100644 --- a/include/common.inc.php +++ b/include/common.inc.php @@ -253,6 +253,30 @@ if (isset($page['auth_key_invalid']) and $page['auth_key_invalid']) ; } +// check if we need to notified user about api_key expiration +if (isset($page['notify_api_key_expiration']) and is_array($page['notify_api_key_expiration'])) +{ + $is_mail_send = notification_api_key_expiration( + $user['username'], + $user['email'], + $page['notify_api_key_expiration']['days_left'] + ); + + if ($is_mail_send) + { + single_update( + USER_AUTH_KEYS_TABLE, + array('last_notified_on' => $page['notify_api_key_expiration']['dbnow']), + array( + 'user_id' => $user['id'], + 'auth_key' => $page['notify_api_key_expiration']['auth_key'] + ), + ); + } + + unset($page['notify_api_key_expiration']); +} + // template instance if (defined('IN_ADMIN') and IN_ADMIN ) {// Admin template diff --git a/include/functions_user.inc.php b/include/functions_user.inc.php index ac19032c7..6ec16e686 100644 --- a/include/functions_user.inc.php +++ b/include/functions_user.inc.php @@ -1694,7 +1694,10 @@ function auth_key_login($auth_key, $connection_by_header=false) SELECT *, '.$conf['user_fields']['username'].' AS username, - NOW() AS dbnow + '.$conf['user_fields']['email'].' AS email, + NOW() AS dbnow, + DATEDIFF(uak.expired_on, NOW()) AS days_left, + SUBDATE(NOW(), INTERVAL 48 HOUR) AS 48h_ago FROM '.USER_AUTH_KEYS_TABLE.' AS uak JOIN '.USER_INFOS_TABLE.' AS ui ON uak.user_id = ui.user_id JOIN '.USERS_TABLE.' AS u ON u.'.$conf['user_fields']['id'].' = ui.user_id @@ -1709,6 +1712,19 @@ SELECT $key = $keys[0]; + // is the key still valid? + if (strtotime($key['expired_on']) < strtotime($key['dbnow'])) + { + $page['auth_key_invalid'] = true; + return false; + } + + // admin/webmaster/guest can't get connected with authentication keys + if ('auth_key' === $valid_key and !in_array($key['status'], array('normal','generic'))) + { + return false; + } + // the key is an api_key if ('api_key' === $valid_key) { @@ -1723,19 +1739,24 @@ SELECT { return false; } - } - // is the key still valid? - if (strtotime($key['expired_on']) < strtotime($key['dbnow'])) - { - $page['auth_key_invalid'] = true; - return false; - } - - // admin/webmaster/guest can't get connected with authentication keys - if ('auth_key' === $valid_key and !in_array($key['status'], array('normal','generic'))) - { - return false; + // check if we need to notificate the user + $days_left = intval($key['days_left']); + if ( + $days_left <= 7 // the key expire in max 7 days + and !empty($key['email']) // the user have an email + and ( + null === $key['last_notified_on'] // we never send an email for this key + or strtotime($key['last_notified_on']) < strtotime($key['48h_ago']) // OR when the last email was sent more than 48 hours ago + ) + ) + { + $page['notify_api_key_expiration'] = array( + 'days_left' => $days_left, + 'dbnow' => $key['dbnow'], + 'auth_key' => $key['auth_key'] + ); + } } $user['id'] = $key['user_id']; @@ -2655,4 +2676,36 @@ function connected_with_pwg_ui() } return false; } + +/** + * Notify an user when his api key is about to expire + * + * @since 16 + * @return bool + */ +function notification_api_key_expiration($username, $email, $days_left) +{ + global $conf; + + include_once(PHPWG_ROOT_PATH . 'include/functions_mail.inc.php'); + $days_left_str = $days_left <= 1 ? + l10n('Your API key will expire in %d day.', $days_left) + : l10n('Your API key will expire in %d days.', $days_left); + + $message = '

' . l10n('Hello %s,', $username) . '

'; + $message .= '

' . $days_left_str . '

'; + $message .= '

' . l10n('To continue using the API, please renew your key before it expires.') . '

'; + $message .= '

' . l10n('You can manage your API keys in your account settings.', get_absolute_root_url().'profile.php') . '

'; + + $result = @pwg_mail( + $email, + array( + 'subject' => '[' . $conf['gallery_title'] . '] ' . l10n('Your API key will expire soon'), + 'content' => $message, + 'content_format' => 'text/html', + ) + ); + + return $result; +} ?> diff --git a/install/db/179-database.php b/install/db/179-database.php new file mode 100644 index 000000000..bb9eb8407 --- /dev/null +++ b/install/db/179-database.php @@ -0,0 +1,24 @@ + \ No newline at end of file diff --git a/language/en_UK/common.lang.php b/language/en_UK/common.lang.php index 441599f9f..7fbc3af55 100644 --- a/language/en_UK/common.lang.php +++ b/language/en_UK/common.lang.php @@ -518,3 +518,8 @@ $lang['Do you really want to revoke the "%s" API key?'] = 'Do you really want to $lang['To manage your API keys, please log in with your username/password.'] = 'To manage your API keys, please log in with your username/password.'; $lang['3xlarge'] = '3XL - extra huge'; $lang['4xlarge'] = '4XL - gigantic'; +$lang['Your API key will expire soon'] = 'Your API key will expire soon'; +$lang['Your API key will expire in %d day.'] = 'Your API key will expire in %d day.'; +$lang['Your API key will expire in %d days.'] = 'Your API key will expire in %d days.'; +$lang['To continue using the API, please renew your key before it expires.'] = 'To continue using the API, please renew your key before it expires.'; +$lang['You can manage your API keys in your account settings.'] = 'You can manage your API keys in your account settings.'; diff --git a/language/fr_FR/common.lang.php b/language/fr_FR/common.lang.php index f139b2c5e..79a0e6cc5 100644 --- a/language/fr_FR/common.lang.php +++ b/language/fr_FR/common.lang.php @@ -517,3 +517,8 @@ $lang['Do you really want to revoke the "%s" API key?'] = 'Voulez-vous vraiment $lang['To manage your API keys, please log in with your username/password.'] = 'Pour gérer vos clés API, veuillez vous connecter avec votre nom d\'utilisateur/mot de passe.'; $lang['3xlarge'] = '3XL - très énorme'; $lang['4xlarge'] = '4XL - gigantesque'; +$lang['Your API key will expire soon'] = 'Votre clé API va bientôt expirer'; +$lang['Your API key will expire in %d day.'] = 'Votre clé API expirera dans %d jour.'; +$lang['Your API key will expire in %d days.'] = 'Votre clé API expirera dans %d jours.'; +$lang['To continue using the API, please renew your key before it expires.'] = 'Pour continuer à utiliser l\'API, veuillez renouveler votre clé avant son expiration.'; +$lang['You can manage your API keys in your account settings.'] = 'Vous pouvez gérer vos clés API dans les paramètres de votre compte.';