diff --git a/project_release/project-release-serve-history.php b/project_release/project-release-serve-history.php index 7c5fc1c..0a4f5e5 100644 --- a/project_release/project-release-serve-history.php +++ b/project_release/project-release-serve-history.php @@ -19,9 +19,19 @@ * location ^= /release-history { * rewrite ^/(.*)$ /modules/project/project_release/project-release-serve-history.php?q=$1; * } + * @endcode + * + * To call this file directly (without the rewrite): * + * @code + * http://example.com/modules/project/project_release/project-release-serve-history.php?q=example_project/1.x&version=1.x-1.0.0&site_key=JF7UsBYsZDXiUL3j97rdUAp49X1WNvsEW-Y4uheoRHw * @endcode * + * Or with the rewrite in place: + * + * @code + * http://example.com/release-history/example_project/1.x?version=1.x-1.0.0&site_key=JF7UsBYsZDXiUL3j97rdUAp49X1WNvsEW-Y4uheoRHw + * @endcode * * Configuration within this file is usually unnecessary and settings should be * automatically determined. If manual setting of the BACKDROP_ROOT or @@ -90,7 +100,7 @@ $version_api = $args[1]; } -// Sanitize the user-supplied input for use in filenames. +// Sanitize the user-supplied input for use in file names. $whitelist_regexp = '@[^a-zA-Z0-9_.-]@'; $safe_project_name = preg_replace($whitelist_regexp, '#', $project_name); $safe_api_vers = preg_replace($whitelist_regexp, '#', $version_api); @@ -129,9 +139,12 @@ // We can't call module_exists without bootstrapping to a higher level so // we'll settle for checking that the table exists. if (db_table_exists('project_usage_raw')) { + // Have to include password.inc for user_hash_password(). + require_once BACKDROP_ROOT . '/' . settings_get('password_inc', 'core/includes/password.inc'); + $site_key = $_GET['site_key']; $project_version = isset($_GET['version']) ? $_GET['version'] : ''; - $ip_address = ip_address(); + $ip_address_hashed = user_hash_password(ip_address()); // Compute a GMT timestamp for beginning of the day. getdate() is // affected by the server's timezone so we need to cancel it out. @@ -139,9 +152,23 @@ $time_parts = getdate($now - date('Z', $now)); $timestamp = gmmktime(0, 0, 0, $time_parts['mon'], $time_parts['mday'], $time_parts['year']); - $result = db_query("UPDATE {project_usage_raw} SET version_api = :version_api, version = :version, hostname = :hostname WHERE name = :name AND timestamp = :timestamp AND site_key = :site_key", array(':version_api' => $version_api, ':version' => $project_version, ':hostname' => $ip_address, ':name' => $project_name, ':timestamp' => $timestamp, ':site_key' => $site_key)); + $result = db_query("UPDATE {project_usage_raw} SET version_api = :version_api, version = :version, hostname = :hostname WHERE name = :name AND timestamp = :timestamp AND site_key = :site_key", array( + ':version_api' => $version_api, + ':version' => $project_version, + ':hostname' => $ip_address_hashed, + ':name' => $project_name, + ':timestamp' => $timestamp, + ':site_key' => $site_key, + )); if ($result->rowCount() === 0) { - db_query("INSERT INTO {project_usage_raw} (name, timestamp, site_key, version_api, version, hostname) VALUES (:name, :timestamp, :site_key, :version_api, :version, :hostname)", array(':name' => $project_name, ':timestamp' => $timestamp, ':site_key' => $site_key, ':version_api' => $version_api, ':version' => $project_version, ':hostname' => $ip_address)); + db_query("INSERT INTO {project_usage_raw} (name, timestamp, site_key, version_api, version, hostname) VALUES (:name, :timestamp, :site_key, :version_api, :version, :hostname)", array( + ':name' => $project_name, + ':timestamp' => $timestamp, + ':site_key' => $site_key, + ':version_api' => $version_api, + ':version' => $project_version, + ':hostname' => $ip_address_hashed, + )); } } } diff --git a/project_usage/project-usage-process.php b/project_usage/project-usage-process.php old mode 100644 new mode 100755 index e667a7e..8fa96e7 --- a/project_usage/project-usage-process.php +++ b/project_usage/project-usage-process.php @@ -3,6 +3,19 @@ /** * @file * Processes the project_usage statistics. + * + * This script should be run from the command line, with a similar format: + * + * @code + * ./project-usage-process.php --url=http://example.com --root=/var/www/html + * @endcode + * + * Running this on a cron job could look like this: + * + * @code + * # Run once per hour: + * 0 * * * * /var/www/html/modules/contrib/project/project_usage/project-usage-process.php --url=http://example.com --root=/var/html/www + * @endcode */ // Define the root directory of the Backdrop installation. diff --git a/project_usage/project_usage.install b/project_usage/project_usage.install index 6ade0e9..50ac0ac 100644 --- a/project_usage/project_usage.install +++ b/project_usage/project_usage.install @@ -80,7 +80,7 @@ function project_usage_schema() { 'default' => 0, ), 'hostname' => array( - 'description' => 'The IP address of the incoming request (to detect possible abuse).', + 'description' => 'The hashed IP address of the incoming request. Actual IP address is not logged for privacy.', 'type' => 'varchar', 'length' => 128, 'not null' => TRUE, @@ -133,7 +133,7 @@ function project_usage_schema() { 'length' => 128, 'not null' => TRUE, 'default' => '', - 'description' => "The IP address of the incoming request (to detect possible abuse).", + 'description' => 'The hashed IP address of the incoming request. Actual IP address is not logged for privacy.', ), ), 'primary key' => array('timestamp', 'site_key', 'project_nid'), @@ -250,3 +250,34 @@ function project_usage_schema() { return $schema; } +/** + * Hash IP addresses for privacy. + */ +function project_usage_update_1000() { + // Include password.inc for user_hash_password(). + require_once BACKDROP_ROOT . '/' . settings_get('password_inc', 'core/includes/password.inc'); + + // Update raw values. Hashed IPs have a longer value (55 characters) than an + // IP address (16 characters max). + $raw_rows = db_query("SELECT hostname FROM {project_usage_raw} WHERE LENGTH(hostname) < :hash_length GROUP BY hostname", array( + 'hash_length' => BACKDROP_HASH_LENGTH, + )); + + foreach ($raw_rows as $raw_row) { + db_query("UPDATE {project_usage_raw} SET hostname = :hostname_hashed WHERE :hostname = :hostname", array( + 'hostname_hashed' => $raw_row->hostname, + 'hostname' => user_hash_password($raw_row->hostname), + )); + } + + // Update daily values with a hashed IP address. + $day_rows = db_query("SELECT hostname FROM {project_usage_day} WHERE LENGTH(hostname) < :hash_length GROUP BY hostname", array( + 'hash_length' => BACKDROP_HASH_LENGTH, + )); + foreach ($day_rows as $day_row) { + db_query("UPDATE {project_usage_day} SET hostname = :hostname_hashed WHERE hostname = :hostname", array( + ':hostname_hashed' => user_hash_password($day_row->hostname), + ':hostname' => $day_row->hostname, + )); + } +}