From 724afe49c1f86d77ea6a4748bbc9535d5bfbf0b4 Mon Sep 17 00:00:00 2001 From: Felicia Seo Date: Thu, 8 Dec 2022 08:48:09 -0500 Subject: [PATCH] post login, post logout, multiclient --- src/http.c | 104 ++++++++++++++++++++++++++++++++++++++++++++++++++--- src/http.h | 3 +- src/main.c | 16 +++++---- 3 files changed, 111 insertions(+), 12 deletions(-) diff --git a/src/http.c b/src/http.c index 4e94027..935837a 100644 --- a/src/http.c +++ b/src/http.c @@ -28,6 +28,8 @@ #include "bufio.h" #include "main.h" +static const char * NEVER_EMBED_A_SECRET_IN_CODE = "supa secret"; + // Need macros here because of the sizeof #define CRLF "\r\n" #define CR "\r" @@ -117,6 +119,10 @@ http_process_headers(struct http_transaction *ta) /* Handle other headers here. Both field_value and field_name * are zero-terminated strings. */ + if (!strcasecmp(field_name, "Cookie")) { + ta->cookie = bufio_ptr2offset(ta->client->bufio, field_name); + ta->token = field_value; // fix this! needs to be just auth_token part + } } } @@ -152,7 +158,15 @@ add_content_length(buffer_t *res, size_t len) static void start_response(struct http_transaction * ta, buffer_t *res) { - buffer_appends(res, "HTTP/1.0 "); + switch (ta->req_version) { + case HTTP_1_0: + buffer_appends(res, "HTTP/1.0 "); + break; + case HTTP_1_1: + default: + buffer_appends(res, "HTTP/1.1 "); + break; + } switch (ta->resp_status) { case HTTP_OK: @@ -354,6 +368,68 @@ out: return success; } +static bool +post_handle_login(struct http_transaction *ta) +{ + char* req_body = bufio_offset2ptr(ta->client->bufio, ta->req_body); + + char* saveptr; + req_body++; + char* u_heading = strtok_r(req_body, ":", &saveptr); + char* username = strtok_r(NULL, ",", &saveptr); + char* p_heading = strtok_r(NULL, ":", &saveptr); + char* password = strtok_r(NULL, "}", &saveptr); + + if (!strcmp(u_heading, "\"username\"") && (strlen(username) > 2) + && !strcmp(p_heading, "\"password\"") && (strlen(password)) > 2) + { + // Create cookie. + jwt_t* cookie; + int rc = jwt_new(&cookie); + if (rc) + return send_error(ta, HTTP_INTERNAL_ERROR, "jwt_new"); + + // Add grants. + username++; + username = strtok_r(username, "\"", &saveptr); + rc = jwt_add_grant(cookie, "sub", username); + if (rc) + return send_error(ta, HTTP_INTERNAL_ERROR, "jwt_add_grant"); + + time_t age = time(NULL); + rc = jwt_add_grant_int(cookie, "iat", age); + if (rc) + return send_error(ta, HTTP_INTERNAL_ERROR, "jwt_add_grant"); + + time_t max_age = age + 3600 * 24; + rc = jwt_add_grant_int(cookie, "exp", max_age); + if (rc) + return send_error(ta, HTTP_INTERNAL_ERROR, "jwt_add_grant"); + + // Set algorithm. + rc = jwt_set_alg(cookie, JWT_ALG_HS256, (unsigned char *)NEVER_EMBED_A_SECRET_IN_CODE, strlen(NEVER_EMBED_A_SECRET_IN_CODE)); + if (rc) + return send_error(ta, HTTP_INTERNAL_ERROR, "jwt_set_alg"); + + // Create token. + char* token = jwt_encode_str(cookie); + if (token == NULL) + return send_error(ta, HTTP_INTERNAL_ERROR, "jwt_encode_str"); + + // Add Set-Cookie header. + http_add_header(&ta->resp_headers, "Set-Cookie", "auth_token=%s; Path=%s; Max-Age=%d; HttpOnly", token, "/", max_age); + + // + char *grants = jwt_get_grants_json(cookie, NULL); + buffer_appends(&ta->resp_body, grants); + buffer_appends(&ta->resp_body, CRLF); + ta->resp_status = HTTP_OK; + return send_response(ta); + } + + return false; +} + static bool get_handle_login(struct http_transaction *ta) { http_add_header(&ta->resp_headers, "Content-Type", "application/json"); @@ -433,6 +509,9 @@ static int val_api_url(struct http_transaction *ta) { if (!strcmp(req_path, "/api/video")) { return 1; } + if (!strcmp(req_path, "/api/logout")) { + return 2; + } return -1; } @@ -449,6 +528,7 @@ handle_api(struct http_transaction *ta) if (val == 0) { if (ta->req_method == HTTP_POST) { // Handle login post + return post_handle_login(ta); } else if (ta->req_method == HTTP_GET){ @@ -461,7 +541,7 @@ handle_api(struct http_transaction *ta) } } - else { + if (val == 1) { DIR* dir = opendir(server_root); char *json = list_videos(dir); fprintf(stderr, "json: %s\n", json); @@ -477,6 +557,12 @@ handle_api(struct http_transaction *ta) return send_response(ta); } + if (ta->req_method == HTTP_POST) // handles logout + { + char* cookie = "auth_token=; Path=/; Max-Age=0; HttpOnly"; + ta->cookie = bufio_ptr2offset(ta->client->bufio, cookie); + return true; + } return false; @@ -489,6 +575,12 @@ http_setup_client(struct http_client *self, struct bufio *bufio) self->bufio = bufio; } +static bool +handle_private(struct http_transaction *ta) +{ + return false; +} + /* Handle a single HTTP transaction. Returns true on success. */ bool http_handle_transaction(struct http_client *self) @@ -499,6 +591,10 @@ http_handle_transaction(struct http_client *self) if (!http_parse_request(&ta)) return false; + + bool is_http_1_1 = false; // false + if (ta.req_version == HTTP_1_1) + is_http_1_1 = true; // true if (!http_process_headers(&ta)) return false; @@ -523,7 +619,7 @@ http_handle_transaction(struct http_client *self) rc = handle_api(&ta); } else if (STARTS_WITH(req_path, "/private")) { - /* not implemented */ + rc = handle_private(&ta); } else { rc = handle_static_asset(&ta, server_root); } @@ -531,5 +627,5 @@ http_handle_transaction(struct http_client *self) buffer_delete(&ta.resp_headers); buffer_delete(&ta.resp_body); - return rc; + return is_http_1_1 && rc; } diff --git a/src/http.h b/src/http.h index 8443d86..05ee571 100644 --- a/src/http.h +++ b/src/http.h @@ -39,7 +39,8 @@ struct http_transaction { size_t req_path; // expressed as offset into the client's bufio. size_t req_body; // ditto int req_content_len; // content length of request body - + + size_t cookie; // offset to cookie header char *token; // authentication token /* response related fields */ diff --git a/src/main.c b/src/main.c index 445c2d5..95375e5 100644 --- a/src/main.c +++ b/src/main.c @@ -35,11 +35,13 @@ int token_expiration_time = 24 * 60 * 60; // root from which static files are served char * server_root; -static void *thr_func(void *c) { +static void *thr_func(void *cs) { - struct http_client *client = c; - while (http_handle_transaction(client)); - bufio_close(client->bufio); + int client_socket = *(int*) cs; + struct http_client client; + http_setup_client(&client, bufio_create(client_socket)); + while (http_handle_transaction(&client)){}; + bufio_close(client.bufio); return NULL; } @@ -65,10 +67,10 @@ server_loop(char *port_string) if (client_socket == -1){ return; } - struct http_client *client = malloc(sizeof(struct http_client)); - http_setup_client(client, bufio_create(client_socket)); + //~ struct http_client *client = malloc(sizeof(struct http_client)); + //~ http_setup_client(client, bufio_create(client_socket)); - int rc = pthread_create(&threads[num_clients++], NULL, thr_func, client); + int rc = pthread_create(&threads[num_clients++], NULL, thr_func, &client_socket); if (rc) { perror(NULL);