diff options
Diffstat (limited to 'nym_sender.php')
| -rw-r--r-- | nym_sender.php | 101 |
1 files changed, 43 insertions, 58 deletions
diff --git a/nym_sender.php b/nym_sender.php index 221de17..e1798a1 100644 --- a/nym_sender.php +++ b/nym_sender.php @@ -4,12 +4,11 @@ declare(strict_types=1); require_once __DIR__ . '/yamn_config.php'; /** - * Send an already encrypted YAMN envelope through the local Rust Nym sender. + * Queue an already encrypted YAMN envelope with the local Rust Nym sender. * - * The handoff callback runs after the complete request has been written to - * the sender's stdin, but before waiting for the sender's bounded flush grace - * period. This lets the HTTP layer finish a FastCGI response while the lock - * remains held until the sender exits. + * The handoff callback runs only after the persistent sender has accepted the + * envelope into its bounded in-memory queue. The daemon is the sole owner of + * the Nym client storage and never writes queued envelopes to disk. */ function sendNymEnvelope( string $payload, @@ -18,17 +17,15 @@ function sendNymEnvelope( ?callable $onHandoff = null ): array { - $sender = yamnConfig('YAMN_NYM_SENDER', '/usr/local/bin/yamn-nym-submit'); - $recipient = yamnConfig('YAMN_NYM_RECIPIENT'); - $storage = yamnConfig('YAMN_NYM_STORAGE', '/var/lib/yamnweb/nym-client'); - $lockPath = yamnConfig('YAMN_NYM_LOCK', '/var/lib/yamnweb/nym-submit.lock'); + $socketPath = yamnConfig('YAMN_NYM_SOCKET', '/run/yamnweb/nym-sender.sock'); $entryAddress = $selectedEntryAddress ?? yamnConfig('YAMN_ENTRY_ADDRESS'); - if (!is_executable($sender)) { - return ['success' => false, 'error' => 'Nym sender is not available']; - } - if ($recipient === '' || strlen($recipient) > 512 || preg_match('/\s/', $recipient)) { - return ['success' => false, 'error' => 'Nym recipient is not configured']; + if ( + dirname($socketPath) !== '/run/yamnweb' + || basename($socketPath) === '' + || str_contains($socketPath, "\0") + ) { + return ['success' => false, 'error' => 'Nym sender socket is not configured correctly']; } if ($entryAddress === '' || strlen($entryAddress) > 320 || preg_match('/[\r\n\0\s]/', $entryAddress)) { return ['success' => false, 'error' => 'YAMN entry address is not configured']; @@ -49,66 +46,54 @@ function sendNymEnvelope( return ['success' => false, 'error' => 'Unable to encode Nym request']; } - $lock = @fopen($lockPath, 'c'); - if ($lock === false) { - return ['success' => false, 'error' => 'Nym sender lock is not available']; - } - if (!flock($lock, LOCK_EX | LOCK_NB)) { - fclose($lock); - return ['success' => false, 'error' => 'Nym sender is busy, please retry later']; - } - - $descriptors = [0 => ['pipe', 'r'], 1 => ['pipe', 'w'], 2 => ['pipe', 'w']]; - $environment = $_ENV; - $environment['YAMN_NYM_RECIPIENT'] = $recipient; - $environment['YAMN_NYM_STORAGE'] = $storage; - $process = proc_open([$sender], $descriptors, $pipes, null, $environment); - if (!is_resource($process)) { - flock($lock, LOCK_UN); - fclose($lock); - return ['success' => false, 'error' => 'Unable to start Nym sender']; + $errno = 0; + $error = ''; + $socket = @stream_socket_client( + 'unix://' . $socketPath, + $errno, + $error, + 3, + STREAM_CLIENT_CONNECT + ); + if (!is_resource($socket)) { + return ['success' => false, 'error' => 'Nym sender is not available']; } + stream_set_timeout($socket, 5); $inputLength = strlen($input); $offset = 0; while ($offset < $inputLength) { - $written = fwrite($pipes[0], substr($input, $offset)); + $written = fwrite($socket, substr($input, $offset)); if ($written === false || $written === 0) { break; } $offset += $written; } if ($offset !== $inputLength) { - fclose($pipes[0]); - proc_terminate($process); - fclose($pipes[1]); - fclose($pipes[2]); - proc_close($process); - flock($lock, LOCK_UN); - fclose($lock); - return ['success' => false, 'error' => 'Unable to hand envelope to Nym sender']; + fclose($socket); + return ['success' => false, 'error' => 'Unable to queue envelope with Nym sender']; } - fclose($pipes[0]); - - if ($onHandoff !== null) { - $onHandoff(); + if (!stream_socket_shutdown($socket, STREAM_SHUT_WR)) { + fclose($socket); + return ['success' => false, 'error' => 'Unable to finish Nym queue request']; } - $stdout = stream_get_contents($pipes[1]); - fclose($pipes[1]); - $stderr = stream_get_contents($pipes[2]); - fclose($pipes[2]); - $status = proc_close($process); - flock($lock, LOCK_UN); - fclose($lock); - - if ($status !== 0) { - return ['success' => false, 'error' => 'Nym submission failed']; + $responseText = stream_get_contents($socket, 4096); + $metadata = stream_get_meta_data($socket); + fclose($socket); + if (($metadata['timed_out'] ?? false) === true || !is_string($responseText)) { + return ['success' => false, 'error' => 'Nym sender did not accept the queue request']; } - - $response = json_decode($stdout, true); + $response = json_decode($responseText, true); if (!is_array($response) || ($response['success'] ?? false) !== true) { - return ['success' => false, 'error' => 'Invalid response from Nym sender']; + $queueError = is_array($response) && is_string($response['error'] ?? null) + ? $response['error'] + : 'Nym sender rejected the queue request'; + return ['success' => false, 'error' => $queueError]; + } + + if ($onHandoff !== null) { + $onHandoff(); } return ['success' => true]; |
