Files
reflector-dashboard/svx-mkadmin.php
T

107 lines
4.2 KiB
PHP

#!/usr/bin/env php
<?php
/*
* SvxPortal — web front-end for SvxReflector
* Copyright (C) 2026 SA7AUX (Björn)
* SPDX-License-Identifier: AGPL-3.0-or-later
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU Affero General Public License as published by the Free
* Software Foundation, either version 3 of the License, or (at your option) any
* later version. See the LICENSE file for details.
*/
declare(strict_types=1);
/*
* svx-mkadmin.php — interaktiv provisionering av ett SvxPortal-konto (t.ex. admin).
*
* Återanvänder portalens EGEN auth/lib.php, så redis-anslutning (socket/lösen/db),
* nyckelprefix, uuid-generering, callsign-normalisering och lösenordshashning
* (password_hash PASSWORD_DEFAULT) blir identiska med signup.php. Inget hårdkodas.
*
* Kör på servern, från prompten:
* php svx-mkadmin.php
*
* Lib-sökväg (default = deployad portal) kan överstyras:
* SVXPORTAL_LIB=/annan/väg/lib.php php svx-mkadmin.php
* php svx-mkadmin.php /annan/väg/lib.php
*/
if (PHP_SAPI !== 'cli') { fwrite(STDERR, "Kör från kommandoraden.\n"); exit(1); }
if (!extension_loaded('redis')) { fwrite(STDERR, "PHP-tillägget 'redis' saknas.\n"); exit(1); }
$LIB = getenv('SVXPORTAL_LIB') ?: ($argv[1] ?? '/var/www/html/svxportal/auth/lib.php');
if (!is_file($LIB)) { fwrite(STDERR, "Hittar inte lib.php: $LIB\n(ange via SVXPORTAL_LIB eller som argument)\n"); exit(1); }
require $LIB; // ger cfg(), redis(), rkey(), uuidv4(), base_call(), norm_email(), *_key()
function ask(string $label, string $def = ''): string {
fwrite(STDOUT, $label . ($def !== '' ? " [$def]" : '') . ': ');
$v = rtrim((string)fgets(STDIN), "\n");
return $v !== '' ? $v : $def;
}
function ask_secret(string $label): string {
fwrite(STDOUT, $label . ': ');
shell_exec('stty -echo 2>/dev/null');
$v = rtrim((string)fgets(STDIN), "\n");
shell_exec('stty echo 2>/dev/null');
fwrite(STDOUT, "\n");
return $v;
}
function fail(string $msg): void { fwrite(STDERR, "FEL: $msg\n"); exit(1); }
$c = cfg()['redis'] ?? [];
fwrite(STDOUT, "Redis: " . ($c['unix_socket'] ?? ($c['host'] ?? '?')) .
" prefix='" . ($c['prefix'] ?? '') . "' (från " . $LIB . ")\n\n");
$r = redis();
/* --- Callsign (samma regler som signup.php) --- */
$cs = base_call(ask('Callsign'));
if (strlen($cs) < 3 || strlen($cs) > 10 || !preg_match('/^[A-Z0-9]+$/', $cs)) {
fail('Callsign måste vara 3-10 tecken A-Z/0-9.');
}
if ((string)$r->get(call_index_key($cs)) !== '') fail("Callsign $cs finns redan.");
/* --- Profil --- */
$first = ask('Förnamn');
$last = ask('Efternamn');
$email = norm_email(ask('E-post'));
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) fail('Ogiltig e-postadress.');
if ((string)$r->get(email_index_key($email)) !== '') fail("E-posten $email finns redan.");
$city = ask('Stad', '');
$state = ask('Region/State', '');
$country = ask('Land', '');
/* --- Adminnivå (1=vanlig, 2=admin, 3=super; jfr acct_admin_level/require_admin) --- */
$level = (int)ask('admin_level (1-3)', '3');
if ($level < 1 || $level > 3) fail('admin_level måste vara 1-3.');
/* --- Lösenord (dolt, dubbelt) --- */
$p1 = ask_secret('Lösenord');
$p2 = ask_secret('Lösenord igen');
if ($p1 !== $p2) fail('Lösenorden matchar inte.');
if (strlen($p1) < 6) fail('Lösenord måste vara minst 6 tecken.');
/* --- Skapa konto + index (samma layout som signup.php) --- */
$uuid = uuidv4();
$r->hMSet(acct_key($uuid), [
'callsign' => $cs,
'firstname' => $first,
'lastname' => $last,
'shortname' => $first,
'email' => $email,
'city' => $city,
'state' => $state,
'country' => $country,
'password_hash' => password_hash($p1, PASSWORD_DEFAULT),
'email_verified' => '1', // admin-provisionering: hoppa över mejlverifiering
'admin_level' => (string)$level,
'created_at' => (string)time(),
]);
$r->set(call_index_key($cs), $uuid);
$r->set(email_index_key($email), $uuid);
fwrite(STDOUT, "\nOK: konto '$cs' skapat (admin_level $level)\n");
fwrite(STDOUT, " uuid = $uuid\n");
fwrite(STDOUT, " logga in med callsign eller e-post + lösenordet ovan.\n");