initializeApi($request); if ($responseInit !== null) { return $responseInit; } $secret = trim((string) $request->get('secret', '')); $timestampRaw = $request->get('timestamp', ''); $deviceId = trim((string) $request->get('device_id', '')); $signature = trim((string) $request->get('signature', '')); if ($secret === '' || $timestampRaw === '' || $deviceId === '' || $signature === '') { return $this->mobileResult(1001, 'Missing parameters'); } $serverSecret = (string) env('AUTH_TOKEN_SECRET', ''); if ($serverSecret === '' || !hash_equals($serverSecret, $secret)) { return $this->mobileResult(1103, 'Invalid secret'); } $timestamp = filter_var($timestampRaw, FILTER_VALIDATE_INT); if ($timestamp === false) { return $this->mobileResult(1002, 'Invalid parameter format'); } $now = time(); $skew = abs($now - $timestamp); if ($skew > 300) { return $this->mobileResult(3001, 'Invalid timestamp'); } $params = [ 'device_id' => $deviceId, 'secret' => $secret, 'timestamp' => (string) $timestamp, ]; ksort($params); $pairs = []; foreach ($params as $k => $v) { $pairs[] = $k . '=' . $v; } $plain = implode('&', $pairs); $expected = strtoupper(md5($plain)); if (!hash_equals($expected, $signature)) { return $this->mobileResult(1103, 'Invalid signature'); } $token = Random::uuid(); $expire = 60 * 60 * 24; Token::set($token, 'auth-token', 0, $expire); return $this->mobileResult(1, 'ok', [ 'auth_token' => $token, 'expires_in' => $expire, 'server_time' => $now, ]); } private function mobileResult(int $code, string $message, array $data = []): Response { $payload = [ 'code' => $code, 'message' => __($message), 'data' => $data, ]; return response(json_encode($payload, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), 200, ['Content-Type' => 'application/json']); } }