sessions = $sessions; $this->settings = $settings; } /** * POST /api/softphone/session - establishes the browser session. */ public function createSession(Request $request) { $user = $request->user(); $companyId = $user ? (int) $user->company_id : null; if (!$this->settings->isEnabled($companyId)) { return $this->error('integration_disabled', 'Softphone integration is disabled.', 503); } if (!$user || !$user->is_active) { return $this->error('user_inactive', 'This user is not active.', 403); } if (!$this->originIsAuthorized($request, $companyId)) { return $this->originError($request, $companyId); } // The browser that made this call now owns the session. $this->sessions->establish($request, $user); Log::info('softphone_integration: browser session established', [ 'user_id' => $user->id, 'company_id' => $companyId, ]); return response()->json([ 'success' => true, // Same fixed URL for every user. 'iframe_url' => route('softphone.integration'), ], 201); } /** * POST /api/softphone/session/revoke - ends the authenticated user's sessions. */ public function revokeSession(Request $request) { $user = $request->user(); $companyId = $user ? (int) $user->company_id : null; if (!$this->settings->isEnabled($companyId)) { return $this->error('integration_disabled', 'Softphone integration is disabled.', 503); } if (!$this->originIsAuthorized($request, $companyId)) { return $this->originError($request, $companyId); } $revoked = $this->sessions->terminateForUser((int) $user->id); return response()->json([ 'success' => true, 'revoked' => $revoked, ]); } /** * CORS preflight; the SoftphoneIntegrationCors middleware answers it. */ public function preflight() { return response()->noContent(); } /** * Requests without an Origin header are not cross-origin (server-to-server * or same-origin calls) and are not subject to the allow-list. */ protected function originIsAuthorized(Request $request, ?int $companyId): bool { $origin = $request->headers->get('Origin'); if ($origin === null || trim($origin) === '') { return true; } return $this->settings->isOriginAllowed($companyId, $origin); } protected function originError(Request $request, ?int $companyId) { Log::warning('softphone_integration: origin rejected', [ 'origin' => $request->headers->get('Origin'), 'company_id' => $companyId, ]); return $this->error( 'origin_not_allowed', 'This origin is not authorized to use the Softphone integration.', 403 ); } protected function error(string $code, string $message, int $status) { return response()->json([ 'success' => false, 'error' => [ 'code' => $code, 'message' => $message, ], ], $status); } }