js: Move app delete to C.
All checks were successful
Build Tilde Friends / Build-All (push) Successful in 14m34s
All checks were successful
Build Tilde Friends / Build-All (push) Successful in 14m34s
This commit is contained in:
parent
2e66666bdf
commit
fa00a41fe0
32
core/core.js
32
core/core.js
@ -995,36 +995,6 @@ async function blobHandler(request, response, blobId, uri) {
|
|||||||
response.writeHead(400, {'Content-Type': 'text/plain; charset=utf-8'});
|
response.writeHead(400, {'Content-Type': 'text/plain; charset=utf-8'});
|
||||||
response.end('Invalid name.');
|
response.end('Invalid name.');
|
||||||
}
|
}
|
||||||
} else if (uri == '/delete') {
|
|
||||||
let match;
|
|
||||||
if ((match = /^\/\~(\w+)\/(\w+)$/.exec(blobId))) {
|
|
||||||
let user = match[1];
|
|
||||||
let appName = match[2];
|
|
||||||
let credentials = await httpd.auth_query(request.headers);
|
|
||||||
if (
|
|
||||||
credentials &&
|
|
||||||
credentials.session &&
|
|
||||||
(credentials.session.name == user ||
|
|
||||||
(credentials.permissions.administration && user == 'core'))
|
|
||||||
) {
|
|
||||||
let database = new Database(user);
|
|
||||||
let apps = new Set();
|
|
||||||
try {
|
|
||||||
apps = new Set(JSON.parse(await database.get('apps')));
|
|
||||||
} catch {}
|
|
||||||
if (apps.delete(appName)) {
|
|
||||||
await database.set('apps', JSON.stringify([...apps].sort()));
|
|
||||||
}
|
|
||||||
database.remove('path:' + appName);
|
|
||||||
} else {
|
|
||||||
response.writeHead(401, {'Content-Type': 'text/plain; charset=utf-8'});
|
|
||||||
response.end('401 Unauthorized');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
response.writeHead(200, {'Content-Type': 'text/plain; charset=utf-8'});
|
|
||||||
response.end('OK');
|
|
||||||
} else {
|
} else {
|
||||||
let data;
|
let data;
|
||||||
let match;
|
let match;
|
||||||
@ -1175,7 +1145,7 @@ loadSettings()
|
|||||||
(match = /^\/([&\%][^\.]{44}(?:\.\w+)?)(\/?.*)/.exec(request.uri))
|
(match = /^\/([&\%][^\.]{44}(?:\.\w+)?)(\/?.*)/.exec(request.uri))
|
||||||
) {
|
) {
|
||||||
return blobHandler(request, response, match[1], match[2]);
|
return blobHandler(request, response, match[1], match[2]);
|
||||||
} else if ((match = /^(.*)(\/(?:save|delete)?)$/.exec(request.uri))) {
|
} else if ((match = /^(.*)(\/(?:save)?)$/.exec(request.uri))) {
|
||||||
return blobHandler(request, response, match[1], match[2]);
|
return blobHandler(request, response, match[1], match[2]);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -39,6 +39,7 @@ const int64_t k_refresh_interval = 1ULL * 7 * 24 * 60 * 60 * 1000;
|
|||||||
|
|
||||||
static JSValue _authenticate_jwt(tf_ssb_t* ssb, JSContext* context, const char* jwt);
|
static JSValue _authenticate_jwt(tf_ssb_t* ssb, JSContext* context, const char* jwt);
|
||||||
static JSValue _httpd_websocket_upgrade(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv);
|
static JSValue _httpd_websocket_upgrade(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv);
|
||||||
|
static bool _is_name_valid(const char* name);
|
||||||
static const char* _make_session_jwt(JSContext* context, tf_ssb_t* ssb, const char* name);
|
static const char* _make_session_jwt(JSContext* context, tf_ssb_t* ssb, const char* name);
|
||||||
static const char* _make_set_session_cookie_header(tf_http_request_t* request, const char* session_cookie);
|
static const char* _make_set_session_cookie_header(tf_http_request_t* request, const char* session_cookie);
|
||||||
const char** _form_data_decode(const char* data, int length);
|
const char** _form_data_decode(const char* data, int length);
|
||||||
@ -1081,6 +1082,89 @@ 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);
|
tf_ssb_run_work(ssb, _httpd_endpoint_view_work, _httpd_endpoint_view_after_work, view);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
typedef struct _delete_t
|
||||||
|
{
|
||||||
|
tf_http_request_t* request;
|
||||||
|
const char* session;
|
||||||
|
int response;
|
||||||
|
} delete_t;
|
||||||
|
|
||||||
|
static void _httpd_endpoint_delete_work(tf_ssb_t* ssb, void* user_data)
|
||||||
|
{
|
||||||
|
delete_t* delete = user_data;
|
||||||
|
tf_http_request_t* request = delete->request;
|
||||||
|
|
||||||
|
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, delete->session);
|
||||||
|
JSValue user = JS_GetPropertyStr(context, jwt, "name");
|
||||||
|
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] == '~' &&
|
||||||
|
/* TODO: admin users used to be able to delete core apps */
|
||||||
|
strncmp(request->path + 2, user_string, length) == 0 && request->path[2 + length] == '/')
|
||||||
|
{
|
||||||
|
char* app_name = tf_strdup(request->path + 2 + length + 1);
|
||||||
|
if (app_name)
|
||||||
|
{
|
||||||
|
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(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 = 401;
|
||||||
|
}
|
||||||
|
|
||||||
|
JS_FreeCString(context, user_string);
|
||||||
|
JS_FreeValue(context, user);
|
||||||
|
JS_FreeValue(context, jwt);
|
||||||
|
JS_FreeContext(context);
|
||||||
|
JS_FreeRuntime(runtime);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _httpd_endpoint_delete_after_work(tf_ssb_t* ssb, int status, void* user_data)
|
||||||
|
{
|
||||||
|
delete_t* delete = user_data;
|
||||||
|
const char* k_payload = tf_http_status_text(delete->response ? delete->response : 404);
|
||||||
|
tf_http_respond(delete->request, delete->response ? delete->response : 404, NULL, 0, k_payload, strlen(k_payload));
|
||||||
|
tf_http_request_unref(delete->request);
|
||||||
|
tf_free((void*)delete->session);
|
||||||
|
tf_free(delete);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _httpd_endpoint_delete(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);
|
||||||
|
delete_t* delete = tf_malloc(sizeof(delete_t));
|
||||||
|
*delete = (delete_t) {
|
||||||
|
.request = request,
|
||||||
|
.session = tf_http_get_cookie(tf_http_request_get_header(request, "cookie"), "session"),
|
||||||
|
};
|
||||||
|
tf_ssb_run_work(ssb, _httpd_endpoint_delete_work, _httpd_endpoint_delete_after_work, delete);
|
||||||
|
}
|
||||||
|
|
||||||
static void _httpd_endpoint_root_callback(const char* path, void* user_data)
|
static void _httpd_endpoint_root_callback(const char* path, void* user_data)
|
||||||
{
|
{
|
||||||
tf_http_request_t* request = user_data;
|
tf_http_request_t* request = user_data;
|
||||||
@ -1402,7 +1486,7 @@ static JSValue _authenticate_jwt(tf_ssb_t* ssb, JSContext* context, const char*
|
|||||||
static bool _session_is_authenticated_as_user(JSContext* context, JSValue session)
|
static bool _session_is_authenticated_as_user(JSContext* context, JSValue session)
|
||||||
{
|
{
|
||||||
bool result = false;
|
bool result = false;
|
||||||
JSValue user = JS_GetPropertyStr(context, session, "user");
|
JSValue user = JS_GetPropertyStr(context, session, "name");
|
||||||
const char* user_string = JS_ToCString(context, user);
|
const char* user_string = JS_ToCString(context, user);
|
||||||
result = user_string && strcmp(user_string, "guest") != 0;
|
result = user_string && strcmp(user_string, "guest") != 0;
|
||||||
JS_FreeCString(context, user_string);
|
JS_FreeCString(context, user_string);
|
||||||
@ -1813,6 +1897,7 @@ void tf_httpd_register(JSContext* context)
|
|||||||
tf_http_add_handler(http, "/~*/*/", _httpd_endpoint_static, NULL, task);
|
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, "/&*.sha256/", _httpd_endpoint_static, NULL, task);
|
||||||
tf_http_add_handler(http, "/*/view", _httpd_endpoint_view, NULL, task);
|
tf_http_add_handler(http, "/*/view", _httpd_endpoint_view, NULL, task);
|
||||||
|
tf_http_add_handler(http, "/~*/*/delete", _httpd_endpoint_delete, NULL, task);
|
||||||
|
|
||||||
tf_http_add_handler(http, "/robots.txt", _httpd_endpoint_robots_txt, NULL, NULL);
|
tf_http_add_handler(http, "/robots.txt", _httpd_endpoint_robots_txt, NULL, NULL);
|
||||||
tf_http_add_handler(http, "/debug", _httpd_endpoint_debug, NULL, task);
|
tf_http_add_handler(http, "/debug", _httpd_endpoint_debug, NULL, task);
|
||||||
|
38
src/ssb.db.c
38
src/ssb.db.c
@ -1787,6 +1787,44 @@ bool tf_ssb_db_set_property(tf_ssb_t* ssb, const char* id, const char* key, cons
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool tf_ssb_db_remove_property(tf_ssb_t* ssb, const char* id, const char* key)
|
||||||
|
{
|
||||||
|
bool result = false;
|
||||||
|
sqlite3* db = tf_ssb_acquire_db_writer(ssb);
|
||||||
|
sqlite3_stmt* statement = NULL;
|
||||||
|
if (sqlite3_prepare(db, "DELETE FROM properties WHERE id = ? AND key = ?", -1, &statement, NULL) == SQLITE_OK)
|
||||||
|
{
|
||||||
|
if (sqlite3_bind_text(statement, 1, id, -1, NULL) == SQLITE_OK && sqlite3_bind_text(statement, 2, key, -1, NULL) == SQLITE_OK)
|
||||||
|
{
|
||||||
|
result = sqlite3_step(statement) == SQLITE_DONE && sqlite3_changes(db) != 0;
|
||||||
|
}
|
||||||
|
sqlite3_finalize(statement);
|
||||||
|
}
|
||||||
|
tf_ssb_release_db_writer(ssb, db);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool tf_ssb_db_remove_value_from_array_property(tf_ssb_t* ssb, const char* id, const char* key, const char* value)
|
||||||
|
{
|
||||||
|
bool result = false;
|
||||||
|
sqlite3* db = tf_ssb_acquire_db_writer(ssb);
|
||||||
|
sqlite3_stmt* statement = NULL;
|
||||||
|
if (sqlite3_prepare(db,
|
||||||
|
"UPDATE properties SET value = json_remove(properties.value, entry.fullkey) FROM json_each(properties.value) AS entry WHERE properties.id = ? AND properties.key = ? "
|
||||||
|
"AND entry.value = ?",
|
||||||
|
-1, &statement, NULL) == SQLITE_OK)
|
||||||
|
{
|
||||||
|
if (sqlite3_bind_text(statement, 1, id, -1, NULL) == SQLITE_OK && sqlite3_bind_text(statement, 2, key, -1, NULL) == SQLITE_OK &&
|
||||||
|
sqlite3_bind_text(statement, 3, value, -1, NULL) == SQLITE_OK)
|
||||||
|
{
|
||||||
|
result = sqlite3_step(statement) == SQLITE_DONE && sqlite3_changes(db) != 0;
|
||||||
|
}
|
||||||
|
sqlite3_finalize(statement);
|
||||||
|
}
|
||||||
|
tf_ssb_release_db_writer(ssb, db);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
bool tf_ssb_db_identity_get_active(sqlite3* db, const char* user, const char* package_owner, const char* package_name, char* out_identity, size_t out_identity_size)
|
bool tf_ssb_db_identity_get_active(sqlite3* db, const char* user, const char* package_owner, const char* package_name, char* out_identity, size_t out_identity_size)
|
||||||
{
|
{
|
||||||
sqlite3_stmt* statement = NULL;
|
sqlite3_stmt* statement = NULL;
|
||||||
|
19
src/ssb.db.h
19
src/ssb.db.h
@ -399,6 +399,25 @@ const char* tf_ssb_db_get_property(tf_ssb_t* ssb, const char* id, const char* ke
|
|||||||
*/
|
*/
|
||||||
bool tf_ssb_db_set_property(tf_ssb_t* ssb, const char* id, const char* key, const char* value);
|
bool tf_ssb_db_set_property(tf_ssb_t* ssb, const char* id, const char* key, const char* value);
|
||||||
|
|
||||||
|
/**
|
||||||
|
** Remove an entry in the properties table.
|
||||||
|
** @param ssb The SSB instance.
|
||||||
|
** @param id The user.
|
||||||
|
** @param key The property key.
|
||||||
|
** @return true if the property was removed successfully.
|
||||||
|
*/
|
||||||
|
bool tf_ssb_db_remove_property(tf_ssb_t* ssb, const char* id, const char* key);
|
||||||
|
|
||||||
|
/**
|
||||||
|
** Remove a value from an entry in the properties table that is a JSON array.
|
||||||
|
** @param ssb The SSB instance.
|
||||||
|
** @param id The user.
|
||||||
|
** @param key The property key.
|
||||||
|
** @param value The value to remove from the JSON array.
|
||||||
|
** @return true if the property was updated.
|
||||||
|
*/
|
||||||
|
bool tf_ssb_db_remove_value_from_array_property(tf_ssb_t* ssb, const char* id, const char* key, const char* value);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
** Resolve a hostname to its index path by global settings.
|
** Resolve a hostname to its index path by global settings.
|
||||||
** @param ssb The SSB instance.
|
** @param ssb The SSB instance.
|
||||||
|
Loading…
Reference in New Issue
Block a user