Salta ai contenuti

API di amministrazione

Moongate include un plugin gRPC facoltativo per l’amministrazione su rete privata. Espone login degli account, informazioni sul server, elenco paginato degli account, creazione degli account e revoca delle sessioni. Un futuro pannello React dovrà chiamare il proprio backend; quel backend chiama questi endpoint gRPC. Il browser non si connette direttamente alle porte dello shard.

MoongateAdminPlugin è registrato in Program.cs dopo MoongateUltimaPlugin. È distribuito con il server, mai tramite la directory plugins/. La porta predefinita è 2590. È disabilitato per impostazione predefinita.

Per una configurazione offline con certificato autofirmato, esegui:

Terminal window
mgctl init /srv/moongate --generate-admin-certificate \
--admin-certificate-hosts "login.example.test,192.0.2.10"

Usa i nomi effettivi degli endpoint al posto di questi esempi. Questo crea certificates/admin.pfx senza password, esporta il certificato pubblico admin.crt e imposta [admin_api].enabled = true con TLS abilitato. Indirizzo di ascolto e porta esistenti restano invariati. Considera attendibile admin.crt nei client del backend e riavvia il server. Vedi configurazione e rinnovo dei certificati.

Per un certificato fornito dall’operatore, configura <MOONGATE_ROOT>/config/moongate.toml:

[admin_api]
enabled = true
listen_address = "127.0.0.1"
port = 2590
session_lifetime_minutes = 30
session_max_age_minutes = 480
max_receive_message_bytes = 65536
max_concurrent_calls = 64
allow_insecure_loopback = false
certificate_path = "certificates/admin.pfx"
certificate_password = "$MOONGATE_ADMIN_CERTIFICATE_PASSWORD"

Usa l’indirizzo dell’interfaccia raggiungibile dal backend del pannello privato. Sia listen_address = "*" sia listen_address = "0.0.0.0" ascoltano su tutte le interfacce IPv4; "*" è un alias di "0.0.0.0", anche all’interno di una rete privata di container. Usa "::" per ascoltare sull’indirizzo wildcard IPv6. Gli indirizzi wildcard richiedono TLS. Limita l’accesso di rete agli host attendibili. Riavvia dopo le modifiche alla configurazione.

L’endpoint usa TLS server standard su HTTP/2. Non usa mTLS, certificati dei peer o il segreto Redis di trasferimento del gioco. Ottieni dalla CA privata un PFX server con chiave privata, uso per autenticazione del server e nomi DNS corrispondenti agli endpoint usati dai client. Posizionalo nel percorso configurato, leggibile solo dall’account di servizio Moongate. Distribuisci ai client del backend il certificato pubblico della CA, non la chiave privata del server. I client devono verificare sia la catena di fiducia sia il nome host.

Un percorso relativo del certificato viene risolto rispetto a MOONGATE_ROOT; sono supportati variabili d’ambiente e ~. Un PFX senza password usa certificate_password = "". Altrimenti fornisci la password tramite un riferimento d’ambiente popolato dal gestore dei segreti. L’avvio normale del server non genera certificati; usa esplicitamente mgctl init <root> --generate-admin-certificate. Certificati mancanti/illeggibili/scaduti, variabili d’ambiente mancanti o una porta occupata fanno fallire l’avvio abilitato con un errore dai dati sensibili oscurati. Gli endpoint disabilitati non caricano certificati né risolvono le variabili delle password.

Solo per lo sviluppo locale:

[admin_api]
enabled = true
listen_address = "127.0.0.1"
port = 2590
allow_insecure_loopback = true

Questa deroga esplicita consente HTTP/2 in chiaro solo su indirizzi letterali di loopback (127.0.0.1 o ::1). Nomi host, indirizzi wildcard e interfacce bridge Docker non possono usare la deroga. Viene registrato un avviso. I client di esempio forniti richiedono TLS; usa un client HTTP/2 configurato in chiaro quando provi questa deroga.

Le impostazioni accettano porte 1–65535, durate e età massime delle sessioni 1–1440 minuti, limiti di ricezione 1024–1048576 byte e limiti di chiamate concorrenti 1–1024. I valori predefiniti sono mostrati sopra. L’API accetta chiamate solo dopo che gli iscritti all’avvio del server hanno terminato; lo spegnimento rifiuta nuove chiamate e completa il lavoro esistente prima dell’arresto delle dipendenze.

Esegui questi comandi nella console locale Login o Standalone (premi * per sbloccarla):

account create <username> <password> Administrator
account api-access <username> on

Sostituisci i segnaposto con credenziali del gestore dei segreti. Gli argomenti della console non possono contenere spazi. account api-access rifiuta l’invocazione in gioco. Disabilita l’accesso con account api-access <username> off; questo revoca anche le sessioni amministrative precedenti.

Gli account creati da account create hanno l’accesso API disabilitato. Anche CreateAccount lo disabilita quando can_access_api è omesso; un chiamante autorizzato può richiedere esplicitamente l’accesso. Questi percorsi di creazione impostano esplicitamente il permesso invece di affidarsi all’inizializzatore dell’entità. La migrazione auth/0004_account_admin_api_access.sql aggiunge la colonna con valore predefinito false nel database; se uno schema di sviluppo esistente ha già la colonna, i valori true espliciti vengono conservati. Applica l’SQL in attesa con il flusso delle migrazioni. Il normale login di gioco è indipendente dall’accesso API.

RPC Login / Standalone Game Permesso
AdminLogin.Login Sì No Password valida, account sbloccato, CanAccessApi = true, tipo di account definito
AdminSession.Logout Sì Sì Token presentato ben formato; già assente equivale a successo
AdminSession.Refresh Sì Sì Un token valido e non scaduto che non ha raggiunto l’età massima della sessione; restituisce un nuovo token e chiude quello presentato
AdminServer.GetServerInfo Sì Sì Qualsiasi sessione amministrativa valida
AdminServer.GetMetrics Sì Sì Qualsiasi sessione amministrativa valida
AdminLogs.GetRecentLogs Sì Sì Administrator
AdminAccounts.ListAccounts Sì No Administrator
AdminAccounts.GetAccount Sì No Administrator
AdminAccounts.CreateAccount Sì No Administrator
AdminAccounts.UpdateAccountAccess Sì No Administrator
AdminAccounts.ChangeAccountPassword Sì No Administrator
AdminAccounts.BanAccount Sì No Administrator
AdminAccounts.UnbanAccount Sì No Administrator
AdminAccountSessions.RevokeAccountSessions Sì No Administrator
AdminFirewall.ListIpBans Sì No Administrator
AdminFirewall.BanIp Sì No Administrator
AdminFirewall.UnbanIp Sì No Administrator
AdminPlayers.ListOnlinePlayers Solo Standalone Sì GameMaster o Administrator
AdminPlayers.ListAccountCharacters Solo Standalone Sì GameMaster o Administrator
AdminHelp.ListHelpPages Solo Standalone Sì GameMaster o Administrator
AdminHelp.TakeHelpPage Solo Standalone Sì GameMaster o Administrator
AdminHelp.AnswerHelpPage Solo Standalone Sì GameMaster o Administrator
AdminHelp.CloseHelpPage Solo Standalone Sì GameMaster o Administrator
AdminSchedule.GetSchedule Solo Standalone Sì Qualsiasi sessione amministrativa valida
AdminJail.GetJail Solo Standalone Sì GameMaster o Administrator
AdminJail.PardonJailPrisoner Solo Standalone Sì GameMaster o Administrator
AdminTemplates.SearchItemTemplates Solo Standalone Sì Administrator
AdminTemplates.GetItemTemplate Solo Standalone Sì Administrator
AdminTemplates.CreateItemTemplate Solo Standalone Sì Administrator
AdminTemplates.UpdateItemTemplate Solo Standalone Sì Administrator
AdminTemplates.DeleteItemTemplate Solo Standalone Sì Administrator
AdminTemplates.SearchMobileTemplates Solo Standalone Sì Administrator
AdminTemplates.GetMobileTemplate Solo Standalone Sì Administrator
AdminTemplates.CreateMobileTemplate Solo Standalone Sì Administrator
AdminTemplates.UpdateMobileTemplate Solo Standalone Sì Administrator
AdminTemplates.DeleteMobileTemplate Solo Standalone Sì Administrator
AdminPlayers.KickPlayer Solo Standalone Sì GameMaster o Administrator, vedi sotto
AdminCharacters.GetCharacter Solo Standalone Sì GameMaster o Administrator
AdminCharacters.RenameCharacter Solo Standalone Sì GameMaster o Administrator
AdminCharacters.SetCharacterFame Solo Standalone Sì GameMaster o Administrator
AdminCharacters.SetCharacterKarma Solo Standalone Sì GameMaster o Administrator
AdminCharacters.TeleportCharacter Solo Standalone Sì GameMaster o Administrator
AdminCharacters.ResurrectCharacter Solo Standalone Sì GameMaster o Administrator
AdminOperations.Broadcast Solo Standalone Sì Administrator
AdminOperations.SaveWorld Solo Standalone Sì Administrator
AdminOperations.CreateSqlBackup Solo Standalone Sì Administrator

Gli host Game non risolvono mai i servizi Accounts né si connettono al database Accounts. I servizi specifici del ruolo non disponibili restituiscono UNIMPLEMENTED. Configura gli indirizzi degli endpoint nel backend del pannello; gli endpoint di amministrazione non vengono annunciati nell’individuazione dei realm.

Il firewall degli host Login e standalone: gli intervalli di indirizzi bannati di auth.ip_bans, quelli da cui ogni listener rifiuta una connessione. BanIp banna un singolo indirizzo o un intervallo CIDR, IPv4 o IPv6, con un motivo (le stesse regole del ban di un account: obbligatorio, al massimo 200 caratteri, nessun carattere di controllo) e una scadenza facoltativa nel futuro - se manca, il ban non finisce da solo; un intervallo la cui parte di rete non è zero viene mascherato sulla sua rete, e bannare un intervallo già bannato ne sostituisce il ban. ListIpBans restituisce i ban ancora validi con la paginazione keyset di ListAccounts, e UnbanIp ne toglie uno (NOT_FOUND quando la sua riga non c’è più). Un ban raggiunge subito i listener dell’host, interrompendo le connessioni che copre; un host che condivide il database ma non ha scritto il ban lo raccoglie al successivo ricaricamento del firewall, circa ogni mezzo minuto, e da allora rifiuta le nuove connessioni da quell’indirizzo. Un host realm senza il database degli account non ha un firewall proprio: le sue connessioni sono rifiutate solo dove vengono accettate, sull’host Login. Le scritture sono solo per Administrator, e la riga di audit di UnbanIp nomina il ban.

Gli host Game (e un host standalone, che ha entrambi) espongono anche il mondo: chi è online, un kick e le operazioni quotidiane. Un host Login non li ha (UNIMPLEMENTED).

ListOnlinePlayers restituisce i personaggi che sono nel mondo, per ID del personaggio, con la paginazione keyset di ListAccounts (after_character_id, next_after_character_id, dimensione predefinita della pagina 50, massimo 200): gli ID di sessione, account e personaggio, il nome, il tipo di account, la mappa e le coordinate. Non restituisce i nomi degli account: un host Game non ha accesso al database Accounts. ListAccountCharacters restituisce i personaggi di un account per slot, compresi quelli offline: l’ID del personaggio, lo slot (-1 per uno in attesa di cancellazione, che ha ceduto il suo slot), il nome, se il personaggio è online e la data della richiesta di cancellazione. Non sa distinguere un account sconosciuto da uno senza personaggi: entrambi danno un elenco vuoto. Legge il database del mondo, la stessa lettura che il login di gioco usa per costruire l’elenco dei personaggi del client.

Un personaggio è leggibile ovunque si trovi, e quello che è nel mondo è anche lavorabile. GetCharacter lo restituisce - quello vivo quando è nel mondo, quello salvato quando non lo è (online li distingue) - con il suo account, nome, titolo, corpo, posizione, le tre statistiche con punti vita, mana e stamina e i loro massimi, fama, karma, le uccisioni con gli omicidi a breve termine, e se è un assassino, un criminale, nascosto, immobilizzato, morto, in prigione o in attesa di cancellazione. Nessun personaggio ha quell’id, o il mondo non ne ha traccia, e la chiamata è NOT_FOUND; un NPC non è un personaggio. RenameCharacter gli dà un nome che segue le regole della creazione del personaggio (da 2 a 16 lettere, uno spazio, un trattino, un punto o un apostrofo all’interno, e nessuna parola vietata - INVALID_ARGUMENT per qualunque altro), SetCharacterFame e SetCharacterKarma prendono gli intervalli dei comandi .fame e .karma, TeleportCharacter prende una mappa e delle coordinate (INVALID_ARGUMENT quando non ci si può stare) e ResurrectCharacter fa rialzare un morto (FAILED_PRECONDITION quando è vivo). Una modifica richiede il personaggio nel mondo (FAILED_PRECONDITION quando non lo è) e gira sul game loop, come i comandi; la risposta è il personaggio com’è dopo la modifica. Valgono le regole di livello di KickPlayer: un GameMaster non può agire su un account del proprio livello o superiore (PERMISSION_DENIED), un Administrator può agire su chiunque, e il chiamante può agire su sé stesso.

La coda di aiuto dei game master, quella del gump .pages, è leggibile e lavorabile anche da fuori del mondo. ListHelpPages restituisce la coda dalla più vecchia, aperta e presa in carico; include_closed aggiunge quelle risposte e chiuse, le cui risposte il giocatore potrebbe non aver ancora letto. TakeHelpPage segna una richiesta come presa in carico da chi chiama, AnswerHelpPage risponde e la chiude (la risposta arriva al giocatore subito o al suo prossimo login, e segue le regole del testo del giocatore: non vuoto, al massimo 128 caratteri, senza caratteri di controllo), e CloseHelpPage la chiude senza risposta. Il nome dello staff di una pagina presa in carico è il nome utente dell’account di chi chiama: lo porta il token di amministrazione. Le modifiche della coda girano sul game loop, come fa il gump; una pagina sconosciuta o già chiusa è NOT_FOUND.

GetSchedule restituisce il calendario di data/schedule.toml così com’è: ogni attività programmata con la sua azione (shutdown, broadcast o chiamata Lua), la sua regola di quando (ogni ora, giorno o settimana; a un’ora; giorni della settimana), la sua prossima occorrenza da ora (l’arresto, per uno shutdown), gli avvisi di shutdown e i dettagli di broadcast o Lua; e ogni evento stagionale con la sua finestra di date, la sua modalità (auto, on o off) e se è attivo ora. È di sola lettura: attivare un evento tramite l’API è lavoro futuro. Accetta qualsiasi sessione amministrativa valida.

Anche il jail è leggibile e lavorabile da fuori del mondo. GetJail restituisce se ce n’è uno, la mappa su cui sono le sue celle, la sentenza più lunga in giorni, ogni cella con la sentenza che la occupa ora, e ogni sentenza: ID e nome del prigioniero, giocatore o NPC, cella, giorni, quando è iniziata e quando finisce, chi l’ha incarcerato e perché, se è in sospeso (in attesa di un prigioniero offline, i cui giorni partono al suo login) o graziata, e se il prigioniero è online. PardonJailPrisoner termina una sentenza subito senza multa e senza nota, come fa la grazia in gioco; un personaggio senza sentenza è NOT_FOUND. Tutto legge e modifica il jail sul game loop, come fa il gump. Incarcerare tramite l’API è lavoro futuro: il comando in gioco richiede il mobile di chi incarcera.

I template di item e mobile di templates/items/ e templates/mobiles/ sono leggibili tramite l’API, e quelli che l’API stessa ha scritto sono modificabili e rimovibili. SearchItemTemplates e SearchMobileTemplates trovano gli ID e i nomi che contengono il testo, senza distinguere le maiuscole, e i template del grafico quando il testo è un numero; GetItemTemplate e GetMobileTemplate ne restituiscono uno per ID. La risposta porta la voce scritta dall’autore - ciò che dice il file, con un campo assente che eredita da base_id - più il grafico e il nome risolti, e il nome del file che la definisce. Create scrive un nuovo template in admin.toml, Update sostituisce la voce di un template che vive lì, e Delete lo rimuove; un template di un file distribuito è letto dall’API e modificato a mano (FAILED_PRECONDITION), perché riscrivere un file distribuito distruggerebbe i commenti e il layout che un operatore potrebbe aver curato. Il primo contratto copre i campi principali: id, base_id, grafico, nome, commento, script e tag, e per gli item anche movable, stackable, peso e prezzi. Ogni scrittura valida l’intero catalogo con gli stessi loader che usa l’avvio - un ID duplicato, un base_id mancante, un ciclo o un valore non valido è INVALID_ARGUMENT e il file viene riportato com’era. Le scritture hanno effetto al prossimo riavvio: il mondo in esecuzione conserva i template che ha caricato. Una scrittura è per gli amministratori. KickPlayer chiude la connessione di un personaggio; un GameMaster non può espellere un account del proprio livello o superiore (PERMISSION_DENIED), un Administrator può espellerne qualsiasi, e nessuno può espellere il proprio account (FAILED_PRECONDITION). Un personaggio sconosciuto o offline è NOT_FOUND. Il reason (al massimo 200 caratteri, senza caratteri di controllo, così non può passare per un’altra riga del log) va nel log del server della chiamata, non al giocatore. La chiamata non attende lo svuotamento della connessione del giocatore: un socket già mezzo morto vale comunque come kick, e la riga di audit nomina l’account del giocatore.

Broadcast invia un testo non vuoto di al massimo 200 caratteri (senza caratteri di controllo) a tutti nel mondo e restituisce il numero di destinatari; un testo che il trasporto non può portare una volta compresso è INVALID_ARGUMENT. Una chiamata ripetuta ripete il messaggio: non esiste un ID di richiesta. SaveWorld salva il mondo come fa save e restituisce i millisecondi impiegati; un salvataggio già in corso (l’autosave) è quello che la chiamata attende, quindi le modifiche fatte subito prima della chiamata potrebbero non esserci, e mentre il server si arresta la chiamata è UNAVAILABLE. CreateSqlBackup esegue il backup di sql_backup (prima salva il mondo) e restituisce i nomi dei file, non i loro percorsi, la dimensione di ciascuno e i fallimenti, ognuno con un testo fisso (il motivo è nel log del server); already_running è impostato quando un altro backup è in corso. Un salvataggio o un backup prosegue quando il client riaggancia o la scadenza termina: la chiamata smette di attendere, il lavoro non si ferma a metà di un file. Al massimo due salvataggi e backup vengono richiesti alla volta (RESOURCE_EXHAUSTED per il successivo), così non possono riempire il cancello di ammissione dell’host. Questi tre sono solo per Administrator, e una chiamata a questo servizio può durare fino a 5 minuti, contati dal momento in cui è autenticata e autorizzata, dove ogni altra ha 15 secondi.

Gli account Regular e GameMaster possono leggere le informazioni del server quando abilitati all’API, ma non possono elencare/creare account o revocare sessioni altrui. I tipi di account sconosciuti vengono rifiutati. CreateAccount può assegnare qualsiasi tipo definito e abilitare esplicitamente l’accesso API perché solo gli Administrator possono invocarlo.

Il package sul protocollo è moongate.admin.v1. Ottieni i client C# generati da Moongate.Admin.Contracts, oppure genera qualsiasi linguaggio supportato dai file grezzi sotto proto/moongate/admin/v1/. Ogni release include moongate-admin-protos-<version>.zip. Gli import standard google/protobuf provengono dalla distribuzione del compilatore.

Una sequenza di richieste:

  1. Chiama AdminLogin.Login su un endpoint Login con username e password.
  2. Conserva l’access_token restituito nella memoria del backend. Invia i metadati authorization: Bearer <token> sulle chiamate protette a Login o Game.
  3. Usa AdminAccounts.CreateAccount e ListAccounts su Login, oppure AdminServer.GetServerInfo su entrambi gli endpoint.
  4. Prima che il token scada, chiama AdminSession.Refresh su uno dei due endpoint per ottenere un nuovo access_token con una nuova durata; il token presentato smette di funzionare subito, quindi sostituiscilo in memoria. Una sessione si può rinnovare fino a session_max_age_minutes dopo il login; poi rifai il login.
  5. Chiama AdminSession.Logout su uno dei due endpoint per rimuovere globalmente il token corrente.

Esempi eseguibili: client C#, client Python. Entrambi usano la verifica TLS standard, credenziali fornite dall’ambiente, scadenze limitate e nessun nuovo tentativo automatico delle mutazioni. Creano un account di prova che rimane in Accounts; usa ambienti eliminabili per la verifica.

ListAccounts usa la paginazione keyset del database: inizia con after_account_id = 0, invia il next_after_account_id restituito nella chiamata successiva, fermati quando è zero. La dimensione predefinita della pagina è 50; il massimo è 200. Gli ID sono uint32 diversi da zero per gli account esistenti. I riepiloghi contengono nome utente, ID, ruolo, flag di accesso/blocco, il motivo e la scadenza del ban e data di creazione UTC, mai password, hash o email.

GetAccount restituisce il record completo di un account di proprietà del database degli account: i campi del riepilogo più l’ultimo login e gli orari di aggiornamento in UTC. L’ultimo login è vuoto per un account che non ha mai fatto il login. L’email resta fuori, come nei riepiloghi.

GetMetrics restituisce l’ultimo snapshot diagnostico dell’host: la sequenza e l’ora della raccolta, l’elenco piatto delle metriche (nomi qualificati come provider.name, con valore, unità e tipo gauge o counter) e i provider che hanno fallito l’ultima raccolta. Accetta qualsiasi sessione amministrativa valida, come GetServerInfo, e non aggiunge alcuna raccolta propria: la risposta è vuota finché non si completa la prima raccolta.

GetRecentLogs restituisce gli ultimi eventi di log del processo, dal più recente, da un buffer limitato in memoria della stessa pipeline che scrivono la console e i file .clef: timestamp, livello, messaggio reso e, quando c’è, l’eccezione completa. minimum_level filtra (zero tiene tutto ciò che la pipeline ha accettato), limit limita (zero chiede il predefinito di 100; sopra 1000 è INVALID_ARGUMENT). La console e i file restano esattamente come sono. È solo per gli amministratori: le righe di log possono portare dati che un game master non ha motivo di vedere.

UpdateAccountAccess modifica il blocco, l’accesso API e il tipo di un account: cambiano solo i campi inviati (i campi hanno presenza, quindi inviare is_locked = false sblocca e ometterlo lo lascia com’è), e ne va inviato almeno uno. Restituisce il riepilogo dell’account com’è dopo la modifica. L’account di chi chiama non può bloccare se stesso, perdere il proprio accesso API né abbassare il proprio tipo (FAILED_PRECONDITION), e nessuna modifica può lasciare il server senza un amministratore sbloccato con accesso API (anch’esso FAILED_PRECONDITION). Gli altri amministratori vengono bloccati, nell’ordine dei loro ID, prima di essere contati, quindi due amministratori che si modificano a vicenda nello stesso momento non possono riuscire entrambi: uno dei due fallisce e può riprovare. ChangeAccountPassword imposta una nuova password (le stesse regole della creazione di un account); la password non viene mai registrata nel log. Per l’account di chi chiama serve anche current_password (INVALID_ARGUMENT quando manca, PERMISSION_DENIED quando è sbagliata, e la sessione resta), così un token rubato da solo non si prende l’account; per un altro account current_password viene ignorata.

BanAccount blocca un account come ban: registra un motivo (obbligatorio, non vuoto, al massimo 200 caratteri, senza caratteri di controllo) e una scadenza facoltativa (banned_until; assente significa che il ban non finisce da solo), e il blocco rifiuta ogni login, ordinario e amministrativo. Un ban non può essere diretto all’account di chi chiama (FAILED_PRECONDITION), non può lasciare senza un amministratore sbloccato con accesso API (FAILED_PRECONDITION), e una scadenza nel passato è INVALID_ARGUMENT. Un ban scaduto si rilascia al login successivo dell’account, ordinario o amministrativo: nessun timer, nessun riavvio. Un blocco senza campi di ban, quello di UpdateAccountAccess, non si rilascia mai da solo. UnbanAccount sblocca l’account e cancella i campi del ban. Entrambi terminano le sessioni dell’account e restituiscono il suo riepilogo com’è dopo la modifica.

Ogni modifica che va a buon fine raggiunge le sessioni del destinatario, anche una che non cambia nulla, come sbloccare un account che non è bloccato. Quando il destinatario è l’account di chi chiama, termina anche la sua sessione e deve fare di nuovo il login. Una modifica rifiutata non termina la sessione di nessuno. Se una chiamata fallisce dopo che la modifica è stata salvata (per esempio la dipendenza che riapre le sessioni non è disponibile), il client vede UNAVAILABLE o INTERNAL anche se la modifica resta; ripetere la chiamata è sicuro, perché applicare la stessa patch due volte non cambia altro.

Omettere CreateAccount.account_type significa Regular. UNSPECIFIED esplicito e valori enum sconosciuti falliscono. can_access_api è false per impostazione predefinita. I nomi utente devono essere non vuoti e lunghi al massimo 255 caratteri; le password sono non vuote e di massimo 1024 byte UTF-8. I caratteri NUL sono rifiutati. Il confronto dei nomi utente mantiene la semantica esistente degli account, sensibile alle maiuscole.

I token hanno 256 bit casuali e una durata assoluta predefinita di 30 minuti. Non esiste un refresh token: AdminSession.Refresh ruota il token di accesso stesso. Richiede un token ancora valido ed emette un token nuovo con una nuova durata, e il vecchio viene rimosso nello stesso passo di Redis, quindi due refresh dello stesso token insieme danno un solo token nuovo. Una sessione finisce definitivamente session_max_age_minutes dopo il login (480 per impostazione predefinita, mai meno della durata), per quante volte sia stata rinnovata; Refresh risponde allora UNAUTHENTICATED e il client rifà il login. Una sessione rinnovata viene revocata dagli stessi eventi di una nuova: logout, ban, blocco, cambio di ruolo, api-access off e RevokeAccountSessions. La durata e l’età massima appartengono alla sessione: sono quelle dell’host che l’ha fatta accedere, conservate in Redis, quindi un rinnovo servito da un altro host non le cambia. Una sessione emessa prima di questa funzione non porta né l’una né l’altra e non si può rinnovare: scade e basta.

Solo il token più recente di una sessione funziona, quindi tieni quello restituito da Refresh e usalo per Logout: uscire con un token più vecchio è un no-op riuscito. Refresh non si ripete: il vecchio token sparisce quando viene emesso il nuovo, quindi una chiamata la cui risposta si perde significa rifare il login. Un token rubato può essere rinnovato da chi lo detiene fino all’età massima; gli eventi sopra, RevokeAccountSessions compreso, lo terminano. Per spegnere il rinnovo, imposta session_max_age_minutes uguale a session_lifetime_minutes: la scadenza finale è allora la prima e un refresh non dà tempo in più. Redis memorizza solo digest dei token e campi di identità sicuri sotto moongate:admin:, separatamente da lease dei realm/ticket di trasferimento. Sono consentite fino a 64 sessioni attive per account. Le sessioni amministrative non hanno un proprio livello di cifratura; proteggi la distribuzione Redis privata e le credenziali come descritto nella configurazione.

Ogni chiamata protetta controlla Redis. Logout e revoca dell’intero account si applicano immediatamente tra host per le richieste appena ammesse. Un riavvio di Redis effimero invalida le sessioni; un riavvio del server non ne rinnova la scadenza. Un’interruzione di Redis nega l’accesso con UNAVAILABLE. Il login è limitato tra host a 10 tentativi/minuto per nome utente esatto e 30/minuto per indirizzo diretto del peer; gli header degli indirizzi inoltrati non sono considerati attendibili.

Le modifiche di sicurezza degli account supportate passano da IAccountAdminAccessService.SetApiAccessAsync, UpdateAccessAsync, PatchAccessAsync, ChangePasswordAsync, ChangeOwnPasswordAsync, BanAsync, UnbanAsync o RevokeSessionsAsync. Questi coordinano i lock di riga PostgreSQL con le generazioni di autorizzazione Redis. Un login in competizione con una modifica di sicurezza non può conservare una sessione privilegiata obsoleta. Una mutazione parzialmente fallita lascia l’accesso bloccato; un login valido successivo recupera rispetto allo stato autorevole dell’account confermato con commit. Gli aggiornamenti SQL diretti e generici tramite IDataAccess aggirano la revoca immediata. Usa i metodi supportati del servizio per le modifiche di sicurezza.

Stato Significato
INVALID_ARGUMENT Input, enum, ID del cursore o dimensione della pagina non validi
UNAUTHENTICATED Credenziali non valide o token mancante, scaduto o revocato; un Refresh di una sessione oltre la sua età massima
PERMISSION_DENIED La sessione valida manca del ruolo richiesto, oppure la password attuale data per cambiare la propria è sbagliata
ALREADY_EXISTS Il nome utente esiste già
NOT_FOUND Il destinatario della revoca, della modifica o della password non esiste
FAILED_PRECONDITION La chiamata escluderebbe chi chiama dal proprio account, oppure non lascerebbe alcun amministratore sbloccato con accesso API
RESOURCE_EXHAUSTED Limite di login/sessioni/chiamate concorrenti raggiunto, oppure richiesta troppo grande
UNAVAILABLE Interruzione di una dipendenza o endpoint non pronto/in arresto
UNIMPLEMENTED Questo ruolo server non espone la RPC
CANCELLED / DEADLINE_EXCEEDED Annullamento del chiamante o esecuzione limitata terminata
INTERNAL Errore inatteso; controlla i log sicuri del server

Le chiamate hanno una finestra massima di esecuzione sul server di 15 secondi (5 minuti per AdminOperations). L’annullamento non annulla una creazione di account già confermata. Se una risposta di creazione va persa, un nuovo tentativo può restituire ALREADY_EXISTS; usa l’elenco per riconciliare. Non esiste garanzia di esecuzione una sola volta né politica di nuovi tentativi automatici. La revoca non annulla le scritture delle richieste già ammesse.

Gli audit registrano operazione, ID degli account, esito e correlazione della richiesta; nessuna password, token o corpo delle richieste. Le future mutazioni del mondo attivo devono essere pianificate tramite GameLoop. Questa versione non espone modifiche dei personaggi o esecuzione di comandi arbitrari.

L’immagine documenta la porta 2590, ma EXPOSE non la abilita né la pubblica. L’override Compose privato abilita TLS con file PFX montati forniti dall’operatore e non pubblica alcuna porta di amministrazione. Vedi la guida Compose.

Controlli del repository:

Terminal window
bash scripts/verify-admin-protos.sh
bash examples/docker/login-realms/admin-smoke.sh

Il primo richiede PostgreSQL e Redis: Docker, oppure MOONGATE_TEST_POSTGRES_CONNECTION_STRING e MOONGATE_TEST_REDIS_CONNECTION_STRING (vedi Verificare le modifiche); usa un ambiente Python temporaneo e fixture TLS reali. Il secondo costruisce le immagini server, crea un proprio progetto Compose eliminabile e una CA di prova, esegue il client Python dalla rete Docker privata e rimuove solo i propri container/volumi/certificati.

Creato con ❤️ da Tom

Offrimi un caffè