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
8.1 KiB

  1. <?php
  2. namespace App\Http\Controllers;
  3. use App\Models\User;
  4. use App\Models\Business;
  5. use App\Models\Fingerprint;
  6. use Illuminate\Support\Str;
  7. use Illuminate\Http\Request;
  8. use Illuminate\Validation\Rule;
  9. use Illuminate\Http\JsonResponse;
  10. use App\Http\Resources\UserResource;
  11. use Illuminate\Support\Facades\Auth;
  12. use Illuminate\Support\Facades\Hash;
  13. use Illuminate\Support\Facades\Cache;
  14. use Laravel\Socialite\Facades\Socialite;
  15. use Illuminate\Session\TokenMismatchException;
  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. $find_user->update([
  30. 'active' => true
  31. ]);
  32. Auth::setUser($find_user);
  33. } else {
  34. $user = User::create($user->user + [
  35. 'password' => Hash::make('google-login-user'),
  36. 'username' => $user->email,
  37. 'active' => true
  38. ]);
  39. Auth::setUser($user);
  40. }
  41. $finger_print = $this->createFingerPrint();
  42. return redirect('http://localhost:3000/login?token='.$finger_print->token);
  43. } catch (Exception $e) {
  44. dd($e->getMessage());
  45. }
  46. }
  47. public function login(Request $request)
  48. {
  49. // todo: Logging in from a new device will result in sending a notification
  50. $this->validate($request, [
  51. 'email' => 'required|email|exists:users,email',
  52. 'password' => 'required|string|min:6'
  53. ]);
  54. $user = User::where('email', $request->email)->first();
  55. if ($user && Hash::check($request->password, $user->password)) {
  56. Auth::setUser($user);
  57. return [
  58. 'auth' => $this->createFingerPrint(),
  59. 'businesses' => Auth::user()->businesses->keyBy('id')->map(fn($b, $bid) => Business::info($bid))
  60. ];
  61. }
  62. return new JsonResponse([
  63. 'message' => trans('auth.failed'),
  64. 'status' => Response::HTTP_NOT_FOUND,
  65. ], Response::HTTP_NOT_FOUND);
  66. }
  67. public function register(Request $request)
  68. {
  69. $this->validate($request, [
  70. 'name' => 'required|string|max:225|min:2',
  71. 'username' => ['required', Rule::unique('users', 'username')],
  72. 'email' => ['required', 'email', Rule::unique('users', 'email')],
  73. 'password' => 'required|string|min:8'
  74. ]);
  75. $request->merge(['password' => Hash::make($request->password)]);
  76. $code_data = ['verification_code' => $this->sendVerificationCode()];
  77. $method_data = ['method' => 'registerMain'];
  78. Cache::put($request->email, $request->all() + $code_data + $method_data, 3600); // remain one hour
  79. return \response()->json([
  80. 'message' => 'Code send for user and user must be verified.'],
  81. Response::HTTP_OK);
  82. }
  83. public function registerMain($user_info)
  84. {
  85. $user = User::create($user_info);
  86. Auth::setUser($user);
  87. return $this->createFingerPrint();
  88. }
  89. public function sendVerificationCode($contact_way = null)
  90. {
  91. $verification_code = 1234; // rand(10001, 99999)
  92. //send code for user with contact way
  93. return $verification_code;
  94. }
  95. public function verification(Request $request)
  96. {
  97. if (!Cache::has($request->email)) {
  98. return \response()->json(['message' => 'Code expired.'], Response::HTTP_BAD_REQUEST);
  99. }
  100. $user_info = Cache::get($request->email);
  101. $this->validate($request, [
  102. 'email' => 'required|email',
  103. 'verification_code' => 'required|string|min:4|max:4|in:'.$user_info['verification_code']
  104. ]);
  105. Cache::forget($request->email);
  106. return isset($user_info['method']) ?
  107. call_user_func('self::'.$user_info['method'], $user_info) :
  108. \response()->json(['message' => 'Code verified successfully.'], Response::HTTP_OK,);
  109. }
  110. public function forgetPassword(Request $request)
  111. {
  112. $this->validate($request, [
  113. 'email' => 'required|email|exists:users,email'
  114. ]);
  115. $code_data = ['verification_code' => $this->sendVerificationCode()];
  116. Cache::put($request->email, $request->all() + $code_data, 3600); // remain one hour
  117. return \response()->json([
  118. 'message' => 'Code send for user and user must be verified.'],
  119. Response::HTTP_OK);
  120. }
  121. public function updatePassword(Request $request)
  122. {
  123. if (!Cache::has($request->email)) {
  124. return \response()->json(['message' => 'Code expired.'], Response::HTTP_BAD_REQUEST);
  125. }
  126. $this->validate($request, [
  127. 'email' => 'required|email',
  128. 'password' => 'required|string|min:8|confirmed',
  129. 'verification_code' => 'required|string|min:4|max:4|in:'.Cache::get($request->email)['verification_code']
  130. ]);
  131. $user = User::where('email', $request->email)->first();
  132. $user->update([
  133. 'password' => Hash::make($request->password)
  134. ]);
  135. Auth::setUser($user);
  136. return $this->createFingerPrint();
  137. }
  138. /**
  139. * @param Request $request
  140. * @return mixed
  141. * @throws TokenMismatchException
  142. */
  143. public function logout(Request $request)
  144. {
  145. $token = $request->bearerToken();
  146. if (blank($token)) {
  147. return new JsonResponse([
  148. 'message' => 'Not authorized request.',
  149. 'status' => Response::HTTP_UNAUTHORIZED
  150. ]);
  151. }
  152. /** @var Fingerprint $token */
  153. $token = Auth::user()->fingerprints()->firstWhere([
  154. 'token' => $token,
  155. ]);
  156. if ($token) {
  157. return $token->delete();
  158. }
  159. throw new TokenMismatchException('Invalid token!');
  160. }
  161. /**
  162. * @param string $token
  163. * @throws TokenMismatchException
  164. */
  165. public function revoke(string $token)
  166. {
  167. /** @var Fingerprint $token */
  168. $token = Fingerprint::firstWhere([
  169. 'token' => $token,
  170. ]);
  171. if ($token) {
  172. return $token->delete();
  173. }
  174. throw new TokenMismatchException();
  175. }
  176. public function auth()
  177. {
  178. return new UserResource(Auth::user());
  179. }
  180. public function authWithInfo()
  181. {
  182. return [
  183. 'auth' => new UserResource(Auth::user()),
  184. 'businesses' => Auth::user()->businesses->keyBy('id') ->map(fn($b, $bid) => Business::info($bid))
  185. ];
  186. }
  187. public function delete(Request $request)
  188. {
  189. Auth::user()->fingerprints()->delete();
  190. unset(Auth::user()->token);
  191. Auth::user()->delete();
  192. return 'success';
  193. }
  194. public function updateFcmToken(Request $request)
  195. {
  196. Auth::user()->fingerprints()->where(
  197. [
  198. ['agent', request()->getAgent()],
  199. ['ip', request()->getClientIp()],
  200. ['os', request()->getOS()],
  201. ['latitude', \request()->getLocation()->getAttribute('lat')],
  202. ['longitude', \request()->getLocation()->getAttribute('lon')],
  203. ]
  204. )->firstOrFail()->update([
  205. 'fcm_token' => $request->fcm_token
  206. ]);
  207. return $this->authWithInfo();
  208. }
  209. public function createFingerPrint()
  210. {
  211. $attributes = [
  212. 'agent' => request()->getAgent(),
  213. 'ip' => request()->getClientIp(),
  214. 'os' => request()->getOS(),
  215. 'latitude' => \request()->getLocation()->getAttribute('lat'),
  216. 'longitude' => \request()->getLocation()->getAttribute('lon'),
  217. ];
  218. $values = [
  219. 'token' => Str::random(60)
  220. ];
  221. return Auth::user()->fingerprints()->firstOrCreate($attributes, $attributes + $values);
  222. }
  223. }