You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

284 lines
9.0 KiB

<?php
namespace App\Http\Controllers;
use App\Models\Business;
use App\Models\User;
use App\Notifications\DBNotification;
use App\Notifications\MailNotification;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Notification;
use Illuminate\Support\Str;
use Illuminate\Validation\Rule;
use Laravel\Socialite\Facades\Socialite;
use Symfony\Component\HttpFoundation\Response;
class AuthController extends Controller
{
public function redirectToGoogle()
{
return Socialite::driver('google')->stateless()->redirect();
}
public function handleGoogleCallback(Request $request)
{
try {
$user = Socialite::driver('google')->stateless()->user();
$find_user = User::where('email', $user->email)->first();
if (!$find_user)
{
$find_user = User::create($user->user + [
'password' => Hash::make(Str::random(8)),
'username' => $user->email,
'active' => true,
'has_password' => false
]);
}
Auth::setUser($find_user);
$finger_print = $this->createFingerPrint();
return redirect('http://localhost:3000/login?token='.$finger_print->token);
} catch (Exception $e) {
dd($e->getMessage());
}
}
public function emailChecking(Request $request)
{
$this->validate($request, [
'email' => 'required|email',
]);
$user = User::where('email', $request->email)->first();
if ($user && $user->has_password) {
// email exists in db
// user before set a password
return response()->json(['message' => 'User exists must be login'], 200);
}
if ($user && !$user->has_password) {
// email exists in db
// user hasn't password (we set password for user)
$this->sendVerification($request->email, 'google');
return response()->json(['message' => 'Send email for validation'], 200);
}
if (Cache::has($request->email)) {
// email exists in cache
$this->sendVerification($request->email, Cache::get($request->email)['type']);
return response()->json(['message' => 'Send email for validation'], 200);
}
if (!$user && !Cache::has($request->email)) {
// user not exists in db and cache
$this->sendVerification($request->email, 'register');
return response()->json(['message' => 'Send email for validation'], 200);
}
}
public function login(Request $request)
{
// todo: Logging in from a new device will result in sending a notification
$this->validate($request, [
'email' => 'required|email|exists:users,email',
'password' => 'required|string|min:6'
]);
$user = User::where('email', $request->email)->first();
if ($user && Hash::check($request->password, $user->password)) {
Auth::setUser($user);
// for new device login
$this->loginNotif($this->firstOrNot());
return [
'auth' => $this->createFingerPrint(),
'businesses' => Auth::user()->businesses->keyBy('id')->map(fn($b, $bid) => Business::info($bid))
];
}
return new JsonResponse([
'message' => trans('auth.failed'),
'status' => Response::HTTP_NOT_FOUND,
], Response::HTTP_NOT_FOUND);
}
public function verification(Request $request)
{
$this->validate($request, [
'email' => 'required|email',
'signature' => 'required|string',
]);
$this->checkValidation($request->email, 'google', $request->signature);
Auth::setUser(User::where('email', $request->email)->first());
return [
'auth' => $this->createFingerPrint(),
'businesses' => Auth::user()->businesses->keyBy('id')->map(fn($b, $bid) => Business::info($bid))
];
}
public function sendVerification($email, $type)
{
$signature = Str::random(30);
Cache::put($email, ['type' => $type, 'signature' => $signature], 3600);
Notification::route('mail', $email)->notify( new MailNotification([
'greeting' => __('notification.auth.verification.greeting'),
'subject' => __('notification.auth.verification.subject'),
'body' => __('notification.auth.verification.new_body'),
'link' => __('notification.auth.verification.link', [
'email' => $email,
'type' => $type,
'signature' => $signature
])
]));
// return $verification_code;
}
public function checkValidation($email, $type, $signature)
{
if (!Cache::has($email) || Cache::get($email)['type'] !== $type || Cache::get($email)['signature'] != $signature)
{
abort(403, 'Validation failed');
}
Cache::forget($email);
}
public function forgetPassword(Request $request)
{
$this->validate($request, [
'email' => 'required|email|exists:users,email'
]);
$this->sendVerification($request->email, 'forget');
return response()->json(['message' => 'Send email for validation'], 200);
}
public function updatePassword(Request $request)
{
$this->validate($request, [
'email' => 'required|email',
'password' => 'required|string|min:8|confirmed',
'signature' => 'required|string'
]);
$this->checkValidation($request->email, 'forget', $request->signature);
$user = User::where('email', $request->email)->first();
$user->update([
'password' => Hash::make($request->password),
'has_password' => true
]);
Auth::setUser($user);
$this->createFingerPrint();
return response()->json(['message' => 'Update successfully you must be login.'], 200);
}
public function register(Request $request)
{
$this->validate($request, [
'name' => 'required|string|max:225|min:2',
'username' => ['required', Rule::unique('users', 'username')],
'email' => ['required', 'email', Rule::unique('users', 'email')],
'password' => 'required|string|min:6',
'signature' => 'required|string'
]);
$this->checkValidation($request->email, 'register', $request->signature);
$request->merge(['password' => Hash::make($request->password)]);
$user = User::create($request->all()+ [
'has_password' => true
]);
Auth::setUser($user);
$this->createFingerPrint();
return response()->json(['message' => 'Register successfully you must be login.'], 200);
}
public function resendLink(Request $request)
{
$this->validate($request, [
'email' => 'required|email',
'type' => 'required|string'
]);
$user_db = User::where('email', $request->email)->first();
$user_cache = Cache::get($request->email);
if ($user_db || $user_cache) {
$this->sendVerification($request->email, $request->type);
return response()->json(['message' => 'Link resend successfully'], 200);
}
abort(403);
}
public function createFingerPrint()
{
$attributes = [
'agent' => request()->getAgent(),
'ip' => request()->getClientIp(),
'os' => request()->getOS(),
'latitude' => \request()->getLocation()->getAttribute('lat'),
'longitude' => \request()->getLocation()->getAttribute('lon'),
];
$values = [
'token' => Str::random(60)
];
return Auth::user()->fingerprints()->firstOrCreate($attributes, $attributes + $values);
}
public function firstOrNot()
{
return Auth::user()->fingerprints()->where([
['agent', '!=',request()->getAgent()],
['ip', '!=',request()->getClientIp()],
['os', '!=',request()->getOS()],
['latitude', '!=',\request()->getLocation()->getAttribute('lat')],
['longitude', '!=',\request()->getLocation()->getAttribute('lon')],
])->exists();
}
public function loginNotif($send)
{
if ($send) {
Notification::send(Auth::user(), new MailNotification([
'greeting' => 'hi',
'subject' => 'login with another device',
'body' => 'Warning someone login to your account with new device. check it and dont worry',
]));
Notification::send(Auth::user(), new DBNotification([
'body' => 'Warning someone login to your account with new device. check it and dont worry',
]));
}
}
}