123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922 |
- <?php
- /**
- * @file
- * Detects changes made to selected roles' accounts.
- */
- /**
- * Indicates that the username was changed.
- */
- define('ACCOUNT_SENTINEL_EVENT_TYPE_NAME', 'name');
- /**
- * Indicates that the password was changed.
- */
- define('ACCOUNT_SENTINEL_EVENT_TYPE_PASS', 'pass');
- /**
- * Indicates that the e-mail address was changed.
- */
- define('ACCOUNT_SENTINEL_EVENT_TYPE_MAIL', 'mail');
- /**
- * Indicates that a monitored role was added.
- */
- define('ACCOUNT_SENTINEL_EVENT_TYPE_ROLE_ADD', 'role_add');
- /**
- * Indicates that a monitored role was revoked.
- */
- define('ACCOUNT_SENTINEL_EVENT_TYPE_ROLE_REMOVE', 'role_remove');
- /**
- * Indicates that the snapshot of the user was not valid.
- *
- * This is a critical event.
- */
- define('ACCOUNT_SENTINEL_EVENT_TYPE_SNAPSHOT_INVALID', 'snapshot_invalid');
- /**
- * Indicates that the snapshot of the user should already exist but it does not.
- *
- * This is a critical event.
- */
- define('ACCOUNT_SENTINEL_EVENT_TYPE_SNAPSHOT_MISSING', 'snapshot_missing');
- /**
- * Indicates that a new user was created with one or more monitored permissions.
- */
- define('ACCOUNT_SENTINEL_EVENT_TYPE_USER_ADD', 'user_add');
- /**
- * Indicates that the user was deleted.
- */
- define('ACCOUNT_SENTINEL_EVENT_TYPE_USER_DELETE', 'user_delete');
- /**
- * Indicates that the user got blocked.
- */
- define('ACCOUNT_SENTINEL_EVENT_TYPE_USER_BLOCK', 'user_block');
- /**
- * Indicates that the user got unblocked.
- */
- define('ACCOUNT_SENTINEL_EVENT_TYPE_USER_UNBLOCK', 'user_unblock');
- /**
- * Indicates that the change was caught via hooks inside Drupal.
- */
- define('ACCOUNT_SENTINEL_EVENT_ORIGIN_HOOK', 'drupal');
- /**
- * Indicates that the change was caught by checking the database.
- *
- * This is a critical event.
- */
- define('ACCOUNT_SENTINEL_EVENT_ORIGIN_DB_CHECK', 'database');
- /**
- * Implements hook_help().
- */
- function account_sentinel_help($path, $arg) {
- switch ($path) {
- case 'admin/help#account_sentinel':
- $help = t("Account Sentinel perceives changes made to a configurable set of monitored roles' accounts, even those that are results of direct database modification (e.g. SQL injection). A set of e-mail addresses can be configured to be notified when such a change is detected, also a log of changes can be viewed in Drupal and via Drush for manual review.");
- return '<p>' . $help . '</p>';
- }
- }
- /**
- * Implements hook_permission().
- */
- function account_sentinel_permission() {
- return array(
- 'access account sentinel logs' => array(
- 'title' => t('Access Account Sentinel logs'),
- ),
- 'administer account sentinel' => array(
- 'title' => t("Change Account Sentinel's configuration"),
- ),
- );
- }
- /**
- * Implements hook_menu().
- */
- function account_sentinel_menu() {
- // Report page.
- $items['admin/reports/account-sentinel'] = array(
- 'title' => 'Account Sentinel log',
- 'description' => 'List of changes to monitored roles\' accounts perceived by Account Sentinel.',
- 'page callback' => 'account_sentinel_page_report',
- 'access arguments' => array('access account sentinel logs'),
- 'file' => 'account_sentinel.pages.inc',
- 'type' => MENU_NORMAL_ITEM,
- );
- // Settings page.
- $items['admin/config/system/account-sentinel'] = array(
- 'title' => 'Account Sentinel settings',
- 'description' => 'Manage Account Sentinel settings.',
- 'page callback' => 'drupal_get_form',
- 'page arguments' => array('account_sentinel_page_settings'),
- 'access arguments' => array('administer account sentinel'),
- 'file' => 'account_sentinel.pages.inc',
- );
- // Cron handler.
- $items['system/account-sentinel-cron'] = array(
- 'title' => 'Run Account Sentinel DB check',
- 'page callback' => 'account_sentinel_callback_cron',
- 'access callback' => TRUE,
- 'file' => 'account_sentinel.pages.inc',
- 'type' => MENU_CALLBACK,
- );
- // Cron key reset handler.
- $items['system/account-sentinel-reset-cron-key'] = array(
- 'title' => "Reset Account Sentinel's cron key",
- 'page callback' => 'account_sentinel_callback_reset_cron_key',
- 'access callback' => TRUE,
- 'access arguments' => array('administer account sentinel'),
- 'file' => 'account_sentinel.pages.inc',
- 'type' => MENU_CALLBACK,
- );
- return $items;
- }
- /**
- * Implements hook_theme().
- */
- function account_sentinel_theme($existing, $type, $theme, $path) {
- return array(
- 'account_sentinel_username' => array(
- 'variables' => array(
- 'uid' => 0,
- ),
- 'file' => 'account_sentinel.themes.inc',
- ),
- );
- }
- /**
- * Implements hook_user_update().
- */
- function account_sentinel_user_update(&$edit, $account, $category) {
- $new = account_sentinel_monitored_account_data($account);
- $original = account_sentinel_monitored_account_data($account->original);
- if ($new['monitored'] || $original['monitored']) {
- $changes = account_sentinel_detect_changes($new, $original);
- if (!empty($changes)) {
- account_sentinel_record_events($account->uid, ACCOUNT_SENTINEL_EVENT_ORIGIN_HOOK, $changes);
- account_sentinel_update_snapshot($new);
- }
- }
- }
- /**
- * Implements hook_password_strength_change().
- */
- function account_sentinel_password_strength_change($account, $strength) {
- // Store password strength for $account for later use.
- account_sentinel_password_strength($account->uid, password_strength_get_score($strength['score']));
- }
- /**
- * Provides static storage for password strengths.
- *
- * @param int $uid
- * UID of the user.
- * @param string $score
- * Password's strength.
- *
- * @return mixed
- * Returns the score for UID's new password or FALSE if not set.
- */
- function account_sentinel_password_strength($uid, $score = NULL) {
- static $strengths = array();
- // Update score.
- if (isset($score)) {
- $strengths[$uid] = $score;
- }
- // Return score.
- if (isset($strengths[$uid])) {
- return $strengths[$uid];
- }
- // Return FALSE if score is not available.
- return FALSE;
- }
- /**
- * Implements hook_account_sentinel_changes_alter().
- */
- function account_sentinel_account_sentinel_changes_alter(array &$changes, array &$new, array &$original) {
- // Include password strength information if available.
- $strength = account_sentinel_password_strength($original['uid']);
- if ($strength) {
- foreach ($changes as &$change) {
- if ($change['type'] == ACCOUNT_SENTINEL_EVENT_TYPE_PASS && !isset($change['data']['strength'])) {
- $change['data']['strength'] = $strength;
- }
- }
- }
- }
- /**
- * Implements hook_user_insert().
- */
- function account_sentinel_user_insert(&$edit, $account, $category) {
- $account = account_sentinel_monitored_account_data($account);
- if ($account['monitored']) {
- $events[] = array(
- 'type' => ACCOUNT_SENTINEL_EVENT_TYPE_USER_ADD,
- 'data' => array(
- 'uid' => $account['uid'],
- 'name' => $account['name'],
- 'mail' => $account['mail'],
- ),
- );
- foreach ($account['roles'] as $rid) {
- $events[] = array(
- 'type' => ACCOUNT_SENTINEL_EVENT_TYPE_ROLE_ADD,
- 'data' => array('rid' => $rid),
- );
- }
- account_sentinel_record_events($account['uid'], ACCOUNT_SENTINEL_EVENT_ORIGIN_HOOK, $events);
- account_sentinel_update_snapshot($account);
- }
- }
- /**
- * Implements hook_user_delete().
- */
- function account_sentinel_user_delete($account) {
- $account = account_sentinel_monitored_account_data($account);
- if ($account['monitored']) {
- $events[] = array(
- 'type' => ACCOUNT_SENTINEL_EVENT_TYPE_USER_DELETE,
- 'data' => array(
- 'uid' => $account['uid'],
- 'name' => $account['name'],
- 'mail' => $account['mail'],
- ),
- );
- account_sentinel_record_events($account['uid'], ACCOUNT_SENTINEL_EVENT_ORIGIN_HOOK, $events);
- account_sentinel_delete_snapshot($account['uid']);
- }
- }
- /**
- * Implements hook_cron().
- */
- function account_sentinel_cron() {
- if (variable_get('account_sentinel_cron_method', 'drupal') == 'drupal') {
- watchdog('account_sentinel', "Invoked database audit from Drupal's cron.");
- module_load_include('inc', 'account_sentinel', 'account_sentinel.audit');
- account_sentinel_audit();
- }
- }
- /**
- * Implements hook_mail().
- */
- function account_sentinel_mail($key, &$message, $params) {
- switch ($key) {
- // Compose notification e-mail.
- case 'notification':
- // Collect information parameters.
- $origin = $params['origin'];
- $events = $params['events'];
- // Collect users' data.
- $users = array(
- 'changed' => array('uid' => $params['uid']),
- 'by' => array('uid' => $params['meta_data']['by_uid']),
- );
- foreach ($users as &$user) {
- $uid = $user['uid'];
- $user_object = user_load($uid);
- if ($user_object !== FALSE) {
- $user['name'] = $user_object->name;
- $user['link'] = l($user_object->name, 'user/' . $uid, array(
- 'absolute' => TRUE,
- ));
- }
- else {
- $user['name'] = t('Unknown');
- $user['link'] = $user['name'];
- }
- }
- // Compose e-mail.
- if (!empty($events)) {
- $message['subject'] = t(
- '[AS] User #@uid (@name) was changed',
- array(
- '@uid' => $users['changed']['uid'],
- '@name' => $users['changed']['name'],
- )
- );
- if ($origin != ACCOUNT_SENTINEL_EVENT_ORIGIN_HOOK) {
- $message['body'][] = '<strong>' . t('Warning: these changes were made outside of Drupal!') . '</strong>';
- }
- $message['body'][] = t(
- 'User #@uid (!user) was changed by user #@by_uid (!by_user) (@ip) at @timestamp.',
- array(
- '@uid' => $users['changed']['uid'],
- '!user' => $users['changed']['link'],
- '@by_uid' => $users['by']['uid'],
- '!by_user' => $users['by']['link'],
- '@ip' => $params['meta_data']['ip'],
- '@timestamp' => format_date($params['meta_data']['timestamp']),
- )
- );
- $message['body'][] = t('The following changes were made to the account:');
- $event_list = '<ul>';
- foreach ($events as $event) {
- $event_list .= '<li>' . account_sentinel_get_event_message($event['type'], $event['data']) . '</li>';
- }
- $event_list .= '</ul>';
- $message['body'][] = $event_list;
- $message['body'][] = '-- <br/>' . t(
- 'Sent by Account Sentinel on <a href="!site_url">@site_name</a>.',
- array(
- '@site_name' => variable_get('site_name'),
- '!site_url' => url('', array('absolute' => TRUE)),
- )
- );
- }
- break;
- }
- }
- /**
- * Returns the ID's of monitored roles.
- *
- * If the monitored roles have not been set yet, it will return the
- * administrator role.
- *
- * @return int[]
- * Array of monitored roles' ids.
- */
- function account_sentinel_get_monitored_roles() {
- $roles = variable_get('account_sentinel_monitored_roles', NULL);
- if ($roles === NULL) {
- return array(
- variable_get('user_admin_role', 3),
- );
- }
- return $roles;
- }
- /**
- * Returns the module's cron key.
- *
- * @return string
- * The cron key.
- */
- function account_sentinel_get_cron_key() {
- $key = variable_get('account_sentinel_cron_key', NULL);
- if ($key === NULL) {
- return account_sentinel_reset_cron_key();
- }
- return $key;
- }
- /**
- * Returns the relevant monitored data of an $account object.
- *
- * The output is an associative array which only stores data needed by Account
- * Sentinel.
- *
- * @param object $account
- * A user entity.
- *
- * @return array
- * An associative array containing the monitored data.
- */
- function account_sentinel_monitored_account_data($account) {
- // Only work with role IDs.
- $roles = array_keys($account->roles);
- // Only work with monitored roles.
- $monitored = account_sentinel_get_monitored_roles();
- $roles = array_intersect($monitored, $roles);
- $output = array(
- 'uid' => $account->uid,
- 'name' => $account->name,
- 'pass' => $account->pass,
- 'mail' => $account->mail,
- 'status' => $account->status,
- 'roles' => $roles,
- 'monitored' => !empty($roles),
- );
- return $output;
- }
- /**
- * Returns an array of event type string - human-readable string associations.
- *
- * @return array
- * Array of translatable strings mapped by their event type constants.
- */
- function account_sentinel_event_type_strings() {
- return array(
- ACCOUNT_SENTINEL_EVENT_TYPE_NAME => t('name changed'),
- ACCOUNT_SENTINEL_EVENT_TYPE_PASS => t('password changed'),
- ACCOUNT_SENTINEL_EVENT_TYPE_MAIL => t('mail changed'),
- ACCOUNT_SENTINEL_EVENT_TYPE_ROLE_ADD => t('role added'),
- ACCOUNT_SENTINEL_EVENT_TYPE_ROLE_REMOVE => t('role removed'),
- ACCOUNT_SENTINEL_EVENT_TYPE_SNAPSHOT_INVALID => t('invalid snapshot'),
- ACCOUNT_SENTINEL_EVENT_TYPE_SNAPSHOT_MISSING => t('missing snapshot'),
- ACCOUNT_SENTINEL_EVENT_TYPE_USER_ADD => t('user added'),
- ACCOUNT_SENTINEL_EVENT_TYPE_USER_DELETE => t('user deleted'),
- ACCOUNT_SENTINEL_EVENT_TYPE_USER_BLOCK => t('blocked'),
- ACCOUNT_SENTINEL_EVENT_TYPE_USER_UNBLOCK => t('unblocked'),
- );
- }
- /**
- * Returns an array of event origin string - human-readable string associations.
- *
- * @return array
- * Array of translatable strings mapped by their event origin constants.
- */
- function account_sentinel_event_origin_strings() {
- return array(
- ACCOUNT_SENTINEL_EVENT_ORIGIN_HOOK => t('Drupal'),
- ACCOUNT_SENTINEL_EVENT_ORIGIN_DB_CHECK => t('database'),
- );
- }
- /**
- * Gets the human-readable name of a given event type.
- *
- * @param string $event_type
- * The event's type.
- *
- * @return string
- * The event type's human-readable name.
- */
- function account_sentinel_event_type_get_string($event_type) {
- $event_type_strings = account_sentinel_event_type_strings();
- if (isset($event_type_strings[$event_type])) {
- return $event_type_strings[$event_type];
- }
- return t('unknown');
- }
- /**
- * Gets the human-readable name of a given event origin.
- *
- * @param string $event_origin
- * The event's origin.
- *
- * @return string
- * The event origin's human-readable name.
- */
- function account_sentinel_event_origin_get_string($event_origin) {
- $event_origin_strings = account_sentinel_event_origin_strings();
- if (isset($event_origin_strings[$event_origin])) {
- return $event_origin_strings[$event_origin];
- }
- return t('unknown');
- }
- /**
- * Generates an event's detailed human-readable message.
- *
- * @param string $event_type
- * The event's type.
- * @param array $data
- * Additional data from the database used to generate informative messages.
- *
- * @return string
- * The generated detailed event message.
- */
- function account_sentinel_get_event_message($event_type, array $data) {
- switch ($event_type) {
- case ACCOUNT_SENTINEL_EVENT_TYPE_NAME:
- return t('Changed name from <strong>@name_old</strong> to <strong>@name_new</strong>.', array(
- '@name_old' => $data['old'],
- '@name_new' => $data['new'],
- ));
- case ACCOUNT_SENTINEL_EVENT_TYPE_PASS:
- $msg = t('Changed password.');
- // Append strength information if set.
- if (isset($data['strength'])) {
- $msg .= ' ' . t('New strength: @strength.', array(
- '@strength' => $data['strength'],
- ));
- }
- return $msg;
- case ACCOUNT_SENTINEL_EVENT_TYPE_MAIL:
- return t('Changed mail from <strong>@mail_old</strong> to <strong>@mail_new</strong>.', array(
- '@mail_old' => $data['old'],
- '@mail_new' => $data['new'],
- ));
- case ACCOUNT_SENTINEL_EVENT_TYPE_ROLE_ADD:
- $role = user_role_load($data['rid']);
- return t('Granted role <strong>@role</strong>.', array(
- '@role' => $role->name,
- ));
- case ACCOUNT_SENTINEL_EVENT_TYPE_ROLE_REMOVE:
- $role = user_role_load($data['rid']);
- return t('Revoked role <strong>@role</strong>.', array(
- '@role' => $role->name,
- ));
- case ACCOUNT_SENTINEL_EVENT_TYPE_SNAPSHOT_INVALID:
- return t("The user's snapshot was altered.");
- case ACCOUNT_SENTINEL_EVENT_TYPE_SNAPSHOT_MISSING:
- return t("The user's snapshot is missing.");
- case ACCOUNT_SENTINEL_EVENT_TYPE_USER_ADD:
- return t('Created user <em>#@uid</em> <strong>@name</strong> (<strong>@mail</strong>).', array(
- '@uid' => $data['uid'],
- '@name' => $data['name'],
- '@mail' => $data['mail'],
- ));
- case ACCOUNT_SENTINEL_EVENT_TYPE_USER_DELETE:
- return t('Deleted user <em>#@uid</em> <strong>@name</strong> (<strong>@mail</strong>).', array(
- '@uid' => $data['uid'],
- '@name' => $data['name'],
- '@mail' => $data['mail'],
- ));
- case ACCOUNT_SENTINEL_EVENT_TYPE_USER_BLOCK:
- return t('Blocked user.');
- case ACCOUNT_SENTINEL_EVENT_TYPE_USER_UNBLOCK:
- return t('Unblocked user.');
- default:
- return t('Unknown event.');
- }
- }
- /**
- * Resets the cron key.
- *
- * @return string
- * Returns the new cron key.
- */
- function account_sentinel_reset_cron_key() {
- $new_key = drupal_random_key();
- variable_set('account_sentinel_cron_key', $new_key);
- watchdog('account_sentinel', 'Cron key reset.');
- return $new_key;
- }
- /**
- * Compares a user account's two states and returns the list of differences.
- *
- * @param array $new
- * The new state of the user.
- * @param array $original
- * The original state of the user.
- *
- * @return array
- * Array of changes.
- *
- * @see account_sentinel_monitored_account_data($account)
- */
- function account_sentinel_detect_changes(array $new, array $original) {
- $changes = array();
- // Check whether name was changed.
- if (isset($new['name']) && $new['name'] != $original['name']) {
- $changes[] = array(
- 'type' => ACCOUNT_SENTINEL_EVENT_TYPE_NAME,
- 'data' => array(
- 'old' => $original['name'],
- 'new' => $new['name'],
- ),
- );
- }
- // Check whether pass was changed.
- if (isset($new['pass']) && $new['pass'] != $original['pass']) {
- $changes[] = array(
- 'type' => ACCOUNT_SENTINEL_EVENT_TYPE_PASS,
- 'data' => array(),
- );
- }
- // Check whether mail was changed.
- if (isset($new['mail']) && $new['mail'] != $original['mail']) {
- $changes[] = array(
- 'type' => ACCOUNT_SENTINEL_EVENT_TYPE_MAIL,
- 'data' => array(
- 'old' => $original['mail'],
- 'new' => $new['mail'],
- ),
- );
- }
- // Check whether status was changed.
- if (isset($new['status']) && $new['status'] != $original['status']) {
- if ($original['status']) {
- $type = ACCOUNT_SENTINEL_EVENT_TYPE_USER_BLOCK;
- }
- else {
- $type = ACCOUNT_SENTINEL_EVENT_TYPE_USER_UNBLOCK;
- }
- $changes[] = array(
- 'type' => $type,
- 'data' => array(),
- );
- }
- if (isset($new['roles'])) {
- // Check whether roles were changed.
- $roles_added = array_diff($new['roles'], $original['roles']);
- $roles_removed = array_diff($original['roles'], $new['roles']);
- foreach ($roles_added as $rid) {
- $changes[] = array(
- 'type' => ACCOUNT_SENTINEL_EVENT_TYPE_ROLE_ADD,
- 'data' => array('rid' => $rid),
- );
- }
- foreach ($roles_removed as $rid) {
- $changes[] = array(
- 'type' => ACCOUNT_SENTINEL_EVENT_TYPE_ROLE_REMOVE,
- 'data' => array('rid' => $rid),
- );
- }
- }
- drupal_alter('account_sentinel_changes', $changes, $new, $original);
- return $changes;
- }
- /**
- * Records events.
- *
- * Stores account changes in the database, sets the new snapshot, sends an email
- * notification and invokes hook_account_sentinel_change().
- *
- * @param int $uid
- * The UID of the account.
- * @param string $origin
- * The origin of the event.
- * @param array $events
- * The array of changes.
- */
- function account_sentinel_record_events($uid, $origin, array $events) {
- global $user;
- $by_uid = ($origin == ACCOUNT_SENTINEL_EVENT_ORIGIN_HOOK) ? $user->uid : 0;
- $meta_data = array(
- 'uid' => $uid,
- 'origin' => $origin,
- 'by_uid' => $by_uid,
- 'ip' => ip_address(),
- 'timestamp' => REQUEST_TIME,
- );
- // Store changes.
- foreach ($events as $event_key => $event) {
- $record = $meta_data;
- $record['type'] = $event['type'];
- $record['data'] = $event['data'];
- // Log to database.
- drupal_write_record('account_sentinel_logs', $record);
- // Inform other modules.
- module_invoke_all('account_sentinel_change', $record);
- }
- // Send one e-mail notification per account.
- account_sentinel_send_notification($uid, $origin, $events, $meta_data);
- }
- /**
- * Sends e-mail notification about events.
- *
- * @param int $uid
- * The UID of the account.
- * @param string $origin
- * The origin of the event.
- * @param array $events
- * The array of changes.
- * @param array $meta_data
- * Additional meta data about the change events.
- */
- function account_sentinel_send_notification($uid, $origin, array $events, array $meta_data) {
- if (!empty($events)) {
- $to = variable_get('account_sentinel_email_to', '');
- if ($to != '') {
- drupal_mail(
- 'account_sentinel',
- 'notification',
- $to,
- language_default(),
- array(
- 'uid' => $uid,
- 'origin' => $origin,
- 'events' => $events,
- 'meta_data' => $meta_data,
- )
- );
- }
- }
- }
- /**
- * Rebuilds the snapshot tables.
- *
- * Invoked after changing which roles are monitored.
- *
- * @param array $roles_old
- * Array of previously monitored role IDs.
- * @param array $roles_new
- * Array of monitored role IDs.
- */
- function account_sentinel_rebuild_snapshots(array $roles_old, array $roles_new) {
- $roles_added = array_diff($roles_new, $roles_old);
- $roles_removed = array_diff($roles_old, $roles_new);
- $auth_in_old = array_search(DRUPAL_AUTHENTICATED_RID, $roles_old) !== FALSE;
- $auth_in_new = array_search(DRUPAL_AUTHENTICATED_RID, $roles_new) !== FALSE;
- $hash_key = drupal_get_hash_salt();
- // Check if we don't have to modify anything.
- if ($auth_in_old && $auth_in_new) {
- // Every user is in the database, and will remain there.
- return;
- }
- // Check if we have to create new user snapshots.
- if (!$auth_in_old && !empty($roles_added)) {
- // Select users' data.
- $select = db_select('users', 'u')
- ->fields('u', array('uid', 'name', 'pass', 'mail', 'status'))
- ->condition('u.uid', '0', '<>')
- ->groupBy('u.uid');
- // Filter by users of added roles.
- if (!$auth_in_new) {
- $select_include = db_select('users_roles', 'ur')
- ->fields('ur', array('uid'))
- ->condition('rid', $roles_added);
- $select->condition('uid', $select_include, 'IN');
- }
- // Exclude users of previous roles.
- if (!empty($roles_old)) {
- $select_exclude = db_select('users_roles', 'ur')
- ->fields('ur', array('uid'))
- ->condition('rid', $roles_old);
- $select->condition('uid', $select_exclude, 'NOT IN');
- }
- // Add checksum.
- $select->addExpression(
- 'sha2(concat(u.uid, u.name, u.pass, u.mail, u.status, :hash_key), 384)', 'checksum',
- array(':hash_key' => $hash_key)
- );
- // Insert.
- $insert = db_insert('account_sentinel_users')
- ->fields(array('uid', 'name', 'pass', 'mail', 'status', 'checksum'))
- ->from($select);
- $insert->execute();
- }
- // Check if we have to remove users snapshots.
- if (!$auth_in_new && !empty($roles_removed)) {
- // Delete records.
- $delete = db_delete('account_sentinel_users');
- // Exclude users of monitored roles.
- if (!empty($roles_new)) {
- $delete_exclude = db_select('users_roles', 'ur')
- ->fields('ur', array('uid'))
- ->condition('rid', $roles_new);
- $delete->condition('uid', $delete_exclude, 'NOT IN');
- }
- // Execute query.
- $delete->execute();
- }
- // Check if we have to create new users_roles snapshots.
- $roles_added = array_diff($roles_added, array(DRUPAL_AUTHENTICATED_RID));
- if (!empty($roles_added)) {
- // Select added roles' records.
- $select = db_select('users_roles', 'ur');
- $select->fields('ur', array('uid', 'rid'))
- ->condition('rid', $roles_added);
- // Add checksum.
- $select->addExpression(
- 'sha2(concat(ur.uid, ur.rid, :hash_key), 384)', 'checksum',
- array(':hash_key' => $hash_key)
- );
- // Insert.
- $insert = db_insert('account_sentinel_users_roles')
- ->fields(array('uid', 'rid', 'checksum'))
- ->from($select);
- $insert->execute();
- }
- // Check if we have to remove users_roles snapshots.
- $roles_removed = array_diff($roles_removed, array(DRUPAL_AUTHENTICATED_RID));
- if (!empty($roles_removed)) {
- // Delete removed roles' records.
- $delete = db_delete('account_sentinel_users_roles');
- $delete->condition('rid', $roles_removed);
- $delete->execute();
- }
- }
- /**
- * Updates a modified user's snapshot.
- *
- * @param array $account
- * Account details.
- *
- * @see account_sentinel_monitored_account_data($account)
- */
- function account_sentinel_update_snapshot(array $account) {
- $uid = $account['uid'];
- account_sentinel_delete_snapshot($uid);
- account_sentinel_create_snapshot($account);
- }
- /**
- * Deletes a user's snapshots from the database.
- *
- * @param int $uid
- * UID of user.
- */
- function account_sentinel_delete_snapshot($uid) {
- // Reset user's snapshot.
- db_delete('account_sentinel_users')
- ->condition('uid', $uid)
- ->execute();
- // Reset users_roles snapshots.
- db_delete('account_sentinel_users_roles')
- ->condition('uid', $uid)
- ->execute();
- }
- /**
- * Creates a snapshot of the given account's state in the database.
- *
- * @param array $account
- * The account.
- *
- * @see account_sentinel_monitored_account_data($account)
- */
- function account_sentinel_create_snapshot(array $account) {
- $uid = $account['uid'];
- $hash_key = drupal_get_hash_salt();
- // Update account_sentinel_users.
- if ($account['monitored']) {
- $checksum = hash('sha384', $uid . $account['name'] . $account['pass'] . $account['mail'] . $account['status'] . $hash_key);
- db_insert('account_sentinel_users')
- ->fields(array(
- 'uid' => $uid,
- 'name' => $account['name'],
- 'pass' => $account['pass'],
- 'mail' => $account['mail'],
- 'status' => $account['status'],
- 'checksum' => $checksum,
- ))
- ->execute();
- }
- // Fill users_roles snapshots.
- foreach ($account['roles'] as $rid) {
- $checksum = hash('sha384', $uid . $rid . $hash_key);
- db_insert('account_sentinel_users_roles')
- ->fields(array(
- 'uid' => $uid,
- 'rid' => $rid,
- 'checksum' => $checksum,
- ))
- ->execute();
- }
- }
|