blessing-skin-server/tests/AuthControllerTest.php

622 lines
20 KiB
PHP
Raw Normal View History

2017-10-30 12:40:34 +08:00
<?php
2018-08-17 15:25:08 +08:00
namespace Tests;
2017-10-30 12:40:34 +08:00
use App\Events;
use App\Models\User;
2018-08-17 15:25:08 +08:00
use App\Models\Player;
2018-07-15 17:42:03 +08:00
use App\Mail\ForgotPassword;
2017-10-30 12:40:34 +08:00
use App\Services\Facades\Option;
2018-08-17 15:25:08 +08:00
use Illuminate\Support\Facades\URL;
2017-10-30 12:40:34 +08:00
use Illuminate\Support\Facades\Mail;
use Illuminate\Foundation\Testing\WithoutMiddleware;
use Illuminate\Foundation\Testing\DatabaseMigrations;
use Illuminate\Foundation\Testing\DatabaseTransactions;
class AuthControllerTest extends TestCase
{
use DatabaseTransactions;
public function testLogin()
{
2018-07-13 15:13:35 +08:00
$this->get('/auth/login')->assertSee('Log in');
2017-10-30 12:40:34 +08:00
}
public function testHandleLogin()
{
$this->expectsEvents(Events\UserTryToLogin::class);
$this->expectsEvents(Events\UserLoggedIn::class);
$user = factory(User::class)->create();
2018-07-19 10:31:44 +08:00
$user->changePassword('12345678');
2018-08-17 15:25:08 +08:00
$player = factory(Player::class)->create(
2017-10-30 12:40:34 +08:00
[
'uid' => $user->uid
]
);
// Should return a warning if `identification` is empty
2018-07-13 15:13:35 +08:00
$this->postJson(
2017-10-30 12:40:34 +08:00
'/auth/login', [], [
'X-Requested-With' => 'XMLHttpRequest'
2018-07-13 15:13:35 +08:00
])->assertJson([
2017-10-30 12:40:34 +08:00
'errno' => 1,
'msg' => trans('validation.required', ['attribute' => trans('auth.identification')])
]);
// Should return a warning if `password` is empty
2018-07-13 15:13:35 +08:00
$this->postJson(
2017-10-30 12:40:34 +08:00
'/auth/login', [
'identification' => $user->email
], [
'X-Requested-With' => 'XMLHttpRequest'
2018-07-13 15:13:35 +08:00
])->assertJson([
2017-10-30 12:40:34 +08:00
'errno' => 1,
'msg' => trans('validation.required', ['attribute' => 'password'])
]);
// Should return a warning if length of `password` is lower than 6
2018-07-13 15:13:35 +08:00
$this->postJson(
2017-10-30 12:40:34 +08:00
'/auth/login', [
'identification' => $user->email,
'password' => '123'
], [
'X-Requested-With' => 'XMLHttpRequest'
2018-07-13 15:13:35 +08:00
])->assertJson([
2017-10-30 12:40:34 +08:00
'errno' => 1,
'msg' => trans('validation.min.string', ['attribute' => 'password', 'min' => 6])
]);
// Should return a warning if length of `password` is greater than 32
2018-07-13 15:13:35 +08:00
$this->postJson(
2017-10-30 12:40:34 +08:00
'/auth/login', [
'identification' => $user->email,
'password' => str_random(80)
], [
'X-Requested-With' => 'XMLHttpRequest'
2018-07-13 15:13:35 +08:00
])->assertJson([
2017-10-30 12:40:34 +08:00
'errno' => 1,
'msg' => trans('validation.max.string', ['attribute' => 'password', 'max' => 32])
2017-10-30 12:40:34 +08:00
]);
$this->flushSession();
2018-08-17 22:54:26 +08:00
$loginFailsCacheKey = sha1('login_fails_'.get_client_ip());
2018-08-16 17:57:24 +08:00
2017-10-30 12:40:34 +08:00
// Logging in should be failed if password is wrong
2018-07-13 15:13:35 +08:00
$this->postJson(
2017-10-30 12:40:34 +08:00
'/auth/login', [
'identification' => $user->email,
'password' => 'wrong-password'
2018-07-13 15:13:35 +08:00
])->assertJson(
2017-10-30 12:40:34 +08:00
[
'errno' => 1,
'msg' => trans('auth.validation.password'),
'login_fails' => 1
]
2018-08-17 15:25:08 +08:00
);
$this->assertCacheHas($loginFailsCacheKey);
2017-10-30 12:40:34 +08:00
$this->flushSession();
// Should check captcha if there are too many fails
2018-08-16 17:57:24 +08:00
$this->withCache([$loginFailsCacheKey => 4])
2018-07-21 08:17:16 +08:00
->postJson(
'/auth/login', [
'identification' => $user->email,
'password' => '12345678',
])->assertJson([
'errno' => 1,
'msg' => trans('validation.required', ['attribute' => 'captcha'])
]);
2017-10-30 12:40:34 +08:00
2018-08-16 17:57:24 +08:00
$this->flushCache();
2017-10-30 12:40:34 +08:00
$this->flushSession();
// Should return a warning if user isn't existed
2018-07-13 15:13:35 +08:00
$this->postJson(
2017-10-30 12:40:34 +08:00
'/auth/login', [
'identification' => 'nope@nope.net',
'password' => '12345678'
2018-07-13 15:13:35 +08:00
])->assertJson([
2017-10-30 12:40:34 +08:00
'errno' => 2,
'msg' => trans('auth.validation.user')
]);
$this->flushSession();
// Should clean the `login_fails` session if logged in successfully
2018-08-16 17:57:24 +08:00
$this->withCache([$loginFailsCacheKey => 1])
->postJson('/auth/login', [
2017-10-30 12:40:34 +08:00
'identification' => $user->email,
'password' => '12345678'
2018-07-13 15:13:35 +08:00
])->assertJson(
2017-10-30 12:40:34 +08:00
[
'errno' => 0,
'msg' => trans('auth.login.success')
2017-10-30 12:40:34 +08:00
]
2018-08-16 17:57:24 +08:00
);
$this->assertCacheMissing($loginFailsCacheKey);
2017-10-30 12:40:34 +08:00
2018-08-16 17:57:24 +08:00
$this->flushCache();
2017-10-30 12:40:34 +08:00
$this->flushSession();
// Logged in should be in success if logged in with player name
2018-07-13 15:13:35 +08:00
$this->postJson(
2017-10-30 12:40:34 +08:00
'/auth/login', [
'identification' => $player->player_name,
'password' => '12345678'
]
2018-07-13 15:13:35 +08:00
)->assertJson(
2017-10-30 12:40:34 +08:00
[
'errno' => 0,
'msg' => trans('auth.login.success')
2017-10-30 12:40:34 +08:00
]
);
$this->assertAuthenticated();
2017-10-30 12:40:34 +08:00
}
public function testLogout()
{
2018-07-13 15:13:35 +08:00
$this->postJson('/auth/logout')
->assertJson([
2017-10-30 12:40:34 +08:00
'errno' => 1,
'msg' => trans('auth.logout.fail')
]);
$user = factory(User::class)->create();
$this->actingAs($user)->postJson('/auth/logout')->assertJson(
[
'errno' => 0,
'msg' => trans('auth.logout.success')
]
);
$this->assertGuest();
2017-10-30 12:40:34 +08:00
}
public function testRegister()
{
2018-07-13 15:13:35 +08:00
$this->get('/auth/register')->assertSee('Register');
2017-10-30 12:40:34 +08:00
option(['user_can_register' => false]);
2018-07-13 15:13:35 +08:00
$this->get('/auth/register')->assertSee(trans('auth.register.close'));
2017-10-30 12:40:34 +08:00
}
public function testHandleRegister()
{
$this->expectsEvents(Events\UserRegistered::class);
// Should return a warning if `email` is empty
2018-07-13 15:13:35 +08:00
$this->postJson(
2017-10-30 12:40:34 +08:00
'/auth/register',
[],
2017-10-30 12:40:34 +08:00
['X-Requested-With' => 'XMLHttpRequest']
2018-07-13 15:13:35 +08:00
)->assertJson([
2017-10-30 12:40:34 +08:00
'errno' => 1,
'msg' => trans('validation.required', ['attribute' => 'email'])
]);
// Should return a warning if `email` is invalid
2018-07-13 15:13:35 +08:00
$this->postJson(
2017-10-30 12:40:34 +08:00
'/auth/register',
['email' => 'not_an_email'],
2017-10-30 12:40:34 +08:00
['X-Requested-With' => 'XMLHttpRequest']
2018-07-13 15:13:35 +08:00
)->assertJson([
2017-10-30 12:40:34 +08:00
'errno' => 1,
'msg' => trans('validation.email', ['attribute' => 'email'])
]);
// An existed user
$existedUser = factory(User::class)->create();
$this->postJson(
'/auth/register',
['email' => $existedUser->email],
['X-Requested-With' => 'XMLHttpRequest']
)->assertJson([
'errno' => 1,
'msg' => trans('validation.unique', ['attribute' => 'email'])
]);
2017-10-30 12:40:34 +08:00
// Should return a warning if `password` is empty
2018-07-13 15:13:35 +08:00
$this->postJson(
2017-10-30 12:40:34 +08:00
'/auth/register',
['email' => 'a@b.c'],
2017-10-30 12:40:34 +08:00
['X-Requested-With' => 'XMLHttpRequest']
2018-07-13 15:13:35 +08:00
)->assertJson([
2017-10-30 12:40:34 +08:00
'errno' => 1,
'msg' => trans('validation.required', ['attribute' => 'password'])
]);
// Should return a warning if length of `password` is lower than 8
2018-07-13 15:13:35 +08:00
$this->postJson(
2017-10-30 12:40:34 +08:00
'/auth/register',
[
'email' => 'a@b.c',
'password' => '1'
2017-10-30 12:40:34 +08:00
],
['X-Requested-With' => 'XMLHttpRequest']
2018-07-13 15:13:35 +08:00
)->assertJson([
2017-10-30 12:40:34 +08:00
'errno' => 1,
'msg' => trans('validation.min.string', ['attribute' => 'password', 'min' => 8])
]);
// Should return a warning if length of `password` is greater than 32
2018-07-13 15:13:35 +08:00
$this->postJson(
2017-10-30 12:40:34 +08:00
'/auth/register',
[
'email' => 'a@b.c',
'password' => str_random(33)
]
2018-07-13 15:13:35 +08:00
)->assertJson([
2017-10-30 12:40:34 +08:00
'errno' => 1,
'msg' => trans('validation.max.string', ['attribute' => 'password', 'max' => 32])
2017-10-30 12:40:34 +08:00
]);
// The register_with_player_name option is set to true by default.
// Should return a warning if `player_name` is empty
$this->postJson(
'/auth/register',
[
'email' => 'a@b.c',
'password' => '12345678',
'captcha' => 'a'
]
)->assertJson([
'errno' => 1,
'msg' => trans('validation.required', ['attribute' => 'Player Name'])
]);
// Should return a warning if `player_name` is invalid
option(['player_name_rule' => 'official']);
$this->postJson(
'/auth/register',
[
'email' => 'a@b.c',
'password' => '12345678',
'player_name' => '角色名',
'captcha' => 'a'
]
)->assertJson([
'errno' => 1,
'msg' => trans('validation.player_name', ['attribute' => 'Player Name'])
]);
// Should return a warning if `player_name` is too long
$this->postJson(
'/auth/register',
[
'email' => 'a@b.c',
'password' => '12345678',
'player_name' => str_random(option('player_name_length_max') + 10),
'captcha' => 'a'
]
)->assertJson([
'errno' => 1,
'msg' => trans('validation.max.string', [
'attribute' => 'Player Name',
'max' => option('player_name_length_max')
])
]);
// Existed player
$player = factory(Player::class)->create();
$this->postJson(
'/auth/register',
[
'email' => 'a@b.c',
'password' => '12345678',
'player_name' => $player->player_name,
'captcha' => 'a'
]
)->assertJson([
'errno' => 2,
'msg' => trans('user.player.add.repeated')
]);
option(['register_with_player_name' => false]);
2017-10-30 12:40:34 +08:00
// Should return a warning if `nickname` is empty
2018-07-13 15:13:35 +08:00
$this->postJson(
2017-10-30 12:40:34 +08:00
'/auth/register',
[
'email' => 'a@b.c',
'password' => '12345678',
'captcha' => 'a'
2017-10-30 12:40:34 +08:00
],
['X-Requested-With' => 'XMLHttpRequest']
2018-07-13 15:13:35 +08:00
)->assertJson([
2017-10-30 12:40:34 +08:00
'errno' => 1,
'msg' => trans('validation.required', ['attribute' => 'nickname'])
]);
// Should return a warning if `nickname` is invalid
2018-07-13 15:13:35 +08:00
$this->postJson(
2017-10-30 12:40:34 +08:00
'/auth/register',
[
'email' => 'a@b.c',
'password' => '12345678',
'nickname' => '\\',
'captcha' => 'a'
2017-10-30 12:40:34 +08:00
],
['X-Requested-With' => 'XMLHttpRequest']
2018-07-13 15:13:35 +08:00
)->assertJson([
2017-10-30 12:40:34 +08:00
'errno' => 1,
'msg' => trans('validation.no_special_chars', ['attribute' => 'nickname'])
2017-10-30 12:40:34 +08:00
]);
// Should return a warning if `nickname` is too long
2018-07-13 15:13:35 +08:00
$this->postJson(
2017-10-30 12:40:34 +08:00
'/auth/register',
[
'email' => 'a@b.c',
'password' => '12345678',
'nickname' => str_random(256),
'captcha' => 'a'
2017-10-30 12:40:34 +08:00
],
['X-Requested-With' => 'XMLHttpRequest']
2018-07-13 15:13:35 +08:00
)->assertJson([
2017-10-30 12:40:34 +08:00
'errno' => 1,
'msg' => trans('validation.max.string', ['attribute' => 'nickname', 'max' => 255])
]);
// Should return a warning if `captcha` is empty
$this->postJson(
'/auth/register',
[
'email' => 'a@b.c',
'password' => '12345678',
'nickname' => 'nickname'
],
['X-Requested-With' => 'XMLHttpRequest']
)->assertJson([
'errno' => 1,
'msg' => trans('validation.required', ['attribute' => 'captcha'])
]);
2017-10-30 12:40:34 +08:00
// Should be forbidden if registering is closed
Option::set('user_can_register', false);
2018-07-13 15:13:35 +08:00
$this->postJson(
2017-10-30 12:40:34 +08:00
'/auth/register',
[
'email' => 'a@b.c',
'password' => '12345678',
'nickname' => 'nickname',
'captcha' => 'a'
],
['X-Requested-With' => 'XMLHttpRequest']
2018-07-13 15:13:35 +08:00
)->assertJson([
2017-10-30 12:40:34 +08:00
'errno' => 7,
'msg' => trans('auth.register.close')
]);
// Reopen for test
Option::set('user_can_register', true);
// Should be forbidden if registering's count current IP is over
Option::set('regs_per_ip', -1);
2018-07-13 15:13:35 +08:00
$this->postJson(
2017-10-30 12:40:34 +08:00
'/auth/register',
[
'email' => 'a@b.c',
'password' => '12345678',
'nickname' => 'nickname',
'captcha' => 'a'
]
2018-07-13 15:13:35 +08:00
)->assertJson([
2017-10-30 12:40:34 +08:00
'errno' => 7,
'msg' => trans('auth.register.max', ['regs' => option('regs_per_ip')])
]);
Option::set('regs_per_ip', 100);
2017-10-30 12:40:34 +08:00
// Database should be updated if succeeded
2018-07-13 15:13:35 +08:00
$response = $this->postJson(
2017-10-30 12:40:34 +08:00
'/auth/register',
[
'email' => 'a@b.c',
'password' => '12345678',
'nickname' => 'nickname',
'captcha' => 'a'
]
);
$newUser = User::where('email', 'a@b.c')->first();
2018-07-13 15:13:35 +08:00
$response->assertJson([
2017-10-30 12:40:34 +08:00
'errno' => 0,
'msg' => trans('auth.register.success')
]);
2017-10-30 12:40:34 +08:00
$this->assertTrue($newUser->verifyPassword('12345678'));
2018-07-13 15:13:35 +08:00
$this->assertDatabaseHas('users', [
2017-10-30 12:40:34 +08:00
'email' => 'a@b.c',
'nickname' => 'nickname',
'score' => option('user_initial_score'),
'ip' => '127.0.0.1',
'permission' => User::NORMAL
]);
$this->assertAuthenticated();
// Require player name
2018-08-19 18:28:38 +08:00
option(['register_with_player_name' => true]);
$this->postJson(
'/auth/register',
[
2018-08-19 18:28:38 +08:00
'email' => 'abc@test.org',
'password' => '12345678',
'player_name' => 'name',
'captcha' => 'a'
]
2018-08-19 18:28:38 +08:00
)->assertJson(['errno' => 0]);
$this->assertNotNull(Player::where('player_name', 'name'));
2017-10-30 12:40:34 +08:00
}
public function testForgot()
{
2018-07-13 15:13:35 +08:00
$this->get('/auth/forgot')->assertSee('Forgot Password');
2017-10-30 12:40:34 +08:00
config(['mail.driver' => '']);
2018-08-17 12:32:44 +08:00
$this->get('/auth/forgot')->assertSee(trans('auth.forgot.disabled'));
2017-10-30 12:40:34 +08:00
}
public function testHandleForgot()
{
2018-07-13 19:23:20 +08:00
Mail::fake();
2017-10-30 12:40:34 +08:00
// Should be forbidden if "forgot password" is closed
config(['mail.driver' => '']);
2018-08-12 16:00:21 +08:00
$this->postJson('/auth/forgot', [
2017-10-30 12:40:34 +08:00
'captcha' => 'a'
2018-07-13 15:13:35 +08:00
])->assertJson([
2017-10-30 12:40:34 +08:00
'errno' => 1,
2018-08-17 12:32:44 +08:00
'msg' => trans('auth.forgot.disabled')
2017-10-30 12:40:34 +08:00
]);
config(['mail.driver' => 'smtp']);
2017-10-30 12:40:34 +08:00
2018-08-17 22:54:26 +08:00
$lastMailCacheKey = sha1('last_mail_'.get_client_ip());
2017-10-30 12:40:34 +08:00
// Should be forbidden if sending email frequently
$this->withCache([
$lastMailCacheKey => time()
])->postJson('/auth/forgot', [
2017-10-30 12:40:34 +08:00
'captcha' => 'a'
2018-07-13 15:13:35 +08:00
])->assertJson([
'errno' => 2,
2017-10-30 12:40:34 +08:00
'msg' => trans('auth.forgot.frequent-mail')
]);
$this->flushCache();
$this->flushSession();
2017-10-30 12:40:34 +08:00
// Should return a warning if user is not existed
$user = factory(User::class)->create();
2018-07-13 15:13:35 +08:00
$this->withSession(['phrase' => 'a'])->postJson('/auth/forgot', [
2017-10-30 12:40:34 +08:00
'email' => 'nope@nope.net',
'captcha' => 'a'
2018-07-13 15:13:35 +08:00
])->assertJson([
2017-10-30 12:40:34 +08:00
'errno' => 1,
'msg' => trans('auth.forgot.unregistered')
]);
2018-07-13 15:13:35 +08:00
$this->postJson('/auth/forgot', [
2017-10-30 12:40:34 +08:00
'email' => $user->email,
'captcha' => 'a'
2018-07-13 15:13:35 +08:00
])->assertJson([
2017-10-30 12:40:34 +08:00
'errno' => 0,
2018-08-16 18:10:09 +08:00
'msg' => trans('auth.forgot.success')
]);
$this->assertCacheHas($lastMailCacheKey);
$this->flushCache();
Mail::assertSent(ForgotPassword::class, function ($mail) use ($user) {
return $mail->hasTo($user->email);
2018-07-15 17:42:03 +08:00
});
2017-10-30 12:40:34 +08:00
// Should handle exception when sending email
2018-07-15 17:42:03 +08:00
Mail::shouldReceive('to')
2017-10-30 12:40:34 +08:00
->once()
->andThrow(new \Mockery\Exception('A fake exception.'));
$this->flushSession();
$this->withSession(['phrase' => 'a'])
2018-07-13 15:13:35 +08:00
->postJson('/auth/forgot', [
2017-10-30 12:40:34 +08:00
'email' => $user->email,
'captcha' => 'a'
2018-07-13 15:13:35 +08:00
])->assertJson([
2017-10-30 12:40:34 +08:00
'errno' => 2,
2018-08-16 18:10:09 +08:00
'msg' => trans('auth.forgot.failed', ['msg' => 'A fake exception.'])
2017-10-30 12:40:34 +08:00
]);
2018-07-23 09:33:55 +08:00
// Addition: Mailable test
$site_name = option_localized('site_name');
$mailable = new ForgotPassword('url');
$mailable->build();
$this->assertTrue($mailable->hasFrom(config('mail.username'), $site_name));
2018-08-16 18:10:09 +08:00
$this->assertEquals(trans('auth.forgot.mail.title', ['sitename' => $site_name]), $mailable->subject);
$this->assertEquals('mails.password-reset', $mailable->view);
2017-10-30 12:40:34 +08:00
}
public function testReset()
{
$user = factory(User::class)->create();
$this->get(
URL::temporarySignedRoute('auth.reset', now()->addHour(), ['uid' => $user->uid])
)->assertSuccessful();
2017-10-30 12:40:34 +08:00
}
public function testHandleReset()
{
$user = factory(User::class)->create();
$url = URL::temporarySignedRoute('auth.reset', now()->addHour(), ['uid' => $user->uid]);
2017-10-30 12:40:34 +08:00
// Should return a warning if `password` is empty
2018-07-13 15:13:35 +08:00
$this->postJson(
$url, [], [
2017-10-30 12:40:34 +08:00
'X-Requested-With' => 'XMLHttpRequest'
2018-07-13 15:13:35 +08:00
])->assertJson([
2017-10-30 12:40:34 +08:00
'errno' => 1,
'msg' => trans('validation.required', ['attribute' => 'password'])
]);
// Should return a warning if `password` is too short
2018-07-13 15:13:35 +08:00
$this->postJson(
$url, [
2017-10-30 12:40:34 +08:00
'password' => '123'
], [
'X-Requested-With' => 'XMLHttpRequest'
2018-07-13 15:13:35 +08:00
])->assertJson([
2017-10-30 12:40:34 +08:00
'errno' => 1,
'msg' => trans('validation.min.string', ['attribute' => 'password', 'min' => 8])
]);
// Should return a warning if `password` is too long
2018-07-13 15:13:35 +08:00
$this->postJson(
$url, [
'password' => str_random(33)
2017-10-30 12:40:34 +08:00
], [
'X-Requested-With' => 'XMLHttpRequest'
2018-07-13 15:13:35 +08:00
])->assertJson([
2017-10-30 12:40:34 +08:00
'errno' => 1,
'msg' => trans('validation.max.string', ['attribute' => 'password', 'max' => 32])
2017-10-30 12:40:34 +08:00
]);
// Success
2018-07-13 15:13:35 +08:00
$this->postJson(
$url, [
'password' => '12345678',
2018-07-13 15:13:35 +08:00
])->assertJson([
2017-10-30 12:40:34 +08:00
'errno' => 0,
'msg' => trans('auth.reset.success')
]);
// We must re-query the user model,
// because the old instance hasn't been changed
// after resetting password.
$user = User::find($user->uid);
$this->assertTrue($user->verifyPassword('12345678'));
}
2018-08-17 12:32:44 +08:00
public function testVerify()
{
$url = URL::signedRoute('auth.verify', ['uid' => 1]);
// Should be forbidden if account verification is disabled
option(['require_verification' => false]);
$this->get($url)->assertSee(trans('user.verification.disabled'));
option(['require_verification' => true]);
$this->get($url)->assertSee(trans('auth.verify.invalid'));
$user = factory(User::class)->create();
$url = URL::signedRoute('auth.verify', ['uid' => $user->uid]);
$this->get($url)->assertSee(trans('auth.verify.invalid'));
$user = factory(User::class)->create(['verified' => false]);
$url = URL::signedRoute('auth.verify', ['uid' => $user->uid]);
$this->get($url)->assertViewIs('auth.verify');
$this->assertEquals(1, User::find($user->uid)->verified);
}
2017-10-30 12:40:34 +08:00
public function testCaptcha()
{
$this->get('/auth/captcha')
2018-07-13 15:13:35 +08:00
->assertSuccessful()
->assertHeader('Content-Type', 'image/png');
2017-10-30 12:40:34 +08:00
}
}