mirror of
https://github.com/projectsend/projectsend.git
synced 2026-09-17 17:15:08 +00:00
25b92c086b
tcp://clamav:3310djlkasjdlk connected happily. PHP reads a port the way atoi does — the digits at the front, the rest ignored — so an address with a typo on the end was saved, tested, and reported as working, while tcp://clamav:33101 went somewhere else and failed. The feedback an operator got had nothing to do with the mistake they made. ScannerAddress says what an address is: tcp:// with a host and a port of 1 to 65535 and nothing after it, or unix:// with an absolute path. It is asked in all three places an address arrives — saving, testing, and connecting. The third matters because a managed address comes from the environment and never passes the screen. The answer names the problem rather than reporting "no answer", which would be true of any unreachable scanner and would send somebody to look at their network for a typo. Checked in a browser with both addresses from the report: each is now refused on Test and on Save, with the same sentence, and tcp://clamav:3310 still comes back "Working. ClamAV 1.5.4 detected the test file".
57 lines
1.7 KiB
PHP
57 lines
1.7 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Modules\Files\Scanning;
|
|
|
|
/**
|
|
* Whether a scanner address is one, and not merely one PHP will accept.
|
|
*
|
|
* `stream_socket_client()` reads a port the way `atoi` does: it takes the
|
|
* digits at the front and ignores whatever follows. So
|
|
* `tcp://clamav:3310djlkasjdlk` connects happily to port 3310, and an
|
|
* address with a typo on the end is saved, tested, and reported as
|
|
* working — until the day something parses it differently. Meanwhile
|
|
* `tcp://clamav:33101` goes somewhere else entirely and fails, so the
|
|
* feedback an operator gets is inconsistent with the mistake they made.
|
|
*
|
|
* This refuses both, and says so while the field is still on screen.
|
|
*/
|
|
final class ScannerAddress
|
|
{
|
|
/**
|
|
* A TCP address: host, then a port of one to five digits and nothing
|
|
* after it. The host is a hostname, an IPv4 address, or an IPv6
|
|
* address in brackets — the three forms PHP itself accepts.
|
|
*/
|
|
private const TCP = '#^tcp://(?:\[[0-9a-fA-F:]+\]|[a-zA-Z0-9._-]+):([0-9]{1,5})$#';
|
|
|
|
/** A Unix socket: an absolute path, and nothing clever. */
|
|
private const UNIX = '#^unix://(/[^\x00]+)$#';
|
|
|
|
public static function isValid(string $address): bool
|
|
{
|
|
$address = trim($address);
|
|
|
|
if (preg_match(self::UNIX, $address) === 1) {
|
|
return true;
|
|
}
|
|
|
|
if (preg_match(self::TCP, $address, $matches) !== 1) {
|
|
return false;
|
|
}
|
|
|
|
$port = (int) $matches[1];
|
|
|
|
return $port >= 1 && $port <= 65535;
|
|
}
|
|
|
|
/**
|
|
* English, and the translation key: what to type instead.
|
|
*/
|
|
public static function message(): string
|
|
{
|
|
return 'Enter the scanner as tcp://host:3310 or unix:///path/to/clamd.sock.';
|
|
}
|
|
}
|