Skip to content

Commit

Permalink
Add test for password recovery and reset.
Browse files Browse the repository at this point in the history
  • Loading branch information
edwh committed Aug 18, 2021
1 parent 801dfa1 commit 77cddc4
Show file tree
Hide file tree
Showing 2 changed files with 176 additions and 28 deletions.
62 changes: 34 additions & 28 deletions app/Http/Controllers/UserController.php
Original file line number Diff line number Diff line change
Expand Up @@ -421,16 +421,14 @@ public function postEdit(Request $request)
return redirect()->back()->with('success', 'Profile updated');
}

/**
* @ToDo : test and delete commented
*/
public function recover()
public function recover(Request $request)
{
$User = new User;

if (strtoupper($_SERVER['REQUEST_METHOD']) == 'POST' && isset($_POST['email']) && ! empty($_POST['email'])) {
$email = $_POST['email'];
if (empty($email) || ! filter_var($email, FILTER_VALIDATE_EMAIL)) {
if ($request->getMethod() == 'POST' && $request->has('email')) {
$email = $request->get('email');

if (!$email || ! filter_var($email, FILTER_VALIDATE_EMAIL)) {
$response['danger'] = 'Please input a <strong>valid</strong> email.';
} else {
$user = $User->where('email', $email)->first();
Expand All @@ -448,8 +446,8 @@ public function recover()

// update record
$user->update([
'recovery' => $data['recovery'],
'recovery_expires' => $data['recovery_expires'],
'recovery' => $data['recovery'],
'recovery_expires' => $data['recovery_expires'],
]);

User::find($id)->notify(new ResetPassword([
Expand All @@ -462,25 +460,25 @@ public function recover()
}
}

return view('auth.forgot-password', [//user.recover
'title' => 'Account recovery',
'response' => $response,
return view('auth.forgot-password', [
'title' => 'Account recovery',
'response' => $response,
]);
}

return view('auth.forgot-password', [//user.recover
'title' => 'Account recovery',
return view('auth.forgot-password', [
'title' => 'Account recovery',
]);
}

public function reset()
public function reset(Request $request)
{
$User = new User;

if (! isset($_GET['recovery']) || empty($_GET['recovery'])) {
if (!$request->has('recovery') || !$request->get('recovery')) {
$valid_code = false;
} else {
$recovery = filter_var($_GET['recovery'], FILTER_SANITIZE_STRING);
$recovery = filter_var($request->get('recovery'), FILTER_SANITIZE_STRING);
$user = $User->where('recovery', '=', $recovery)->first();

if (is_object($user) && strtotime($user->recovery_expires) > time()) {
Expand All @@ -490,10 +488,16 @@ public function reset()
}
}

if (strtoupper($_SERVER['REQUEST_METHOD']) == 'POST' && isset($_POST['password']) && ! empty($_POST['password']) && isset($_POST['confirm_password']) && ! empty($_POST['confirm_password'])) {
$recovery = $_POST['recovery'];
$pwd = $_POST['password'];
$cpwd = $_POST['confirm_password'];
if ($request->getMethod() == 'POST' &&
$request->has('recovery') &&
$request->has('password') &&
$request->get('password') &&
$request->has('confirm_password') &&
$request->get('confirm_password')) {
$recovery = $request->post('recovery');
$pwd = $request->post('password');
$cpwd = $request->post('confirm_password');

if (empty($recovery) || ! filter_var($recovery, FILTER_SANITIZE_STRING)) {
$response['danger'] = 'Recovery code invalid.';
} elseif ($pwd !== $cpwd) {
Expand All @@ -502,10 +506,12 @@ public function reset()
$user = $User->where('recovery', '=', $recovery)->first();
if (! empty($user)) {
$data = [
'password' => crypt($pwd, '$1$'.strrev(md5(env('APP_KEY')))),
'password' => Hash::make($pwd),
];
$update = $user->update($data);
if ($update) {
event(new PasswordChanged($user));

return redirect('login')->with('success', 'Password updated, please login to continue');
} else {
$response['danger'] = 'Could not update the password.';
Expand All @@ -530,12 +536,12 @@ public function reset()
$email = null;
}

return view('auth.reset-password', [//user.reset
'title' => 'Account recovery',
'recovery' => $recovery,
'valid_code' => $valid_code,
'response' => $response,
'email' => $email,
return view('auth.reset-password', [
'title' => 'Account recovery',
'recovery' => $recovery,
'valid_code' => $valid_code,
'response' => $response,
'email' => $email,
]);
}

Expand Down
142 changes: 142 additions & 0 deletions tests/Feature/Users/Registration/RecoverTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
<?php

namespace Tests\Feature;

use App\Notifications\ResetPassword;
use App\Events\PasswordChanged;
use App\User;
use DB;
use Hash;
use Illuminate\Support\Facades\Notification;
use Illuminate\Support\Facades\Event;
use Mockery;
use Symfony\Component\DomCrawler\Crawler;
use Tests\TestCase;

class RecoverTest extends TestCase
{
public function testRecover()
{
$restarter = factory(User::class)->state('Restarter')->create([
'password' => Hash::make('passw0rd'),
]);

// Fetch the recover page.
$response = $this->get('/user/recover');
$response->assertStatus(200);
$response->assertSee(__('auth.forgotten_pw_text'));

// Post a recover request - invalid email
$response = $this->post('/user/recover', [
'email' => 'zzzz'
]);
$response->assertSee('alert-danger');

// Post a valid recover request.
Notification::fake();

$response = $this->post('/user/recover', [
'email' => $restarter->email
]);
$response->assertSee('alert-success');

$this->recovery = null;

Notification::assertSentTo(
$restarter,
ResetPassword::class,
function ($notification, $channels) use ($restarter)
{
// retrive the mail content
$mailData = $notification->toMail($restarter)->toArray();
$this->recovery = $mailData['actionUrl'];
return true;
});

// Now fetch the reset page - first in error.
$response = $this->get('/user/reset');
$response->assertSee('The recovery code you\'re using is invalid');
$response = $this->get($this->recovery . 'zz');
$response->assertSee('The recovery code you\'re using is invalid');

$response = $this->get($this->recovery);
$response->assertSee('id="confirm_password"');

// Now submit the reset request - first in error.
$response = $this->post($this->recovery, [
'password' => "1234",
'confirm_password' => "1234",
'recovery' => null
]);
$response->assertSee('Recovery code invalid');

$response = $this->post($this->recovery, [
'password' => "1234",
'confirm_password' => "12345",
'recovery' => $this->recovery
]);
$response->assertSee('The passwords do not match');

$response = $this->post($this->recovery, [
'password' => "1234",
'confirm_password' => "1234",
'recovery' => 'wibble'
]);
$response->assertSee('No account matches the recovery code');

// Now a successful reset, which redirects back to the login page.
$p = strrpos($this->recovery, '=');
$value = substr($this->recovery, $p + 1);

Event::fake([
PasswordChanged::class,
]);

$response = $this->post($this->recovery, [
'password' => "1234",
'confirm_password' => "1234",
'recovery' => $value
]);
$this->assertTrue($response->isRedirection());
Event::assertDispatched(PasswordChanged::class);

$response->assertSessionHas('success');

// Now log in with the new password.
$response = $this->get('/login');
$response->assertStatus(200);

$crawler = new Crawler($response->getContent());

$tokens = $crawler->filter('input[name=_token]')->each(function (Crawler $node, $i) {
return $node;
});

$tokenValue = $tokens[0]->attr('value');

$names = $crawler->filter('input[name=my_name]')->each(function (Crawler $node, $i) {
return $node;
});

$nameValue = $names[0]->attr('value');

$times = $crawler->filter('input[name=my_time]')->each(function (Crawler $node, $i) {
return $node;
});

$timeValue = $times[0]->attr('value');

$response = $this->post('/login', [
'_token' => $tokenValue,
'my_name' => $nameValue,
'my_time' => $timeValue,
'email' => $restarter->email,
'password' => '1234',
]);

// Should redirect to dashboard.
$this->assertTrue($response->isRedirection());
$redirectTo = $response->getTargetUrl();
$this->assertNotFalse(strpos($redirectTo, '/dashboard'));
}
}

0 comments on commit 77cddc4

Please sign in to comment.