From f17591b1ad5fb7c525d4cab302d27f809cde8029 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Anton=20Luka=20=C5=A0ijanec?= Date: Tue, 17 May 2022 14:15:41 +0200 Subject: nekaj --- prijave.c | 104 ++++++++++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 85 insertions(+), 19 deletions(-) (limited to 'prijave.c') diff --git a/prijave.c b/prijave.c index c9edb56..8a9b3f0 100644 --- a/prijave.c +++ b/prijave.c @@ -41,7 +41,9 @@ enum action { NO_ACTION, CREATE_POLL, FIND_POLLS, - MODIFY_POLL + MODIFY_POLL, + DELETE_POLL, + ADD_QUESTION }; struct request { struct MHD_PostProcessor * post_processor; @@ -59,6 +61,8 @@ static enum MHD_Result iterator (void * userdata, enum MHD_ValueKind kind __attr ACTION_TRANSLATION("cp", CREATE_POLL); ACTION_TRANSLATION("fp", FIND_POLLS); ACTION_TRANSLATION("mp", MODIFY_POLL); + ACTION_TRANSLATION("dp", DELETE_POLL); + ACTION_TRANSLATION("aq", ADD_QUESTION); #define OBTAIN_PARAMETER(name) \ if (!strcmp(key, STR(name))) { \ if (request->name) { \ @@ -104,7 +108,9 @@ static char * options (sqlite3 * db, sqlite3_int64 id, int poll_admin, enum ques // id obrazca, ime obrazca, število vprašanj v stolpcu // SELECT polls.rowid, polls.name, COUNT(*) FROM polls INNER JOIN questions ON questions.poll = polls.rowid GROUP BY questions.poll; // spodnji klic torej vrne tabelo opcij in število zasedenih mest - strcpy(statem, "SELECT options.rowid, options.text, options.max, COUNT(*) FROM options INNER JOIN responses ON responses.answer=options.rowid GROUP BY responses.answer WHERE options.question=:i"); + // see TODO#1 + // strcpy(statem, "SELECT options.rowid, options.text, options.max, COUNT(*) FROM options INNER JOIN responses ON responses.answer=options.rowid GROUP BY responses.answer WHERE options.question=:i"); + strcpy(statem, "SELECT rowid, text, max FROM options WHERE question=:i;"); if ((ret = sqlite3_prepare_v3(db, statem, -1, 0, &stmt, NULL)) != SQLITE_OK) return hscf(db_error(db, "options prepare", ret, stmt, statem)); if ((ret = sqlite3_bind_int64(stmt, sqlite3_bind_parameter_index(stmt, ":i"), id)) != SQLITE_OK) @@ -114,7 +120,7 @@ static char * options (sqlite3 * db, sqlite3_int64 id, int poll_admin, enum ques long long int rowid = sqlite3_column_int64(stmt, 0); char * text = htmlspecialchars((const char *) sqlite3_column_text(stmt, 1)); int max = sqlite3_column_int(stmt, 2); - int responses = sqlite3_column_int(stmt, 3); + // int responses = sqlite3_column_int(stmt, 3); char * old = response; response = realloc(response, (strlen(text ? text : "")+2048)*2); if (!response) { @@ -124,7 +130,7 @@ static char * options (sqlite3 * db, sqlite3_int64 id, int poll_admin, enum ques return strdup("[err @ options] oom"); } if (poll_admin) - sprintf(response+strlen(response), "




  • število odgovorov: %d
  • ", rowid, text ? text : "", max, responses); + sprintf(response+strlen(response), "



  • ", rowid, text ? text : "", max); else sprintf(response+strlen(response), "not implemented"); free(text); @@ -140,7 +146,9 @@ static char * questions (sqlite3 * db, sqlite3_int64 id, int poll_admin) { int ret; char statem[2048]; sqlite3_stmt * stmt; - strcpy(statem, "SELECT questions.rowid, questions.text, questions.type, COUNT(*) FROM questions INNER JOIN responses ON responses.question=questions.rowid WHERE questions.poll=:i GROUP BY responses.question"); + // TODO#1: fix number of responses: this does not work if there are no responses for a question. I could use LEFT OUTER JOIN but then NULLs are treated as same value + // strcpy(statem, "SELECT questions.rowid, questions.text, questions.type, COUNT(*) FROM questions INNER JOIN responses ON responses.question=questions.rowid WHERE questions.poll=:i GROUP BY responses.question"); + strcpy(statem, "SELECT rowid, text, type FROM questions WHERE poll=:i"); if ((ret = sqlite3_prepare_v3(db, statem, -1, 0, &stmt, NULL)) != SQLITE_OK) return hscf(db_error(db, "questions prepare", ret, stmt, statem)); if ((ret = sqlite3_bind_int64(stmt, sqlite3_bind_parameter_index(stmt, ":i"), id)) != SQLITE_OK) @@ -150,7 +158,7 @@ static char * questions (sqlite3 * db, sqlite3_int64 id, int poll_admin) { long long int rowid = sqlite3_column_int64(stmt, 0); char * text = htmlspecialchars((const char *) sqlite3_column_text(stmt, 1)); enum question type = sqlite3_column_int(stmt, 2); - int responses = sqlite3_column_int(stmt, 3); + // int responses = sqlite3_column_int(stmt, 3); char * opts = options(db, id, poll_admin, type); char * old = response; response = realloc(response, (strlen(response ? response : "")+strlen(text ? text : "")+strlen(opts ? opts : "")+2048)*2); @@ -162,7 +170,7 @@ static char * questions (sqlite3 * db, sqlite3_int64 id, int poll_admin) { return strdup("[err @ questions] oom"); } if (poll_admin) - sprintf(response+strlen(response), "


  • ", rowid, text ? text : "", responses, opts ? "

    možnosti

    " : "", opts ? opts : ""); + sprintf(response+strlen(response), "


  • ", rowid, text ? text : "", opts ? "

    možnosti

    " : "", opts ? opts : ""); else sprintf(response+strlen(response), "not implemented"); free(opts); @@ -175,6 +183,24 @@ static char * questions (sqlite3 * db, sqlite3_int64 id, int poll_admin) { } return response; } +static char * auth (struct prijave * prijave, const char * pass, long long int id) { + int ret; + char statem[2048]; + if (pass && prijave->pass && !strcmp(pass, prijave->pass)) + return NULL; // system admin password authentication + sqlite3_stmt * stmt; + strcpy(statem, "SELECT rowid FROM polls WHERE rowid=:i AND password=:pw;"); + if ((ret = sqlite3_prepare_v3(prijave->db, statem, -1, 0, &stmt, NULL)) != SQLITE_OK) + return db_error(prijave->db, "502: auth prepare", ret, stmt, statem); + if ((ret = sqlite3_bind_int64(stmt, sqlite3_bind_parameter_index(stmt, ":i"), id)) != SQLITE_OK) + return db_error(prijave->db, "502: auth bind_int64 id", ret, stmt, statem); + if ((ret = sqlite3_bind_text(stmt, sqlite3_bind_parameter_index(stmt, ":pw"), pass, -1, SQLITE_STATIC)) != SQLITE_OK) + return db_error(prijave->db, "502: auth bind_text password", ret, stmt, statem); + if ((ret = sqlite3_step(stmt)) != SQLITE_ROW) + return db_error(prijave->db, "403: auth step", ret, stmt, statem); + sqlite3_finalize(stmt); + return NULL; +} // returns an error string that must be freed on error or NULL on success static enum MHD_Result httpd (void * userdata, struct MHD_Connection * connection, const char * path, const char * meth, const char * ver __attribute__((unused)), const char * upload, size_t * upload_size, void ** cls) { struct prijave * prijave = (struct prijave *) userdata; char * response = prijave->hp ? prijave->hp : "HTTP 502: httpd !prijave->hp\n"; @@ -295,32 +321,28 @@ static enum MHD_Result httpd (void * userdata, struct MHD_Connection * connectio goto r; } strcpy(statem, "INSERT INTO polls (password, name, description) VALUES (:pw, :n, :d);"); - ret = sqlite3_prepare_v3(prijave->db, statem, -1, 0, &stmt, NULL); - if (ret != SQLITE_OK) { + if ((ret = sqlite3_prepare_v3(prijave->db, statem, -1, 0, &stmt, NULL)) != SQLITE_OK) { free(response); RETURN_ERROR("CREATE_POLL prepare"); } - ret = sqlite3_bind_text(stmt, sqlite3_bind_parameter_index(stmt, ":pw"), request->pp, -1, SQLITE_STATIC); - if (ret != SQLITE_OK) { + if ((ret = sqlite3_bind_text(stmt, sqlite3_bind_parameter_index(stmt, ":pw"), request->pp, -1, SQLITE_STATIC)) != SQLITE_OK) { free(response); RETURN_ERROR("CREATE_POLL bind_text password"); } - ret = sqlite3_bind_text(stmt, sqlite3_bind_parameter_index(stmt, ":n"), request->pn, -1, SQLITE_STATIC); - if (ret != SQLITE_OK) { + if ((ret = sqlite3_bind_text(stmt, sqlite3_bind_parameter_index(stmt, ":n"), request->pn, -1, SQLITE_STATIC)) != SQLITE_OK) { free(response); RETURN_ERROR("CREATE_POLL bind_text name"); } - ret = sqlite3_bind_text(stmt, sqlite3_bind_parameter_index(stmt, ":d"), request->pd, -1, SQLITE_STATIC); - if (ret != SQLITE_OK) { + if ((ret = sqlite3_bind_text(stmt, sqlite3_bind_parameter_index(stmt, ":d"), request->pd, -1, SQLITE_STATIC)) != SQLITE_OK) { free(response); RETURN_ERROR("CREATE_POLL bind_text description"); } - ret = sqlite3_step(stmt); - sqlite3_finalize(stmt); - if (ret != SQLITE_DONE) { + if ((ret = sqlite3_step(stmt)) != SQLITE_DONE) { + sqlite3_finalize(stmt); free(response); RETURN_ERROR("CREATE_POLL step"); } + sqlite3_finalize(stmt); status_code = MHD_HTTP_SEE_OTHER; rmm = MHD_RESPMEM_MUST_FREE; // THREADSAFE: the following call to sqlite3_last_insert_rowid is racy. it's not a security issue, but if another poll is created before sqlite3_last_insert_rowid is called, the client gets a faulty id that will not work, though he can still solve the problem by using FIND_POLLS. @@ -418,7 +440,51 @@ static enum MHD_Result httpd (void * userdata, struct MHD_Connection * connectio sqlite3_finalize(stmt); response = "HTTP 201: MODIFY_POLL\n"; goto r; - + case DELETE_POLL: + strcpy(statem, "DELETE FROM polls WHERE rowid=:i AND (password=:pw OR 1="); + if (prijave->pass && pass && !strcmp(prijave->pass, pass)) + strcat(statem, "1)"); + else + strcat(statem, "0)"); + if ((ret = sqlite3_prepare_v3(prijave->db, statem, -1, 0, &stmt, NULL)) != SQLITE_OK) + RETURN_ERROR("DELETE_POLL prepare"); + if ((ret = sqlite3_bind_int64(stmt, sqlite3_bind_parameter_index(stmt, ":i"), id)) != SQLITE_OK) + RETURN_ERROR("DELETE_POLL bind_int64 id"); + if ((ret = sqlite3_bind_text(stmt, sqlite3_bind_parameter_index(stmt, ":pw"), pass, -1, SQLITE_STATIC)) != SQLITE_OK) + RETURN_ERROR("DELETE_POLL bind_text password"); + if ((ret = sqlite3_step(stmt)) != SQLITE_DONE) + QUERY_FAILED("DELETE_POLL"); + sqlite3_finalize(stmt); + free_location = 0; + location = "?dp"; + rmm = MHD_RESPMEM_PERSISTENT; + response = "HTTP 201: DELETE_POLL\n"; + content_type = "text/plain; charset=UTF-8"; + status_code = MHD_HTTP_SEE_OTHER; + goto r; + case ADD_QUESTION: + ; + char * auth_ret; + if ((auth_ret = auth(prijave, pass, id))) { + rmm = MHD_RESPMEM_MUST_FREE; + response = auth_ret; + content_type = "text/plain; charset=UTF-8"; + status_code = MHD_HTTP_FORBIDDEN; + goto r; + } + sprintf(statem, "INSERT INTO questions (poll, type) VALUES (%lld, %d);", id, HIDDEN); + if ((ret = sqlite3_prepare_v3(prijave->db, statem, -1, 0, &stmt, NULL)) != SQLITE_OK) + RETURN_ERROR("ADD_QUESTION prepare"); + if ((ret = sqlite3_step(stmt)) != SQLITE_DONE) + RETURN_ERROR("ADD_QUESTION step"); + sqlite3_finalize(stmt); + location = (char *) MHD_lookup_connection_value(connection, MHD_HEADER_KIND, "Referer"); + free_location = 0; + rmm = MHD_RESPMEM_PERSISTENT; + response = "HTTP 201: ADD_QUESTION\n"; + content_type = "text/plain; charset=UTF-8"; + status_code = MHD_HTTP_SEE_OTHER; + goto r; } if (id_string) { if (prijave->pass && pass && !strcmp(pass, prijave->pass)) { -- cgit v1.2.3