From 81f12ab7c97055a9493f79fc601453ebad96e62a Mon Sep 17 00:00:00 2001 From: RonaldReagan Date: Wed, 21 Apr 2021 17:48:06 -0600 Subject: [PATCH 01/17] Enable passwordless authentication through the vita config. --- source/src/clientgame.cpp | 2 ++ source/src/server.cpp | 26 +++++++++++++++++++++----- 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/source/src/clientgame.cpp b/source/src/clientgame.cpp index 99123e1b..026f7d89 100644 --- a/source/src/clientgame.cpp +++ b/source/src/clientgame.cpp @@ -1665,6 +1665,8 @@ void setadmin(int *claim, char *password) } else if(*claim != 0 && *password) addmsg(SV_SETADMIN, "ris", *claim, genpwdhash(player1->name, password, sessionid)); + else if(*claim != 0) + addmsg(SV_SETADMIN, "ri", *claim); } COMMAND(setadmin, "is"); diff --git a/source/src/server.cpp b/source/src/server.cpp index f7129f75..ff8ff504 100644 --- a/source/src/server.cpp +++ b/source/src/server.cpp @@ -2627,19 +2627,35 @@ void callvotepacket (int cn, voteinfo *v = curvote) void changeclientrole(int client, int role, char *pwd, bool force) { pwddetail pd; + bool success = false; if(!isdedicated || !valid_client(client)) return; pd.line = -1; - if(force || role == CR_DEFAULT || (role == CR_ADMIN && pwd && pwd[0] && passwords.check(clients[client]->name, pwd, clients[client]->salt, &pd) && !pd.denyadmin)) - { - if(role == clients[client]->role) return; + + if(role == clients[client]->role) return; + + if(force) success = true; + + if(role == CR_ADMIN + && pwd + && pwd[0] + && passwords.check(clients[client]->name, pwd, clients[client]->salt, &pd) + && !pd.denyadmin) { + mlog(ACLOG_INFO,"[%s] player %s used admin password in line %d", clients[client]->hostname, clients[client]->name[0] ? clients[client]->name : "[unnamed]", pd.line); + success = true; + } + + if(clients[client]->checkvitadate(VS_ADMIN)) { + mlog(ACLOG_INFO,"[%s] player %s claimed admin through valid vita claim (pubkey: %s)", clients[client]->hostname, clients[client]->name[0] ? clients[client]->name : "[unnamed]", clients[client]->pubkeyhex); + success = true; + } + + if(success) { if(role > CR_DEFAULT) { loopv(clients) clients[i]->role = CR_DEFAULT; } clients[client]->role = role; sendserveropinfo(-1); - if(pd.line > -1) - mlog(ACLOG_INFO,"[%s] player %s used admin password in line %d", clients[client]->hostname, clients[client]->name[0] ? clients[client]->name : "[unnamed]", pd.line); mlog(ACLOG_INFO,"[%s] set role of player %s to %s", clients[client]->hostname, clients[client]->name[0] ? clients[client]->name : "[unnamed]", role == CR_ADMIN ? "admin" : "normal player"); // flowtron : connecting players haven't got a name yet (connectadmin) if(role > CR_DEFAULT) sendiplist(client); } From f1803b2f5211d0c86c9381cef1416d1d7d0faa89 Mon Sep 17 00:00:00 2001 From: RonaldReagan Date: Fri, 23 Apr 2021 06:59:49 -0600 Subject: [PATCH 02/17] Allow passwordless connect admin --- source/src/client.cpp | 2 -- source/src/server.cpp | 21 +++++++++++++++++++++ 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/source/src/client.cpp b/source/src/client.cpp index 09b46959..1a7e57a5 100644 --- a/source/src/client.cpp +++ b/source/src/client.cpp @@ -115,7 +115,6 @@ COMMANDN(connect, connectserv, "sis"); void connectadmin(char *servername, int *serverport, char *password) { modprotocol = false; - if(!password[0]) return; connectserv_(servername, *serverport, password, CR_ADMIN); } COMMAND(connectadmin, "sis"); @@ -137,7 +136,6 @@ COMMANDN(modconnect, modconnectserv, "sis"); void modconnectadmin(char *servername, int *serverport, char *password) { modprotocol = true; - if(!password[0]) return; connectserv_(servername, *serverport, password, CR_ADMIN); } COMMAND(modconnectadmin, "sis"); diff --git a/source/src/server.cpp b/source/src/server.cpp index ff8ff504..6699ae72 100644 --- a/source/src/server.cpp +++ b/source/src/server.cpp @@ -3096,6 +3096,9 @@ void process(ENetPacket *packet, int sender, int chan) bool srvfull = numnonlocalclients() > scl.maxclients; bool srvprivate = sg->mastermode == MM_PRIVATE || sg->mastermode == MM_MATCH; bool matchreconnect = sg->mastermode == MM_MATCH && findscore(*cl, false); + if (cl->pubkeyhex[0]) { + concatformatstring(tags, ", pubkey: %s", cl->pubkeyhex); + } int bl = 0, wl = nickblacklist.checkwhitelist(*cl); if(wl == NWL_PASS) concatstring(tags, ", nickname whitelist match"); if(wl == NWL_UNLISTED) bl = nickblacklist.checkblacklist(cl->name); @@ -3132,6 +3135,24 @@ void process(ENetPacket *packet, int sender, int chan) } mlog(ACLOG_INFO, "[%s] %s logged in using the admin password in line %d%s", cl->hostname, cl->name, pd.line, tags); } + else if(wantrole == CR_ADMIN && cl->checkvitadate(VS_ADMIN) && bantype != BAN_MASTER) // pass admins always through + { // Set as admin in vita and is trying to connect as admin + cl->isauthed = true; + clientrole = CR_ADMIN; + if(bantype == BAN_VOTE) + { + loopv(bans) if(bans[i].address.host == cl->peer->address.host) { bans.remove(i); concatstring(tags, ", ban removed"); break; } // remove admin bans + } + if(srvfull) + { + loopv(clients) if(i != sender && clients[i]->type==ST_TCPIP) + { + disconnect_client(i, DISC_MAXCLIENTS); // disconnect someone else to fit maxclients again + break; + } + } + mlog(ACLOG_INFO, "[%s] %s logged in using the vita admin claim%s", cl->hostname, cl->name, tags); + } else if(scl.serverpassword[0] && !(srvprivate || srvfull || banned)) { // server password required if(!strcmp(genpwdhash(cl->name, scl.serverpassword, cl->salt), cl->pwd)) From 9391547af73a657ede79a2798a67c875474404ad Mon Sep 17 00:00:00 2001 From: RonaldReagan Date: Sun, 25 Apr 2021 12:43:06 -0600 Subject: [PATCH 03/17] Add ability to ban/whitelist via server vita --- source/src/protocol.h | 2 +- source/src/protos.h | 5 +++-- source/src/server.cpp | 8 ++++++++ source/src/serverfiles.h | 4 ++-- 4 files changed, 14 insertions(+), 5 deletions(-) diff --git a/source/src/protocol.h b/source/src/protocol.h index 5dd27b61..a3094818 100644 --- a/source/src/protocol.h +++ b/source/src/protocol.h @@ -86,7 +86,7 @@ enum { DISC_PROTOCOL = 0, DISC_EOP, DISC_CN, DISC_TAGT, DISC_DUP, DISC_OVERFLOW, DISC_REMOVED = 32, DISC_SOPLOGINFAIL, DISC_BADNICK, DISC_ANNOY, DISC_SPAM, DISC_DOS, DISC_SPEEDING, DISC_FISHSLAP, DISC_AFK, // disconnected DISC_KICK = 48, DISC_BAN, DISC_VOTEKICK, DISC_VOTEBAN, DISC_OPKICK, DISC_OPBAN, DISC_TKKICK, DISC_TKBAN, DISC_FFKICK, DISC_FFBAN, DISC_AUTOKICK, DISC_AUTOBAN, DISC_UNKNOWN = 99, DISC_BECAUSE }; -enum { BAN_NONE = 0, BAN_VOTE, BAN_AUTO, BAN_BLACKLIST, BAN_MASTER }; +enum { BAN_NONE = 0, BAN_VOTE, BAN_AUTO, BAN_BLACKLIST, BAN_VITA, BAN_MASTER }; #define EXT_ACK -1 #define EXT_VERSION 104 diff --git a/source/src/protos.h b/source/src/protos.h index 65d54b94..fb281862 100644 --- a/source/src/protos.h +++ b/source/src/protos.h @@ -1026,8 +1026,9 @@ extern void dumpexecutionstack(stream *f); extern const char *currentserver(int i); // server -enum { /* timecodes */ VS_FIRSTLOGIN = 0, VS_LASTLOGIN, VS_MUTE, VS_NOVOTE, VS_BAN, VS_ADMIN, VS_OWNER, VS_MAPUPLOAD, - /* stats/counters */ VS_MINUTESCONNECTED, VS_MINUTESACTIVE, VS_FLAGS, VS_FRAGS, VS_DEATHS, VS_TKS, VS_DAMAGE, VS_FF, VS_NUM, VS_NUMCOUNTERS = VS_MINUTESCONNECTED }; +enum { /* timecodes */ VS_FIRSTLOGIN = 0, VS_LASTLOGIN, VS_BAN, VS_WHITELISTED, VS_ADMIN, VS_OWNER, + /* stats/counters */ VS_MINUTESCONNECTED, VS_MINUTESACTIVE, VS_FLAGS, VS_FRAGS, VS_DEATHS, VS_TKS, VS_DAMAGE, VS_FF, + /* meta */ VS_NUM, VS_NUMCOUNTERS = VS_MINUTESCONNECTED }; extern const char *vskeywords[VS_NUM + 1], *vsnames[VS_NUM + 1]; extern int modeacronyms; extern void servertoclient(int chan, uchar *buf, int len, bool demo = false); diff --git a/source/src/server.cpp b/source/src/server.cpp index 6699ae72..1cc772c3 100644 --- a/source/src/server.cpp +++ b/source/src/server.cpp @@ -2404,6 +2404,7 @@ int getbantype(int cn) if(!valid_client(cn)) return BAN_NONE; client &c = *clients[cn]; if(c.type==ST_LOCAL) return BAN_NONE; + if(c.checkvitadate(VS_BAN)) return BAN_VITA; if(checkgban(c.peer->address.host)) return BAN_MASTER; if(ipblacklist.check(c.peer->address.host)) return BAN_BLACKLIST; loopv(bans) @@ -3102,6 +3103,13 @@ void process(ENetPacket *packet, int sender, int chan) int bl = 0, wl = nickblacklist.checkwhitelist(*cl); if(wl == NWL_PASS) concatstring(tags, ", nickname whitelist match"); if(wl == NWL_UNLISTED) bl = nickblacklist.checkblacklist(cl->name); + + bool vitawhitelist = cl->checkvitadate(VS_WHITELISTED); + if (vitawhitelist) { + concatstring(tags, ", vita whitelist match"); + banned = false; + } + if(matchreconnect && !banned) { // former player reconnecting to a server in match mode cl->isauthed = true; diff --git a/source/src/serverfiles.h b/source/src/serverfiles.h index f1b99478..1fc46203 100644 --- a/source/src/serverfiles.h +++ b/source/src/serverfiles.h @@ -1983,8 +1983,8 @@ void serverparameters_dumpdocu(char *fname) // player ID bookkeeping -const char *vskeywords[VS_NUM + 1] = { "first", "last", "mute", "novote", "ban", "admin", "owner", "mapupload", "minconn", "minact", "flags", "frags", "deaths", "tks", "damage", "ff", "" }; -const char *vsnames[VS_NUM + 1] = { "first login", "last login", "muted until", "novote until", "banned until", "admin until", "owner until", "mapupload until", +const char *vskeywords[VS_NUM + 1] = { "first", "last", "ban", "whitelist", "admin", "owner", "minconn", "minact", "flags", "frags", "deaths", "tks", "damage", "ff", "" }; +const char *vsnames[VS_NUM + 1] = { "first login", "last login", "banned until", "whitelisted untils", "admin until", "owner until", "minutes connected", "minutes active", "flags", "frags", "deaths", "teamkills", "damage dealt", "team damage dealt", "" }; hashtable vitas; From 42c3c4ebcc5bf3a593e250b3ac8c62aeddc3ed89 Mon Sep 17 00:00:00 2001 From: RonaldReagan Date: Sun, 25 Apr 2021 13:05:35 -0600 Subject: [PATCH 04/17] #263 Keep track of flags for vitastat --- source/src/server.cpp | 4 +++- source/src/server.h | 7 +++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/source/src/server.cpp b/source/src/server.cpp index 1cc772c3..23d53b73 100644 --- a/source/src/server.cpp +++ b/source/src/server.cpp @@ -1437,6 +1437,7 @@ void flagaction(int flag, int action, int actor) { client *c = clients[actor]; c->state.flagscore += score; + c->incrementvitacounter(VS_FLAGS, score); sendf(-1, 1, "riii", SV_FLAGCNT, actor, c->state.flagscore); } if(valid_client(actor)) @@ -1912,6 +1913,7 @@ void serverdamage(client *target, client *actor, int damage, int gun, bool gib, if((suic || tk) && (m_htf || m_ktf) && targethasflag >= 0) { actor->state.flagscore--; + actor->incrementvitacounter(VS_FLAGS, -1); sendf(-1, 1, "riii", SV_FLAGCNT, actor->clientnum, actor->state.flagscore); } target->position.setsize(0); @@ -4459,7 +4461,7 @@ void serverslice(uint timeout) // main server update, called from cube main lo loopv(clients) if(clients[i]->type == ST_TCPIP && clients[i]->isauthed && clients[i]->vita) { clients[i]->vita->vs[VS_MINUTESCONNECTED]++; - if(clients[i]->isonrightmap && team_isactive(clients[i]->team)) clients[i]->vita->vs[VS_MINUTESACTIVE]++; + if(clients[i]->isonrightmap && team_isactive(clients[i]->team)) clients[i]->incrementvitacounter(VS_MINUTESACTIVE, 1); } } diff --git a/source/src/server.h b/source/src/server.h index 9cb9fcb1..1a44985e 100644 --- a/source/src/server.h +++ b/source/src/server.h @@ -354,6 +354,13 @@ struct client // server side version of "dynent" type extern int servclock; return vita && (vita->vs[n] == 1 || (servclock - vita->vs[n]) < 0); } + + void incrementvitacounter(int vitastat, int amount) + { + if (!vita) return; + vita->vs[vitastat] += amount; + + } }; struct ban From 587b0f8c4b47bfd17845b1ff0e008c1192a93e15 Mon Sep 17 00:00:00 2001 From: RonaldReagan Date: Sun, 25 Apr 2021 13:41:34 -0600 Subject: [PATCH 05/17] #263 Add in stat tracking for the rest of the vita stats --- source/src/protos.h | 2 +- source/src/server.cpp | 23 +++++++++++++++++++++-- source/src/serverfiles.h | 4 ++-- 3 files changed, 24 insertions(+), 5 deletions(-) diff --git a/source/src/protos.h b/source/src/protos.h index fb281862..9f4fd74c 100644 --- a/source/src/protos.h +++ b/source/src/protos.h @@ -1027,7 +1027,7 @@ extern const char *currentserver(int i); // server enum { /* timecodes */ VS_FIRSTLOGIN = 0, VS_LASTLOGIN, VS_BAN, VS_WHITELISTED, VS_ADMIN, VS_OWNER, - /* stats/counters */ VS_MINUTESCONNECTED, VS_MINUTESACTIVE, VS_FLAGS, VS_FRAGS, VS_DEATHS, VS_TKS, VS_DAMAGE, VS_FF, + /* stats/counters */ VS_MINUTESCONNECTED, VS_MINUTESACTIVE, VS_FLAGS, VS_ANTIFLAGS, VS_FRAGS, VS_DEATHS, VS_TKS, VS_SUICIDES, VS_DAMAGE, VS_FRIENDLYDAMAGE, /* meta */ VS_NUM, VS_NUMCOUNTERS = VS_MINUTESCONNECTED }; extern const char *vskeywords[VS_NUM + 1], *vsnames[VS_NUM + 1]; extern int modeacronyms; diff --git a/source/src/server.cpp b/source/src/server.cpp index 23d53b73..3f3c0f26 100644 --- a/source/src/server.cpp +++ b/source/src/server.cpp @@ -1876,7 +1876,18 @@ void serverdamage(client *target, client *actor, int damage, int gun, bool gib, if(damage < INT_MAX) { actor->state.damage += damage; + sendf(-1, 1, "ri7", gib ? SV_GIBDAMAGE : SV_DAMAGE, target->clientnum, actor->clientnum, gun, damage, ts.armour, ts.health); + + if (!isteam(target->team, actor->team)) + { + actor->incrementvitacounter(VS_DAMAGE, damage); + } + else + { + actor->incrementvitacounter(VS_FRIENDLYDAMAGE, damage); + } + if(target!=actor) { if(!hitpush.iszero()) @@ -1893,19 +1904,27 @@ void serverdamage(client *target, client *actor, int damage, int gun, bool gib, int targethasflag = clienthasflag(target->clientnum); bool tk = false, suic = false; target->state.deaths++; + target->incrementvitacounter(VS_DEATHS, 1); + if(target!=actor) { - if(!isteam(target->team, actor->team)) actor->state.frags += gib && gun != GUN_GRENADE && gun != GUN_SHOTGUN ? 2 : 1; + if(!isteam(target->team, actor->team)) + { + actor->state.frags += gib && gun != GUN_GRENADE && gun != GUN_SHOTGUN ? 2 : 1; + actor->incrementvitacounter(VS_FRAGS, 1); + } else { actor->state.frags--; actor->state.teamkills++; + actor->incrementvitacounter(VS_TKS, 1); tk = true; } } else { // suicide actor->state.frags--; + actor->incrementvitacounter(VS_TKS, 1); suic = true; mlog(ACLOG_INFO, "[%s] %s suicided", actor->hostname, actor->name); } @@ -1913,7 +1932,7 @@ void serverdamage(client *target, client *actor, int damage, int gun, bool gib, if((suic || tk) && (m_htf || m_ktf) && targethasflag >= 0) { actor->state.flagscore--; - actor->incrementvitacounter(VS_FLAGS, -1); + actor->incrementvitacounter(VS_ANTIFLAGS, 1); sendf(-1, 1, "riii", SV_FLAGCNT, actor->clientnum, actor->state.flagscore); } target->position.setsize(0); diff --git a/source/src/serverfiles.h b/source/src/serverfiles.h index 1fc46203..43e507ab 100644 --- a/source/src/serverfiles.h +++ b/source/src/serverfiles.h @@ -1983,9 +1983,9 @@ void serverparameters_dumpdocu(char *fname) // player ID bookkeeping -const char *vskeywords[VS_NUM + 1] = { "first", "last", "ban", "whitelist", "admin", "owner", "minconn", "minact", "flags", "frags", "deaths", "tks", "damage", "ff", "" }; +const char *vskeywords[VS_NUM + 1] = { "first", "last", "ban", "whitelist", "admin", "owner", "minconn", "minact", "flags", "antiflags", "frags", "deaths", "tks", "suicides", "damage", "ff", "" }; const char *vsnames[VS_NUM + 1] = { "first login", "last login", "banned until", "whitelisted untils", "admin until", "owner until", - "minutes connected", "minutes active", "flags", "frags", "deaths", "teamkills", "damage dealt", "team damage dealt", "" }; + "minutes connected", "minutes active", "flags", "flag score lost", "frags", "deaths", "teamkills", "suicides", "damage dealt", "team damage dealt", "" }; hashtable vitas; void vita_s::addname(const char *name) From 1444d9db2e08f102b2bd31db190070d965273934 Mon Sep 17 00:00:00 2001 From: RonaldReagan Date: Mon, 26 Apr 2021 16:51:01 -0600 Subject: [PATCH 06/17] #263 Prevent removal of active admin/whitelist/ban vita records --- source/src/server.cpp | 5 ++++- source/src/server.h | 1 - 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/source/src/server.cpp b/source/src/server.cpp index 3f3c0f26..681dd54c 100644 --- a/source/src/server.cpp +++ b/source/src/server.cpp @@ -241,7 +241,10 @@ void poll_serverthreads() // called once per mainloop-timeslice int too_old = 0; enumeratekt(vitas, uchar32, k, vita_s, v, { - if((servclock - v.vs[VS_LASTLOGIN]) / (60 * 24 * 31) <= vitamaxage) + if((servclock - v.vs[VS_LASTLOGIN]) / (60 * 24 * 31) <= vitamaxage // Vita is within the max age (months) + || (v.vs[VS_BAN] == 1 || (servclock - v.vs[VS_BAN]) < 0) // Do not remove if vita has the ban, whitelist, or admin flag set + || (v.vs[VS_WHITELISTED] == 1 || (servclock - v.vs[VS_WHITELISTED]) < 0) + || (v.vs[VS_ADMIN] == 1 || (servclock - v.vs[VS_ADMIN]) < 0)) { vk.k = &k; vk.v = &v; diff --git a/source/src/server.h b/source/src/server.h index 1a44985e..01dcdd5d 100644 --- a/source/src/server.h +++ b/source/src/server.h @@ -359,7 +359,6 @@ struct client // server side version of "dynent" type { if (!vita) return; vita->vs[vitastat] += amount; - } }; From 55e6cf302f828c77d863951194415e3b5f18949f Mon Sep 17 00:00:00 2001 From: RonaldReagan Date: Tue, 11 May 2021 20:26:01 -0600 Subject: [PATCH 07/17] #263 Expose vita data to server admins (protocol bump) --- source/src/clientgame.cpp | 7 +++++++ source/src/clients2c.cpp | 33 +++++++++++++++++++++++++++++++++ source/src/protocol.cpp | 1 + source/src/protocol.h | 3 ++- source/src/server.cpp | 19 ++++++++++++++++++- 5 files changed, 61 insertions(+), 2 deletions(-) diff --git a/source/src/clientgame.cpp b/source/src/clientgame.cpp index 026f7d89..39d96418 100644 --- a/source/src/clientgame.cpp +++ b/source/src/clientgame.cpp @@ -1642,6 +1642,13 @@ void whois(int *cn) } COMMAND(whois, "i"); +void getvita(int *cn) +{ + addmsg(SV_GETVITA, "ri", *cn); +} +COMMAND(getvita, "i"); + + void findcn(char *name) { loopv(players) if(players[i] && !strcmp(name, players[i]->name)) diff --git a/source/src/clients2c.cpp b/source/src/clients2c.cpp index 0438c347..6282bd28 100644 --- a/source/src/clients2c.cpp +++ b/source/src/clients2c.cpp @@ -1354,6 +1354,39 @@ void parsemessages(int cn, playerent *d, ucharbuf &p, bool demo = false) getip4(p); p.get((uchar*)text, 64); break; + + case SV_VITADATA: { // Server sending vita data of a client. Possibly expose this to cubescript in the future + uchar pubkey[32]; + char pubkeyhex[68]; + string privatecomment; + string publiccomment; + int vs[VS_NUM]; + + int targetcn = getint(p); + playerent *target = getclient(targetcn); + + if (target && p.get(pubkey, 32) == 32) { + getstring(text, p); + filtertext(privatecomment, text, FTXT__VITACOMMENT); + getstring(text, p); + filtertext(publiccomment, text, FTXT__VITACOMMENT); + + loopi(VS_NUM) vs[i] = getint(p); + + bin2hex(pubkeyhex, pubkey, 32); + + conoutf("\f0Vita Info for \f5%s \f0(\f5%d\f0) \f2pubkey: \f1%s", target->name, targetcn, pubkeyhex); + if(privatecomment[0]) conoutf("\f0Private Comment: \f1%s", privatecomment); + if(publiccomment[0]) conoutf("\f0Public Comment: \f1%s", publiccomment); + + string msg = "\f0Flags:"; + for (int i = 0; i < VS_NUM; i++) { + concatformatstring(msg, " \f2%s=\f1%d", vskeywords[i], vs[i]); + } + conoutf("%s", msg); + } + break; + } default: neterr("type"); diff --git a/source/src/protocol.cpp b/source/src/protocol.cpp index cc3a6b9d..fc0ec990 100644 --- a/source/src/protocol.cpp +++ b/source/src/protocol.cpp @@ -605,6 +605,7 @@ static const int msgsizes[] = // size inclusive message token, 0 f SV_EXTENSION, 0, SV_MAPIDENT, 3, SV_DEMOCHECKSUM, 0, SV_DEMOSIGNATURE, 0, SV_PAUSEMODE, 1, + SV_GETVITA, 2, SV_VITADATA, 0, -1 }; diff --git a/source/src/protocol.h b/source/src/protocol.h index a3094818..7e9ea1f7 100644 --- a/source/src/protocol.h +++ b/source/src/protocol.h @@ -7,7 +7,7 @@ #define CUBE_SERVINFO_PORT(serverport) (serverport+1) #define CUBE_SERVINFO_TO_SERV_PORT(servinfoport) (servinfoport-1) #define CLIENTIPCENSOR 12 // blank out the last 12 bits of client's IPs before telling them to others (compromise between "16" from AC 0.9x and "8" from AC 1.1) -#define PROTOCOL_VERSION 1203 // bump when protocol changes (use negative numbers for mods!) +#define PROTOCOL_VERSION 1204 // bump when protocol changes (use negative numbers for mods!) #define DEMO_VERSION 2 // bump when demo format changes #define DEMO_MAGIC "ASSAULTCUBE_DEMO" #define DEMO_MINTIME 10000 // don't keep demo recordings with less than 10 seconds @@ -50,6 +50,7 @@ enum SV_EXTENSION, SV_MAPIDENT, SV_DEMOCHECKSUM, SV_DEMOSIGNATURE, SV_PAUSEMODE, + SV_GETVITA, SV_VITADATA, SV_NUM }; diff --git a/source/src/server.cpp b/source/src/server.cpp index 681dd54c..25580a2d 100644 --- a/source/src/server.cpp +++ b/source/src/server.cpp @@ -2648,7 +2648,6 @@ void callvotepacket (int cn, voteinfo *v = curvote) sendpacket(cn, 1, q.finalize()); } -// TODO: use AUTH code void changeclientrole(int client, int role, char *pwd, bool force) { pwddetail pd; @@ -4031,6 +4030,24 @@ void process(ENetPacket *packet, int sender, int chan) case SV_PAUSEMODE: break; + + case SV_GETVITA: + { + int targetcn = getint(p); + + // If the client is admin or could be admin through vita + if ((cl->role >= CR_ADMIN || cl->checkvitadate(VS_ADMIN) || cl->checkvitadate(VS_OWNER)) + && valid_client(targetcn)) { + client *target = clients[targetcn]; + + if (target->vita) { + sendf(sender, 1, "riimssv", SV_VITADATA, targetcn, 32, target->pubkey.u, + target->vita->privatecomment, target->vita->publiccomment, + VS_NUM, target->vita->vs); + } + } + break; + } case SV_EXTENSION: { From 858744e6bcab60831a7c33f42d6fe8f0190b52a3 Mon Sep 17 00:00:00 2001 From: RonaldReagan Date: Tue, 11 May 2021 20:47:49 -0600 Subject: [PATCH 08/17] Use incrementvitacounter for VS_MINUTESCONNECTED --- source/src/server.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/src/server.cpp b/source/src/server.cpp index 25580a2d..ea04110c 100644 --- a/source/src/server.cpp +++ b/source/src/server.cpp @@ -4499,7 +4499,7 @@ void serverslice(uint timeout) // main server update, called from cube main lo serverhost->totalSentData = serverhost->totalReceivedData = 0; loopv(clients) if(clients[i]->type == ST_TCPIP && clients[i]->isauthed && clients[i]->vita) { - clients[i]->vita->vs[VS_MINUTESCONNECTED]++; + clients[i]->incrementvitacounter(VS_MINUTESCONNECTED, 1); if(clients[i]->isonrightmap && team_isactive(clients[i]->team)) clients[i]->incrementvitacounter(VS_MINUTESACTIVE, 1); } } From 797fb48295a27ce0ab1c04826a5aeccdaef09452 Mon Sep 17 00:00:00 2001 From: RonaldReagan Date: Tue, 11 May 2021 20:59:08 -0600 Subject: [PATCH 09/17] Improve error messages on SV_GETVITA handling --- source/src/server.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/source/src/server.cpp b/source/src/server.cpp index ea04110c..d1bae3cd 100644 --- a/source/src/server.cpp +++ b/source/src/server.cpp @@ -4036,8 +4036,12 @@ void process(ENetPacket *packet, int sender, int chan) int targetcn = getint(p); // If the client is admin or could be admin through vita - if ((cl->role >= CR_ADMIN || cl->checkvitadate(VS_ADMIN) || cl->checkvitadate(VS_OWNER)) - && valid_client(targetcn)) { + if (!(cl->role >= CR_ADMIN || cl->checkvitadate(VS_ADMIN) || cl->checkvitadate(VS_OWNER))) { + sendservmsg("\f3You must be admin to get vita"); + break; + } + + if (valid_client(targetcn)) { client *target = clients[targetcn]; if (target->vita) { @@ -4045,6 +4049,8 @@ void process(ENetPacket *packet, int sender, int chan) target->vita->privatecomment, target->vita->publiccomment, VS_NUM, target->vita->vs); } + } else { + sendservmsg("\f3Invalid cn to retrieve vita data"); } break; } From 7cbf8fb67c935ba058a69898484679b28964a077 Mon Sep 17 00:00:00 2001 From: RonaldReagan Date: Sat, 15 May 2021 11:20:39 -0600 Subject: [PATCH 10/17] Move key saving to their own functions --- source/src/crypto.cpp | 89 ++++++++++++++++++++++++++++++------------- 1 file changed, 62 insertions(+), 27 deletions(-) diff --git a/source/src/crypto.cpp b/source/src/crypto.cpp index 5bd96291..9941904e 100644 --- a/source/src/crypto.cpp +++ b/source/src/crypto.cpp @@ -741,6 +741,63 @@ static int passdeferred(void *pass) // decrypt the private key in the backgrou return 0; } +void savepreprivkey(const char *filename, uchar *preprivkey, uchar preprivlen, uchar *psalt, uint preprivpwdcfg) { + char hextemp[128 * 2 + 1]; + char *oldfile = loadfile(filename, NULL), *b; + stream *f = openfile(filename, "wb"); + if(f) + { + if(!oldfile) + { + f->printf("\n" "// remove this file from your computer immediately!\n" + "// either print it out and delete it or move it to a thumbdrive.\n" + "// YOU DO NOT NEED THIS FILE TO PLAY AC!\n" "\n"); + } + else + { + for(char *l = strtok_r(oldfile, "\n\r", &b); l; l = strtok_r(NULL, "\n\r", &b)) + { + if(*l && l[0] != '/') + f->printf("// %s\n", l); + if(*l && l[0] == '/') + f->printf("%s\n", l); + } + } + + f->printf("authsetup pre %s", bin2hex(hextemp, preprivkey, preprivlen)); + if(preprivpwdcfg) f->printf(" %s %u", bin2hex(hextemp, psalt, 16), preprivpwdcfg & ~1); + f->printf("\n\n"); + delete f; + } + DELETEA(oldfile); +} + + +void saveprivkey(const char *filename, uchar *privkey, uchar *pubkey, uchar salt[16], uint privpwdcfg) { + char hextemp[65]; + char *oldfile = loadfile(filename, NULL), *b; + stream *f = openfile(filename, "wb"); + if(f) + { + if(oldfile) + { + for(char *l = strtok_r(oldfile, "\n\r", &b); l; l = strtok_r(NULL, "\n\r", &b)) + { + if(*l && l[0] != '/') + f->printf("// %s\n", l); + if(*l && l[0] == '/') + f->printf("%s\n", l); + } + } + + f->printf("\nauthsetup priv %s", bin2hex(hextemp, privkey, 32)); + if(privpwdcfg) f->printf(" %s %u", bin2hex(hextemp, salt, 16), privpwdcfg); + f->printf("\nauthsetup pub %s\n\n", bin2hex(hextemp, pubkey, 32)); + delete f; + } + DELETEA(oldfile); +} + void authsetup(char **args, int numargs) // set up private and public keys { const int preprivminlen = 32, preprivmaxlen = 128; @@ -865,21 +922,8 @@ void authsetup(char **args, int numargs) // set up private and public keys preprivpwdcfg = (iterations << 10) | authmemusage; xor_block(prepriv, keyhash, preprivlen); } - const char *fn = numargs > 2 && args[2][0] ? path(args[2]) : AUTHPREPRIVATECFGFILE; - char *oldfile = loadfile(fn, NULL), *b; - stream *f = openfile(fn, "wb"); - if(f) - { - f->printf("\n" "// remove this file from your computer immediately!\n" - "// either print it out and delete it or move it to a thumbdrive.\n" - "// YOU DO NOT NEED THIS FILE TO PLAY AC!\n" "\n"); - if(oldfile) for(char *l = strtok_r(oldfile, "\n\r", &b); l; l = strtok_r(NULL, "\n\r", &b)) if(*l) f->printf("// %s\n", l); - f->printf("authsetup pre %s", bin2hex(hextemp, prepriv, preprivlen)); - if(preprivpwdcfg) f->printf(" %s %u", bin2hex(hextemp, psalt, 16), preprivpwdcfg & ~1); - f->printf("\n\n"); - delete f; - } - DELETEA(oldfile); + savepreprivkey(numargs > 2 && args[2][0] ? path(args[2]) : AUTHPREPRIVATECFGFILE + , prepriv, preprivlen, psalt, preprivpwdcfg); } } else if(!strcasecmp(args[0], "NEWPASS")) @@ -896,18 +940,8 @@ void authsetup(char **args, int numargs) // set up private and public keys privpwdcfg = (iterations << 10) | authmemusage; xor_block(priv, keyhash, 32); } - const char *fn = numargs > 2 && args[2][0] ? path(args[2]) : AUTHPRIVATECFGFILE; - char *oldfile = loadfile(fn, NULL), *b; - stream *f = openfile(fn, "wb"); - if(f) - { - if(oldfile) for(char *l = strtok_r(oldfile, "\n\r", &b); l; l = strtok_r(NULL, "\n\r", &b)) if(*l) f->printf("// %s\n", l); - f->printf("\nauthsetup priv %s", bin2hex(hextemp, priv, 32)); - if(privpwdcfg) f->printf(" %s %u", bin2hex(hextemp, salt, 16), privpwdcfg); - f->printf("\nauthsetup pub %s\n\n", bin2hex(hextemp, keyhash + 32, 32)); - delete f; - } - DELETEA(oldfile); + saveprivkey(numargs > 2 && args[2][0] ? path(args[2]) : AUTHPRIVATECFGFILE, + priv, keyhash + 32, salt, privpwdcfg); } } #ifndef PRODUCTION @@ -935,6 +969,7 @@ void authsetup(char **args, int numargs) // set up private and public keys } COMMAND(authsetup, "v"); + void mypubkey() { string res = ""; From 4fe207e7213744ca3f548d1567605a5c4ac4646b Mon Sep 17 00:00:00 2001 From: RonaldReagan Date: Tue, 18 May 2021 06:41:57 -0600 Subject: [PATCH 11/17] Move auth files to new private folder within profile --- source/src/crypto.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/source/src/crypto.cpp b/source/src/crypto.cpp index 9941904e..ec0dfa2c 100644 --- a/source/src/crypto.cpp +++ b/source/src/crypto.cpp @@ -377,7 +377,7 @@ void popMT() // undo last seedMT() #define ENTCHUNKS 32 // pool size (in 128-bytes chunks) #define ENTPOOLSIZE (ENTCHUNKS * 128) -#define ENTROPYSAVEFILE "config" PATHDIVS "entropy.dat" +#define ENTROPYSAVEFILE "private" PATHDIVS "entropy.dat" static uchar *entpool = NULL; @@ -719,8 +719,8 @@ COMMAND(ed25519speedtest, ""); // * it is used during playing to authenticate the player to the server // * needs special protection... -#define AUTHPREPRIVATECFGFILE "config" PATHDIVS "authpreprivate.cfg" -#define AUTHPRIVATECFGFILE "config" PATHDIVS "authprivate.cfg" +#define AUTHPREPRIVATECFGFILE "private" PATHDIVS "authpreprivate.cfg" +#define AUTHPRIVATECFGFILE "private" PATHDIVS "authprivate.cfg" VARP(authmemusage, 2, 24, (1<<10) - 1); // megabytes of RAM to use for password hash (when using a new password) VARP(authrounds, 0, 0, INT_MAX - 1); // create new password hashes with a fixed number of rounds (if authrounds > 0) From 3e950bba2ceaa6f7871d6e9f1d826afbc324598e Mon Sep 17 00:00:00 2001 From: RonaldReagan Date: Fri, 21 May 2021 12:18:29 -0600 Subject: [PATCH 12/17] #263 New auth menus. Allow saving keys without setting password --- config/docs.cfg | 4 +- config/menus.cfg | 1 + config/menus_auth.cfg | 88 ++++++++++++++++++++++++++++++++++++ config/menus_multiplayer.cfg | 83 +--------------------------------- config/menus_settings.cfg | 4 +- source/src/crypto.cpp | 15 ++++-- 6 files changed, 106 insertions(+), 89 deletions(-) create mode 100644 config/menus_auth.cfg diff --git a/config/docs.cfg b/config/docs.cfg index 9a0e0dfa..968707fc 100644 --- a/config/docs.cfg +++ b/config/docs.cfg @@ -7388,9 +7388,9 @@ docremark ["authsetup genpriv" - generates private key from prepriv key.]; docremark ["authsetup genpub" - generates public key from private key.]; -docremark ["authsetup newppass preprivpass [preprivfilename]" - encrypts prepriv key with new password and saves the result to file. The default filename is config/authpreprivate.cfg and an existing file gets overwritten - but the former file content is kept and also written, each line commented out.]; +docremark ["authsetup newppass preprivpass [preprivfilename]" - encrypts prepriv key with new password and saves the result to file. The default filename is private/authpreprivate.cfg and an existing file gets overwritten - but the former file content is kept and also written, each line commented out.]; -docremark ["authsetup newpass privpass [privatefilename]" - encrypts private key with new password and saves the encrypted private key and the public key to file. The default filename is config/authprivate.cfg and an existing file gets overwritten - but the former file content is kept and also written, each line commented out.]; +docremark ["authsetup newpass privpass [privatefilename]" - encrypts private key with new password and saves the encrypted private key and the public key to file. The default filename is private/authprivate.cfg and an existing file gets overwritten - but the former file content is kept and also written, each line commented out.]; docremark ["authsetup unarmed" - sets private and public keys to a fixed value. For testing only. Can be used to "log out".]; diff --git a/config/menus.cfg b/config/menus.cfg index 75ddb30a..c7bde3aa 100644 --- a/config/menus.cfg +++ b/config/menus.cfg @@ -143,6 +143,7 @@ exec config/menus_bot.cfg exec config/menus_edit.cfg exec config/menus_licenses.cfg exec config/menus_settings.cfg +exec config/menus_auth.cfg exec config/menus_multiplayer.cfg exec config/menus_voicecom.cfg exec config/favourites.cfg diff --git a/config/menus_auth.cfg b/config/menus_auth.cfg new file mode 100644 index 00000000..fb8476a1 --- /dev/null +++ b/config/menus_auth.cfg @@ -0,0 +1,88 @@ + +newmenu [Auth Setup] +menuinit [ tempalias ___ppass "" ; tempalias ___pass ""; tempalias ___rememberpass 0; ] +menuitem "To play online you need to create a game account which will be used" -1 +menuitem "identify you to game servers. This identity is stored as a public/private" -1 +menuitem "keypair and only the public key is ever transmitted to the server. You are" -1 +menuitem "able to change the password at a future point in time." -1 +menuitem "" -1 +menuitem "There exists a mechanism to recover your identity if lost that uses a" -1 +menuitem "seperate password." -1 +menuitem "" -1 +menuitem "To learn more about this functionality you can go to this URL in your browser" -1 +menuitem "\f1https://assault.cubers.net/docs/auth.html" -1 +menuitem "" -1 +menuitem "\f0Set passwords \f4(recommended)" +menuitemtextinput "Password for your game account\t" "" [___pass = $arg1] [] 64 +menuitemtextinput "Password for account restoration\t" "" [___ppass = $arg1] [] 64 +menuitem "" -1 +menuitemradio "Remember game account password: " 0 1 [ ] [ "No \f4(recommended)" "Yes"] [ ___rememberpass = (= $arg1 1)] +menuitem "\f2\t\t\t [ OK ]" [ + // if (strcmp $___ppass "") [ ___ppass = "unppass" ] [] + // if (strcmp $___pass "") [ ___pass = "unpass" ] [] + authsetup genpre + authsetup genpriv + authsetup genpub + if (= $___rememberpass 1) [ alias savedpass $___pass ] [ if (checkalias savedpass) [ delalias savedpass ] ] + + closecurmenu + showmenu "Auth Progress" +] + + +newmenu "game account" +menuitem "To play online you need to create a game account first." -1 +menuitem "" -1 +menuitem "\t\t\f0[Create game account]" [ closecurmenu; showmenu "Auth Setup"; ] +menuitem "\t\t[Not now...]" closecurmenu + +newmenu "Auth Progress" +menuinit [ sleep 100 [ + if (strcmp $___ppass "") [ authsetup savepre ] [ authsetup newppass $__ppass; authsetup savepre ] + if (strcmp $___pass "") [ authsetup savepriv ] [ authsetup newpass $___pass; authsetup savepriv ] + ___ppass = "" + ___pass = "" + if (authsetup) [ echo "\f0created game account" ] + closecurmenu + checkaccount + ] ] +menuitem "Please wait while we create your account..." -1 + +newmenu "enter password" +menuitemtextinput "please enter the password for your game account\t" "" [ __loginpass = $arg1; closecurmenu; showmenu authentication ] [] 64 1 + +newmenu "authentication" +menuinit [ sleep 100 [ echo "checking..." ; authsetup passd $__loginpass authfinish; __loginpass = "" ] ] +menuitem "Please wait while we authenticate your game account..." -1 + +const authfinish [ + closecurmenu + if (authsetup) [ + echo "\f0authentication successful" + ] [ + echo "\f3authentication failed, please enter the correct password for your game account" + ] +] + +// try to authenticate the game account or offer to create a new game account if none exists +// set $arg1 to 1 to enable silent mode to prevent any user interactions +const checkaccount [ + if (authsetup) [] [ + if (authsetup needpass) [] [ + // load the password protected private key + exec private/authprivate.cfg + ] + if (authsetup needpass) [ + if (checkalias savedpass) [ + // try the saved password if there is one + authsetup passd $savedpass + ] [ + // saved password does not exist so ask for password + if (= $arg1 0) [ showmenu "enter password" ] + ] + ] [ + // game account does not seem to be set up, ask user to create new game account + if (= $arg1 0) [ showmenu "game account" ] + ] + ] +] diff --git a/config/menus_multiplayer.cfg b/config/menus_multiplayer.cfg index e9e7ebe1..30679127 100644 --- a/config/menus_multiplayer.cfg +++ b/config/menus_multiplayer.cfg @@ -172,7 +172,7 @@ menuitem [Join a LAN server] [ ifauthsetup joinlanservermenu ] menuitem [Custom connect] [ ifauthsetup customconnectmenu ] menuitem [Connect as Admin] [ ifauthsetup adminconnectmenu ] menuitem [] -1 -menuitem [Reset game account] [ showmenu [create game account] ] +menuitem [Reset game account] [ showmenu [Auth Setup] ] menuitem [Force serverlist update] [ updatefrommaster 1; ifauthsetup joinservermenu ] //// Main > Multiplayer > Custom connect //// @@ -330,83 +330,4 @@ menuinit [ menuitem "\f2 [ Download the servers map version and join the game ]" [ getmap ] menuitem "\f3 [ Keep the local map version and disconnect from the server ]" [ showmenu ""; disconnect ] menuinitselection 4 -] - -// game account management menus - -newmenu "game account" -menuitem "To play online you need to create a game account first." -1 -menuitem "" -1 -menuitem "\t\t\f0[Create game account]" [ closecurmenu; showmenu "create game account"; ] -menuitem "\t\t[Not now...]" closecurmenu - -newmenu "create game account" -menuinit [ tempalias ___ppass "" ; tempalias ___pass ""; tempalias ___rememberpass 0; ] -menuitemtextinput "Please enter a password for account restoration\t" "" [___ppass = $arg1] [] 64 -menuitemtextinput "Please enter a password for your game account\t" "" [___pass = $arg1] [] 64 -menuitem "" -1 -menuitemradio "Remember game account password: " 0 1 [ ] [ "No (recommended)" "Yes"] [ ___rememberpass = (= $arg1 1)] -menuitem "" -1 -menuitem "\t\t\f0[Ok]" [ - if (strcmp $___ppass "") [ menuselection (curmenu) 0; -1 ] [ - if (strcmp $___pass "") [ menuselection (curmenu) 1; -1 ] [ - authsetup genpre - authsetup genpriv - authsetup genpub - if (= $___rememberpass 1) [ alias savedpass $___pass ] [ if (checkalias savedpass) [ delalias savedpass ] ] - closecurmenu - showmenu "progress" - ] - ] -] - -newmenu "progress" -menuinit [ sleep 100 [ - authsetup newppass $___ppass - authsetup newpass $___pass - ___ppass = "" - ___pass = "" - if (authsetup) [ echo "\f0created game account" ] - closecurmenu - checkaccount - ] ] -menuitem "Please wait while we create your account..." -1 - -newmenu "enter password" -menuitemtextinput "please enter the password for your game account\t" "" [ __loginpass = $arg1; closecurmenu; showmenu authentication ] [] 64 1 - -newmenu "authentication" -menuinit [ sleep 100 [ echo "checking..." ; authsetup passd $__loginpass authfinish; __loginpass = "" ] ] -menuitem "Please wait while we authenticate your game account..." -1 - -const authfinish [ - closecurmenu - if (authsetup) [ - echo "\f0authentication successful" - ] [ - echo "\f3authentication failed, please enter the correct password for your game account" - ] -] - -// try to authenticate the game account or offer to create a new game account if none exists -// set $arg1 to 1 to enable silent mode to prevent any user interactions -const checkaccount [ - if (authsetup) [] [ - if (authsetup needpass) [] [ - // load the password protected private key - exec config/authprivate.cfg - ] - if (authsetup needpass) [ - if (checkalias savedpass) [ - // try the saved password if there is one - authsetup passd $savedpass - ] [ - // saved password does not exist so ask for password - if (= $arg1 0) [ showmenu "enter password" ] - ] - ] [ - // game account does not seem to be set up, ask user to create new game account - if (= $arg1 0) [ showmenu "game account" ] - ] - ] -] +] \ No newline at end of file diff --git a/config/menus_settings.cfg b/config/menus_settings.cfg index 45adf2bc..7bb075e5 100644 --- a/config/menus_settings.cfg +++ b/config/menus_settings.cfg @@ -706,8 +706,8 @@ menuitemslider "Graphics detail: " 1 6 "$gfxqualityalias" [Horrible Low Mediu menuitemslider "Sound detail: " 1 3 "$__soundquality" [Low Medium High] [ __set_sound_quality $arg1 ] menuitemslider "Field of view: " 75 120 "$fov" 2 [ fov $arg1 ] 1 menuitem "" -1 -menuitem "\f0\t\t\t [ OK; View FAQ ]" [ closecurmenu; resetgl; load_faq ; showmenu faq ] -menuitem "\f2\t\t\t [ OK ]" [ closecurmenu; resetgl ] +menuitem "\f0\t\t\t [ View FAQ ]" [ load_faq ; showmenu faq ] +menuitem "\f2\t\t\t [ OK ]" [ closecurmenu; resetgl; showmenu [Auth Setup] ] const new_gfx_quality [ if (= $arg1 6) [ // "INSANE!" gfx quality diff --git a/source/src/crypto.cpp b/source/src/crypto.cpp index ec0dfa2c..739d980e 100644 --- a/source/src/crypto.cpp +++ b/source/src/crypto.cpp @@ -922,8 +922,6 @@ void authsetup(char **args, int numargs) // set up private and public keys preprivpwdcfg = (iterations << 10) | authmemusage; xor_block(prepriv, keyhash, preprivlen); } - savepreprivkey(numargs > 2 && args[2][0] ? path(args[2]) : AUTHPREPRIVATECFGFILE - , prepriv, preprivlen, psalt, preprivpwdcfg); } } else if(!strcasecmp(args[0], "NEWPASS")) @@ -940,10 +938,19 @@ void authsetup(char **args, int numargs) // set up private and public keys privpwdcfg = (iterations << 10) | authmemusage; xor_block(priv, keyhash, 32); } - saveprivkey(numargs > 2 && args[2][0] ? path(args[2]) : AUTHPRIVATECFGFILE, - priv, keyhash + 32, salt, privpwdcfg); } } + else if(!strcasecmp(args[0], "SAVEPRIV")) + { + ed25519_pubkey_from_private(keyhash + 32, priv); + saveprivkey(numargs > 2 && args[2][0] ? path(args[2]) : AUTHPRIVATECFGFILE, + priv, keyhash + 32, salt, privpwdcfg); + } + else if(!strcasecmp(args[0], "SAVEPRE")) + { + savepreprivkey(numargs > 2 && args[2][0] ? path(args[2]) : AUTHPREPRIVATECFGFILE, + prepriv, preprivlen, psalt, preprivpwdcfg); + } #ifndef PRODUCTION else if(!strcasecmp(args[0], "UNARMED")) // FIXME: this is for testing purposes only - to test simultaneous logins from the same account - delete before release! { From a02a75eef2b9eb3e551ea861675651c6c211c408 Mon Sep 17 00:00:00 2001 From: RonaldReagan Date: Fri, 21 May 2021 15:05:54 -0600 Subject: [PATCH 13/17] #263 add setclipboardtext cubescript --- source/src/client.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/source/src/client.cpp b/source/src/client.cpp index 1a7e57a5..e157529f 100644 --- a/source/src/client.cpp +++ b/source/src/client.cpp @@ -753,3 +753,5 @@ COMMANDF(timestring, "", () }); COMMANDF(millis, "", () { intret(totalmillis); }); + +COMMANDN(setclipboardtext, SDL_SetClipboardText, "s"); From ed5477d94e90ed5e682757072cc840d3130f874b Mon Sep 17 00:00:00 2001 From: RonaldReagan Date: Fri, 21 May 2021 15:06:53 -0600 Subject: [PATCH 14/17] #263 Flesh out the auth menu system --- config/menus_auth.cfg | 71 ++++++++++++++++++++++++++++-------- config/menus_multiplayer.cfg | 2 +- config/menus_settings.cfg | 2 +- source/src/crypto.cpp | 5 +++ 4 files changed, 63 insertions(+), 17 deletions(-) diff --git a/config/menus_auth.cfg b/config/menus_auth.cfg index fb8476a1..868453ef 100644 --- a/config/menus_auth.cfg +++ b/config/menus_auth.cfg @@ -1,5 +1,5 @@ -newmenu [Auth Setup] +newmenu [auth setup] menuinit [ tempalias ___ppass "" ; tempalias ___pass ""; tempalias ___rememberpass 0; ] menuitem "To play online you need to create a game account which will be used" -1 menuitem "identify you to game servers. This identity is stored as a public/private" -1 @@ -17,29 +17,20 @@ menuitemtextinput "Password for your game account\t" "" [___pass = $arg1] [] 64 menuitemtextinput "Password for account restoration\t" "" [___ppass = $arg1] [] 64 menuitem "" -1 menuitemradio "Remember game account password: " 0 1 [ ] [ "No \f4(recommended)" "Yes"] [ ___rememberpass = (= $arg1 1)] -menuitem "\f2\t\t\t [ OK ]" [ - // if (strcmp $___ppass "") [ ___ppass = "unppass" ] [] - // if (strcmp $___pass "") [ ___pass = "unpass" ] [] +menuitem "\f2\t\t\t [ OK ]" [ authsetup genpre authsetup genpriv authsetup genpub if (= $___rememberpass 1) [ alias savedpass $___pass ] [ if (checkalias savedpass) [ delalias savedpass ] ] closecurmenu - showmenu "Auth Progress" + showmenu "auth setup progress" ] - -newmenu "game account" -menuitem "To play online you need to create a game account first." -1 -menuitem "" -1 -menuitem "\t\t\f0[Create game account]" [ closecurmenu; showmenu "Auth Setup"; ] -menuitem "\t\t[Not now...]" closecurmenu - -newmenu "Auth Progress" +newmenu "auth setup progress" menuinit [ sleep 100 [ - if (strcmp $___ppass "") [ authsetup savepre ] [ authsetup newppass $__ppass; authsetup savepre ] - if (strcmp $___pass "") [ authsetup savepriv ] [ authsetup newpass $___pass; authsetup savepriv ] + if (strcmp $___ppass "") [ authsetup savepre ] [ authsetup newppass $___ppass; authsetup savepre ] + if (strcmp $___pass "") [ authsetup savepriv ] [ authsetup newpass $___pass ] ___ppass = "" ___pass = "" if (authsetup) [ echo "\f0created game account" ] @@ -48,6 +39,56 @@ menuinit [ sleep 100 [ ] ] menuitem "Please wait while we create your account..." -1 + +newmenu [auth] +menuinit [ + resetcurmenu + + if (authsetup) [ + menuitem (format "\f0Pub key: \f5%1" (mypubkey)) -1 + menuitem "\f2[ Copy to clipboard ]" [setclipboardtext (mypubkey)] + menuitem "" -1 + menuitem "\f2[ Change password ]" [ showmenu [auth password change]] + menuitem "\f2[ Reset auth ]" [ showmenu [auth setup]] + ] [ + menuitem "\f3Auth not setup" -1 + menuitem "\f2[ Setup Auth ]" [ showmenu [auth setup] ] + ] +] + + +newmenu [auth password change] +menuinit [ tempalias ___pass ""; tempalias ___rememberpass 0; ] +menuitem "Please choose a new password for your private key" -1 +menuitem "" -1 +menuitemtextinput "Password for your game account\t" "" [___pass = $arg1] [] 64 +menuitemradio "Remember game account password: " 0 1 [ ] [ "No \f4(recommended)" "Yes"] [ ___rememberpass = (= $arg1 1)] +menuitem "\f2[ Set Password ]" [ + if (= $___rememberpass 1) [ alias savedpass $___pass ] [ if (checkalias savedpass) [ delalias savedpass ] ] + + closecurmenu + showmenu "auth password change progress" +] +menuitem "\f7[ Cancel ]" closecurmenu + +newmenu "auth password change progress" +menuinit [ sleep 100 [ + if (strcmp $___pass "") [ ] [ authsetup newpass $___pass ] + ___pass = "" + if (authsetup) [ echo "\f0updated game account" ] + closecurmenu + checkaccount + ] ] +menuitem "Please wait while we update your account..." -1 + + +newmenu "game account" +menuitem "To play online you need to create a game account first." -1 +menuitem "" -1 +menuitem "\t\t\f0[Create game account]" [ closecurmenu; showmenu "auth setup"; ] +menuitem "\t\t[Not now...]" closecurmenu + + newmenu "enter password" menuitemtextinput "please enter the password for your game account\t" "" [ __loginpass = $arg1; closecurmenu; showmenu authentication ] [] 64 1 diff --git a/config/menus_multiplayer.cfg b/config/menus_multiplayer.cfg index 30679127..9d0a6c44 100644 --- a/config/menus_multiplayer.cfg +++ b/config/menus_multiplayer.cfg @@ -172,7 +172,7 @@ menuitem [Join a LAN server] [ ifauthsetup joinlanservermenu ] menuitem [Custom connect] [ ifauthsetup customconnectmenu ] menuitem [Connect as Admin] [ ifauthsetup adminconnectmenu ] menuitem [] -1 -menuitem [Reset game account] [ showmenu [Auth Setup] ] +menuitem [Auth settings] [ showmenu [auth] ] menuitem [Force serverlist update] [ updatefrommaster 1; ifauthsetup joinservermenu ] //// Main > Multiplayer > Custom connect //// diff --git a/config/menus_settings.cfg b/config/menus_settings.cfg index 7bb075e5..7ae9f580 100644 --- a/config/menus_settings.cfg +++ b/config/menus_settings.cfg @@ -707,7 +707,7 @@ menuitemslider "Sound detail: " 1 3 "$__soundquality" [Low Medium High] [ __s menuitemslider "Field of view: " 75 120 "$fov" 2 [ fov $arg1 ] 1 menuitem "" -1 menuitem "\f0\t\t\t [ View FAQ ]" [ load_faq ; showmenu faq ] -menuitem "\f2\t\t\t [ OK ]" [ closecurmenu; resetgl; showmenu [Auth Setup] ] +menuitem "\f2\t\t\t [ OK ]" [ closecurmenu; resetgl; showmenu [auth setup] ] const new_gfx_quality [ if (= $arg1 6) [ // "INSANE!" gfx quality diff --git a/source/src/crypto.cpp b/source/src/crypto.cpp index 739d980e..20fbe57a 100644 --- a/source/src/crypto.cpp +++ b/source/src/crypto.cpp @@ -923,6 +923,9 @@ void authsetup(char **args, int numargs) // set up private and public keys xor_block(prepriv, keyhash, preprivlen); } } + + savepreprivkey(numargs > 2 && args[2][0] ? path(args[2]) : AUTHPREPRIVATECFGFILE, + prepriv, preprivlen, psalt, preprivpwdcfg); } else if(!strcasecmp(args[0], "NEWPASS")) { @@ -938,6 +941,8 @@ void authsetup(char **args, int numargs) // set up private and public keys privpwdcfg = (iterations << 10) | authmemusage; xor_block(priv, keyhash, 32); } + saveprivkey(numargs > 2 && args[2][0] ? path(args[2]) : AUTHPRIVATECFGFILE, + priv, keyhash + 32, salt, privpwdcfg); } } else if(!strcasecmp(args[0], "SAVEPRIV")) From 15637569470c0758fe1643451e22448289b10f49 Mon Sep 17 00:00:00 2001 From: RonaldReagan Date: Fri, 21 May 2021 15:38:19 -0600 Subject: [PATCH 15/17] #263 Clean up auth menu system a little bit --- config/autostart/checkaccount.cfg | 2 +- config/menus_auth.cfg | 52 +++++++++++++++++++++---------- 2 files changed, 36 insertions(+), 18 deletions(-) diff --git a/config/autostart/checkaccount.cfg b/config/autostart/checkaccount.cfg index ad4d5964..6be90d44 100644 --- a/config/autostart/checkaccount.cfg +++ b/config/autostart/checkaccount.cfg @@ -1,5 +1,5 @@ // try to authenticate game account during startup in silent mode so that users with saved passwords are authenticated asap -sleep 1000 [ checkaccount 1 ] +sleep 100 [ checkaccount 1 ] sleep 1000 [ echo "\fs\f3Beware: This is an ALPHA version of AssaultCube v1.3" diff --git a/config/menus_auth.cfg b/config/menus_auth.cfg index 868453ef..e8e87ea2 100644 --- a/config/menus_auth.cfg +++ b/config/menus_auth.cfg @@ -39,23 +39,6 @@ menuinit [ sleep 100 [ ] ] menuitem "Please wait while we create your account..." -1 - -newmenu [auth] -menuinit [ - resetcurmenu - - if (authsetup) [ - menuitem (format "\f0Pub key: \f5%1" (mypubkey)) -1 - menuitem "\f2[ Copy to clipboard ]" [setclipboardtext (mypubkey)] - menuitem "" -1 - menuitem "\f2[ Change password ]" [ showmenu [auth password change]] - menuitem "\f2[ Reset auth ]" [ showmenu [auth setup]] - ] [ - menuitem "\f3Auth not setup" -1 - menuitem "\f2[ Setup Auth ]" [ showmenu [auth setup] ] - ] -] - newmenu [auth password change] menuinit [ tempalias ___pass ""; tempalias ___rememberpass 0; ] @@ -81,6 +64,41 @@ menuinit [ sleep 100 [ ] ] menuitem "Please wait while we update your account..." -1 + +newmenu [auth] +menuinit [ + resetcurmenu + + tempalias ___pass ""; tempalias ___rememberpass 0; + + if (authsetup) [ + menuitem "\f0Pub key:" -1 + menuitem (format "\fY%1" (mypubkey)) -1 + menuitem "\f2[ Copy to clipboard ]" [setclipboardtext (mypubkey)] + menuitem "" -1 + menuitem "\f0Change Password" -1 + menuitemtextinput "New password" "" [___pass = $arg1] [] 64 + menuitemradio "Remember game account password: " 0 1 [ ] [ "No \f4(recommended)" "Yes"] [ ___rememberpass = (= $arg1 1)] + menuitem "\f2[ Update Password ]" [ + if (= $___rememberpass 1) [ alias savedpass $___pass ] [ if (checkalias savedpass) [ delalias savedpass ] ] + + closecurmenu + showmenu "auth password change progress" + ] + menuitem "" -1 + menuitem "\f3[ Reset auth ]" [ showmenu [auth setup]] + ] [ + if (authsetup needpass) [ + menuitem "\f3Password required to authenticate \f2[ Enter password ]" [ showmenu [enter password]] + menuitem "" -1 + menuitem "\f3[ Reset Auth ]" [ showmenu [auth setup] ] + ] [ + menuitem "\f3Auth not setup" -1 + menuitem "\f2[ Setup Auth ]" [ showmenu [auth setup] ] + ] + ] +] + newmenu "game account" menuitem "To play online you need to create a game account first." -1 From c25aebbd9fbfb7fe79180e30d5815b2a83f26606 Mon Sep 17 00:00:00 2001 From: RonaldReagan Date: Fri, 21 May 2021 20:39:41 -0600 Subject: [PATCH 16/17] Fix arg for authset savepriv/savepre --- source/src/crypto.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/src/crypto.cpp b/source/src/crypto.cpp index 20fbe57a..039a21b9 100644 --- a/source/src/crypto.cpp +++ b/source/src/crypto.cpp @@ -948,12 +948,12 @@ void authsetup(char **args, int numargs) // set up private and public keys else if(!strcasecmp(args[0], "SAVEPRIV")) { ed25519_pubkey_from_private(keyhash + 32, priv); - saveprivkey(numargs > 2 && args[2][0] ? path(args[2]) : AUTHPRIVATECFGFILE, + saveprivkey(numargs > 1 && args[1][0] ? path(args[1]) : AUTHPRIVATECFGFILE, priv, keyhash + 32, salt, privpwdcfg); } else if(!strcasecmp(args[0], "SAVEPRE")) { - savepreprivkey(numargs > 2 && args[2][0] ? path(args[2]) : AUTHPREPRIVATECFGFILE, + savepreprivkey(numargs > 1 && args[1][0] ? path(args[1 ]) : AUTHPREPRIVATECFGFILE, prepriv, preprivlen, psalt, preprivpwdcfg); } #ifndef PRODUCTION From ed20f09b1274a379702e1a9ccd05f6828671974e Mon Sep 17 00:00:00 2001 From: RonaldReagan Date: Fri, 21 May 2021 20:40:17 -0600 Subject: [PATCH 17/17] Cubescript documentation update for authsetup and setclipboardtext --- docs/reference.xml | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/docs/reference.xml b/docs/reference.xml index 5e77b9e1..30aad75f 100644 --- a/docs/reference.xml +++ b/docs/reference.xml @@ -1728,7 +1728,11 @@ name="AssaultCube Documentation" version="Current" xsi:schemaLocation="xml/cuber
This section describes general identifiers. - + + + + + Toggle for taking an automatic screenshot during intermission. @@ -10212,7 +10216,7 @@ name="AssaultCube Documentation" version="Current" xsi:schemaLocation="xml/cuber and to lock and unlock the private key with a password. - Private and public keys are used to authenticate the player to servers, and are loaded from config/authprivate.cfg. + Private and public keys are used to authenticate the player to servers, and are loaded from private/authprivate.cfg. Private keys can be stored in an "encrypted with password" version - in which case the player has to enter the password after game start. To prevent brute-force cracking of the password, the key-derivation function uses a constant time to encode (usually several seconds). Because of that, the decoding at game start can be done @@ -10241,17 +10245,19 @@ name="AssaultCube Documentation" version="Current" xsi:schemaLocation="xml/cuber "authsetup genpre [prelen]" - generates new prepriv key. "authsetup genpriv" - generates private key from prepriv key. "authsetup genpub" - generates public key from private key. + "authsetup savepre [preprivfilename]" - saves the prepriv key. The default filename is private/authpreprivate.cfg + "authsetup savepre [privatefilename]" - saves the private key. The default filename is private/authprivate.cfg "authsetup newppass preprivpass [preprivfilename]" - encrypts prepriv key with new password and saves the result to file. - The default filename is config/authpreprivate.cfg and an existing file gets overwritten - but the former file + The default filename is private/authpreprivate.cfg and an existing file gets overwritten - but the former file content is kept and also written, each line commented out. "authsetup newpass privpass [privatefilename]" - encrypts private key with new password and saves the encrypted - private key and the public key to file. The default filename is config/authprivate.cfg and an existing file + private key and the public key to file. The default filename is private/authprivate.cfg and an existing file gets overwritten - but the former file content is kept and also written, each line commented out. - "authsetup unarmed" - sets private and public keys to a fixed value. For testing only. Can be used to "log out". + "authsetup unarmed" - sets private and public keys to a fixed value. For testing only. Can be used to "log out". Only available in development versions of the game ---------- "authmemusage", "authrounds", "authmaxtime" are only used, when new passwords are created (authsetup new[p]pass).