This module tracks each user event like User Login, User Logout and User Node view events and also store these event data in your database. This data is then exposed to views so you can report on it if required.

Project link

https://www.drupal.org/project/rtub

Git instructions

git clone --branch 8.x-1.x https://git.drupalcode.org/project/rtub.git

PAReview checklist

https://pareview.sh/pareview/https-git.drupal.org-project-rtub.git

Comments

maheshkp92 created an issue. See original summary.

apaderno’s picture

Status: Needs review » Needs work
Issue tags: -PAreview: single application approval

Thank you for applying! rtub-dev.8.x isn't a correct branch name, which eventually would be 8.x-1.x. Wrong branches need to be removed.

maheshkp92’s picture

Issue summary: View changes
maheshkp92’s picture

Status: Needs work » Needs review

I have deleted the incorrect branch called "rtub-dev.8.x" from these project repository.

Thanks for your support!

Vernit’s picture

PAEeview say readme missing. Please add it

According to Drupal standards, modules should include a useful README.file.
https://www.drupal.org/docs/develop/documenting-your-project/module-docu...

Vernit’s picture

Status: Needs review » Needs work
Vernit’s picture

Please create a dev release to enable automated testing.

Vernit’s picture

Status: Needs work » Needs review
vuil’s picture

Status: Needs review » Needs work

Thank you for the contribution!

Please, fix the Pareview mentioned issue (at first):
README.md or README.txt is missing, see the guidelines for in-project documentation.

Then the project will go through the manual security review process.
Please, be patience through the whole review process.

maheshkp92’s picture

Status: Needs work » Needs review

I have fixed all PAReview issues for this project. I have also created dev release "8.x-1.x" for this project.

Thank you all for your support!

- Mahesh Patil

vuil’s picture

Status: Needs review » Needs work

Thank you for the contribution!

1. Please, update the deprecated constant REQUEST_TIME into your code:
The REQUEST_TIME global constant has also been deprecated, scheduled to be removed before 9.0.0
See more: https://www.drupal.org/node/2785211
Replace the REQUEST_TIME with the \Drupal::time()->getRequestTime()

2. Replace the deprecated UrlGeneratorTrait:
trait \Drupal\Core\Routing\UrlGeneratorTrait is deprecated in Drupal 8.0.0 and will be removed before Drupal 9.0.0. Use \Drupal\Core\Url instead.
https://api.drupal.org/api/drupal/core%21lib%21Drupal%21Core%21Routing%2...

3. EntityManagerInterface is deprecated in the latest Drupal 8 version and should be replaced with EntityTypeManagerInterface.
https://api.drupal.org/api/drupal/core%21lib%21Drupal%21Core%21Entity%21...

maheshkp92’s picture

Status: Needs work » Needs review

Thanks for providing valuable feedback.
As per your recommendation, I have removed the following deprecated function from this Module and replace it with the appropriate functions.

  1. REQUEST_TIME
  2. UrlGeneratorTrait
  3. EntityTypeManagerInterface

Thanks,
Mahesh Patil

vuil’s picture

I have not found any security related issues into the code.

klausi’s picture

Status: Needs review » Needs work
Issue tags: +PAreview: security

Thanks for you contribution!

  1. PostNodeDataController: this is vulnerable to access bypass attacks. An attacker can send an arbitrary user ID, so they can write arbitrary events for other users. You need to take the user ID from the current logged in user and not from the sent POST data.
  2. PostNodeDataController: a second vulnerability is the event type. An attacker can send arbitrary event types and messages, so they could send fake logout events for example. You could generate a HMAC for the JS settings you are creating with Crypt::hmacBase64(). The data would be a string concantenated of all the setting values. The key would be Settings::getHashSalt(). If you exclude the user ID then it would even work for cached node pages since the HMAC would be the same for all users.
  3. PostNodeDataController: a potential third vulnerability is CSRF. An attacker can trick users into POST requests so that an event record is written. We prevent that usually with the Form API or by validating a CSRF token. However - in the case of tracking views/clicks CSRF is most of the time not a useful attack vector, so for example Drupal core's statistics module also does not prevent against CSRF. So I consider this fine.

Please fix vulnerability 1 and 2, then we can continue here.

parvind87’s picture

Thanks for your contribution.
Review of the 8.x-1.x branch (commit dfcf442):
No automated test cases were found, did you consider writing PHPUnit tests? This is not a requirement but encouraged for professional software development.

maheshkp92’s picture

Status: Needs work » Needs review

@klausi,

I have fixed following 2 vulnerability in below commit -https://git.drupalcode.org/project/rtub/commit/e62f7c7075f22ca2150e623fd...

1. PostNodeDataController: this is vulnerable to access bypass attacks. An attacker can send an arbitrary user ID, so they can write arbitrary events for other users. You need to take the user ID from the current logged in user and not from the sent POST data.

2. PostNodeDataController: a second vulnerability is the event type. An attacker can send arbitrary event types and messages, so they could send fake logout events for example. You could generate an HMAC for the JS settings you are creating with Crypt::hmacBase64(). The data would be a string concatenated of all the setting values. The key would be Settings::getHashSalt(). If you exclude the user ID then it would even work for cached node pages since the HMAC would be the same for all users.

Thanks,
Mahesh Patil

vuil’s picture

apaderno’s picture

maheshkp92’s picture

Please provide Security Approval for this module.

Thanks,

batkor’s picture

Error in this line , add a space

$newStr = $event['eData'] . " | " . $event['eType'];

https://git.drupalcode.org/project/rtub/blob/8.x-1.x/src/Controller/Post...

Best practical used function.
#Example

/**
 * Returns data for "hmacBase64".
 *
 * @param $title
 *  Node title.
 * @param $type
 *  Event type.
 * @return string
 */
function _get_cript_data($title, $type) {
  return "User on {$title} | {$type}";
}

And use

$eStr = Crypt::hmacBase64(_get_cript_data($node->getTitle(), 'nodeview'), Settings::getHashSalt());

Please view csrfToken and system route system.csrftoken for get user token.

UP:
Why use js for check node view?

maheshkp92’s picture

Hi @batkor,

Thank you for your evaluation.

I have fixed most of the issues below commit.
https://git.drupalcode.org/project/rtub/commit/942ad5967f2352783d1bbae2a...

Why use js for check node view?
I have tried to trigger node view events using various hooks like entity_view, various hook_alter. But, the node view event is not captured by the above-mentioned hooks on a cached page, so that why I am using js to capture node view event on the cached/non-cached page in D8.

batkor’s picture

@maheshkp92 Good question.

vuil’s picture

Issue summary: View changes

I update the summary only.

apaderno’s picture

Issue summary: View changes
maheshkp92’s picture

Please help me closing the issue to release the stable version of this module.

Thanks,
Mahesh Patil

jayprakash01’s picture

Thanks for the contribution @maheshkp92 !

I have not find any security related issues in the code.

Thanks

batkor’s picture

Status: Needs review » Reviewed & tested by the community
apaderno’s picture

Status: Reviewed & tested by the community » Needs work
    $newStr = "User on {$title} | {$type}";
    $eStr = Crypt::hmacBase64($newStr, Settings::getHashSalt());

    if ($event['eToken'] == $eStr) {
      // Valid post request.
      $connection = $this->connection;
      $connection->insert('rtub')
        ->fields([
          'uid' => $this->currentUser()->id(),
          'event_type' => $type,
          'event_timestamp' => $this->time->getRequestTime(),
          'event_data' => "User on {$title} Page",
        ])->execute();

      $response['status'] = TRUE;
      return new JsonResponse($response);
    }

Hashes are not checked using the == operator. There is a PHP function to compare two hashes, which is used also from Drupal.

function rtub_preprocess_node(&$variables) {
  $node = $variables['node'];
  $ntype = $node->getType();
  $user = \Drupal::currentUser();
  // Do not track data for Anonymous users.
  if ($user->isAnonymous()) {
    return;
  }
  // Check User permission.
  if (!$user->hasPermission("track $ntype view content")) {
    return;
  }

  if (!(\Drupal::service('path.matcher')->isFrontPage())) {
    // Do not track front page.
    $variables['#attached']['library'][] = 'rtub/rtub-js';
    $variables['#attached']['drupalSettings']['rtub']['nodeview']['eventData'] = $node->getTitle();
    $variables['#attached']['drupalSettings']['rtub']['nodeview']['eventType'] = "nodeview";

    $eStr = Crypt::hmacBase64(_get_cript_data($node->getTitle(), 'nodeview'), Settings::getHashSalt());

    $variables['#attached']['drupalSettings']['rtub']['nodeview']['eventToken'] = $eStr;
  }
}

Since the code isn't executed for the anonymous users, it probably makes more sense to use the csrf_token service.

  if (!$current_user->isAnonymous()) {
    // Track activity for login users.
    try {
      $connection = \Drupal::database();
      $connection->insert('rtub')
        ->fields([
          'uid' => $uid,
          'event_type' => $eventName,
          'event_timestamp' => $event_time,
          'event_data' => $message,
        ])->execute();

    }
    catch (exception $e) {
      \Drupal::logger('rtub')->warning(print_r('Something went wrong', TRUE));
    }
  }

There isn't no need to use print_r() to pass a string to warning(). Something went wrong is also a message that doesn't allow to understand what happened; it should be replaced from the message associated with the exception.

function _get_cript_data($title, $type) {
  return "User on {$title} | {$type}";
}

Every function should be prefixed from the module machine name. A comment on this application already suggested to remove it and use the string directly.

maheshkp92’s picture

Hi, kiamlaluno

I have fixed below issues:

  • Rename the _get_cript_data() function to rtub_get_cript_data().
  • Remove print_r() and add exception message string in Drupal log message.
  • Used hash_equals() function comapre two hash values.

All the above issues fixed in below commit:
https://git.drupalcode.org/project/rtub/commit/3325915b0a1af6ad962ac242e...

Thanks!!

AkashKumar07’s picture

Status: Needs work » Needs review
apaderno’s picture

Assigned: Unassigned » apaderno
Status: Needs review » Fixed

Thank you for your contribution! I am going to update your account.

These are some recommended readings to help with excellent maintainership:

You can find more contributors chatting on the IRC #drupal-contribute channel. So, come hang out and stay involved.
Thank you, also, for your patience with the review process.
Anyone is welcome to participate in the review process. Please consider reviewing other projects that are pending review. I encourage you to learn more about that process and join the group of reviewers.

I thank all the dedicated reviewers as well.

apaderno’s picture

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.