Software Engineer | Technical Evangelist

Blog PostsResume

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


$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;


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->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);

© 2019 | Ujjwal Bhardwaj. All Rights Reserved.