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

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