summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAnton Luka Šijanec <anton@sijanec.eu>2021-09-10 23:12:04 +0200
committerAnton Luka Šijanec <anton@sijanec.eu>2021-09-10 23:12:04 +0200
commit900e4b546e56a11cbc75f1af7195ebbaca9c95ac (patch)
treeb278966fab02fb724285760da54cde66211a7dd4
parentsome fixing work (diff)
downloaddiscord.c-900e4b546e56a11cbc75f1af7195ebbaca9c95ac.tar
discord.c-900e4b546e56a11cbc75f1af7195ebbaca9c95ac.tar.gz
discord.c-900e4b546e56a11cbc75f1af7195ebbaca9c95ac.tar.bz2
discord.c-900e4b546e56a11cbc75f1af7195ebbaca9c95ac.tar.lz
discord.c-900e4b546e56a11cbc75f1af7195ebbaca9c95ac.tar.xz
discord.c-900e4b546e56a11cbc75f1af7195ebbaca9c95ac.tar.zst
discord.c-900e4b546e56a11cbc75f1af7195ebbaca9c95ac.zip
-rw-r--r--misc/api/README.md1
-rw-r--r--misc/api/v9/auth/login/index.php6
-rw-r--r--src/api.c87
-rw-r--r--src/h.c14
4 files changed, 76 insertions, 32 deletions
diff --git a/misc/api/README.md b/misc/api/README.md
new file mode 100644
index 0000000..f4ad906
--- /dev/null
+++ b/misc/api/README.md
@@ -0,0 +1 @@
+when debugging, you can run `php -S 0:80` in `misc/` to debug some things, though this is just for my personal use.
diff --git a/misc/api/v9/auth/login/index.php b/misc/api/v9/auth/login/index.php
new file mode 100644
index 0000000..9f8ff72
--- /dev/null
+++ b/misc/api/v9/auth/login/index.php
@@ -0,0 +1,6 @@
+<?php
+header("custom-header: customm");
+echo "v kolikor te zanimajo kvalitetne moške obutve po sezonskih cenah, obišči mlad.si";
+error_log("post body: " . file_get_contents("php://input"));
+error_log(implode(",", getallheaders()));
+?>
diff --git a/src/api.c b/src/api.c
index 2a52f72..70bae66 100644
--- a/src/api.c
+++ b/src/api.c
@@ -1,8 +1,11 @@
#define DC_LOGIN_FORMAT "{\"login\":\"%s\",\"password\":\"%s\",\"undelete\":false,\"captcha_key\":null,\"login_source\":null,\"gift_code_sku_id\":null}"
#define DC_USER_AGENT "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.131 Safari/537.36"
-#define DC_SERVER_ADDRESS "localhost"
+#define DC_SERVER_ADDRESS "discord.com"
+#define DC_SERVER_PORT 443
+#define DC_SERVER_SSL 1
+#define DC_SERVER_ORIGIN "https://discord.com"
#define DC_API_PREFIX "/api/v9/"
-// #define DC_LWS_ABLE_TO_PARSE_HEADERS 1
+#define DC_LWS_ABLE_TO_PARSE_HEADERS 1
/* libwebsockets information: libwebsockets works with event loops and discord.c primary targets debian for building (it must work on debian), but debian does not ship libwebsockets with glib or libevent event loop support, so loops are implemented in the classic poll() style. this reduces performance probably. if you use discord.c API with support for a platform specific event loop, you may rewrite LWS to do things differently. currently calls into API (dc_api_i and dc_api_o) will both do LWS stuff. */
void dc_api_stack (struct dc_api_io i) { /* stack output struct to be delivered via dc_api_o 2usr */
DC_MR(i.program->api_ios);
@@ -45,10 +48,10 @@ static int dc_lws_cb (struct lws * wsi, enum lws_callback_reasons rs, void * us,
return 1;
}
lws_client_http_body_pending(wsi, 0);
- if (pass->api_io.status & DC_MUST_FREE) {
+ if (pass->api_io.status & DC_MUST_FREE)
free(pass->body);
- pass->body = NULL;
- }
+ pass->body = NULL;
+ pass->body_length = 0;
break;
case LWS_CALLBACK_ESTABLISHED_CLIENT_HTTP:
pass->status = lws_http_client_http_response(wsi); /* 200 OK, 404 Not Found,...*/
@@ -59,10 +62,10 @@ static int dc_lws_cb (struct lws * wsi, enum lws_callback_reasons rs, void * us,
pass->headers[i][0] = '\0'; /* to clear any headers we requested with */
int n = lws_hdr_custom_length(wsi, dc_lws_headers[i], strlen(dc_lws_headers[i]));
if (n < -1)
- lwsl_notice("No header %s.\n", dc_lws_headers[i]);
+ lwsl_notice("Error with header %s.\n", dc_lws_headers[i]);
else
if (lws_hdr_custom_copy(wsi, pass->headers[i], DC_LWS_MAX_HEADER_LENGTH, dc_lws_headers[i], strlen(dc_lws_headers[i])) < 0)
- lwsl_notice("Header %s too long.\n", dc_lws_headers[i]);
+ lwsl_notice("Header %s too long or non existent.\n", dc_lws_headers[i]);
else
lwsl_notice("%s %s\n", dc_lws_headers[i], pass->headers[i]);
}
@@ -71,18 +74,18 @@ static int dc_lws_cb (struct lws * wsi, enum lws_callback_reasons rs, void * us,
case LWS_CALLBACK_RECEIVE_CLIENT_HTTP_READ: /* chunked body, without headers */
fprintf(stderr, "RECEIVE_CLIENT_HTTP_READ: read %d\n", len);
lwsl_hexdump_notice(in, len); /* for debugging purposes, kek */
- pass->body_length = len;
- pass->body = in;
- pass->body[len] = '\0'; /* NULL terminating note0 src/h.c */
- if (pass->api_io.pass != pass)
- fprintf(stderr, "[!!!] REPORT THIS BUG: pass->api_io.pass != pass\n");
- pass->api_io.status |= DC_FROM_LWS;
- dc_api_i(pass->api_io);
- pass->api_io.status &= ~DC_FROM_LWS;
+ if (!(pass->api_io.status & DC_MUST_FREE)) { /* we start filling the ->body */
+ pass->api_io.status |= DC_MUST_FREE; /* buffer, on end of wsi session */
+ pass->body = NULL; /* dc_api_i is called from DC_CALLBACK_WSI_DESTROY */
+ } /* if ->body from input was not freed and it should be, res body is appended */
+ pass->body_length += len; /* if ->body was static, pointer is changed to NULL */
+ pass->body = realloc(pass->body, pass->body_length + 1); /* normally - no edge */
+ memcpy(pass->body+pass->body_length-len, in, len); /* case - resp body will be */
+ pass->body[pass->body_length] = '\0'; /* on heap and freed on _DESTROY. */
return 0; /* don't pass to lws_callback_http_dummy */
case LWS_CALLBACK_RECEIVE_CLIENT_HTTP: /* uninterpreted http content */
- fprintf(stderr, "LCRCH\n"); /* +1 to bufsize for NULL term, note0 src/h.c */
- char buffer[DC_LWS_BUF + LWS_PRE + 1 /* lws needs this many bytes b4 the ptr */];
+ fprintf(stderr, "LCRCH\n");
+ char buffer[DC_LWS_BUF + LWS_PRE];
char * ptr = buffer + LWS_PRE; /* see, BEFORE the pointer - lower addr */
int len2 /* DC_LWS_BUF again */ = sizeof(buffer) - LWS_PRE;
if (lws_http_client_read(wsi, &ptr, &len2) < 0) {
@@ -97,11 +100,17 @@ static int dc_lws_cb (struct lws * wsi, enum lws_callback_reasons rs, void * us,
lwsl_user("LWS_CALLBACK_CLOSED_CLIENT_HTTP\n");
break;
case LWS_CALLBACK_WSI_DESTROY: /* if I understand the docs correctly, this is allways */
+ if (pass->api_io.pass != pass)
+ fprintf(stderr, "[!!!] REPORT THIS BUG: pass->api_io.pass != pass\n");
+ pass->api_io.status |= DC_FROM_LWS;
+ dc_api_i(pass->api_io);
+ pass->api_io.status &= ~DC_FROM_LWS;
fprintf(stderr, "pass before freed is %p\n", (void *) pass);
+ if (pass->api_io.status & DC_MUST_FREE) /* we still do this check in case */
+ free(pass->body); /* _READ was not called and pointer was static */
free(pass); /* called at the final moment when user pointer and wsi is still */
- pass = NULL;
- break;
- default: /* accessible, so we can now free the struct that was passed in as a heap ptr */
+ break; /* accessible - we can free the struct that was passed in as a heap ptr */
+ default:
break;
}
return lws_callback_http_dummy(wsi, rs, us, in, len);
@@ -125,12 +134,14 @@ void dc_api_i (struct dc_api_io i) { /* this function does not call attached fun
struct lws_client_connect_info info;
memset(&info, 0, sizeof(info));
info.context = i.program->lws_context;
- /* info.ssl_connection = LCCSCF_USE_SSL | LCCSCF_HTTP_MULTIPART_MIME; */
- info.port = 80;
+#if DC_SERVER_SSL
+ info.ssl_connection = LCCSCF_USE_SSL;
+#endif
+ info.port = DC_SERVER_PORT;
info.address = DC_SERVER_ADDRESS;
info.path = DC_API_PREFIX "auth/login";
info.host = info.address;
- info.origin = info.address;
+ /* info.origin = DC_SERVER_ORIGIN; */ /* just don't send it */
info.method = "POST";
struct dc_lws_pass * pass = calloc(1, sizeof(struct dc_lws_pass)); /* cb frees */
fprintf(stderr, "allocated pass at %p\n", (void *) pass);
@@ -140,18 +151,40 @@ void dc_api_i (struct dc_api_io i) { /* this function does not call attached fun
i.type = DC_API_LOGIN_CB;
memcpy(&pass->api_io, &i, sizeof(i));
pass->api_io.pass = pass;
+ strcpy(pass->headers[DC_LWS_CONTENT_TYPE], "application/json");
info.userdata = pass;
-#ifdef DC_LWS_ABLE_TO_PARSE_HEADERS
+#if DC_LWS_ABLE_TO_PARSE_HEADERS
info.alpn = "http/1.1";
#endif
info.protocol = dc_lws_protocols[0].name;
- if (i.client->authorization) { /* TODO: attempt cookie login without user/pass */
- ;
- }
+ if (i.client->authorization) /* attempt cookie login without user/pass */
+ strcpy(pass->headers[DC_LWS_AUTHORIZATION], i.client->authorization);
lws_client_connect_via_info(&info);
break;
case DC_API_LOGIN_CB:
+#define DC_STACK_RETURN(x) do { i.status = x; dc_api_stack(i); return; } while (0)
+ i.type = DC_API_LOGIN;
+ if (!i.pass->body) {
+ i.status |= DC_REQUEST_FAILED;
+ i.status &= ~(DC_OK);
+ dc_api_stack(i);
+ break;
+ }
fprintf(stderr, "DEBUG: %s\n", i.pass->body);
+ if (strstr(i.pass->body, "INVALID_LOGIN"))
+ DC_STACK_ERROR(DC_BAD_LOGIN);
+ if (strstr(i.pass->body, "captcha-required"))
+ DC_STACK_ERROR(DC_CAPTCHA_NEEDED);
+ if (strstr(i.pass->body, "ACCOUNT_LOGIN_VERIFICATION_EMAIL"))
+ DC_STACK_ERROR(DC_VERIFICATION_NEEDED);
+ char * cp, c2;
+ if (!(cp = strstr(i.pass->body, "\"token\": \"")) || !(c2 = strchr(cp+strlen("\"token\": \""), '"')))
+ DC_STACK_ERROR(DC_ERROR);
+ c2[0] = '\0'; /* body is on heap, we can edit it */
+ free(i.client->authorization); /* in case we set it previously */
+ i.client->authorization = strdup(cp);
+ fprintf(stderr, "got token %s\n", i.client->authorization);
+ DC_STACK_RETURN(DC_OK | DC_INCOMPLETE /* we now have to request properties */);
break;
case DC_API_REGISTER:
break;
diff --git a/src/h.c b/src/h.c
index 07852a3..19e52fb 100644
--- a/src/h.c
+++ b/src/h.c
@@ -19,7 +19,7 @@ enum dc_status { /* theese are flags and should be and-checked */
DC_UNSET = 0, /* default value when enum is calloced */
DC_INCOMPLETE = 1 << 0, /* struct SHALL NOT be used by the ui, it is yet to be filled by api */
DC_OK = 1 << 1, /* success status, api usually sets this after completion/filling of the strct */
- DC_BAD_LOGIN = 1 << 2, /* login failed */
+ DC_BAD_LOGIN = 1 << 2, /* login failed because of wrong credentials */
DC_VERIFICATION_NEEDED = 1 << 3, /* login: check email, click link/reg: tough luck ur IP flagd */
DC_CAPTCHA_NEEDED = 1 << 4, /* must solve captcha, tough luck, not impl, use browser login */
DC_BAD_USERNAME = 1 << 5, /* provided username can't be registered */
@@ -28,7 +28,9 @@ enum dc_status { /* theese are flags and should be and-checked */
DC_CONTINUE = 1 << 8, /* attached handlers return this to continue processing this output, N/I */
DC_BREAK = 1 << 9, /* attached handlers return this to stop processing this output */
DC_FROM_LWS = 1 << 10, /* LWS cb is the caller, so do not attempt to do lws_service (loop) */
- DC_MUST_FREE = 1 << 11 /* cb pass: body must be freed when request is done with user_data */
+ DC_MUST_FREE = 1 << 11, /* cb pass: body must be freed when request is done with user_data */
+ DC_REQUEST_FAILED = 1 << 12, /* http request failed, reported to ui */
+ DC_ERROR = 1 << 13 /* unknown error, non implemented non expected response */
};
enum dc_permissions { /* other permissions exist, but are not implemented/understood */
DC_ALL_PERMISSIONS = 1 << 3, /* this is incredibly retarded, why is this SEPARATE?!? - admins */
@@ -59,9 +61,9 @@ enum dc_api_io_type {
DC_API_GUILD, /* i: TODO: create a guild-tr0 */
/* o: TODO: new guild created, GUI spawn it */
DC_API_LOGIN, /* i: pass a dc_client-tr1, to relogin FIX prev retd cl not create new */
- /* o: the previously passed dc_client with set status */
+ /* o: the previously passed dc_client with set status, do not use yet! \/ */
DC_API_LOGIN_CB,/* i: used internally for passing response from http client to api, see source */
- /* o: n/a */
+ /* o: to tell user that client is now fully filled and ready for use */
DC_API_REGISTER,/* i: pass a dc_client, to relogin FIX pr rt cl&cl->user not creat new */
/* o: the previously passed dc_client with set status */
DC_API_STATUS, /* i: N/A */
@@ -99,14 +101,16 @@ void dc_api_io_free (struct dc_api_io * s) {
void dc_api_i (struct dc_api_io);
enum dc_lws_headers {
DC_LWS_AUTHORIZATION,
+ DC_LWS_CONTENT_TYPE,
DC_LWS_HEADERS_LENGTH
};
char * dc_lws_headers[] = {
"Authorization:",
+ "Content-Type:"
};
struct dc_lws_pass { /* struct that is allocated for in dc_lws_cb unique per connection in void * us */
char * body; /* this contains post body and when _CB is called, it contains response */
- size_t body_length; /* body is NULL terminated - note0 in src/api.c */
+ size_t body_length; /* body is NULL terminated or NULL in case of failure */
char headers[DC_LWS_HEADERS_LENGTH][DC_LWS_MAX_HEADER_LENGTH]; /* nofree, a static 2d array */
int status; /* HTTP response code /\ headers contain request headers, then resp. */
struct dc_api_io api_io; /* so dc_api_io can decide what shall be passed into _CB */