update: use fortify for authentication

This commit is contained in:
Roardom
2023-06-13 21:37:26 +00:00
parent 531628124e
commit 326adb5c08
32 changed files with 1175 additions and 852 deletions
@@ -1,53 +0,0 @@
<?php
/**
* NOTICE OF LICENSE.
*
* UNIT3D Community Edition is open-sourced software licensed under the GNU Affero General Public License v3.0
* The details is bundled with this project in the file LICENSE.txt.
*
* @project UNIT3D Community Edition
*
* @author HDVinnie <hdinnovations@protonmail.com>
* @license https://www.gnu.org/licenses/agpl-3.0.en.html/ GNU Affero General Public License v3.0
*/
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use App\Models\Group;
use App\Models\UserActivation;
use App\Services\Unit3dAnnounce;
/**
* @see \Tests\Feature\Http\Controllers\Auth\ActivationControllerTest
*/
class ActivationController extends Controller
{
public function activate($token): \Illuminate\Http\RedirectResponse
{
$bannedGroup = cache()->rememberForever('banned_group', fn () => Group::where('slug', '=', 'banned')->pluck('id'));
$memberGroup = cache()->rememberForever('member_group', fn () => Group::where('slug', '=', 'user')->pluck('id'));
$activation = UserActivation::with('user')->where('token', '=', $token)->firstOrFail();
if ($activation->user->id && $activation->user->group->id != $bannedGroup[0]) {
$activation->user->active = 1;
$activation->user->can_upload = 1;
$activation->user->can_download = 1;
$activation->user->can_request = 1;
$activation->user->can_comment = 1;
$activation->user->can_invite = 1;
$activation->user->group_id = $memberGroup[0];
$activation->user->save();
$activation->delete();
Unit3dAnnounce::addUser($activation->user);
return to_route('login')
->withSuccess(trans('auth.activation-success'));
}
return to_route('login')
->withErrors(trans('auth.activation-error'));
}
}
@@ -1,40 +0,0 @@
<?php
/**
* NOTICE OF LICENSE.
*
* UNIT3D Community Edition is open-sourced software licensed under the GNU Affero General Public License v3.0
* The details is bundled with this project in the file LICENSE.txt.
*
* @project UNIT3D Community Edition
*
* @author HDVinnie <hdinnovations@protonmail.com>
* @license https://www.gnu.org/licenses/agpl-3.0.en.html/ GNU Affero General Public License v3.0
*/
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\SendsPasswordResetEmails;
use Illuminate\Http\Request;
class ForgotPasswordController extends Controller
{
use SendsPasswordResetEmails;
public function __construct()
{
$this->middleware('guest');
}
protected function validateEmail(Request $request): void
{
if (! config('captcha.enabled')) {
$request->validate(['email' => 'required|email']);
} else {
$request->validate([
'email' => 'required|email',
'captcha' => 'hiddencaptcha',
]);
}
}
}
@@ -1,69 +0,0 @@
<?php
/**
* NOTICE OF LICENSE.
*
* UNIT3D Community Edition is open-sourced software licensed under the GNU Affero General Public License v3.0
* The details is bundled with this project in the file LICENSE.txt.
*
* @project UNIT3D Community Edition
*
* @author HDVinnie <hdinnovations@protonmail.com>
* @license https://www.gnu.org/licenses/agpl-3.0.en.html/ GNU Affero General Public License v3.0
*/
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use App\Models\User;
use App\Notifications\UsernameReminder;
use Illuminate\Http\Request;
/**
* @see \Tests\Feature\Http\Controllers\Auth\ForgotUsernameControllerTest
*/
class ForgotUsernameController extends Controller
{
/**
* Forgot Username Form.
*/
public function showForgotUsernameForm(): \Illuminate\Contracts\View\Factory|\Illuminate\View\View
{
return view('auth.username');
}
/**
* Send Username Reminder.
*/
public function sendUsernameReminder(Request $request): \Illuminate\Http\RedirectResponse
{
$email = $request->get('email');
if (! config('captcha.enabled')) {
$v = validator($request->all(), [
'email' => 'required',
]);
} else {
$v = validator($request->all(), [
'email' => 'required',
'captcha' => 'hiddencaptcha',
]);
}
if ($v->fails()) {
return to_route('username.request')
->withErrors($v->errors());
}
$user = User::where('email', '=', $email)->first();
if (empty($user)) {
return to_route('username.request')
->withErrors(trans('email.no-email-found'));
}
//send username reminder notification
$user->notify(new UsernameReminder());
return to_route('login')
->withSuccess(trans('email.username-sent'));
}
}
@@ -1,137 +0,0 @@
<?php
/**
* NOTICE OF LICENSE.
*
* UNIT3D Community Edition is open-sourced software licensed under the GNU Affero General Public License v3.0
* The details is bundled with this project in the file LICENSE.txt.
*
* @project UNIT3D Community Edition
*
* @author HDVinnie <hdinnovations@protonmail.com>
* @license https://www.gnu.org/licenses/agpl-3.0.en.html/ GNU Affero General Public License v3.0
*/
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use App\Models\Group;
use App\Services\Unit3dAnnounce;
use Illuminate\Foundation\Auth\AuthenticatesUsers;
use Illuminate\Http\Request;
class LoginController extends Controller
{
use AuthenticatesUsers;
// Upon Successful Login
protected string $redirectTo = '/';
// Max Attempts Until Lockout
public int $maxAttempts = 3;
// Minutes Lockout
public int $decayMinutes = 60;
/**
* LoginController Constructor.
*/
public function __construct()
{
$this->middleware('guest', ['except' => 'logout']);
}
public function username(): string
{
return 'username';
}
/**
* Validate The User Login Request.
*
*
* @throws \Illuminate\Validation\ValidationException
*/
protected function validateLogin(Request $request): void
{
if (config('captcha.enabled')) {
$this->validate($request, [
$this->username() => 'required|string',
'password' => 'required|string',
'captcha' => 'hiddencaptcha',
]);
} else {
$this->validate($request, [
$this->username() => 'required|string',
'password' => 'required|string',
]);
}
}
protected function authenticated(Request $request, $user): \Illuminate\Http\RedirectResponse
{
$bannedGroup = cache()->rememberForever('banned_group', fn () => Group::where('slug', '=', 'banned')->pluck('id'));
$validatingGroup = cache()->rememberForever('validating_group', fn () => Group::where('slug', '=', 'validating')->pluck('id'));
$disabledGroup = cache()->rememberForever('disabled_group', fn () => Group::where('slug', '=', 'disabled')->pluck('id'));
$memberGroup = cache()->rememberForever('member_group', fn () => Group::where('slug', '=', 'user')->pluck('id'));
if ($user->active == 0 || $user->group_id == $validatingGroup[0]) {
$this->guard()->logout();
$request->session()->invalidate();
return to_route('login')
->withErrors(trans('auth.not-activated'));
}
if ($user->group_id == $bannedGroup[0]) {
$this->guard()->logout();
$request->session()->invalidate();
return to_route('login')
->withErrors(trans('auth.banned'));
}
if ($user->group_id == $disabledGroup[0]) {
$user->group_id = $memberGroup[0];
$user->can_upload = 1;
$user->can_download = 1;
$user->can_comment = 1;
$user->can_invite = 1;
$user->can_request = 1;
$user->can_chat = 1;
$user->disabled_at = null;
$user->save();
cache()->forget('user:'.$user->passkey);
Unit3dAnnounce::addUser($user);
return to_route('home.index')
->withSuccess(trans('auth.welcome-restore'));
}
if (auth()->viaRemember() && $user->group_id == $disabledGroup[0]) {
$user->group_id = $memberGroup[0];
$user->can_upload = 1;
$user->can_download = 1;
$user->can_comment = 1;
$user->can_invite = 1;
$user->can_request = 1;
$user->can_chat = 1;
$user->disabled_at = null;
$user->save();
cache()->forget('user:'.$user->passkey);
Unit3dAnnounce::addUser($user);
return to_route('home.index')
->withSuccess(trans('auth.welcome-restore'));
}
if ($user->read_rules == 0) {
return redirect()->to(config('other.rules_url'))
->withWarning(trans('auth.require-rules'));
}
return redirect()->intended()
->withSuccess(trans('auth.welcome'));
}
}
@@ -1,184 +0,0 @@
<?php
/**
* NOTICE OF LICENSE.
*
* UNIT3D Community Edition is open-sourced software licensed under the GNU Affero General Public License v3.0
* The details is bundled with this project in the file LICENSE.txt.
*
* @project UNIT3D Community Edition
*
* @author HDVinnie <hdinnovations@protonmail.com>
* @license https://www.gnu.org/licenses/agpl-3.0.en.html/ GNU Affero General Public License v3.0
*/
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use App\Jobs\SendActivationMail;
use App\Models\Group;
use App\Models\Invite;
use App\Models\PrivateMessage;
use App\Models\User;
use App\Models\UserActivation;
use App\Models\UserNotification;
use App\Models\UserPrivacy;
use App\Repositories\ChatRepository;
use App\Rules\EmailBlacklist;
use Illuminate\Http\Request;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Str;
class RegisterController extends Controller
{
/**
* RegisterController Constructor.
*/
public function __construct(private readonly ChatRepository $chatRepository)
{
}
/**
* Registration Form.
*/
public function registrationForm($code = null): \Illuminate\Contracts\View\Factory|\Illuminate\View\View|\Illuminate\Http\RedirectResponse
{
// Make sure open reg is off, invite code is not present and application signups enabled
if ($code === 'null' && config('other.invite-only') == 1 && config('other.application_signups')) {
return to_route('application.create')
->withInfo(trans('auth.allow-invite-appl'));
}
// Make sure open reg is off and invite code is not present
if ($code === 'null' && config('other.invite-only') == 1) {
return to_route('login')
->withWarning(trans('auth.allow-invite'));
}
return view('auth.register', ['code' => $code]);
}
public function register(Request $request, $code = null): \Illuminate\Http\RedirectResponse
{
// Make sure open reg is off and invite code exist and has not been used already
$key = Invite::where('code', '=', $code)->first();
if (config('other.invite-only') == 1 && (! $key || $key->accepted_by !== null)) {
return to_route('registrationForm', ['code' => $code])
->withErrors(trans('auth.invalid-key'));
}
$validatingGroup = cache()->rememberForever('validating_group', fn () => Group::where('slug', '=', 'validating')->pluck('id'));
$user = new User();
$user->username = $request->input('username');
$user->email = $request->input('email');
$user->password = Hash::make($request->input('password'));
$user->passkey = md5(random_bytes(60).$user->password);
$user->rsskey = md5(random_bytes(60).$user->password);
$user->uploaded = config('other.default_upload');
$user->downloaded = config('other.default_download');
$user->style = config('other.default_style', 0);
$user->locale = config('app.locale');
$user->group_id = $validatingGroup[0];
if (config('email-blacklist.enabled')) {
if (! config('captcha.enabled')) {
$v = validator($request->all(), [
'username' => 'required|alpha_dash|string|between:3,25|unique:users',
'password' => 'required|string|between:8,16',
'email' => [
'required',
'string',
'email',
'max:70',
'unique:users',
new EmailBlacklist(),
],
]);
} else {
$v = validator($request->all(), [
'username' => 'required|alpha_dash|string|between:3,25|unique:users',
'password' => 'required|string|between:8,16',
'email' => [
'required',
'string',
'email',
'max:70',
'unique:users',
new EmailBlacklist(),
],
'captcha' => 'hiddencaptcha',
]);
}
} elseif (! config('captcha.enabled')) {
$v = validator($request->all(), [
'username' => 'required|alpha_dash|string|between:3,25|unique:users',
'password' => 'required|string|between:8,16',
'email' => 'required|string|email|max:70|unique:users',
]);
} else {
$v = validator($request->all(), [
'username' => 'required|alpha_dash|string|between:3,25|unique:users',
'password' => 'required|string|between:6,16',
'email' => 'required|string|email|max:70|unique:users',
'captcha' => 'hiddencaptcha',
]);
}
if ($v->fails()) {
return to_route('registrationForm', ['code' => $code])
->withErrors($v->errors());
}
$user->save();
$userPrivacy = new UserPrivacy();
$userPrivacy->setDefaultValues();
$userPrivacy->user_id = $user->id;
$userPrivacy->save();
$userNotification = new UserNotification();
$userNotification->setDefaultValues();
$userNotification->user_id = $user->id;
$userNotification->save();
if ($key) {
// Update The Invite Record
$key->accepted_by = $user->id;
$key->accepted_at = new Carbon();
$key->save();
}
// Handle The Activation System
$token = hash_hmac('sha256', $user->username.$user->email.Str::random(16), config('app.key'));
$userActivation = new UserActivation();
$userActivation->user_id = $user->id;
$userActivation->token = $token;
$userActivation->save();
dispatch(new SendActivationMail($user, $token));
// Select A Random Welcome Message
$profileUrl = href_profile($user);
$welcomeArray = [
sprintf('[url=%s]%s[/url], Welcome to ', $profileUrl, $user->username).config('other.title').'! Hope you enjoy the community :rocket:',
sprintf("[url=%s]%s[/url], We've been expecting you :space_invader:", $profileUrl, $user->username),
sprintf("[url=%s]%s[/url] has arrived. Party's over. :cry:", $profileUrl, $user->username),
sprintf("It's a bird! It's a plane! Nevermind, it's just [url=%s]%s[/url].", $profileUrl, $user->username),
sprintf('Ready player [url=%s]%s[/url].', $profileUrl, $user->username),
sprintf('A wild [url=%s]%s[/url] appeared.', $profileUrl, $user->username),
'Welcome to '.config('other.title').sprintf(' [url=%s]%s[/url]. We were expecting you ( ͡° ͜ʖ ͡°)', $profileUrl, $user->username),
];
$selected = random_int(0, \count($welcomeArray) - 1);
$this->chatRepository->systemMessage(
$welcomeArray[$selected]
);
// Send Welcome PM
$privateMessage = new PrivateMessage();
$privateMessage->sender_id = 1;
$privateMessage->receiver_id = $user->id;
$privateMessage->subject = config('welcomepm.subject');
$privateMessage->message = config('welcomepm.message');
$privateMessage->save();
return to_route('login')
->withSuccess(trans('auth.register-thanks'));
}
}
@@ -1,51 +0,0 @@
<?php
/**
* NOTICE OF LICENSE.
*
* UNIT3D Community Edition is open-sourced software licensed under the GNU Affero General Public License v3.0
* The details is bundled with this project in the file LICENSE.txt.
*
* @project UNIT3D Community Edition
*
* @author HDVinnie <hdinnovations@protonmail.com>
* @license https://www.gnu.org/licenses/agpl-3.0.en.html/ GNU Affero General Public License v3.0
*/
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use App\Models\Group;
use App\Models\UserActivation;
use Illuminate\Foundation\Auth\ResetsPasswords;
use Illuminate\Support\Str;
class ResetPasswordController extends Controller
{
use ResetsPasswords;
protected string $redirectTo = '/';
public function __construct()
{
$this->middleware('guest');
}
protected function resetPassword($user, $password): void
{
$validatingGroup = cache()->rememberForever('validating_group', fn () => Group::where('slug', '=', 'validating')->pluck('id'));
$memberGroup = cache()->rememberForever('member_group', fn () => Group::where('slug', '=', 'user')->pluck('id'));
$user->password = bcrypt($password);
$user->remember_token = Str::random(60);
if ($user->group_id === $validatingGroup[0]) {
$user->group_id = $memberGroup[0];
}
$user->active = true;
$user->save();
UserActivation::where('user_id', '=', $user->id)->delete();
$this->guard()->login($user);
}
}