Software Development Engineer

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

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

© 2024 Ujjwal Bhardwaj. All Rights Reserved.