#define _GNU_SOURCE #include <stdio.h> #include <stdbool.h> #include <stdlib.h> #include <string.h> #include <curl/curl.h> #include <tidy/tidy.h> #include <tidy/tidybuffio.h> #include <time.h> #include "config.h" struct memory { char *response; size_t size; }; struct submit_action { int contest_id; int task_id; char *local_file; char *reported_filename; }; static size_t write_callback(void *data, size_t size, size_t nmemb, void *userp) { size_t realsize = size *nmemb; struct memory *mem = (struct memory *)userp; char *ptr = realloc(mem->response, mem->size + realsize + 1); if (ptr == NULL) return 0; mem->response = ptr; memcpy(&(mem->response[mem->size]), data, realsize); mem->size += realsize; mem->response[mem->size] = 0; return realsize; } static void debug_print_cookies(CURL *curl) { CURLcode res; struct curl_slist *cookies; struct curl_slist *nc; int i; printf("Cookies, curl knows:\n"); res = curl_easy_getinfo(curl, CURLINFO_COOKIELIST, &cookies); if (res != CURLE_OK) { fprintf(stderr, "Curl curl_easy_getinfo failed: %s\n", curl_easy_strerror(res)); return; } nc = cookies; i = 0; while (nc) { printf("[%d]: %s\n", i, nc->data); nc = nc->next; i++; } if (i == 0) { printf("(none)\n"); } curl_slist_free_all(cookies); } void setup_curl(CURL *curl, struct memory *chunk) { chunk->response = NULL; chunk->size = 0; curl_easy_setopt(curl, CURLOPT_COOKIEFILE, ""); curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L); // skip cert verification curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L); // skip hostname verification (is it measureably faster?) curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback); curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)chunk); curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L); } void free_body(struct memory *chunk) { free(chunk->response); chunk->response = NULL; chunk->size=0; } void print_body(CURL *curl, struct memory *chunk) { printf("%li\n", chunk->size); printf("BEGIN >>>>>>\n"); for (int i = 0; i < chunk->size; i++) { printf("%c", chunk->response[i]); } printf("\n<<<<<< END\n"); } void perform_get(CURL *curl, char *url) { CURLcode res; curl_easy_setopt(curl, CURLOPT_URL, url); res = curl_easy_perform(curl); if (res != CURLE_OK) fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res)); } void search_csrf(TidyDoc doc, TidyNode tnod, char **csrf) { TidyNode child; for (child = tidyGetChild(tnod); child; child = tidyGetNext(child) ) { ctmbstr name = tidyNodeGetName(child); if (name) { // It is HTML tag TidyAttr attr; bool it_is_csrf = false; const char *it_has_value = NULL; for (attr = tidyAttrFirst(child); attr; attr = tidyAttrNext(attr) ) { if (!strcmp(tidyAttrName(attr), "id")) { if (!strcmp(tidyAttrValue(attr), "csrf_token")) { it_is_csrf = true; } } if (!strcmp(tidyAttrName(attr), "value")) { it_has_value = tidyAttrValue(attr); } } if (it_is_csrf && it_has_value) { //printf("Yay! csrf token = %s\n", it_has_value); if (*csrf) free(*csrf); *csrf = strdup(it_has_value); } } search_csrf(doc, child, csrf); } } void extract_csrf(struct memory *chunk, char **csrf) { TidyDoc tdoc; TidyBuffer docbuf = {0}; TidyBuffer tidy_errbuf = {0}; tdoc = tidyCreate(); tidySetErrorBuffer(tdoc, &tidy_errbuf); tidyBufInit(&docbuf); // copy response buffer tidyBufAppend(&docbuf, chunk->response, chunk->size); tidyParseBuffer(tdoc, &docbuf); // real parse search_csrf(tdoc, tidyGetRoot(tdoc), csrf); // find element //fprintf(stderr, "%s\n", tidy_errbuf.bp); // print errors tidyBufFree(&docbuf); tidyBufFree(&tidy_errbuf); tidyRelease(tdoc); } void load_login_page (CURL *curl, struct memory *chunk, char **csrf) { perform_get(curl, BASE_URL "/"); free_body(chunk); perform_get(curl, BASE_URL "/auth/login"); //print_body(curl, chunk); //print_cookies(curl); extract_csrf(chunk, csrf); //printf("csrf token = %s\n", csrf); free_body(chunk); } void do_login (CURL *curl, struct memory *chunk, char **csrf, char *login_email, char *login_password) { char *enc_email = curl_easy_escape(curl, login_email, strlen(login_email)); char *enc_password = curl_easy_escape(curl, login_password, strlen(login_password)); char *enc_submit = curl_easy_escape(curl, "Přihlásit se", strlen("Přihlásit se")); char *post_data; asprintf(&post_data, "csrf_token=%s&email=%s&passwd=%s&submit=%s&next=", *csrf, enc_email, enc_password, enc_submit); curl_free(enc_email); curl_free(enc_password); curl_free(enc_submit); curl_easy_setopt(curl, CURLOPT_POSTFIELDS, post_data); perform_get(curl, BASE_URL "/auth/login"); curl_easy_setopt(curl, CURLOPT_POSTFIELDS, NULL); curl_easy_setopt(curl, CURLOPT_HTTPGET, 1L); free(post_data); free_body(chunk); } void load_contest (CURL *curl, struct memory *chunk, int contest_id) { char *url; asprintf(&url, BASE_URL "/user/contest/%i/", contest_id); perform_get(curl, url); free(url); //print_body(curl, chunk); free_body(chunk); } void load_task (CURL *curl, struct memory *chunk, char **csrf, int contest_id, int task_id) { char *url; asprintf(&url, BASE_URL "/user/contest/%i/task/%i/", contest_id, task_id); perform_get(curl, url); free(url); //print_body(curl, chunk); extract_csrf(chunk, csrf); //printf("csrf token = %s\n", csrf); free_body(chunk); } bool submit_task (CURL *curl, struct memory *chunk, char **csrf, int contest_id, int task_id, char *local_file, char *reported_filename) { char *url; asprintf(&url, BASE_URL "/user/contest/%i/task/%i/", contest_id, task_id); curl_mime *mime; curl_mimepart *part; mime = curl_mime_init(curl); part = curl_mime_addpart(mime); curl_mime_data(part, *csrf, CURL_ZERO_TERMINATED); curl_mime_name(part, "csrf_token"); part = curl_mime_addpart(mime); curl_mime_data(part, "Jenduv automatizovany test submit", CURL_ZERO_TERMINATED); curl_mime_name(part, "note"); part = curl_mime_addpart(mime); curl_mime_data(part, "Odevzdat", CURL_ZERO_TERMINATED); curl_mime_name(part, "submit"); part = curl_mime_addpart(mime); curl_mime_filedata(part, local_file); curl_mime_filename(part, reported_filename); curl_mime_name(part, "file"); curl_easy_setopt(curl, CURLOPT_MIMEPOST, mime); curl_easy_setopt(curl, CURLOPT_URL, url); char errbuf[CURL_ERROR_SIZE]; curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, errbuf); errbuf[0] = 0; CURLcode res = curl_easy_perform(curl); if(res != CURLE_OK) { size_t len = strlen(errbuf); fprintf(stderr, "\nlibcurl: (%d) ", res); if(len) fprintf(stderr, "%s%s", errbuf, ((errbuf[len - 1] != '\n') ? "\n" : "")); else fprintf(stderr, "%s\n", curl_easy_strerror(res)); } free(url); curl_easy_setopt(curl, CURLOPT_MIMEPOST, NULL); curl_easy_setopt(curl, CURLOPT_HTTPGET, 1L); curl_mime_free(mime); long http_code = 0; curl_easy_getinfo (curl, CURLINFO_RESPONSE_CODE, &http_code); if (http_code != 200) { printf("Post file failed:\n"); print_body(curl, chunk); free_body(chunk); return false; } free_body(chunk); return true; } bool full_test(char *login_email, char *login_password, struct submit_action *actions) { bool ret = true; CURL *curl; curl_global_init(CURL_GLOBAL_DEFAULT); curl = curl_easy_init(); struct memory chunk; char *csrf = NULL; if (curl) { setup_curl(curl, &chunk); load_login_page(curl, &chunk, &csrf); do_login(curl, &chunk, &csrf, login_email, login_password); while (actions->contest_id) { /* printf("performing action %i %i %s %s\n", actions->contest_id, actions->task_id, actions->local_file, actions->reported_filename); */ load_contest(curl, &chunk, actions->contest_id); load_task(curl, &chunk,&csrf, actions->contest_id, actions->task_id); if (!submit_task(curl, &chunk, &csrf, actions->contest_id, actions->task_id, actions->local_file, actions->reported_filename)) { ret = false; } actions++; } // cleanup curl_easy_cleanup(curl); } curl_global_cleanup(); if (csrf) free(csrf); return ret; } int main() { char *login_email = "had+ucastnik@kam.mff.cuni.cz"; char *login_password = "UTX0seFkVim51vkOwER5G8GjB5eEq7G9"; struct submit_action actions[] = { //{ 25, 3, "/home/had/BratruvZpevnik_v4-0.pdf", "zpevnik.pdf"}, //{ 25, 4, "testsubmit_02.pdf", "moje_reseni.pdf"}, //{ 25, 5, "/home/had/sada3.pdf", "sendvic.pdf"}, //{ 25, 6, "/home/had/stitek.pdf", "sken.pdf"}, { 0, 0, NULL, NULL} }; full_test(login_email, login_password, actions); return 0; }