Skip to content

Commit

Permalink
Merge branch 'feature/longer-activation-token-expiry'
Browse files Browse the repository at this point in the history
  • Loading branch information
jasonvarga committed Jun 1, 2020
2 parents 64fd2d8 + 2b3bd27 commit 059e958
Show file tree
Hide file tree
Showing 14 changed files with 122 additions and 25 deletions.
16 changes: 16 additions & 0 deletions config/users.php
Expand Up @@ -62,4 +62,20 @@
//
],

/*
|--------------------------------------------------------------------------
| Password Brokers
|--------------------------------------------------------------------------
|
| When resetting passwords, Statamic uses an appropriate password broker.
| Here you may define which broker should be used for each situation.
| You may want a longer expiry for user activations, for example.
|
*/

'passwords' => [
'resets' => config('auth.defaults.passwords'),
'activations' => config('auth.defaults.passwords'),
],

];
8 changes: 3 additions & 5 deletions resources/views/auth/passwords/reset.blade.php
Expand Up @@ -3,11 +3,11 @@

@section('content')

<h1 class="mb-3 pt-7 text-center text-grey-80">{{ __('Reset Password') }}</h1>
<h1 class="mb-3 pt-7 text-center text-grey-80">{{ $title }}</h1>

<div class="card auth-card mx-auto">

<form method="POST" action="{{ route('statamic.password.reset.action') }}">
<form method="POST" action="{{ $action }}">
@csrf

<input type="hidden" name="token" value="{{ $token }}">
Expand Down Expand Up @@ -42,9 +42,7 @@
<input id="password-confirm" type="password" class="input-text input-text" name="password_confirmation" required>
</div>

<button type="submit" class="btn-primary">
{{ __('Reset Password') }}
</button>
<button type="submit" class="btn-primary">{{ $title }}</button>

</form>

Expand Down
3 changes: 3 additions & 0 deletions routes/web.php
Expand Up @@ -29,6 +29,9 @@
Route::post('password/email', 'ForgotPasswordController@sendResetLinkEmail')->name('password.email');
Route::get('password/reset/{token}', 'ResetPasswordController@showResetForm')->name('password.reset');
Route::post('password/reset', 'ResetPasswordController@reset')->name('password.reset.action');

Route::get('activate/{token}', 'ActivateAccountController@showResetForm')->name('account.activate');
Route::post('activate', 'ActivateAccountController@reset')->name('account.activate.action');
});

Statamic::additionalActionRoutes();
Expand Down
6 changes: 5 additions & 1 deletion src/Actions/SendPasswordReset.php
Expand Up @@ -35,6 +35,10 @@ public function buttonText()

public function run($users, $values)
{
$users->each->generateTokenAndSendPasswordResetNotification();
$users->each(function ($user) {
$user->password()
? $user->generateTokenAndSendPasswordResetNotification()
: $user->generateTokenAndSendActivateAccountNotification();
});
}
}
1 change: 1 addition & 0 deletions src/Auth/Passwords/PasswordBrokerManager.php
Expand Up @@ -18,6 +18,7 @@ protected function createTokenRepository(array $config)
return new TokenRepository(
$this->app['files'],
$this->app['hash'],
$config['table'],
$key,
$config['expire'],
$config['throttle'] ?? 0
Expand Down
11 changes: 9 additions & 2 deletions src/Auth/Passwords/PasswordReset.php
Expand Up @@ -4,14 +4,21 @@

class PasswordReset
{
const BROKER_RESETS = 'resets';
const BROKER_ACTIVATIONS = 'activations';

protected static $url;
protected static $redirect;

public static function url($token)
public static function url($token, $broker)
{
$route = $broker === self::BROKER_ACTIVATIONS ? 'statamic.account.activate' : 'statamic.password.reset';

$defaultUrl = route($route, $token);

$url = static::$url
? sprintf('%s?token=%s', static::$url, $token)
: route('statamic.password.reset', $token);
: $defaultUrl;

parse_str(parse_url($url, PHP_URL_QUERY) ?: '', $query);

Expand Down
8 changes: 6 additions & 2 deletions src/Auth/Passwords/TokenRepository.php
Expand Up @@ -17,15 +17,15 @@ class TokenRepository extends DatabaseTokenRepository
protected $expires;
protected $path;

public function __construct(Filesystem $files, HasherContract $hasher, $hashKey, $expires = 60, $throttle = 60)
public function __construct(Filesystem $files, HasherContract $hasher, $table, $hashKey, $expires = 60, $throttle = 60)
{
$this->files = $files;
$this->hasher = $hasher;
$this->hashKey = $hashKey;
$this->expires = $expires * 60;
$this->throttle = $throttle;

$this->path = storage_path('statamic/password_resets.yaml');
$this->path = storage_path("statamic/password_resets/$table.yaml");
}

public function create(CanResetPasswordContract $user)
Expand Down Expand Up @@ -92,6 +92,10 @@ protected function getResets()

protected function putResets($resets)
{
if (! $this->files->isDirectory($dir = dirname($this->path))) {
$this->files->makeDirectory($dir);
}

$this->files->put($this->path, YAML::dump($resets->all()));
}
}
24 changes: 17 additions & 7 deletions src/Auth/User.php
Expand Up @@ -183,26 +183,36 @@ public function routeNotificationForMail($notification = null)

public function sendPasswordResetNotification($token)
{
$notification = $this->password()
? new PasswordResetNotification($token)
: new ActivateAccountNotification($token);
$this->notify(new PasswordResetNotification($token));
}

$this->notify($notification);
public function sendActivateAccountNotification($token)
{
$this->notify(new ActivateAccountNotification($token));
}

public function generateTokenAndSendPasswordResetNotification()
{
$this->sendPasswordResetNotification($this->generatePasswordResetToken());
}

public function getPasswordResetUrl()
public function generateTokenAndSendActivateAccountNotification()
{
return PasswordReset::url($this->generatePasswordResetToken());
$this->sendActivateAccountNotification($this->generateActivateAccountToken());
}

public function generatePasswordResetToken()
{
return Password::broker()->createToken($this);
$broker = config('statamic.users.passwords.'.PasswordReset::BROKER_RESETS);

return Password::broker($broker)->createToken($this);
}

public function generateActivateAccountToken()
{
$broker = config('statamic.users.passwords.'.PasswordReset::BROKER_ACTIVATIONS);

return Password::broker($broker)->createToken($this);
}

public static function __callStatic($method, $parameters)
Expand Down
24 changes: 24 additions & 0 deletions src/Http/Controllers/ActivateAccountController.php
@@ -0,0 +1,24 @@
<?php

namespace Statamic\Http\Controllers;

use Illuminate\Support\Facades\Password;
use Statamic\Auth\Passwords\PasswordReset;

class ActivateAccountController extends ResetPasswordController
{
protected function resetFormAction()
{
return route('statamic.account.activate.action');
}

protected function resetFormTitle()
{
return __('Activate Account');
}

public function broker()
{
return Password::broker(PasswordReset::BROKER_ACTIVATIONS);
}
}
8 changes: 6 additions & 2 deletions src/Http/Controllers/CP/Users/UsersController.php
Expand Up @@ -3,6 +3,7 @@
namespace Statamic\Http\Controllers\CP\Users;

use Illuminate\Http\Request;
use Statamic\Auth\Passwords\PasswordReset;
use Statamic\Contracts\Auth\User as UserContract;
use Statamic\CP\Column;
use Statamic\Facades\Blueprint;
Expand Down Expand Up @@ -127,12 +128,15 @@ public function store(Request $request)
if ($request->invitation['send']) {
ActivateAccount::subject($request->invitation['subject']);
ActivateAccount::body($request->invitation['message']);
$user->generateTokenAndSendPasswordResetNotification();
$user->generateTokenAndSendActivateAccountNotification();
$url = null;
} else {
$url = PasswordReset::url($user->generateActivateAccountToken(), PasswordReset::BROKER_ACTIVATIONS);
}

return [
'redirect' => $user->editUrl(),
'activationUrl' => $request->invitation['send'] ? null : $user->getPasswordResetUrl(),
'activationUrl' => $url,
];
}

Expand Down
6 changes: 6 additions & 0 deletions src/Http/Controllers/ForgotPasswordController.php
Expand Up @@ -3,6 +3,7 @@
namespace Statamic\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Password;
use Statamic\Auth\Passwords\PasswordReset;
use Statamic\Auth\SendsPasswordResetEmails;
use Statamic\Facades\URL;
Expand Down Expand Up @@ -32,4 +33,9 @@ public function sendResetLinkEmail(Request $request)

return $this->traitSendResetLinkEmail($request);
}

public function broker()
{
return Password::broker(PasswordReset::BROKER_RESETS);
}
}
26 changes: 23 additions & 3 deletions src/Http/Controllers/ResetPasswordController.php
Expand Up @@ -3,6 +3,8 @@
namespace Statamic\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Password;
use Statamic\Auth\Passwords\PasswordReset;
use Statamic\Auth\ResetsPasswords;
use Statamic\Http\Middleware\RedirectIfAuthenticated;

Expand All @@ -19,9 +21,22 @@ public function __construct()

public function showResetForm(Request $request, $token = null)
{
return view('statamic::auth.passwords.reset')->with(
['token' => $token, 'email' => $request->email]
);
return view('statamic::auth.passwords.reset')->with([
'token' => $token,
'email' => $request->email,
'action' => $this->resetFormAction(),
'title' => $this->resetFormTitle(),
]);
}

protected function resetFormAction()
{
return route('statamic.password.reset.action');
}

protected function resetFormTitle()
{
return __('Reset Password');
}

public function redirectPath()
Expand All @@ -38,4 +53,9 @@ protected function resetPassword($user, $password)

$this->traitResetPassword($user, $password);
}

public function broker()
{
return Password::broker(PasswordReset::BROKER_RESETS);
}
}
2 changes: 1 addition & 1 deletion src/Notifications/ActivateAccount.php
Expand Up @@ -39,7 +39,7 @@ public function toMail($notifiable)
return (new MailMessage)
->subject(static::$subject ?? __('statamic::messages.activate_account_notification_subject'))
->line(static::$body ?? __('statamic::messages.activate_account_notification_body'))
->action(__('Activate Account'), PasswordResetManager::url($this->token));
->action(__('Activate Account'), PasswordResetManager::url($this->token, PasswordResetManager::BROKER_ACTIVATIONS));
}

/**
Expand Down
4 changes: 2 additions & 2 deletions src/Notifications/PasswordReset.php
Expand Up @@ -5,7 +5,7 @@
use Illuminate\Bus\Queueable;
use Illuminate\Notifications\Messages\MailMessage;
use Illuminate\Notifications\Notification;
use Statamic\Auth\Passwords\PasswordReset as PasswordResetUrl;
use Statamic\Auth\Passwords\PasswordReset as PasswordResetManager;

class PasswordReset extends Notification
{
Expand Down Expand Up @@ -40,7 +40,7 @@ public function toMail($notifiable)
return (new MailMessage)
->subject(__('statamic::messages.reset_password_notification_subject'))
->line(__('statamic::messages.reset_password_notification_body'))
->action(__('Reset Password'), PasswordResetUrl::url($this->token))
->action(__('Reset Password'), PasswordResetManager::url($this->token, PasswordResetManager::BROKER_RESETS))
->line(__('statamic::messages.reset_password_notification_no_action'));
}

Expand Down

0 comments on commit 059e958

Please sign in to comment.