From 731985b30ffba598c0d7959c38c174dff47b1df1 Mon Sep 17 00:00:00 2001 From: Sebastian Grewe Date: Tue, 31 Dec 2013 22:31:47 +0100 Subject: [PATCH 1/3] [IMPROVED] Token expiration timers * Added new SQL file to update tokentypes table * Added new function to base class * Renamed function in base class used in shares class * Added new error code * Added new cronjob to delete expired tokens * Added new cronjob to run-cron scripts and monitoring page * Added new function to tokentype class * Added new function to token class Will address #1181 once merged. --- cronjobs/run-crons.sh | 2 +- cronjobs/run-maintenance.sh | 2 +- cronjobs/token_cleanup.php | 39 +++++++++++++++++++ public/include/classes/base.class.php | 25 ++++++++++-- public/include/classes/share.class.php | 2 +- public/include/classes/token.class.php | 29 ++++++++++++++ public/include/classes/tokentype.class.php | 21 ++++++++++ public/include/config/error_codes.inc.php | 3 +- public/include/pages/admin/monitoring.inc.php | 2 +- sql/009_tokentype_update.sql | 2 + 10 files changed, 119 insertions(+), 8 deletions(-) create mode 100755 cronjobs/token_cleanup.php create mode 100644 sql/009_tokentype_update.sql diff --git a/cronjobs/run-crons.sh b/cronjobs/run-crons.sh index 4cfe9325..759d1879 100755 --- a/cronjobs/run-crons.sh +++ b/cronjobs/run-crons.sh @@ -10,7 +10,7 @@ PHP_BIN=$( which php ) # List of cruns to execute -CRONS="findblock.php proportional_payout.php pplns_payout.php pps_payout.php blockupdate.php payouts.php tickerupdate.php notifications.php statistics.php archive_cleanup.php" +CRONS="findblock.php proportional_payout.php pplns_payout.php pps_payout.php blockupdate.php payouts.php tickerupdate.php notifications.php statistics.php token_cleanup.php archive_cleanup.php" # Output additional runtime information VERBOSE="0" diff --git a/cronjobs/run-maintenance.sh b/cronjobs/run-maintenance.sh index 7a7a2dca..05bd93a6 100755 --- a/cronjobs/run-maintenance.sh +++ b/cronjobs/run-maintenance.sh @@ -10,7 +10,7 @@ PHP_BIN=$( which php ) # List of cruns to execute -CRONS="tickerupdate.php notifications.php archive_cleanup.php" +CRONS="tickerupdate.php notifications.php token_cleanup.php archive_cleanup.php" # Output additional runtime information VERBOSE="0" diff --git a/cronjobs/token_cleanup.php b/cronjobs/token_cleanup.php new file mode 100755 index 00000000..d1a350e4 --- /dev/null +++ b/cronjobs/token_cleanup.php @@ -0,0 +1,39 @@ +#!/usr/bin/php +cleanupTokens()) { + $oToken->deleted == 0 ? $log->logDebug('Did not find any expired tokens') : $log->logInfo('Deleted ' . $oToken->deleted . ' expired tokens'); +} else { + $log->logError('Failed to delete expired tokens: ' . $oToken->getCronError()); + // Treat as critical since tokens like password resets will never expire + $monitoring->endCronjob($cron_name, 'E0074', 1, true, true); +} + +// Cron cleanup and monitoring +require_once('cron_end.inc.php'); +?> diff --git a/public/include/classes/base.class.php b/public/include/classes/base.class.php index 839ddd45..3afba032 100644 --- a/public/include/classes/base.class.php +++ b/public/include/classes/base.class.php @@ -116,17 +116,36 @@ class Base { } /** - * Get an element as an associated array + * Fetch all entries as an assoc array from a table + * This should, in general, not be used but sometimes it's just easier + * @param none + * @return array Assoc array of all rows found in table **/ - protected function getAllAssoc($value, $field='id', $type='i') { + public function getAllAssoc() { + $this->debug->append("STA " . __METHOD__, 4); + $stmt = $this->mysqli->prepare("SELECT * FROM $this->table"); + if ($this->checkStmt($stmt) && $stmt->execute() && $result = $stmt->get_result()) + return $result->fetch_all(MYSQLI_ASSOC); + return $this->sqlError(); + } + + /** + * Get a single row as an assoc array + * @param value string Value to search for + * @param field string Column to search for + * @param type string Type of value + * @return array Resulting row + **/ + protected function getSingleAssoc($value, $field='id', $type='i') { $this->debug->append("STA " . __METHOD__, 4); $stmt = $this->mysqli->prepare("SELECT * FROM $this->table WHERE $field = ? LIMIT 1"); if ($this->checkStmt($stmt) && $stmt->bind_param($type, $value) && $stmt->execute() && $result = $stmt->get_result()) return $result->fetch_assoc(); return false; } + /** - * Get a single row from the table + * Get a single value from a row matching the query specified * @param value string Value to search for * @param search Return column to search for * @param field string Search column diff --git a/public/include/classes/share.class.php b/public/include/classes/share.class.php index 337d1b77..d0fd0144 100644 --- a/public/include/classes/share.class.php +++ b/public/include/classes/share.class.php @@ -27,7 +27,7 @@ class Share Extends Base { * @return array Share data **/ public function getShareById($id) { - return $this->getAllAssoc($id); + return $this->getSingleAssoc($id); } /** diff --git a/public/include/classes/token.class.php b/public/include/classes/token.class.php index dd0552f0..8453c245 100644 --- a/public/include/classes/token.class.php +++ b/public/include/classes/token.class.php @@ -54,6 +54,35 @@ class Token Extends Base { return true; return $this->sqlError(); } + + /** + * Cleanup token table of expired tokens + * @param none + * @return bool + **/ + public function cleanupTokens() { + // Get all tokens that have an expiration set + if (!$aTokenTypes = $this->tokentype->getAllExpirations()) { + // Verbose error for crons since this should not happen + $this->setCronMessage('Failed to fetch tokens with expiration times: ' . $this->tokentype->getCronError()); + return false; + } + + $failed = $this->deleted = 0; + foreach ($aTokenTypes as $aTokenType) { + $stmt = $this->mysqli->prepare("DELETE FROM $this->table WHERE (NOW() - time) > ? AND type = ?"); + if (! ($this->checkStmt($stmt) && $stmt->bind_param('ii', $aTokenType['expiration'], $aTokenType['id']) && $stmt->execute())) { + $failed++; + } else { + $this->deleted += $stmt->affected_rows; + } + } + if ($failed > 0) { + $this->setCronMessage('Failed to delete ' . $failed . ' token types from ' . $this->table . ' table'); + return false; + } + return true; + } } $oToken = new Token(); diff --git a/public/include/classes/tokentype.class.php b/public/include/classes/tokentype.class.php index f4f238ee..8befe7f0 100644 --- a/public/include/classes/tokentype.class.php +++ b/public/include/classes/tokentype.class.php @@ -15,6 +15,27 @@ class Token_Type Extends Base { public function getTypeId($strName) { return $this->getSingle($strName, 'id', 'name', 's'); } + + /** + * Return expiration time for token type + * @param id int Token ID + * @param time int Time in seconds for expiration + **/ + public function getExpiration($id) { + return $this->getSingle($id, 'expiration', 'id', 'i'); + } + + /** + * Fetch all tokens that have an expiration set + * @param none + * @return array Tokens with expiration times set + **/ + public function getAllExpirations() { + $stmt = $this->mysqli->prepare("SELECT * FROM $this->table WHERE expiration > 0"); + if ($this->checkStmt($stmt) && $stmt->execute() && $result = $stmt->get_result()) + return $result->fetch_all(MYSQLI_ASSOC); + return $this->sqlError(); + } } $tokentype = new Token_Type(); diff --git a/public/include/config/error_codes.inc.php b/public/include/config/error_codes.inc.php index 1c5eee85..f0979fc1 100644 --- a/public/include/config/error_codes.inc.php +++ b/public/include/config/error_codes.inc.php @@ -70,5 +70,6 @@ $aErrorCodes['E0063'] = 'Upstream share already assigned to previous block'; $aErrorCodes['E0064'] = 'Failed to create transaction record'; $aErrorCodes['E0065'] = 'Remaining balance is greater than 0'; $aErrorCodes['E0072'] = 'Worker names must be alphanumeric'; -$aErrorCodes['E0073'] = 'Worker name is too long; try entering a shorter name' +$aErrorCodes['E0073'] = 'Worker name is too long; try entering a shorter name'; +$aErrorCodes['E0074'] = 'Failed deleting expired tokens'; ?> diff --git a/public/include/pages/admin/monitoring.inc.php b/public/include/pages/admin/monitoring.inc.php index 4fabe56e..9b8f795c 100644 --- a/public/include/pages/admin/monitoring.inc.php +++ b/public/include/pages/admin/monitoring.inc.php @@ -10,7 +10,7 @@ if (!$user->isAuthenticated() || !$user->isAdmin($_SESSION['USERDATA']['id'])) { } // Default crons to monitor -$aCrons = array('statistics','payouts','archive_cleanup','blockupdate','findblock','notifications','tickerupdate'); +$aCrons = array('statistics','payouts','token_cleanup','archive_cleanup','blockupdate','findblock','notifications','tickerupdate'); // Special cases, only add them if activated switch ($config['payout_system']) { diff --git a/sql/009_tokentype_update.sql b/sql/009_tokentype_update.sql new file mode 100644 index 00000000..bacbc551 --- /dev/null +++ b/sql/009_tokentype_update.sql @@ -0,0 +1,2 @@ +ALTER TABLE `token_types` ADD `expiration` INT NULL DEFAULT '0'; +UPDATE `token_types` SET `expiration` = 3600 WHERE `id` = 1; From 0b5e6ae25074b658730c2f8150d437c46b1828ec Mon Sep 17 00:00:00 2001 From: Sebastian Grewe Date: Tue, 31 Dec 2013 22:38:52 +0100 Subject: [PATCH 2/3] [FIX] Removed debug test --- cronjobs/token_cleanup.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cronjobs/token_cleanup.php b/cronjobs/token_cleanup.php index d1a350e4..dec00bd9 100755 --- a/cronjobs/token_cleanup.php +++ b/cronjobs/token_cleanup.php @@ -26,7 +26,7 @@ chdir(dirname(__FILE__)); require_once('shared.inc.php'); // Cleanup old expired tokens -if (!$oToken->cleanupTokens()) { +if ($oToken->cleanupTokens()) { $oToken->deleted == 0 ? $log->logDebug('Did not find any expired tokens') : $log->logInfo('Deleted ' . $oToken->deleted . ' expired tokens'); } else { $log->logError('Failed to delete expired tokens: ' . $oToken->getCronError()); From 1e612c5a943194de38b93cb9c7c35b384c722193 Mon Sep 17 00:00:00 2001 From: Sebastian Grewe Date: Wed, 1 Jan 2014 10:32:11 +0100 Subject: [PATCH 3/3] [ADDED] Updated base structure --- sql/000_base_structure.sql | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/sql/000_base_structure.sql b/sql/000_base_structure.sql index 6c8acc1a..502d22b2 100644 --- a/sql/000_base_structure.sql +++ b/sql/000_base_structure.sql @@ -189,14 +189,15 @@ CREATE TABLE IF NOT EXISTS `tokens` ( CREATE TABLE IF NOT EXISTS `token_types` ( `id` tinyint(4) unsigned NOT NULL AUTO_INCREMENT, `name` varchar(25) NOT NULL, + `expiration` INT NULL DEFAULT '0', PRIMARY KEY (`id`), UNIQUE KEY `name` (`name`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -INSERT INTO `token_types` (`id`, `name`) VALUES -(1, 'password_reset'), -(2, 'confirm_email'), -(3, 'invitation'); +INSERT INTO `token_types` (`id`, `name`, `expiration`) VALUES +(1, 'password_reset', 3600), +(2, 'confirm_email', 0), +(3, 'invitation', 0); CREATE TABLE IF NOT EXISTS `transactions` ( `id` int(255) NOT NULL AUTO_INCREMENT,