diff -Nrup services/services.module services_patched/services.module --- services/services.module 2008-09-07 01:17:30.000000000 +0200 +++ services_patched/services.module 2009-01-14 00:12:28.750000000 +0100 @@ -241,14 +241,22 @@ function services_error($message) { return $message; } +function services_access_log($loglevel, $method_name, $args, $method_requires_key = FALSE, $api_key = '') { + if (module_exists('services_statistics')) { + services_statistics_access_log($loglevel, $method_name, $args, $method_requires_key, $api_key); + } +} + /** * This is the magic function through which all remote method calls must pass. */ function services_method_call($method_name, $args = array()) { $method = services_method_get($method_name); + $original_args = $args; // Check that method exists. if (empty($method)) { + services_access_log(SERVICES_STATS_UNKNOWNMETHOD, $method_name, $original_args); return services_error(t('Method %name does not exist.', array('%name' => $method_name))); } @@ -257,6 +265,7 @@ function services_method_call($method_na foreach ($method['#args'] as $key => $arg) { if (!$arg['#optional']) { if (!is_numeric($args[$key]) and empty($args[$key])) { + services_access_log(SERVICES_STATS_MISSINGREQUIREDARGUMENTS, $method_name, $original_args, $method['#key']); return services_error(t('Missing required arguments.')); } } @@ -286,6 +295,7 @@ function services_method_call($method_na $expiry_time = $timestamp + variable_get('services_key_expiry', 30); if ($expiry_time < time()) { + services_access_log(SERVICES_STATS_EXPIREDTOKEN, $method_name, $original_args, TRUE); return services_error(t('Token has expired.')); } @@ -293,6 +303,7 @@ function services_method_call($method_na if (db_result(db_query("SELECT count(*) FROM {services_timestamp_nonce} WHERE domain = '%s' AND timestamp = %d AND nonce = '%s'", $domain, $timestamp, $nonce))) { + services_access_log(SERVICES_STATS_USEDTOKEN, $method_name, $original_args, TRUE); return services_error(t('Token has been used previously for a request.')); } else{ @@ -302,9 +313,15 @@ function services_method_call($method_na $api_key = db_result(db_query("SELECT kid FROM {services_keys} WHERE domain = '%s'", $domain)); - if (!services_validate_key($api_key, $timestamp, $domain, $nonce, $method_name, $hash_parameters, $hash)) { + if (!$api_key) { + services_access_log(SERVICES_STATS_INVALIDKEY, $method_name, $original_args, TRUE); return services_error(t('Invalid API key.')); } + + if (!services_validate_key($api_key, $timestamp, $domain, $nonce, $method_name, $hash_parameters, $hash)) { + services_access_log(SERVICES_STATS_INVALIDHASH, $method_name, $original_args, TRUE, $api_key); + return services_error(t('Invalid hash.')); + } } // Add additonal processing for methods requiring authentication @@ -312,6 +329,7 @@ function services_method_call($method_na if ($method['#auth'] and variable_get('services_use_sessid', TRUE)) { $sessid = array_shift($args); if (empty($sessid)) { + services_access_log(SERVICES_STATS_INVALIDSESSION, $method_name, $original_args, $method['#key']); return services_error(t('Invalid sessid.')); } $session_backup = services_session_load($sessid); @@ -326,6 +344,7 @@ function services_method_call($method_na $access_arguments = isset($method['#access arguments']) ? $method['#access arguments'] : $args; // Call default or custom access callback if (call_user_func_array($method['#access callback'], $access_arguments) != TRUE) { + services_access_log(SERVICES_STATS_ACCESSDENIED, $method_name, $original_args, $method['#key']); return services_error(t('Access denied.')); } @@ -346,6 +365,7 @@ function services_method_call($method_na services_session_unload($session_backup); } + services_access_log(SERVICES_STATS_SUCCESS, $method_name, $original_args, $method['#key']); return $result; } diff -Nrup services/services_statistics/services_statistics.info services_patched/services_statistics/services_statistics.info --- services/services_statistics/services_statistics.info 1970-01-01 01:00:00.000000000 +0100 +++ services_patched/services_statistics/services_statistics.info 2009-01-14 00:06:09.750000000 +0100 @@ -0,0 +1,6 @@ +; $Id$ +name = Services log +description = Logs and records services access. +package = Services - optional +dependencies[] = services +core = 6.x \ No newline at end of file diff -Nrup services/services_statistics/services_statistics.install services_patched/services_statistics/services_statistics.install --- services/services_statistics/services_statistics.install 1970-01-01 01:00:00.000000000 +0100 +++ services_patched/services_statistics/services_statistics.install 2009-01-14 00:07:36.375000000 +0100 @@ -0,0 +1,75 @@ + t('Stores services access information for statistics.'), + 'fields' => array( + 'lid' => array( + 'type' => 'serial', + 'not null' => TRUE, + 'description' => t('Primary Key: Unique services log ID.'), + ), + 'timestamp' => array( + 'type' => 'int', + 'unsigned' => TRUE, + 'not null' => TRUE, + 'default' => 0, + 'description' => t('Timestamp of when the service method was called.'), + ), + 'loglevel' => array( + 'type' => 'int', + 'size' => 'small', + 'unsigned' => TRUE, + 'not null' => TRUE, + 'default' => 0, + 'description' => t('How far did the service request get? Saves \'succes\' on completion.'), + ), + 'method' => array( + 'type' => 'varchar', + 'length' => 255, + 'not null' => TRUE, + 'default' => '', + 'description' => t('Name of service method.'), + ), + 'arguments' => array( + 'type' => 'text', + 'not null' => TRUE, + 'default' => '', + 'description' => t('Method arguments (serialized).'), + ), + 'kid' => array( + 'type' => 'varchar', + 'length' => 32, + 'not null' => TRUE, + 'default' => '', + 'description' => t('The API key (if available).'), + ), + ), + 'indexes' => array( + 'services_log_timestamp' => array('timestamp'), + 'method_name' => array('method'), + 'api_key' => array('kid'), + ), + 'primary key' => array('lid'), + ); + + return $schema; +} diff -Nrup services/services_statistics/services_statistics.module services_patched/services_statistics/services_statistics.module --- services/services_statistics/services_statistics.module 1970-01-01 01:00:00.000000000 +0100 +++ services_patched/services_statistics/services_statistics.module 2009-01-14 00:18:56.781250000 +0100 @@ -0,0 +1,112 @@ + 'Services access log', + 'description' => 'View services\'s access logs.', + 'page callback' => 'services_statistics_overview', + 'access arguments' => array('administer services'), + ); + + return $items; +} + +/** + * Page showing log entries + */ +function services_statistics_overview() { + $output = '
'.t('Shows wich methods have been accessed, when, which API key was used (if available) and which log level was reached.').'
'; + + $sql = 'SELECT loglevel, timestamp, method, kid FROM {services_log}'; + $limit = 20; + $header = array( + array('data' => t('Timestamp'), 'field' => 'timestamp', 'sort' => 'desc'), + array('data' => t('Level'), 'field' => 'loglevel'), + array('data' => t('Method'), 'field' => 'method'), + array('data' => t('API key'), 'field' => 'kid') + ); + $tablesort = tablesort_sql($header); + $result = pager_query($sql . $tablesort, $limit); + $rows = array(); + while ($log = db_fetch_object($result)) { + $rows[] = array( + date('d/m/y H:i:s', $log->timestamp), + services_statistics_loglevel_tostring($log->loglevel), + check_plain($log->method), + check_plain($log->kid) + ); + } + if (!count($rows)) { + $rows[] = array(array('data' => t('No statistics yet.'), 'colspan' => 4)); + } + $output .= theme('table', $header, $rows); + $output .= theme('pager', NULL, $limit, 0); + + return $output; +} + +function services_statistics_loglevel_tostring($loglevel) { + switch ($loglevel) { + case SERVICES_STATS_UNKNOWNMETHOD: + return t('unknown method'); + break; + case SERVICES_STATS_MISSINGREQUIREDARGUMENTS: + return t('missing required arguments'); + break; + case SERVICES_STATS_EXPIREDTOKEN: + return t('token expired'); + break; + case SERVICES_STATS_USEDTOKEN: + return t('token has been used before'); + break; + case SERVICES_STATS_INVALIDHASH: + return t('invalid hash'); + break; + case SERVICES_STATS_INVALIDKEY: + return t('invalid API key'); + break; + case SERVICES_STATS_INVALIDSESSION: + return t('invalid session'); + break; + case SERVICES_STATS_ACCESSDENIED: + return t('access denied'); + break; + case SERVICES_STATS_SUCCESS: + return t('success'); + break; + default: + return t('unknown log level'); + break; + } +} + +function services_statistics_access_log($loglevel, $method_name, $args, $method_requires_key = FALSE, $api_key = '') { + if ($method_requires_key && variable_get('services_use_key', TRUE) && empty($api_key)) { + $api_key = db_result(db_query("SELECT kid FROM {services_keys} WHERE domain = '%s'", $args[1])); + } + + db_query("INSERT INTO {services_log} (timestamp, loglevel, method, arguments, kid) + values(%d, %d, '%s', '%s', '%s')", + time(), $loglevel, $method_name, serialize($args), $api_key); +}