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.

249 lines
7.7 KiB

4 years ago
  1. <?php
  2. namespace App\Http\Controllers;
  3. use App\Models\Business;
  4. use App\Models\User;
  5. use App\Notifications\MailNotification;
  6. use Illuminate\Http\JsonResponse;
  7. use Illuminate\Http\Request;
  8. use Illuminate\Support\Facades\Auth;
  9. use Illuminate\Support\Facades\Cache;
  10. use Illuminate\Support\Facades\Hash;
  11. use Illuminate\Support\Facades\Notification;
  12. use Illuminate\Support\Str;
  13. use Illuminate\Validation\Rule;
  14. use Laravel\Socialite\Facades\Socialite;
  15. use Symfony\Component\HttpFoundation\Response;
  16. class AuthController extends Controller
  17. {
  18. public function redirectToGoogle()
  19. {
  20. return Socialite::driver('google')->stateless()->redirect();
  21. }
  22. public function handleGoogleCallback(Request $request)
  23. {
  24. try {
  25. $user = Socialite::driver('google')->stateless()->user();
  26. $find_user = User::where('email', $user->email)->first();
  27. if (!$find_user)
  28. {
  29. $find_user = User::create($user->user + [
  30. 'password' => Hash::make(Str::random(8)),
  31. 'username' => $user->email,
  32. 'active' => true,
  33. 'has_password' => false
  34. ]);
  35. }
  36. Auth::setUser($find_user);
  37. $finger_print = $this->createFingerPrint();
  38. return redirect('http://localhost:3000/login?token='.$finger_print->token);
  39. } catch (Exception $e) {
  40. dd($e->getMessage());
  41. }
  42. }
  43. public function emailChecking(Request $request)
  44. {
  45. $this->validate($request, [
  46. 'email' => 'required|email',
  47. ]);
  48. $user = User::where('email', $request->email)->first();
  49. if ($user && $user->has_password) {
  50. // email exists in db
  51. // user before set a password
  52. return response()->json(['message' => 'User exists must be login'], 200);
  53. }
  54. if ($user && !$user->has_password) {
  55. // email exists in db
  56. // user hasn't password (we set password for user)
  57. $this->sendVerification($request->email, 'google');
  58. return response()->json(['message' => 'Send email for validation'], 200);
  59. }
  60. if (Cache::has($request->email)) {
  61. // email exists in cache
  62. $this->sendVerification($request->email, Cache::get($request->email)['type']);
  63. return response()->json(['message' => 'Send email for validation'], 200);
  64. }
  65. if (!$user && !Cache::has($request->email)) {
  66. // user not exists in db and cache
  67. $this->sendVerification($request->email, 'register');
  68. return response()->json(['message' => 'Send email for validation'], 200);
  69. }
  70. }
  71. public function login(Request $request)
  72. {
  73. // todo: Logging in from a new device will result in sending a notification
  74. $this->validate($request, [
  75. 'email' => 'required|email|exists:users,email',
  76. 'password' => 'required|string|min:6'
  77. ]);
  78. $user = User::where('email', $request->email)->first();
  79. if ($user && Hash::check($request->password, $user->password)) {
  80. Auth::setUser($user);
  81. return [
  82. 'auth' => $this->createFingerPrint(),
  83. 'businesses' => Auth::user()->businesses->keyBy('id')->map(fn($b, $bid) => Business::info($bid))
  84. ];
  85. }
  86. return new JsonResponse([
  87. 'message' => trans('auth.failed'),
  88. 'status' => Response::HTTP_NOT_FOUND,
  89. ], Response::HTTP_NOT_FOUND);
  90. }
  91. public function verification(Request $request)
  92. {
  93. $this->validate($request, [
  94. 'email' => 'required|email',
  95. 'signature' => 'required|string',
  96. ]);
  97. $this->checkValidation($request->email, 'google', $request->signature);
  98. Auth::setUser(User::where('email', $request->email)->first());
  99. return [
  100. 'auth' => $this->createFingerPrint(),
  101. 'businesses' => Auth::user()->businesses->keyBy('id')->map(fn($b, $bid) => Business::info($bid))
  102. ];
  103. }
  104. public function sendVerification($email, $type)
  105. {
  106. $signature = Str::random(30);
  107. Cache::put($email, ['type' => $type, 'signature' => $signature], 3600);
  108. Notification::route('mail', $email)->notify( new MailNotification([
  109. 'greeting' => __('notification.auth.verification.greeting'),
  110. 'subject' => __('notification.auth.verification.subject'),
  111. 'body' => __('notification.auth.verification.new_body'),
  112. 'link' => __('notification.auth.verification.link', [
  113. 'email' => $email,
  114. 'type' => $type,
  115. 'signature' => $signature
  116. ])
  117. ]));
  118. // return $verification_code;
  119. }
  120. public function checkValidation($email, $type, $signature)
  121. {
  122. if (!Cache::has($email) || Cache::get($email)['type'] !== $type || Cache::get($email)['signature'] != $signature)
  123. {
  124. abort(403, 'Validation failed');
  125. }
  126. Cache::forget($email);
  127. }
  128. public function forgetPassword(Request $request)
  129. {
  130. $this->validate($request, [
  131. 'email' => 'required|email|exists:users,email'
  132. ]);
  133. $this->sendVerification($request->email, 'forget');
  134. return response()->json(['message' => 'Send email for validation'], 200);
  135. }
  136. public function updatePassword(Request $request)
  137. {
  138. $this->validate($request, [
  139. 'email' => 'required|email',
  140. 'password' => 'required|string|min:8|confirmed',
  141. 'signature' => 'required|string'
  142. ]);
  143. $this->checkValidation($request->email, 'forget', $request->signature);
  144. $user = User::where('email', $request->email)->first();
  145. $user->update([
  146. 'password' => Hash::make($request->password),
  147. 'has_password' => true
  148. ]);
  149. Auth::setUser($user);
  150. $this->createFingerPrint();
  151. return response()->json(['message' => 'Update successfully you must be login.'], 200);
  152. }
  153. public function register(Request $request)
  154. {
  155. $this->validate($request, [
  156. 'name' => 'required|string|max:225|min:2',
  157. 'username' => ['required', Rule::unique('users', 'username')],
  158. 'email' => ['required', 'email', Rule::unique('users', 'email')],
  159. 'password' => 'required|string|min:6',
  160. 'signature' => 'required|string'
  161. ]);
  162. $this->checkValidation($request->email, 'register', $request->signature);
  163. $request->merge(['password' => Hash::make($request->password)]);
  164. $user = User::create($request->all()+ [
  165. 'has_password' => true
  166. ]);
  167. Auth::setUser($user);
  168. $this->createFingerPrint();
  169. return response()->json(['message' => 'Register successfully you must be login.'], 200);
  170. }
  171. public function resendLink(Request $request)
  172. {
  173. $this->validate($request, [
  174. 'email' => 'required|email',
  175. 'type' => 'required|string'
  176. ]);
  177. $this->sendVerification($request->email, $request->type);
  178. return response()->json(['message' => 'Link resend successfully'], 200);
  179. }
  180. public function createFingerPrint()
  181. {
  182. $attributes = [
  183. 'agent' => request()->getAgent(),
  184. 'ip' => request()->getClientIp(),
  185. 'os' => request()->getOS(),
  186. 'latitude' => \request()->getLocation()->getAttribute('lat'),
  187. 'longitude' => \request()->getLocation()->getAttribute('lon'),
  188. ];
  189. $values = [
  190. 'token' => Str::random(60)
  191. ];
  192. return Auth::user()->fingerprints()->firstOrCreate($attributes, $attributes + $values);
  193. }
  194. }