Integrations and are * resolved from the company's settings context (never from environment * variables), so each company has its own switch and allow-list. */ class SoftphoneIntegrationSettings { /** * Whether the integration is enabled for the given company. * * Disabled by default: an explicit opt-in is required. */ public function isEnabled(?int $companyId): bool { if (!$companyId) { return false; } $value = CompanySettings::get( SettingsHelper::S_COMPANY_SOFTPHONE_INTEGRATION_ENABLED, null, $companyId ); return in_array(strtolower(trim((string) $value)), ['1', 'true', 'on', 'yes'], true); } /** * Origins (scheme://host[:port]) authorized to call the integration API * and embed the integration page. * * @return string[] */ public function origins(?int $companyId): array { if (!$companyId) { return []; } return SettingsHelper::splitSoftphoneIntegrationOrigins( CompanySettings::get( SettingsHelper::S_COMPANY_SOFTPHONE_INTEGRATION_ORIGINS, '', $companyId ) ); } /** * Whether the given request Origin is authorized for the company. */ public function isOriginAllowed(?int $companyId, ?string $origin): bool { $origin = SettingsHelper::normalizeSoftphoneIntegrationOrigin($origin); if ($origin === null) { return false; } foreach ($this->origins($companyId) as $allowed) { if (hash_equals($allowed, $origin)) { return true; } } return false; } /** * CSP frame-ancestors value: the platform itself plus every authorized * company origin. */ public function frameAncestors(?int $companyId): string { return implode(' ', array_merge(["'self'"], $this->origins($companyId))); } }