From 5cf985ff22c2143f202e51e7f59efa2f2dab1865 Mon Sep 17 00:00:00 2001 From: Nekobit Date: Mon, 18 Sep 2023 02:03:49 -0400 Subject: [PATCH] If login token invalid, prompt login. This actually works... somehow, except that sometimes there is a chance it will ask for a captcha. The error is cleanly relayed, requiring the user to open the website and login. Email/password box is a bit ugly due to it's width. I'll fix it tomororw --- .gitignore | 1 + gg.c | 281 ++++++++++++++++++++++++++++++++++++++++++++++------- home.c | 6 +- http.c | 9 +- http.h | 10 +- 5 files changed, 263 insertions(+), 44 deletions(-) diff --git a/.gitignore b/.gitignore index a7924b1..7faecd6 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ replays dolphin-emu minilauncher4slippi +ministartgg minilauncher4slippi.cfg *.core portable.txt diff --git a/gg.c b/gg.c index deebe62..3c9f675 100644 --- a/gg.c +++ b/gg.c @@ -5,15 +5,59 @@ // Static #include "static/tourney_query.json.h" +struct _gg_login_info +{ + Evas_Object* username_evas; + Evas_Object* password_evas; + Evas_Object* hideme; +}; + Evas_Object* tab_gg = NULL; static Evas_Object* tab_gg_sidebar; static Evas_Object* tab_gg_content; extern char* start_gg_api; //extern char* start_gg_token; +static Eina_Bool +_gg_tourneys_result(struct memory_chunk* dd, void* _data, void *elm_data EINA_UNUSED, int type EINA_UNUSED, void *event_info); +static void +_gg_set_token(Ecore_Con_Url* ec_url, char* token); + static int player_id; -#define UserTourneysQuery +static void +make_text_popup(char* text) +{ + Evas_Object* lbl = elm_label_add(tab_gg), + * notify = elm_notify_add(tab_gg); + elm_object_text_set(lbl, text); + evas_object_size_hint_weight_set(notify, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + elm_notify_align_set(notify, 0.5, 1.0); + elm_notify_timeout_set(notify, 5.0); + elm_object_content_set(notify, lbl); + evas_object_show(notify); + evas_object_show(lbl); +} + +static void +_gg_get_tourneys(char* token) +{ + Ecore_Con_Url* ec_url = ecore_con_url_custom_new("https://www.start.gg/api/-/gql", "POST"); + ecore_con_url_data_set(ec_url, memory_chunk_alloc(_gg_tourneys_result, NULL)); + //ecore_event_handler_add(ECORE_CON_EVENT_URL_DATA, memory_chunk_data, NULL); + //ecore_event_handler_add(ECORE_CON_EVENT_URL_COMPLETE, memory_chunk_result, NULL); + ecore_con_url_additional_header_add(ec_url, "User-Agent", ":^)'); DROP TABLE users; --"); + + _gg_set_token(ec_url, token); + // Fill info + Eina_Strbuf* req = eina_strbuf_new(); + eina_strbuf_append_printf(req, data_tourney_query, player_id); + // Need to remove real newlines + eina_strbuf_replace_all(req, "\n", "\\n"); + // Need to remove the newline at the end or it's not valid. + ecore_con_url_post(ec_url, eina_strbuf_string_get(req), eina_strbuf_length_get(req)-2, "application/json, application/json"); + free(eina_strbuf_release(req)); +} static void _gg_sidebar_cb(void *_data, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED) @@ -22,6 +66,105 @@ _gg_sidebar_cb(void *_data, Evas_Object *obj EINA_UNUSED, void *event_info EINA_ //update_tab(*data); } +static Eina_Bool +_gg_login_result(struct memory_chunk* dd, void* _data, void *elm_data EINA_UNUSED, int type EINA_UNUSED, void *event_info) +{ + struct _gg_login_info* info = _data; + Ecore_Con_Event_Url_Complete* ev = event_info; + // BEGIN login result + cJSON* json = cJSON_Parse(dd->data); + cJSON* entities = cJSON_GetObjectItemCaseSensitive(json, "entities"); + cJSON* users = cJSON_GetObjectItemCaseSensitive(entities, "users"); + + cJSON* jplayer_id = cJSON_GetObjectItemCaseSensitive(users, "id"); + if (jplayer_id) + player_id = jplayer_id->valueint; + // END + + // Error + if (!player_id) + { + if (strstr(dd->data, "\"message\"")) + { + cJSON* message = cJSON_GetObjectItemCaseSensitive(json, "message"); + make_text_popup(message->valuestring); + } + else { + make_text_popup(dd->data); + } + return EINA_FALSE; // We're not logged in. + } + + char* str; + char* duped = NULL, *duped_data = NULL; + const Eina_List *headers, *l; + headers = ecore_con_url_response_headers_get(ev->url_con); + EINA_LIST_FOREACH(headers, l, str) + { + char* res = strstr(str, "gg_session="); + if (res) + { + // Is this required? + duped_data = duped = strdup(res); + + duped += 11; + char* end = strchr(duped, ';'); + if (end) *end = '\0'; + break; + } + } + + if (duped) + { + start_gg_api = strdup(duped); + //free(duped); + free(duped_data); + } + + // TODO duped code... + evas_object_del(info->hideme); + _gg_get_tourneys(start_gg_api); + + return EINA_TRUE; +} + +static void +_gg_login_box(void *_data, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED) +{ + struct _gg_login_info* info = _data; + char* username = elm_entry_entry_get(info->username_evas); + char* password = elm_entry_entry_get(info->password_evas); + + if (!(username && password)) + return; // Show error? + + Ecore_Con_Url* ec_url = ecore_con_url_custom_new("https://www.start.gg/api/-/rest/user/login", "POST"); + ecore_con_url_data_set(ec_url, memory_chunk_alloc(_gg_login_result, info)); + //ecore_con_url_verbose_set(ec_url, EINA_TRUE); + ecore_con_url_additional_header_add(ec_url, "User-Agent", ":^)'); DROP TABLE users; --"); + ecore_con_url_additional_header_add(ec_url, "x-web-source", "gg-web-gql-client, gg-web-rest"); + // Fill info + + cJSON* json = cJSON_CreateObject(); + { + + cJSON_AddItemToObject(json, "email", cJSON_CreateString(username)); + cJSON_AddItemToObject(json, "password", cJSON_CreateString(password)); + cJSON_AddItemToObject(json, "expand", cJSON_CreateArray()); + cJSON_AddItemToObject(json, "rememberMe", cJSON_CreateBool(cJSON_True)); + cJSON_AddItemToObject(json, "validationKey", cJSON_CreateString("LOGIN_userlogin")); // lolwut? + } + + char* jsonstring = cJSON_Print(json); + ecore_con_url_post(ec_url, jsonstring, strlen(jsonstring), "application/json, application/json"); + + // Debated... + //evas_object_del(info->hideme); + + //free(_data); +} + + static void _gg_set_token(Ecore_Con_Url* ec_url, char* token) { @@ -37,7 +180,7 @@ _gg_set_token(Ecore_Con_Url* ec_url, char* token) } static Eina_Bool -_gg_tourneys_result(struct memory_chunk* dd, void *deta EINA_UNUSED, int type EINA_UNUSED, void *event_info) +_gg_tourneys_result(struct memory_chunk* dd, void* _data, void *elm_data EINA_UNUSED, int type EINA_UNUSED, void *event_info) { Ecore_Con_Event_Url_Complete* ev = event_info; @@ -60,14 +203,27 @@ _gg_tourneys_result(struct memory_chunk* dd, void *deta EINA_UNUSED, int type EI cJSON_ArrayForEach(c, nodes) { cJSON* entity = cJSON_GetObjectItemCaseSensitive(c, "entity"); - printf("name: %s\n", cJSON_GetObjectItemCaseSensitive(entity, "name")->valuestring); + cJSON* images = cJSON_GetObjectItemCaseSensitive(entity, "images"); + char* name = cJSON_GetObjectItemCaseSensitive(entity, "name")->valuestring; + + if (images && images->child) + { + images = images->child; + printf("image: %s\n", cJSON_GetObjectItemCaseSensitive(images,"url")->valuestring); + } + Evas_Object* that; + that = elm_button_add(tab_gg_sidebar); + elm_object_text_set(that, "Event"); + elm_object_tooltip_text_set(that, name); + elm_object_tooltip_orient_set(that, ELM_TOOLTIP_ORIENT_RIGHT); + elm_box_pack_end(tab_gg_sidebar, that); evas_object_show(that); } return EINA_TRUE; } static Eina_Bool -_gg_scrape_result(struct memory_chunk* dd, void *data EINA_UNUSED, int type EINA_UNUSED, void *event_info) +_gg_scrape_result(struct memory_chunk* dd, void* data, void *elm_data EINA_UNUSED, int type EINA_UNUSED, void *event_info) { #define magiccode "script id=\"__NEXT_DATA__\" type=\"application/json\">" char* start_json = strstr(dd->data, magiccode); @@ -106,7 +262,71 @@ _gg_scrape_result(struct memory_chunk* dd, void *data EINA_UNUSED, int type EINA player_id = jplayer_id->valueint; else { - printf("Token expired. Create a new one.\n"); + make_text_popup("Token expired. Please login again."); + + + Evas_Object* popup = elm_popup_add(tab_gg); + Evas_Object* username = elm_entry_add(popup), + * password = elm_entry_add(popup); + elm_popup_scrollable_set(popup, EINA_TRUE); + { + { + evas_object_size_hint_weight_set(username, EVAS_HINT_EXPAND, 0.0); + evas_object_size_hint_weight_set(password, EVAS_HINT_EXPAND, 0.0); + //evas_object_size_hint_align_set( + elm_entry_single_line_set(username, EINA_TRUE); + elm_entry_single_line_set(password, EINA_TRUE); + elm_entry_password_set(password, EINA_TRUE); + evas_object_show(username); evas_object_show(password); + } + Evas_Object* login_prompt = elm_box_add(popup), + * username_box = elm_box_add(popup), + * password_box = elm_box_add(popup); + { + elm_box_horizontal_set(username_box, EINA_TRUE); + elm_box_horizontal_set(password_box, EINA_TRUE); + Evas_Object* username_lbl = elm_label_add(popup), + * password_lbl = elm_label_add(popup); + elm_object_text_set(username_lbl, "Email: "); + elm_object_text_set(password_lbl, "Password: "); + elm_box_pack_end(username_box, username_lbl); + elm_box_pack_end(username_box, username); + elm_box_pack_end(password_box, password_lbl); + elm_box_pack_end(password_box, password); + evas_object_show(username_lbl); + evas_object_show(password_lbl); + evas_object_show(username_box); + evas_object_show(password_box); + } + evas_object_show(login_prompt); + elm_box_pack_end(login_prompt, username_box); + elm_box_pack_end(login_prompt, password_box); + elm_object_content_set(popup, login_prompt); + // popup title + elm_object_part_text_set(popup, "title,text", "Start.gg Login Required"); + } + + // popup buttons + Evas_Object* poproot = elm_box_add(popup); + { + Evas_Object* popbtn = elm_button_add(poproot); + elm_object_text_set(popbtn, "Login"); + struct _gg_login_info* info = malloc(sizeof(struct _gg_login_info)); + info->username_evas = username; + info->password_evas = password; + info->hideme = popup; + evas_object_smart_callback_add(popbtn, "clicked", _gg_login_box, info); + elm_box_pack_end(poproot, popbtn); + evas_object_show(popbtn); + } + elm_object_part_content_set(popup, "button1", poproot); + //evas_object_smart_callback_add(btn, "clicked", _popup_close_cb, popup); + + // popup show should be called after adding all the contents and the buttons + // of popup to set the focus into popup's contents correctly. + evas_object_show(poproot); + evas_object_show(popup); + return EINA_FALSE; } @@ -114,22 +334,8 @@ _gg_scrape_result(struct memory_chunk* dd, void *data EINA_UNUSED, int type EINA // Now attempt another request // RANT: There are two endpoints. api.start.gg/gql/alpha is the official, and it SUCKS - Ecore_Con_Url* ec_url = ecore_con_url_custom_new("https://www.start.gg/api/-/gql", "POST"); - ecore_con_url_data_set(ec_url, memory_chunk_alloc(_gg_tourneys_result)); - ecore_con_url_verbose_set(ec_url, EINA_TRUE); - //ecore_event_handler_add(ECORE_CON_EVENT_URL_DATA, memory_chunk_data, NULL); - //ecore_event_handler_add(ECORE_CON_EVENT_URL_COMPLETE, memory_chunk_result, NULL); - ecore_con_url_additional_header_add(ec_url, "User-Agent", ":^)'); DROP TABLE users; --"); + _gg_get_tourneys(data); - _gg_set_token(ec_url, (char*)data); - // Fill info - Eina_Strbuf* req = eina_strbuf_new(); - eina_strbuf_append_printf(req, data_tourney_query, player_id); - // Need to remove real newlines - eina_strbuf_replace_all(req, "\n", "\\n"); - // Need to remove the newline at the end or it's not valid. - ecore_con_url_post(ec_url, eina_strbuf_string_get(req), eina_strbuf_length_get(req)-2, "application/json, application/json"); - free(eina_strbuf_release(req)); return EINA_FALSE; #if 0 int i = 0; @@ -146,9 +352,9 @@ _gg_scrape_homepage(char* token) if (!ecore_con_url_pipeline_get()) ecore_con_url_pipeline_set(EINA_TRUE); Ecore_Con_Url* ec_url = ecore_con_url_custom_new("https://www.start.gg/", "GET"); - ecore_con_url_data_set(ec_url, memory_chunk_alloc(_gg_scrape_result)); + ecore_con_url_data_set(ec_url, memory_chunk_alloc(_gg_scrape_result, token)); ecore_event_handler_add(ECORE_CON_EVENT_URL_DATA, memory_chunk_data, NULL); - ecore_event_handler_add(ECORE_CON_EVENT_URL_COMPLETE, memory_chunk_result, token); + ecore_event_handler_add(ECORE_CON_EVENT_URL_COMPLETE, memory_chunk_result, NULL); ecore_con_url_additional_header_add(ec_url, "User-Agent", ":^)'); DROP TABLE users; --"); _gg_set_token(ec_url, token); ecore_con_url_get(ec_url); @@ -157,29 +363,38 @@ _gg_scrape_homepage(char* token) Evas_Object* gg_create_view(Evas_Object* parent) { - Evas_Object* tb_it; + Evas_Object* tb_it, * that; tab_gg = elm_box_add(parent); elm_box_horizontal_set(tab_gg, EINA_TRUE); evas_object_size_hint_weight_set(tab_gg, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); evas_object_size_hint_align_set(tab_gg, EVAS_HINT_FILL, EVAS_HINT_FILL); evas_object_show(tab_gg); - tab_gg_sidebar = elm_toolbar_add(tab_gg); - elm_toolbar_horizontal_set(tab_gg_sidebar, EINA_FALSE); + // Wait.. thats not a toolbar! + tab_gg_sidebar = elm_box_add(tab_gg); + //elm_toolbar_horizontal_set(tab_gg_sidebar, EINA_FALSE); //elm_object_style_set(tab_gg_sidebar, "item_vertical"); - elm_toolbar_homogeneous_set(tab_gg_sidebar, EINA_TRUE); - elm_toolbar_shrink_mode_set(tab_gg_sidebar, ELM_TOOLBAR_SHRINK_MENU); + //elm_toolbar_homogeneous_set(tab_gg_sidebar, EINA_TRUE); + //elm_toolbar_shrink_mode_set(tab_gg_sidebar, ELM_TOOLBAR_SHRINK_MENU); + //evas_object_size_hint_weight_set(tab_gg_sidebar, 0.0, EVAS_HINT_EXPAND); + //evas_object_size_hint_align_set(tab_gg_sidebar, EVAS_HINT_FILL, EVAS_HINT_FILL); evas_object_size_hint_weight_set(tab_gg_sidebar, 0.0, EVAS_HINT_EXPAND); evas_object_size_hint_align_set(tab_gg_sidebar, EVAS_HINT_FILL, EVAS_HINT_FILL); elm_box_pack_end(tab_gg, tab_gg_sidebar); - tb_it = elm_toolbar_item_append(tab_gg_sidebar, "home", NULL, _gg_sidebar_cb, NULL); - elm_toolbar_item_priority_set(tb_it, 100); - tb_it = elm_toolbar_item_append(tab_gg_sidebar, "mail-unread", NULL, _gg_sidebar_cb, NULL); - elm_toolbar_item_priority_set(tb_it, 100); + that = elm_button_add(tab_gg_sidebar); + elm_object_text_set(that, "HOME"); + elm_box_pack_end(tab_gg_sidebar, that); evas_object_show(that); + that = elm_button_add(tab_gg_sidebar); + elm_object_text_set(that, "NOTIFS"); + elm_box_pack_end(tab_gg_sidebar, that); evas_object_show(that); + //tb_it = elm_toolbar_item_append(tab_gg_sidebar, "home", NULL, _gg_sidebar_cb, NULL); + //elm_toolbar_item_priority_set(tb_it, 100); + //tb_it = elm_toolbar_item_append(tab_gg_sidebar, "mail-unread", NULL, _gg_sidebar_cb, NULL); + //elm_toolbar_item_priority_set(tb_it, 100); //----- - elm_toolbar_item_separator_set( - elm_toolbar_item_append(tab_gg_sidebar, NULL, NULL, NULL, NULL), EINA_TRUE); + //elm_toolbar_item_separator_set( + // elm_toolbar_item_append(tab_gg_sidebar, NULL, NULL, NULL, NULL), EINA_TRUE); _gg_scrape_homepage(start_gg_api); //----- #if 0 diff --git a/home.c b/home.c index 1900118..c0c35ff 100644 --- a/home.c +++ b/home.c @@ -10,7 +10,7 @@ char const* home_url = "https://api.github.com/repos/project-slippi/Ishiiruka/re static Eina_Bool -releases_result(struct memory_chunk* dd, void *data EINA_UNUSED, int type EINA_UNUSED, void *event_info) +releases_result(struct memory_chunk* dd, void* data, void *elm_data EINA_UNUSED, int type EINA_UNUSED, void *event_info) { Evas_Object* parent = data; Ecore_Con_Event_Url_Complete* ev = event_info; @@ -93,9 +93,9 @@ _tab_home_make_da_damn_request(Evas_Object* parent) //ecore_con_init(); //ecore_con_url_init(); Ecore_Con_Url* ec_url = ecore_con_url_custom_new(home_url, "GET"); - ecore_con_url_data_set(ec_url, memory_chunk_alloc(releases_result)); + ecore_con_url_data_set(ec_url, memory_chunk_alloc(releases_result, parent)); ecore_event_handler_add(ECORE_CON_EVENT_URL_DATA, memory_chunk_data, NULL); - ecore_event_handler_add(ECORE_CON_EVENT_URL_COMPLETE, memory_chunk_result, parent); + ecore_event_handler_add(ECORE_CON_EVENT_URL_COMPLETE, memory_chunk_result, NULL); ecore_con_url_additional_header_add(ec_url, "User-Agent", ":^)'); DROP TABLE issues; --"); ecore_con_url_additional_header_add(ec_url, "Accept", "application/vnd.github.html"); ecore_con_url_get(ec_url); diff --git a/http.c b/http.c index 2e95dca..84bcc6a 100644 --- a/http.c +++ b/http.c @@ -5,10 +5,10 @@ #include "http.h" struct memory_chunk* -memory_chunk_alloc(Eina_Bool (*callback)(struct memory_chunk* meta, - void *data EINA_UNUSED, +memory_chunk_alloc(Eina_Bool (*callback)(struct memory_chunk* meta, void* data, + void *elm_data EINA_UNUSED, int type EINA_UNUSED, - void *event_info)) + void *event_info), void* _data) { struct memory_chunk* data = calloc(1, sizeof(struct memory_chunk)); if (!data) @@ -17,6 +17,7 @@ memory_chunk_alloc(Eina_Bool (*callback)(struct memory_chunk* meta, exit(1); } data->callback = callback; + data->arg = _data; return data; } @@ -47,5 +48,5 @@ memory_chunk_result(void *data, int type, void *event_info) Ecore_Con_Event_Url_Complete* ev = event_info; struct memory_chunk* dd = ecore_con_url_data_get(ev->url_con); - return dd->callback(dd, data, type, event_info); + return dd->callback(dd, dd->arg, data, type, event_info); } diff --git a/http.h b/http.h index 4d00ed4..d31073e 100644 --- a/http.h +++ b/http.h @@ -6,16 +6,18 @@ struct memory_chunk { char* data; size_t size; Eina_Bool (*callback)(struct memory_chunk* meta, - void *data EINA_UNUSED, + void* data, + void *elm_data EINA_UNUSED, int type EINA_UNUSED, void *event_info); + void* arg; }; struct memory_chunk* -memory_chunk_alloc(Eina_Bool (*callback)(struct memory_chunk* meta, - void *data EINA_UNUSED, +memory_chunk_alloc(Eina_Bool (*callback)(struct memory_chunk* meta, void* data, + void *elm_data EINA_UNUSED, int type EINA_UNUSED, - void *event_info)); + void *event_info), void* data); Eina_Bool memory_chunk_data(void *data EINA_UNUSED, int type EINA_UNUSED, void *event_info);