isManaged() || $this->settings->get(Setting::VirusScanningEnabled) === true; } /** * An address to use instead of the stored one, for this request only. * * The Test button exists to answer "is *this* address right?", and * the address in question is the one being typed — testing what is * saved would make the button useless exactly when it is needed, on * the first attempt, before anything is saved. Set by * VirusScanningSettingsController::test() and never persisted. */ private ?string $preview = null; public function preview(string $address): void { $this->preview = trim($address); } public function isManaged(): bool { return $this->managedAddress() !== ''; } public function address(): string { // Ahead of the managed address too: an operator on a managed // installation has no field to type in, so nothing sets this // there — and where something does, it was asked for. if ($this->preview !== null && $this->preview !== '') { return $this->preview; } if ($this->isManaged()) { return $this->managedAddress(); } $stored = $this->settings->get(Setting::VirusScannerAddress); return is_string($stored) ? trim($stored) : ''; } /** * The largest file this installation sends to the scanner, in bytes. * Zero means no limit of our own — clamd's StreamMaxLength still * applies, and answers with tooLarge when it is reached. */ public function maxScanBytes(): int { return max(0, (int) $this->settings->get(Setting::VirusScanMaxSizeMb)) * 1024 * 1024; } /** What happens to a file the scanner could not open. */ public function blocksUnscannable(): bool { return $this->settings->get(Setting::VirusUnscannablePolicy) === 'block'; } /** Whether uploads wait for a scanner that is not answering. */ public function holdsWhileUnavailable(): bool { return $this->settings->get(Setting::VirusScannerDownPolicy) === 'hold'; } /** How long a file waits for an unreachable scanner before the policy applies. */ public function unavailableWaitMinutes(): int { return max(1, (int) $this->settings->get(Setting::VirusScannerWaitMinutes)); } /** How many already-stored files an hour-long backfill may scan per minute. */ public function existingScanRatePerMinute(): int { return max(1, (int) $this->settings->get(Setting::VirusScanExistingRatePerMinute)); } public function connectTimeoutSeconds(): int { return max(1, (int) config('projectsend.scanning.connect_timeout', 5)); } public function replyTimeoutSeconds(): int { return max(1, (int) config('projectsend.scanning.reply_timeout', 600)); } private function managedAddress(): string { $address = config('projectsend.scanning.address', ''); return is_string($address) ? trim($address) : ''; } }