only(['email', 'password', 'recaptcha']); $this->recaptcha->check($credentials); if (!auth()->attempt([ 'email' => $credentials['email'], 'password' => $credentials['password'], ])) { $this->recaptcha->incrementCaptchaAmounts(); $this->recaptcha->check($credentials); throw new AuthorizationException(AuthorizationException::ERROR_TYPE_UNAUTHORIZED); } $user = auth()->user(); if (!$user || !$user->active) { $this->recaptcha->incrementCaptchaAmounts(); throw new AuthorizationException(AuthorizationException::ERROR_TYPE_USER_DISABLED); } if ($user->invitation_sent) { $user->invitation_sent = false; $user->save(); } $this->recaptcha->clearCaptchaAmounts(); if (preg_match('/' . config('auth.cattr-client-agent') . '/', $request->header('User_agent'))) { $user->client_installed = 1; $user->save(); } return responder()->success([ 'token' => $user->createToken(Str::uuid())->plainTextToken, ], new AuthTokenTransformer)->respond(); } /** * @api {post} /auth/logout Logout * @apiDescription Invalidate current token * * @apiVersion 4.0.0 * @apiName Logout * @apiGroup Auth * * @apiUse AuthHeader * * @apiSuccessExample {json} Response Example * HTTP/1.1 204 OK * * @apiUse 400Error * @apiUse UnauthorizedError */ public function logout(Request $request): JsonResponse { $request->user()->currentAccessToken()->delete(); return responder()->success()->respond(204); } /** * @api {post} /auth/logout-from-all Logout from all * @apiDescription Invalidate all user tokens * * @apiVersion 4.0.0 * @apiName Logout all * @apiGroup Auth * * @apiUse AuthHeader * * @apiSuccessExample {json} Response Example * HTTP/1.1 204 OK * * @apiUse 400Error * @apiUse UnauthorizedError */ public function logoutFromAll(Request $request): JsonResponse { $request->user()->tokens()->delete(); return responder()->success()->respond(204); } /** * @api {get} /auth/me Me * @apiDescription Get authenticated User Entity * * @apiVersion 4.0.0 * @apiName Me * @apiGroup Auth * * @apiUse AuthHeader * * @apiSuccess {Integer} id ID of the user * @apiSuccess {String} full_name Full name of the user * @apiSuccess {String} email Email of the user * @apiSuccess {String} [url] URL of the user (optional) * @apiSuccess {Integer} company_id Company ID of the user * @apiSuccess {String} [avatar] Avatar URL of the user (optional) * @apiSuccess {Boolean} screenshots_active Indicates if screenshots are active * @apiSuccess {Boolean} manual_time Indicates if manual time tracking is allowed * @apiSuccess {Integer} computer_time_popup Time interval for computer time popup * @apiSuccess {Boolean} blur_screenshots Indicates if screenshots are blurred * @apiSuccess {Boolean} web_and_app_monitoring Indicates if web and app monitoring is enabled * @apiSuccess {Integer} screenshots_interval Interval for taking screenshots * @apiSuccess {Boolean} active Indicates if the user is active * @apiSuccess {String} [deleted_at] Deletion timestamp (if applicable, otherwise null) * @apiSuccess {String} created_at Creation timestamp * @apiSuccess {String} updated_at Last update timestamp * @apiSuccess {String} [timezone] Timezone of the user (optional) * @apiSuccess {Boolean} important Indicates if the user is marked as important * @apiSuccess {Boolean} change_password Indicates if the user needs to change password * @apiSuccess {Integer} role_id Role ID of the user * @apiSuccess {String} user_language Language of the user * @apiSuccess {String} type Type of the user (e.g., "employee") * @apiSuccess {Boolean} invitation_sent Indicates if invitation is sent to the user * @apiSuccess {Integer} nonce Nonce value of the user * @apiSuccess {Boolean} client_installed Indicates if client is installed * @apiSuccess {Boolean} permanent_screenshots Indicates if screenshots are permanent * @apiSuccess {String} last_activity Last activity timestamp of the user * @apiSuccess {Boolean} online Indicates if the user is online * @apiSuccess {Boolean} can_view_team_tab Indicates if the user can view team tab * @apiSuccess {Boolean} can_create_task Indicates if the user can create tasks * * @apiSuccessExample {json} Response Example: * HTTP/1.1 200 OK * { * "id": 1, * "full_name": "Admin", * "email": "admin@cattr.app", * "url": "", * "company_id": 1, * "avatar": "", * "screenshots_active": 1, * "manual_time": 0, * "computer_time_popup": 300, * "blur_screenshots": false, * "web_and_app_monitoring": true, * "screenshots_interval": 5, * "active": 1, * "deleted_at": null, * "created_at": "2023-10-26T10:26:17.000000Z", * "updated_at": "2024-02-15T19:06:42.000000Z", * "timezone": null, * "important": 0, * "change_password": 0, * "role_id": 0, * "user_language": "en", * "type": "employee", * "invitation_sent": false, * "nonce": 0, * "client_installed": 0, * "permanent_screenshots": 0, * "last_activity": "2023-10-26 10:26:17", * "online": false, * "can_view_team_tab": true, * "can_create_task": true * } * * @apiUse 400Error * @apiUse UnauthorizedError */ public function me(Request $request): JsonResponse { return responder()->success($request->user())->respond(); } /** * @api {get} /auth/desktop-key Issue key * @apiDescription Issues key for desktop auth * * @apiVersion 4.0.0 * @apiName Issue key * @apiGroup Auth * * @apiUse AuthHeader * @apiUse User * @apiUse UnauthorizedError */ /** * @param Request $request * * @return JsonResponse * @throws Exception */ public function issueDesktopKey(Request $request): JsonResponse { $token = Str::random(40); $lifetime = now()->addMinutes(config('auth.lifetime_minutes.desktop_token')); Cache::store('octane')->put( sha1($request->ip()) . ":$token", $request->user()->id, $lifetime, ); return responder()->success([ 'token' => $token, 'type' => 'desktop', 'expires' => now()->addMinutes(config('auth.lifetime_minutes.desktop_token'))->toIso8601String(), ], new AuthTokenTransformer)->meta(['frontend_uri' => config('app.frontend_url')])->respond(); } /** * @api {put} /auth/desktop-key Key auth * @apiDescription Exchange desktop key to JWT * * @apiVersion 4.0.0 * @apiName Key auth * @apiGroup Auth * * @apiUse AuthHeader * @apiUse User * * @apiUse 400Error * @apiUse UnauthorizedError */ /** * @param Request $request * * @return JsonResponse * @throws Exception */ public function authDesktopKey(Request $request): JsonResponse { $token = $request->header('Authorization'); if (!$token) { throw new AuthorizationException(AuthorizationException::ERROR_TYPE_UNAUTHORIZED); } $token = explode(' ', $token); if (count($token) !== 2 || $token[0] !== 'desktop' || !Cache::store('octane')->has(sha1($request->ip()) . ":$token[1]")) { throw new AuthorizationException(AuthorizationException::ERROR_TYPE_UNAUTHORIZED); } $user = auth()->loginUsingId(Cache::store('octane')->get(sha1($request->ip()) . ":$token[1]")); if (!optional($user)->active) { throw new AuthorizationException(AuthorizationException::ERROR_TYPE_USER_DISABLED); } return responder()->success([ 'token' => $user->createToken(Str::uuid())->plainTextToken, ], new AuthTokenTransformer)->respond(); } /** * @apiDeprecated Exists only for compatibility with old Cattr client * @api {post} /auth/refresh Refresh * @apiDescription Refreshes JWT * * @apiVersion 4.0.0 * @apiName Refresh * @apiGroup Auth * * @apiUse AuthHeader * * @apiSuccess {String} access_token Token * @apiSuccess {String} token_type Token Type * @apiSuccess {String} expires_in Token TTL 8601String Date * * @apiUse 400Error * @apiUse UnauthorizedError */ /** * @return JsonResponse * @deprecated Exists only for compatibility with old Cattr client */ public function refresh(): JsonResponse { throw new DeprecatedApiException(); } }