This commit is contained in:
Felicia Seo 2022-12-11 12:23:40 -05:00
parent a874b62771
commit aeb235246d
3 changed files with 90 additions and 33 deletions

View File

@ -84,6 +84,8 @@ http_parse_request(struct http_transaction *ta)
static bool
http_process_headers(struct http_transaction *ta)
{
ta->from = -1;
ta->to = -1;
for (;;) {
size_t header_offset;
ssize_t len = bufio_readline(ta->client->bufio, &header_offset);
@ -121,13 +123,42 @@ http_process_headers(struct http_transaction *ta)
* are zero-terminated strings.
*/
if (!strcasecmp(field_name, "Cookie")) {
if ((field_value == NULL) || (strlen(field_value) <= 11)
if ((field_value == NULL) || (strlen(field_value) <= 11))
{
ta->resp_status = HTTP_PERMISSION_DENIED;
return false;
printf("%s\n", field_value);
}
ta->token = field_value + 11; // + 11 gets rid of "auth_token=" heading.
ta->valid_token = validate_token_exp(ta, ta->token);
}
if (!strcasecmp(field_name, "Range")){
char *endp;
char *token = strtok_r(field_value, "= ", &endp);
while (token != NULL && strcasecmp(token, "bytes")) {
token = strtok_r(NULL, "= ", &endp);
}
token = strtok_r(NULL, "= ", &endp);
if (token != NULL) {
if (token[0] == '-') {
ta->to = atol(token + 1);
}
else if (token[strlen(token) - 1] == '-') {
token[strlen(token) - 1] = '\0';
ta->from = atol(token);
}
else {
char *to;
char *from = strtok_r(token, "- ", &to);
ta->from = atol(from);
ta->to = atol(to);
}
}
ta->range_request = true;
}
}
}
@ -295,6 +326,9 @@ guess_mime_type(char *filename)
if (!strcasecmp(suffix, ".js"))
return "text/javascript";
if (!strcasecmp(suffix, ".mp4"))
return "video/mp4";
return "text/plain";
}
@ -305,12 +339,12 @@ bool validate_token_exp(struct http_transaction *ta, char* token) {
// Decode token.
int rc = jwt_decode(&cookie, ta->token, (unsigned char *)NEVER_EMBED_A_SECRET_IN_CODE, strlen(NEVER_EMBED_A_SECRET_IN_CODE));
if (rc)
return send_error(ta, HTTP_OK, "{}");
return false;
// Get claim (formatted grants).
char* grants = jwt_get_grants_json(cookie, NULL);
if (grants == NULL)
return send_error(ta, HTTP_OK, "{}");
return false;
ta->grants = grants;
// Get expiration time.
@ -320,6 +354,8 @@ bool validate_token_exp(struct http_transaction *ta, char* token) {
const char *sub;
json_unpack(jgrants, "{s:I, s:I, s:s}", "exp", &exp, "iat", &iat, "sub", &sub);
ta->exp = exp;
// Check expiration time.
if (time(NULL) >= exp)
return false;
@ -327,7 +363,7 @@ bool validate_token_exp(struct http_transaction *ta, char* token) {
return true;
}
/* Handle HTTP transaction for static files. */
/* Handle HTTP transaction for static files. */
static bool
handle_static_asset(struct http_transaction *ta, char *basedir)
{
@ -385,9 +421,28 @@ handle_static_asset(struct http_transaction *ta, char *basedir)
http_add_header(&ta->resp_headers, "Content-Type", "%s", guess_mime_type(fname));
off_t from = 0, to = st.st_size - 1;
if (ta->range_request) {
if (ta->from >= 0) {
from = ta->from;
}
if (ta->to >= 0) {
to = ta->to;
}
}
off_t content_length = to + 1 - from;
add_content_length(&ta->resp_headers, content_length);
http_add_header(&ta->resp_headers, "Accept-Ranges", "bytes");
if (ta->range_request) {
ta->resp_status = HTTP_PARTIAL_CONTENT;
http_add_header(&ta->resp_headers, "Content-Range",
"bytes %ld-%ld/%ld", from, to, st.st_size);
}
bool success = send_response_header(ta);
if (!success)
goto out;
@ -404,17 +459,21 @@ out:
static bool
post_handle_login(struct http_transaction *ta)
{
http_add_header(&ta->resp_headers, "Content-Type", "application/json");
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);
req_body[ta->req_content_len] = '\0';
json_error_t error;
json_t *jgrants = json_loadb(req_body, strlen(req_body), 0, &error);
const char *username;
const char *password;
int rc = json_unpack(jgrants, "{s:s, s:s}", "username", &username, "password", &password);
if (rc == -1)
{
return send_error(ta, HTTP_PERMISSION_DENIED, "???");
}
if (!strcmp(u_heading, "\"username\"") && (strlen(username) > 2)
&& !strcmp(p_heading, "\"password\"") && (strlen(password)) > 2)
if (!strcmp(username, "user0") && !strcmp(password, "thepassword"))
{
// Create cookie.
jwt_t* cookie;
@ -423,8 +482,6 @@ post_handle_login(struct http_transaction *ta)
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");
@ -455,14 +512,13 @@ post_handle_login(struct http_transaction *ta)
// Get claim (formatted grants).
char *grants = jwt_get_grants_json(cookie, NULL);
buffer_appends(&ta->resp_body, grants);
buffer_appends(&ta->resp_body, CRLF);
// Send claim.
ta->resp_status = HTTP_OK;
return send_response(ta);
}
return false;
return send_error(ta, HTTP_PERMISSION_DENIED, "???");
}
@ -470,16 +526,12 @@ static bool get_handle_login(struct http_transaction *ta) {
http_add_header(&ta->resp_headers, "Content-Type", "application/json");
if (!ta->valid_token) {
return send_error(ta, HTTP_PERMISSION_DENIED,"Permission denied.\n");
buffer_appends(&ta->resp_body, "{}");
ta->resp_status = HTTP_OK;
return send_response(ta);
}
//~ char *json = buffer_ensure_capacity(&ta->resp_body, MAX_HEADER_LEN);
//~ int len = snprintf(json, strlen(ta->grants) + 2, "%s\n", ta->grants);
//~ int length = len > MAX_HEADER_LEN ? MAX_HEADER_LEN - 1 : len;
//~ ta->resp_body.len += length;
buffer_appends(&ta->resp_body, ta->grants);
buffer_appends(&ta->resp_body, CRLF);
ta->resp_status = HTTP_OK;
return send_response(ta);
@ -581,14 +633,13 @@ handle_api(struct http_transaction *ta)
return send_response(ta);
}
if (ta->req_method == HTTP_POST) // handles logout
if (val == 2) // handles logout
{
// Add Set-Cookie header.
http_add_header(&ta->resp_headers, "Set-Cookie", "auth_token=; Path=/; Max-Age=0; HttpOnly");
// Send message.
buffer_appends(&ta->resp_body, "{\"message\":\"logging out\"}");
buffer_appends(&ta->resp_body, CRLF);
ta->resp_status = HTTP_OK;
return send_response(ta);
}
@ -608,9 +659,10 @@ static bool
handle_private(struct http_transaction *ta)
{
if (ta->valid_token) {
ta->resp_status = HTTP_OK;
return handle_static_asset(ta, server_root);
}
return send_error(ta, HTTP_PERMISSION_DENIED,"Forbidden.\n");
return send_error(ta, HTTP_PERMISSION_DENIED, "invalid token");
}
/* Handle a single HTTP transaction. Returns true on success. */

View File

@ -42,6 +42,7 @@ struct http_transaction {
char *token; // authentication token
bool valid_token;
long exp;
char* grants;
/* response related fields */
@ -50,6 +51,10 @@ struct http_transaction {
buffer_t resp_body;
struct http_client *client;
off_t from; // range from
off_t to; // range to
bool range_request;
};
struct http_client {

View File

@ -73,8 +73,8 @@ socket_open_bind_listen(char * port_number_string, int backlog)
/* Skip any non-IPv4 addresses.
* Adding support for protocol independence/IPv6 is part of the project.
*/
if (pinfo->ai_family != AF_INET)
continue;
//if (pinfo->ai_family != AF_INET)
//continue;
int s = socket(pinfo->ai_family, pinfo->ai_socktype, pinfo->ai_protocol);
if (s == -1) {