record on stdin, one JSON object // php node_chat_receive.php --flush retry this host's own undelivered spool // // Exit 0 means stored. The sender treats anything else as undelivered and spools for retry, so // a non-zero exit here is a message that will arrive later rather than one that is lost. // // OPERATIONAL SAFEGUARDS // Reached only over SSH with a key this mesh installed, so the caller already has root. This // file therefore validates shape, not authority — there is no privilege here to protect that // the transport has not already granted. // // The channel is resolved against this host's own membership. A name that is not a channel // this machine belongs to is refused, so the argument cannot address a path outside the store. // // Storage is append-and-trim through vv_nc_append(), which is idempotent on message id — a // retry of something that already landed is a no-op rather than a duplicate. // // DEPENDS ON // include/node_chat.php vv_nc_append(), vv_nc_channel(), vv_nc_flush_spool() // ═══════════════════════════════════════════════════════════════════════════════════════════════ require_once dirname(__DIR__) . '/include/node_chat.php'; $args = $argv ?? []; if (in_array('--flush', $args, true)) { $n = vv_nc_flush_spool(); if ($n) echo "delivered $n queued message(s)\n"; exit(0); } $channel = ''; foreach ($args as $a) { if (str_starts_with($a, '--channel=')) $channel = substr($a, 10); } if ($channel === '' || !vv_nc_channel($channel)) { fwrite(STDERR, "unknown channel\n"); exit(2); } $raw = stream_get_contents(STDIN); $msg = json_decode((string)$raw, true); if (!is_array($msg) || empty($msg['id']) || !isset($msg['text'])) { fwrite(STDERR, "malformed message\n"); exit(2); } // Rebuilt rather than stored as sent: a record is only ever the fields this store understands, // so a sender running newer code cannot write keys this one will later hand to a page. $clean = [ 'id' => preg_replace('/[^a-f0-9]/i', '', (string)$msg['id']), 'ts' => (int)($msg['ts'] ?? time()), 'from' => preg_replace('/[^a-z0-9]/i', '', strtolower((string)($msg['from'] ?? ''))), 'kind' => in_array($msg['kind'] ?? 'msg', ['msg', 'question', 'notice'], true) ? $msg['kind'] : 'msg', 'text' => mb_substr((string)$msg['text'], 0, 4000), 'style' => [ 'color' => preg_match('/^#[0-9a-f]{6}$/i', $msg['style']['color'] ?? '') ? $msg['style']['color'] : '', 'font' => in_array($msg['style']['font'] ?? '', ['mono','sans','serif'], true) ? $msg['style']['font'] : '', ], ]; if ($clean['id'] === '' || $clean['from'] === '') { fwrite(STDERR, "malformed message\n"); exit(2); } exit(vv_nc_append($channel, $clean) ? 0 : 1);