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.

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