js: Move /save to C.
All checks were successful
Build Tilde Friends / Build-All (push) Successful in 15m51s
All checks were successful
Build Tilde Friends / Build-All (push) Successful in 15m51s
This commit is contained in:
274
src/httpd.js.c
274
src/httpd.js.c
@ -966,6 +966,56 @@ static void _httpd_endpoint_static(tf_http_request_t* request)
|
||||
tf_file_stat(task, path, _httpd_endpoint_static_stat, request);
|
||||
}
|
||||
|
||||
typedef struct _user_app_t
|
||||
{
|
||||
const char* user;
|
||||
const char* app;
|
||||
} user_app_t;
|
||||
|
||||
static user_app_t* _parse_user_app_from_path(const char* path, const char* expected_suffix)
|
||||
{
|
||||
if (!path || path[0] != '/' || path[1] != '~')
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
size_t length = strlen(path);
|
||||
size_t suffix_length = expected_suffix ? strlen(expected_suffix) : 0;
|
||||
if (length < suffix_length || strcmp(path + length - suffix_length, expected_suffix) != 0)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char* slash = strchr(path + 2, '/');
|
||||
if (!slash)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char* user = path + 2;
|
||||
size_t user_length = (size_t)(slash - user);
|
||||
const char* app = slash + 1;
|
||||
size_t app_length = (size_t)(length - suffix_length - user_length - 3);
|
||||
user_app_t* result = tf_malloc(sizeof(user_app_t) + user_length + 1 + app_length + 1);
|
||||
|
||||
*result = (user_app_t) {
|
||||
.user = (char*)(result + 1),
|
||||
.app = (char*)(result + 1) + user_length + 1,
|
||||
};
|
||||
memcpy((char*)result->user, user, user_length);
|
||||
((char*)result->user)[user_length] = '\0';
|
||||
memcpy((char*)result->app, app, app_length);
|
||||
((char*)result->app)[app_length] = '\0';
|
||||
|
||||
if (!_is_name_valid(result->user) || !_is_name_valid(result->app))
|
||||
{
|
||||
tf_free(result);
|
||||
result = NULL;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
typedef struct _view_t
|
||||
{
|
||||
tf_http_request_t* request;
|
||||
@ -996,24 +1046,23 @@ static void _httpd_endpoint_view_work(tf_ssb_t* ssb, void* user_data)
|
||||
view_t* view = user_data;
|
||||
tf_http_request_t* request = view->request;
|
||||
char blob_id[256] = "";
|
||||
if (request->path[0] == '/' && request->path[1] == '~')
|
||||
|
||||
user_app_t* user_app = _parse_user_app_from_path(request->path, "/view");
|
||||
if (user_app)
|
||||
{
|
||||
char user[256] = "";
|
||||
char path[1024] = "";
|
||||
const char* slash = strchr(request->path + 2, '/');
|
||||
if (slash)
|
||||
{
|
||||
snprintf(user, sizeof(user), "%.*s", (int)(slash - (request->path + 2)), request->path + 2);
|
||||
snprintf(path, sizeof(path), "path:%.*s", (int)(strlen(slash + 1) - strlen("/view")), slash + 1);
|
||||
const char* value = tf_ssb_db_get_property(ssb, user, path);
|
||||
snprintf(blob_id, sizeof(blob_id), "%s", value);
|
||||
tf_free((void*)value);
|
||||
}
|
||||
size_t app_path_length = strlen("path:") + strlen(user_app->app) + 1;
|
||||
char* app_path = tf_malloc(app_path_length);
|
||||
snprintf(app_path, app_path_length, "path:%s", user_app->app);
|
||||
const char* value = tf_ssb_db_get_property(ssb, user_app->user, app_path);
|
||||
snprintf(blob_id, sizeof(blob_id), "%s", value);
|
||||
tf_free(app_path);
|
||||
tf_free((void*)value);
|
||||
}
|
||||
else if (request->path[0] == '/' && request->path[1] == '&')
|
||||
{
|
||||
snprintf(blob_id, sizeof(blob_id), "%.*s", (int)(strlen(request->path) - strlen("/view") - 1), request->path + 1);
|
||||
}
|
||||
tf_free(user_app);
|
||||
|
||||
if (*blob_id)
|
||||
{
|
||||
@ -1082,6 +1131,162 @@ static void _httpd_endpoint_view(tf_http_request_t* request)
|
||||
tf_ssb_run_work(ssb, _httpd_endpoint_view_work, _httpd_endpoint_view_after_work, view);
|
||||
}
|
||||
|
||||
typedef struct _save_t
|
||||
{
|
||||
tf_http_request_t* request;
|
||||
int response;
|
||||
char blob_id[256];
|
||||
} save_t;
|
||||
|
||||
static void _httpd_endpoint_save_work(tf_ssb_t* ssb, void* user_data)
|
||||
{
|
||||
save_t* save = user_data;
|
||||
tf_http_request_t* request = save->request;
|
||||
const char* session = tf_http_get_cookie(tf_http_request_get_header(request, "cookie"), "session");
|
||||
|
||||
JSMallocFunctions funcs = { 0 };
|
||||
tf_get_js_malloc_functions(&funcs);
|
||||
JSRuntime* runtime = JS_NewRuntime2(&funcs, NULL);
|
||||
JSContext* context = JS_NewContext(runtime);
|
||||
|
||||
JSValue jwt = _authenticate_jwt(ssb, context, session);
|
||||
JSValue user = JS_GetPropertyStr(context, jwt, "name");
|
||||
const char* user_string = JS_ToCString(context, user);
|
||||
|
||||
if (user_string && _is_name_valid(user_string))
|
||||
{
|
||||
user_app_t* user_app = _parse_user_app_from_path(request->path, "/save");
|
||||
if (user_app)
|
||||
{
|
||||
if (strcmp(user_string, user_app->user) == 0 || (strcmp(user_app->user, "core") == 0 && tf_ssb_db_user_has_permission(ssb, user_string, "administration")))
|
||||
{
|
||||
size_t path_length = strlen("path:") + strlen(user_app->app) + 1;
|
||||
char* app_path = tf_malloc(path_length);
|
||||
snprintf(app_path, path_length, "path:%s", user_app->app);
|
||||
|
||||
const char* old_blob_id = tf_ssb_db_get_property(ssb, user_app->user, app_path);
|
||||
|
||||
JSValue new_app = JS_ParseJSON(context, request->body, request->content_length, NULL);
|
||||
tf_util_report_error(context, new_app);
|
||||
if (JS_IsObject(new_app))
|
||||
{
|
||||
uint8_t* old_blob = NULL;
|
||||
size_t old_blob_size = 0;
|
||||
if (tf_ssb_db_blob_get(ssb, old_blob_id, &old_blob, &old_blob_size))
|
||||
{
|
||||
JSValue old_app = JS_ParseJSON(context, (const char*)old_blob, old_blob_size, NULL);
|
||||
if (JS_IsObject(old_app))
|
||||
{
|
||||
JSAtom previous = JS_NewAtom(context, "previous");
|
||||
JS_DeleteProperty(context, old_app, previous, 0);
|
||||
JS_DeleteProperty(context, new_app, previous, 0);
|
||||
|
||||
JSValue old_app_json = JS_JSONStringify(context, old_app, JS_NULL, JS_NULL);
|
||||
JSValue new_app_json = JS_JSONStringify(context, new_app, JS_NULL, JS_NULL);
|
||||
const char* old_app_str = JS_ToCString(context, old_app_json);
|
||||
const char* new_app_str = JS_ToCString(context, new_app_json);
|
||||
|
||||
if (old_app_str && new_app_str && strcmp(old_app_str, new_app_str) == 0)
|
||||
{
|
||||
snprintf(save->blob_id, sizeof(save->blob_id), "/%s", old_blob_id);
|
||||
save->response = 200;
|
||||
}
|
||||
|
||||
JS_FreeCString(context, old_app_str);
|
||||
JS_FreeCString(context, new_app_str);
|
||||
JS_FreeValue(context, old_app_json);
|
||||
JS_FreeValue(context, new_app_json);
|
||||
JS_FreeAtom(context, previous);
|
||||
}
|
||||
JS_FreeValue(context, old_app);
|
||||
tf_free(old_blob);
|
||||
}
|
||||
|
||||
if (!save->response)
|
||||
{
|
||||
if (old_blob_id)
|
||||
{
|
||||
JS_SetPropertyStr(context, new_app, "previous", JS_NewString(context, old_blob_id));
|
||||
}
|
||||
JSValue new_app_json = JS_JSONStringify(context, new_app, JS_NULL, JS_NULL);
|
||||
size_t new_app_length = 0;
|
||||
const char* new_app_str = JS_ToCStringLen(context, &new_app_length, new_app_json);
|
||||
|
||||
char blob_id[250] = { 0 };
|
||||
if (tf_ssb_db_blob_store(ssb, (const uint8_t*)new_app_str, new_app_length, blob_id, sizeof(blob_id), NULL) &&
|
||||
tf_ssb_db_set_property(ssb, user_app->user, app_path, blob_id))
|
||||
{
|
||||
tf_ssb_db_add_value_to_array_property(ssb, user_app->user, "apps", user_app->app);
|
||||
snprintf(save->blob_id, sizeof(save->blob_id), "/%s", blob_id);
|
||||
save->response = 200;
|
||||
}
|
||||
|
||||
JS_FreeCString(context, new_app_str);
|
||||
JS_FreeValue(context, new_app_json);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
save->response = 400;
|
||||
}
|
||||
JS_FreeValue(context, new_app);
|
||||
|
||||
tf_free(app_path);
|
||||
tf_free((void*)old_blob_id);
|
||||
}
|
||||
else
|
||||
{
|
||||
save->response = 401;
|
||||
}
|
||||
tf_free(user_app);
|
||||
}
|
||||
else if (strcmp(request->path, "/save") == 0)
|
||||
{
|
||||
char blob_id[250] = { 0 };
|
||||
if (tf_ssb_db_blob_store(ssb, request->body, request->content_length, blob_id, sizeof(blob_id), NULL))
|
||||
{
|
||||
snprintf(save->blob_id, sizeof(save->blob_id), "/%s", blob_id);
|
||||
save->response = 200;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
save->response = 400;
|
||||
}
|
||||
}
|
||||
|
||||
tf_free((void*)session);
|
||||
JS_FreeCString(context, user_string);
|
||||
JS_FreeValue(context, user);
|
||||
JS_FreeValue(context, jwt);
|
||||
JS_FreeContext(context);
|
||||
JS_FreeRuntime(runtime);
|
||||
}
|
||||
|
||||
static void _httpd_endpoint_save_after_work(tf_ssb_t* ssb, int status, void* user_data)
|
||||
{
|
||||
save_t* save = user_data;
|
||||
tf_http_request_t* request = save->request;
|
||||
if (*save->blob_id)
|
||||
{
|
||||
tf_http_respond(request, 200, NULL, 0, save->blob_id, strlen(save->blob_id));
|
||||
}
|
||||
tf_http_request_unref(request);
|
||||
tf_free(save);
|
||||
}
|
||||
|
||||
static void _httpd_endpoint_save(tf_http_request_t* request)
|
||||
{
|
||||
tf_http_request_ref(request);
|
||||
tf_task_t* task = request->user_data;
|
||||
tf_ssb_t* ssb = tf_task_get_ssb(task);
|
||||
save_t* save = tf_malloc(sizeof(save_t));
|
||||
*save = (save_t) {
|
||||
.request = request,
|
||||
};
|
||||
tf_ssb_run_work(ssb, _httpd_endpoint_save_work, _httpd_endpoint_save_after_work, save);
|
||||
}
|
||||
|
||||
typedef struct _delete_t
|
||||
{
|
||||
tf_http_request_t* request;
|
||||
@ -1104,32 +1309,31 @@ static void _httpd_endpoint_delete_work(tf_ssb_t* ssb, void* user_data)
|
||||
const char* user_string = JS_ToCString(context, user);
|
||||
if (user_string && _is_name_valid(user_string))
|
||||
{
|
||||
size_t length = strlen(user_string);
|
||||
if (request->path && request->path[0] == '/' && request->path[1] == '~' &&
|
||||
(strncmp(request->path + 2, user_string, length) == 0 ||
|
||||
(strncmp(request->path + 2, "core", strlen("core")) == 0 && tf_ssb_db_user_has_permission(ssb, user_string, "administration"))) &&
|
||||
request->path[2 + length] == '/')
|
||||
user_app_t* user_app = _parse_user_app_from_path(request->path, "/delete");
|
||||
if (user_app)
|
||||
{
|
||||
char* app_name = tf_strdup(request->path + 2 + length + 1);
|
||||
if (app_name)
|
||||
if (strcmp(user_string, user_app->user) == 0 || (strcmp(user_app->user, "core") == 0 && tf_ssb_db_user_has_permission(ssb, user_string, "administration")))
|
||||
{
|
||||
if (strlen(app_name) > strlen("/delete") && strcmp(app_name + strlen(app_name) - strlen("/delete"), "/delete") == 0)
|
||||
{
|
||||
app_name[strlen(app_name) - strlen("/delete")] = '\0';
|
||||
}
|
||||
size_t path_length = strlen("path:") + strlen(user_app->app) + 1;
|
||||
char* app_path = tf_malloc(path_length);
|
||||
snprintf(app_path, path_length, "path:%s", user_app->app);
|
||||
|
||||
bool changed = false;
|
||||
changed = tf_ssb_db_remove_value_from_array_property(ssb, user_string, "apps", user_app->app) || changed;
|
||||
changed = tf_ssb_db_remove_property(ssb, user_string, app_path) || changed;
|
||||
delete->response = changed ? 200 : 404;
|
||||
tf_free(app_path);
|
||||
}
|
||||
else
|
||||
{
|
||||
delete->response = 401;
|
||||
}
|
||||
|
||||
size_t path_length = strlen("path:") + strlen(app_name) + 1;
|
||||
char* app_path = tf_malloc(path_length);
|
||||
snprintf(app_path, path_length, "path:%s", app_name);
|
||||
|
||||
bool changed = false;
|
||||
changed = tf_ssb_db_remove_value_from_array_property(ssb, user_string, "apps", app_name) || changed;
|
||||
changed = tf_ssb_db_remove_property(ssb, user_string, app_path) || changed;
|
||||
delete->response = changed ? 200 : 404;
|
||||
tf_free(app_name);
|
||||
tf_free(app_path);
|
||||
}
|
||||
else
|
||||
{
|
||||
delete->response = 404;
|
||||
}
|
||||
tf_free(user_app);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -1898,7 +2102,9 @@ void tf_httpd_register(JSContext* context)
|
||||
tf_http_add_handler(http, "/~*/*/", _httpd_endpoint_static, NULL, task);
|
||||
tf_http_add_handler(http, "/&*.sha256/", _httpd_endpoint_static, NULL, task);
|
||||
tf_http_add_handler(http, "/*/view", _httpd_endpoint_view, NULL, task);
|
||||
tf_http_add_handler(http, "/~*/*/save", _httpd_endpoint_save, NULL, task);
|
||||
tf_http_add_handler(http, "/~*/*/delete", _httpd_endpoint_delete, NULL, task);
|
||||
tf_http_add_handler(http, "/save", _httpd_endpoint_save, NULL, task);
|
||||
|
||||
tf_http_add_handler(http, "/robots.txt", _httpd_endpoint_robots_txt, NULL, NULL);
|
||||
tf_http_add_handler(http, "/debug", _httpd_endpoint_debug, NULL, task);
|
||||
|
Reference in New Issue
Block a user