diff options
| author | Gab <24553253+gabrix73@users.noreply.github.com> | 2026-06-29 00:13:23 +0200 |
|---|---|---|
| committer | Gab <24553253+gabrix73@users.noreply.github.com> | 2026-06-29 00:13:23 +0200 |
| commit | 1d1d06c025be8b16a3535ecceffc26fe303977db (patch) | |
| tree | cc814b265bcaa2711f092f53349cc66068a6256a /identicon.php | |
| parent | 322a17dba0d44200f6c241b18a58761220050aba (diff) | |
| download | m2usenet-and-mail2news-1d1d06c025be8b16a3535ecceffc26fe303977db.tar.gz m2usenet-and-mail2news-1d1d06c025be8b16a3535ecceffc26fe303977db.tar.xz m2usenet-and-mail2news-1d1d06c025be8b16a3535ecceffc26fe303977db.zip | |
Update m2usenet UI and backend; add identicon renderer and nacl libs
- index.php, send.php: updated client UI
- m2usenet.go: backend changes
- identicon.php: new identicon renderer
- nacl.min.js, nacl-util.min.js: vendored client crypto libs
Diffstat (limited to 'identicon.php')
| -rw-r--r-- | identicon.php | 59 |
1 files changed, 59 insertions, 0 deletions
diff --git a/identicon.php b/identicon.php new file mode 100644 index 0000000..742cdf0 --- /dev/null +++ b/identicon.php @@ -0,0 +1,59 @@ +<?php +// /var/www/m2usenet/identicon.php +// VFACE identicon generator for m2usenet — wraps the ORIGINAL identicons-cli +// engine (Ch1ffr3punk algorithm), the same binary used by identicons.virebent.art. +// Input is PUBLIC only (username|email|ed25519-pubkey); no secret key involved. +// No logging (privacy). + +ini_set('display_errors', 0); +error_reporting(0); +header('Content-Type: application/json'); +header('Referrer-Policy: no-referrer'); +header('X-Content-Type-Options: nosniff'); + +define('IDENTICONS_CLI', '/usr/local/bin/identicons-cli'); + +function fail(string $msg, int $code = 400): void { + http_response_code($code); + echo json_encode(['error' => $msg]); + exit; +} + +if ($_SERVER['REQUEST_METHOD'] !== 'POST') fail('POST only', 405); +if (!is_executable(IDENTICONS_CLI)) fail('engine unavailable', 503); + +$username = trim($_POST['username'] ?? ''); +$email = trim($_POST['email'] ?? ''); +$pubkey = trim($_POST['pubkey'] ?? ''); + +// Validation: public fields only. No '|' (identity-string separator) allowed inside. +if ($username === '' || mb_strlen($username) > 64 || strpos($username, '|') !== false) fail('bad username'); +if ($email === '' || mb_strlen($email) > 128 || strpos($email, '|') !== false) fail('bad email'); +if (!preg_match('#^[A-Za-z0-9+/=]{1,128}$#', $pubkey)) fail('bad pubkey'); + +// Identity string = exact format consumed by identicons-cli / identicons.virebent.art +$input = $username . '|' . $email . '|' . $pubkey; + +function identiconB64(string $input, int $size): ?string { + $cmd = IDENTICONS_CLI . ' -input ' . escapeshellarg($input) . + ' -size ' . intval($size) . ' -transparent -format base64 2>/dev/null'; + $out = trim(shell_exec($cmd) ?? ''); + return ($out !== '' && preg_match('#^[A-Za-z0-9+/=]+$#', $out)) ? $out : null; +} + +// Single-line Face: header (no folding) so the base64 stays clean in the +// saved identity JSON and after downstream RFC unfolding. ~222 octets < 998. +function foldFaceHeader(string $base64): string { + return 'Face: ' . $base64; +} + +$face48 = identiconB64($input, 48); +$face256 = identiconB64($input, 256); +if ($face48 === null || $face256 === null) fail('generation failed', 500); + +echo json_encode([ + 'hash' => hash('sha256', $input), + 'face48' => $face48, // raw base64 PNG (48x48) -> Face: header + 'faceHeader' => foldFaceHeader($face48), // ready-to-paste folded Face: header + 'preview' => 'data:image/png;base64,' . $face256, // 256x256 dataurl for display +]); |
