diff --git a/sql/ckdb.sql b/sql/ckdb.sql index a14896e9..5774ef4f 100644 --- a/sql/ckdb.sql +++ b/sql/ckdb.sql @@ -21,6 +21,8 @@ CREATE TABLE users ( passwordhash character varying(256) NOT NULL, secondaryuserid character varying(64) NOT NULL, salt character varying(256) DEFAULT ''::character varying NOT NULL, + userdata text DEFAULT ''::text NOT NULL, + userbits bigint NOT NULL, createdate timestamp with time zone NOT NULL, createby character varying(64) DEFAULT ''::character varying NOT NULL, createcode character varying(128) DEFAULT ''::character varying NOT NULL, @@ -57,6 +59,7 @@ CREATE TABLE workers ( difficultydefault integer DEFAULT 0 NOT NULL, -- 0 means default idlenotificationenabled char DEFAULT 'n'::character varying NOT NULL, idlenotificationtime integer DEFAULT 10 NOT NULL, + workerbits bigint NOT NULL, createdate timestamp with time zone NOT NULL, createby character varying(64) DEFAULT ''::character varying NOT NULL, createcode character varying(128) DEFAULT ''::character varying NOT NULL, diff --git a/sql/v1.0.0-v1.0.1.sql b/sql/v1.0.0-v1.0.1.sql new file mode 100644 index 00000000..1fa009a6 --- /dev/null +++ b/sql/v1.0.0-v1.0.1.sql @@ -0,0 +1,38 @@ +SET SESSION AUTHORIZATION 'postgres'; + +BEGIN transaction; + +DO $$ +DECLARE ver TEXT; +BEGIN + + UPDATE version set version='1.0.1' where vlock=1 and version='1.0.0'; + + IF found THEN + RETURN; + END IF; + + SELECT version into ver from version + WHERE vlock=1; + + RAISE EXCEPTION 'Wrong DB version - expect "1.0.0" - found "%"', ver; + +END $$; + +ALTER TABLE ONLY users + ADD COLUMN userdata text DEFAULT ''::text NOT NULL, + ADD COLUMN userbits bigint NOT NULL DEFAULT 0; + +ALTER TABLE ONLY users + ALTER COLUMN userbits DROP DEFAULT; + +-- match based on ckdb_data.c like_address() +UPDATE users set userbits=1 where username ~ '[13][A-HJ-NP-Za-km-z1-9]{15,}'; + +ALTER TABLE ONLY workers + ADD COLUMN workerbits bigint NOT NULL DEFAULT 0; + +ALTER TABLE ONLY workers + ALTER COLUMN workerbits DROP DEFAULT; + +END transaction; diff --git a/src/ckdb.h b/src/ckdb.h index b3feaaa7..80b95f7b 100644 --- a/src/ckdb.h +++ b/src/ckdb.h @@ -54,7 +54,7 @@ */ #define DB_VLOCK "1" -#define DB_VERSION "1.0.0" +#define DB_VERSION "1.0.1" #define CKDB_VERSION DB_VERSION"-1.120" #define WHERE_FFL " - from %s %s() line %d" @@ -1017,6 +1017,9 @@ typedef struct users { char passwordhash[TXT_BIG+1]; char secondaryuserid[TXT_SML+1]; char salt[TXT_BIG+1]; + char *userdata; + int64_t databits; // non-DB field, Bitmask of userdata content + int64_t userbits; // Bitmask of user attributes HISTORYDATECONTROLFIELDS; } USERS; @@ -1031,6 +1034,19 @@ typedef struct users { #define SALTSIZHEX 32 #define SALTSIZBIN 16 +#define DATABITS_SEP ',' +#define DATABITS_SEP_STR "," + +// databits attributes +// These are generated at dbload time from userdata +// Google Auth 2FA +#define USER_GOOGLEAUTH_NAME "gauth" +#define USER_GOOGLEAUTH 0x1 + +// userbits attributes +// Address account, not a username account +#define USER_ADDRESS 0x1 + extern K_TREE *users_root; extern K_TREE *userid_root; extern K_LIST *users_free; @@ -1073,6 +1089,7 @@ typedef struct workers { int32_t difficultydefault; char idlenotificationenabled[TXT_FLAG+1]; int32_t idlenotificationtime; + int64_t workerbits; // Bitmask of worker attributes HISTORYDATECONTROLFIELDS; } WORKERS; @@ -1086,6 +1103,8 @@ extern K_TREE *workers_root; extern K_LIST *workers_free; extern K_STORE *workers_store; +// Currently no workerbits attributes + #define DIFFICULTYDEFAULT_MIN 10 #define DIFFICULTYDEFAULT_MAX 0x7fffffff // 0 means it's not set @@ -2299,8 +2318,8 @@ extern bool users_update(PGconn *conn, K_ITEM *u_item, char *oldhash, char *newhash, char *email, char *by, char *code, char *inet, tv_t *cd, K_TREE *trf_root, char *status); extern K_ITEM *users_add(PGconn *conn, char *username, char *emailaddress, - char *passwordhash, char *by, char *code, char *inet, - tv_t *cd, K_TREE *trf_root); + char *passwordhash, int64_t userbits, char *by, + char *code, char *inet, tv_t *cd, K_TREE *trf_root); extern bool users_fill(PGconn *conn); extern bool useratts_item_add(PGconn *conn, K_ITEM *ua_item, tv_t *cd, bool begun); extern K_ITEM *useratts_add(PGconn *conn, char *username, char *attname, diff --git a/src/ckdb_cmd.c b/src/ckdb_cmd.c index c7b4565a..7bf914d3 100644 --- a/src/ckdb_cmd.c +++ b/src/ckdb_cmd.c @@ -67,7 +67,7 @@ static char *cmd_adduser(PGconn *conn, char *cmd, char *id, tv_t *now, char *by, u_item = users_add(conn, transfer_data(i_username), transfer_data(i_emailaddress), - transfer_data(i_passwordhash), + transfer_data(i_passwordhash), 0, by, code, inet, now, trf_root); } @@ -2476,7 +2476,7 @@ static char *cmd_auth_do(PGconn *conn, char *cmd, char *id, char *by, if (!u_item) { DATA_OPTIONCONTROL(optioncontrol, oc_item); u_item = users_add(conn, username, EMPTY, - optioncontrol->optionvalue, + optioncontrol->optionvalue, 0, by, code, inet, cd, trf_root); } } diff --git a/src/ckdb_data.c b/src/ckdb_data.c index cc5ca7b5..c3f596d1 100644 --- a/src/ckdb_data.c +++ b/src/ckdb_data.c @@ -2971,7 +2971,7 @@ double payout_stats(PAYOUTS *payouts, char *statname) pos += len+1; // They should only contain +ve numbers if (*pos && isdigit(*pos)) { - tab = strchr(pos, '\t'); + tab = strchr(pos, FLDSEP); if (!tab) numlen = strlen(pos); else @@ -2984,7 +2984,7 @@ double payout_stats(PAYOUTS *payouts, char *statname) } break; } - pos = strchr(pos, '\t'); + pos = strchr(pos, FLDSEP); if (pos) pos++; } diff --git a/src/ckdb_dbio.c b/src/ckdb_dbio.c index a0ea1bc5..775583ed 100644 --- a/src/ckdb_dbio.c +++ b/src/ckdb_dbio.c @@ -527,8 +527,8 @@ unparam: } K_ITEM *users_add(PGconn *conn, char *username, char *emailaddress, - char *passwordhash, char *by, char *code, char *inet, - tv_t *cd, K_TREE *trf_root) + char *passwordhash, int64_t userbits, char *by, + char *code, char *inet, tv_t *cd, K_TREE *trf_root) { ExecStatusType rescode; bool conned = false; @@ -540,7 +540,7 @@ K_ITEM *users_add(PGconn *conn, char *username, char *emailaddress, uint64_t hash; __maybe_unused uint64_t tmp; bool dup, ok = false; - char *params[8 + HISTORYDATECOUNT]; + char *params[10 + HISTORYDATECOUNT]; int n, par = 0; LOGDEBUG("%s(): add", __func__); @@ -592,6 +592,9 @@ K_ITEM *users_add(PGconn *conn, char *username, char *emailaddress, row->passwordhash, sizeof(row->passwordhash)); } + row->userdata = EMPTY; + row->userbits = userbits; + HISTORYDATEINIT(row, cd, by, code, inet); HISTORYDATETRANSFER(trf_root, row); @@ -608,13 +611,15 @@ K_ITEM *users_add(PGconn *conn, char *username, char *emailaddress, params[par++] = str_to_buf(row->passwordhash, NULL, 0); params[par++] = str_to_buf(row->secondaryuserid, NULL, 0); params[par++] = str_to_buf(row->salt, NULL, 0); + params[par++] = str_to_buf(row->userdata, NULL, 0); + params[par++] = bigint_to_buf(row->userbits, NULL, 0); HISTORYDATEPARAMS(params, par, row); PARCHK(par, params); ins = "insert into users " "(userid,username,status,emailaddress,joineddate,passwordhash," - "secondaryuserid,salt" - HISTORYDATECONTROL ") values (" PQPARAM13 ")"; + "secondaryuserid,salt,userdata,userbits" + HISTORYDATECONTROL ") values (" PQPARAM15 ")"; if (!conn) { conn = dbconnect(); @@ -652,6 +657,26 @@ unitem: return NULL; } +static void users_checkfor(USERS *row, char *name, int64_t bits) +{ + char *ptr; + + ptr = strstr(row->userdata, name); + if (ptr) { + size_t len = strlen(name); + if ((ptr == row->userdata || *(ptr-1) == DATABITS_SEP) && + *(ptr+len) == '=') { + row->databits |= bits; + } + } +} + +static void users_databits(USERS *row) +{ + if (row->userdata && *(row->userdata)) + users_checkfor(row, USER_GOOGLEAUTH_NAME, USER_GOOGLEAUTH); +} + bool users_fill(PGconn *conn) { ExecStatusType rescode; @@ -661,14 +686,14 @@ bool users_fill(PGconn *conn) USERS *row; char *field; char *sel; - int fields = 8; + int fields = 10; bool ok; LOGDEBUG("%s(): select", __func__); sel = "select " "userid,username,status,emailaddress,joineddate," - "passwordhash,secondaryuserid,salt" + "passwordhash,secondaryuserid,salt,userdata,userbits" HISTORYDATECONTROL " from users"; res = PQexec(conn, sel, CKPQ_READ); @@ -741,6 +766,18 @@ bool users_fill(PGconn *conn) break; TXT_TO_STR("salt", field, row->salt); + PQ_GET_FLD(res, i, "userdata", field, ok); + if (!ok) + break; + TXT_TO_PTR("userdata", field, row->userdata); + LIST_MEM_ADD(users_free, row->userdata); + users_databits(row); + + PQ_GET_FLD(res, i, "userbits", field, ok); + if (!ok) + break; + TXT_TO_BIGINT("userbits", field, row->userbits); + HISTORYDATEFLDS(res, i, row, ok); if (!ok) break; @@ -1159,7 +1196,7 @@ K_ITEM *workers_add(PGconn *conn, int64_t userid, char *workername, K_ITEM *item, *ret = NULL; WORKERS *row; char *ins; - char *params[6 + HISTORYDATECOUNT]; + char *params[7 + HISTORYDATECOUNT]; int n, par = 0; int32_t diffdef; int32_t nottime; @@ -1222,6 +1259,8 @@ K_ITEM *workers_add(PGconn *conn, int64_t userid, char *workername, if (row->idlenotificationtime == IDLENOTIFICATIONTIME_DEF) row->idlenotificationenabled[0] = IDLENOTIFICATIONDISABLED[0]; + row->workerbits = 0; + HISTORYDATEINIT(row, cd, by, code, inet); HISTORYDATETRANSFER(trf_root, row); @@ -1232,13 +1271,14 @@ K_ITEM *workers_add(PGconn *conn, int64_t userid, char *workername, params[par++] = int_to_buf(row->difficultydefault, NULL, 0); params[par++] = str_to_buf(row->idlenotificationenabled, NULL, 0); params[par++] = int_to_buf(row->idlenotificationtime, NULL, 0); + params[par++] = bigint_to_buf(row->workerbits, NULL, 0); HISTORYDATEPARAMS(params, par, row); PARCHK(par, params); ins = "insert into workers " "(workerid,userid,workername,difficultydefault," - "idlenotificationenabled,idlenotificationtime" - HISTORYDATECONTROL ") values (" PQPARAM11 ")"; + "idlenotificationenabled,idlenotificationtime,workerbits" + HISTORYDATECONTROL ") values (" PQPARAM12 ")"; res = PQexecParams(conn, ins, par, NULL, (const char **)params, NULL, NULL, 0, CKPQ_WRITE); rescode = PQresultStatus(res); @@ -1371,8 +1411,8 @@ bool workers_update(PGconn *conn, K_ITEM *item, char *difficultydefault, ins = "insert into workers " "(workerid,userid,workername,difficultydefault," - "idlenotificationenabled,idlenotificationtime" - HISTORYDATECONTROL ") values (" PQPARAM11 ")"; + "idlenotificationenabled,idlenotificationtime,workerbits" + HISTORYDATECONTROL ") values (" PQPARAM12 ")"; par = 0; params[par++] = bigint_to_buf(row->workerid, NULL, 0); @@ -1381,6 +1421,7 @@ bool workers_update(PGconn *conn, K_ITEM *item, char *difficultydefault, params[par++] = int_to_buf(row->difficultydefault, NULL, 0); params[par++] = str_to_buf(row->idlenotificationenabled, NULL, 0); params[par++] = int_to_buf(row->idlenotificationtime, NULL, 0); + params[par++] = bigint_to_buf(row->workerbits, NULL, 0); HISTORYDATEPARAMS(params, par, row); PARCHK(par, params); @@ -1418,14 +1459,14 @@ bool workers_fill(PGconn *conn) WORKERS *row; char *field; char *sel; - int fields = 6; + int fields = 7; bool ok; LOGDEBUG("%s(): select", __func__); sel = "select " "userid,workername,difficultydefault," - "idlenotificationenabled,idlenotificationtime" + "idlenotificationenabled,idlenotificationtime,workerbits" HISTORYDATECONTROL ",workerid from workers"; res = PQexec(conn, sel, CKPQ_READ); @@ -1483,6 +1524,11 @@ bool workers_fill(PGconn *conn) break; TXT_TO_INT("idlenotificationtime", field, row->idlenotificationtime); + PQ_GET_FLD(res, i, "workerbits", field, ok); + if (!ok) + break; + TXT_TO_BIGINT("workerbits", field, row->workerbits); + HISTORYDATEFLDS(res, i, row, ok); if (!ok) break; @@ -5495,7 +5541,8 @@ bool auths_add(PGconn *conn, char *poolinstance, char *username, if (!u_item) { if (addressuser) { u_item = users_add(conn, username, EMPTY, EMPTY, - by, code, inet, cd, trf_root); + USER_ADDRESS, by, code, inet, cd, + trf_root); } else { LOGDEBUG("%s(): unknown user '%s'", __func__,