Student | Freelance Web Developer | Open Source Developer

About meResume

ownCloud 10.0 Bug Solved: Prevent password reset email spamming

ownCloud enables its users to request resetting the password by sending a 'Password Reset Email'. The email is sent to the registered user email id. This feature had a little bug in it. A password reset email could be asked continuously for an infinite number of times. This led to a possibility of sending spam emails to users.

In order to solve this bug, it was needed to add only a few lines of code. Since ownCloud stored a password reset token along with the time it was requested, the timestamp could be compared with current timestamp to check if a certain amount of time has passed. Thus with the suggestion of the mentors, the timestamp was checked so that a delay of 5 minutes could be added before another password reset mail was requested. Pull Request: #27346

Implementation

$token = $this->config->getUserValue($user, 'owncloud', 'lostpassword');
    if ($token !== '') {
        $splittedToken = explode(':', $token);
        if ((count($splittedToken)) === 2 && $splittedToken[0] > ($this->timeFactory->getTime() - 60 * 5)) {
            $this->logger->alert('The email is not sent because a password reset email was sent recently.');
            return false;
        }
    }

Tests

Even though all the previous tests we accepted by the changes that I made, the code required an update of the unit tests which applied on the following functionality. I added a test, testSpamEmail(). which made sure that the code asserts false whenever an email was requested before the 5 minutes delay had passed. Along with this, I also updated the testEmailSuccessful() function.

    public function testSpamEmail() {
      $user = 'ExistingUser';
      $this->userManager->expects($this->once())->method('userExists')->with($user)->will($this->returnValue(true));

      $this->userManager->expects($this->once())->method('get')->with($user)->will($this->returnValue($this->existingUser));

      $this->config->expects($this->once())->method('getUserValue')->with('ExistingUser', 'owncloud', 'lostpassword')->will($this->returnValue('12000:AVerySecretToken'));

      $this->timeFactory->expects($this->any())->method('getTime')->willReturnOnConsecutiveCalls(12001, 12348);

      $this->logger->expects($this->any())->method('alert')->with('The email is not sent because a password reset email was sent recently.');

      $expectedResponse = [
        'status' => 'success'
      ];
      $response = $this->lostController->email($user);
      $this->assertSame($expectedResponse, $response);
  }