core: Move invoking the permission test to C, at least for adding/removing blocks.
This commit is contained in:
229
src/api.js.c
229
src/api.js.c
@@ -796,6 +796,231 @@ static JSValue _tf_ssb_globalSettingsGet(JSContext* context, JSValueConst this_v
|
||||
return result;
|
||||
}
|
||||
|
||||
typedef struct _modify_block_t
|
||||
{
|
||||
const char* user;
|
||||
char id[k_id_base64_len];
|
||||
bool add;
|
||||
bool completed;
|
||||
JSValue result;
|
||||
JSValue promise[2];
|
||||
} modify_block_t;
|
||||
|
||||
static void _tf_ssb_modify_block_work(tf_ssb_t* ssb, void* user_data)
|
||||
{
|
||||
modify_block_t* work = user_data;
|
||||
sqlite3* db = tf_ssb_acquire_db_writer(ssb);
|
||||
if (work->add)
|
||||
{
|
||||
tf_ssb_db_add_block(db, work->id);
|
||||
}
|
||||
else
|
||||
{
|
||||
tf_ssb_db_remove_block(db, work->id);
|
||||
}
|
||||
tf_ssb_release_db_writer(ssb, db);
|
||||
work->completed = true;
|
||||
}
|
||||
|
||||
static void _tf_ssb_modify_block_after_work(tf_ssb_t* ssb, int status, void* user_data)
|
||||
{
|
||||
modify_block_t* request = user_data;
|
||||
JSContext* context = tf_ssb_get_context(ssb);
|
||||
JSValue error = JS_Call(context, request->completed ? request->promise[0] : request->promise[1], JS_UNDEFINED, 1, &request->result);
|
||||
tf_util_report_error(context, error);
|
||||
JS_FreeValue(context, error);
|
||||
JS_FreeValue(context, request->promise[0]);
|
||||
JS_FreeValue(context, request->promise[1]);
|
||||
JS_FreeValue(context, request->result);
|
||||
tf_free((void*)request->user);
|
||||
tf_free(request);
|
||||
}
|
||||
|
||||
typedef void(permission_test_callback_t)(JSContext* context, bool granted, JSValue value, void* user_data);
|
||||
|
||||
typedef struct _permission_test_t
|
||||
{
|
||||
permission_test_callback_t* callback;
|
||||
void* user_data;
|
||||
} permission_test_t;
|
||||
|
||||
static JSValue _tf_ssb_permission_test_resolve(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv, int magic, JSValue* data)
|
||||
{
|
||||
JSClassID class_id = 0;
|
||||
permission_test_t* work = JS_GetAnyOpaque(data[0], &class_id);
|
||||
JS_FreeValue(context, data[0]);
|
||||
work->callback(context, true, argv[0], work->user_data);
|
||||
tf_free(work);
|
||||
return JS_UNDEFINED;
|
||||
}
|
||||
|
||||
static JSValue _tf_ssb_permission_test_reject(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv, int magic, JSValue* data)
|
||||
{
|
||||
JSClassID class_id = 0;
|
||||
permission_test_t* work = JS_GetAnyOpaque(data[0], &class_id);
|
||||
JS_FreeValue(context, data[0]);
|
||||
work->callback(context, false, argv[0], work->user_data);
|
||||
tf_free(work);
|
||||
return JS_UNDEFINED;
|
||||
}
|
||||
|
||||
static void _tf_ssb_permission_test(JSContext* context, JSValue process, const char* permission, const char* description, permission_test_callback_t* callback, void* user_data)
|
||||
{
|
||||
permission_test_t* payload = tf_malloc(sizeof(permission_test_t));
|
||||
*payload = (permission_test_t) {
|
||||
.callback = callback,
|
||||
.user_data = user_data,
|
||||
};
|
||||
JSValue opaque = JS_NewObject(context);
|
||||
JS_SetOpaque(opaque, payload);
|
||||
JSValue imports = JS_GetPropertyStr(context, process, "imports");
|
||||
JSValue core = JS_GetPropertyStr(context, imports, "core");
|
||||
JSValue permission_test = JS_GetPropertyStr(context, core, "permissionTest");
|
||||
JSValue args[] = {
|
||||
JS_NewString(context, permission),
|
||||
JS_NewString(context, description),
|
||||
};
|
||||
JSValue promise = JS_Call(context, permission_test, imports, tf_countof(args), args);
|
||||
JSValue then = JS_GetPropertyStr(context, promise, "then");
|
||||
JSValue catch = JS_GetPropertyStr(context, promise, "catch");
|
||||
JSValue resolve = JS_NewCFunctionData(context, _tf_ssb_permission_test_resolve, 1, 0, 1, &opaque);
|
||||
JSValue reject = JS_NewCFunctionData(context, _tf_ssb_permission_test_reject, 1, 0, 1, &opaque);
|
||||
JSValue result = JS_Call(context, then, promise, 1, &resolve);
|
||||
tf_util_report_error(context, result);
|
||||
JS_FreeValue(context, result);
|
||||
result = JS_Call(context, catch, promise, 1, &reject);
|
||||
tf_util_report_error(context, result);
|
||||
JS_FreeValue(context, promise);
|
||||
JS_FreeValue(context, resolve);
|
||||
JS_FreeValue(context, reject);
|
||||
JS_FreeValue(context, result);
|
||||
JS_FreeValue(context, then);
|
||||
JS_FreeValue(context, catch);
|
||||
for (int i = 0; i < tf_countof(args); i++)
|
||||
{
|
||||
JS_FreeValue(context, args[i]);
|
||||
}
|
||||
JS_FreeValue(context, permission_test);
|
||||
JS_FreeValue(context, core);
|
||||
JS_FreeValue(context, imports);
|
||||
}
|
||||
|
||||
static void _tf_ssb_modify_block_start_work(JSContext* context, bool granted, JSValue value, void* user_data)
|
||||
{
|
||||
tf_task_t* task = tf_task_get(context);
|
||||
tf_ssb_t* ssb = tf_task_get_ssb(task);
|
||||
modify_block_t* work = user_data;
|
||||
work->result = JS_DupValue(context, value);
|
||||
if (granted)
|
||||
{
|
||||
tf_ssb_run_work(ssb, _tf_ssb_modify_block_work, _tf_ssb_modify_block_after_work, work);
|
||||
}
|
||||
else
|
||||
{
|
||||
_tf_ssb_modify_block_after_work(ssb, 0, work);
|
||||
}
|
||||
}
|
||||
|
||||
static JSValue _tf_ssb_add_block(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv, int magic, JSValue* data)
|
||||
{
|
||||
const char* id = JS_ToCString(context, argv[0]);
|
||||
modify_block_t* work = tf_malloc(sizeof(modify_block_t));
|
||||
*work = (modify_block_t) {
|
||||
.user = _tf_ssb_get_process_credentials_session_name(context, data[0]),
|
||||
.add = true,
|
||||
};
|
||||
tf_string_set(work->id, sizeof(work->id), id);
|
||||
JSValue result = JS_NewPromiseCapability(context, work->promise);
|
||||
JS_FreeCString(context, id);
|
||||
|
||||
char description[256] = "";
|
||||
snprintf(description, sizeof(description), "Block %s.", work->id);
|
||||
_tf_ssb_permission_test(context, data[0], "modify_blocks", description, _tf_ssb_modify_block_start_work, work);
|
||||
return result;
|
||||
}
|
||||
|
||||
static JSValue _tf_ssb_remove_block(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv, int magic, JSValue* data)
|
||||
{
|
||||
const char* id = JS_ToCString(context, argv[0]);
|
||||
modify_block_t* work = tf_malloc(sizeof(modify_block_t));
|
||||
*work = (modify_block_t) {
|
||||
.user = _tf_ssb_get_process_credentials_session_name(context, data[0]),
|
||||
.add = false,
|
||||
};
|
||||
tf_string_set(work->id, sizeof(work->id), id);
|
||||
JSValue result = JS_NewPromiseCapability(context, work->promise);
|
||||
JS_FreeCString(context, id);
|
||||
|
||||
char description[256] = "";
|
||||
snprintf(description, sizeof(description), "Unblock %s.", work->id);
|
||||
_tf_ssb_permission_test(context, data[0], "modify_blocks", description, _tf_ssb_modify_block_start_work, work);
|
||||
return result;
|
||||
}
|
||||
|
||||
typedef struct _block_t
|
||||
{
|
||||
char id[k_id_base64_len];
|
||||
double timestamp;
|
||||
} block_t;
|
||||
|
||||
typedef struct _get_blocks_t
|
||||
{
|
||||
block_t* blocks;
|
||||
int count;
|
||||
JSValue promise[2];
|
||||
} get_blocks_t;
|
||||
|
||||
static void _get_blocks_callback(const char* id, double timestamp, void* user_data)
|
||||
{
|
||||
get_blocks_t* work = user_data;
|
||||
work->blocks = tf_resize_vec(work->blocks, sizeof(block_t) * (work->count + 1));
|
||||
work->blocks[work->count] = (block_t) { .timestamp = timestamp };
|
||||
tf_string_set(work->blocks[work->count].id, sizeof(work->blocks[work->count].id), id);
|
||||
work->count++;
|
||||
}
|
||||
|
||||
static void _tf_ssb_get_blocks_work(tf_ssb_t* ssb, void* user_data)
|
||||
{
|
||||
sqlite3* db = tf_ssb_acquire_db_reader(ssb);
|
||||
tf_ssb_db_get_blocks(db, _get_blocks_callback, user_data);
|
||||
tf_ssb_release_db_reader(ssb, db);
|
||||
}
|
||||
|
||||
static void _tf_ssb_get_blocks_after_work(tf_ssb_t* ssb, int status, void* user_data)
|
||||
{
|
||||
get_blocks_t* work = user_data;
|
||||
JSContext* context = tf_ssb_get_context(ssb);
|
||||
|
||||
JSValue result = JS_NewArray(context);
|
||||
for (int i = 0; i < work->count; i++)
|
||||
{
|
||||
JSValue entry = JS_NewObject(context);
|
||||
JS_SetPropertyStr(context, entry, "id", JS_NewString(context, work->blocks[i].id));
|
||||
JS_SetPropertyStr(context, entry, "timestamp", JS_NewFloat64(context, work->blocks[i].timestamp));
|
||||
JS_SetPropertyUint32(context, result, i, entry);
|
||||
}
|
||||
|
||||
JSValue error = JS_Call(context, work->promise[0], JS_UNDEFINED, 1, &result);
|
||||
JS_FreeValue(context, result);
|
||||
tf_util_report_error(context, error);
|
||||
JS_FreeValue(context, error);
|
||||
JS_FreeValue(context, work->promise[0]);
|
||||
JS_FreeValue(context, work->promise[1]);
|
||||
tf_free(work->blocks);
|
||||
tf_free(work);
|
||||
}
|
||||
|
||||
static JSValue _tf_ssb_get_blocks(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv, int magic, JSValue* data)
|
||||
{
|
||||
tf_task_t* task = tf_task_get(context);
|
||||
tf_ssb_t* ssb = tf_task_get_ssb(task);
|
||||
get_blocks_t* work = tf_malloc(sizeof(get_blocks_t));
|
||||
*work = (get_blocks_t) { 0 };
|
||||
JSValue result = JS_NewPromiseCapability(context, work->promise);
|
||||
tf_ssb_run_work(ssb, _tf_ssb_get_blocks_work, _tf_ssb_get_blocks_after_work, work);
|
||||
return result;
|
||||
}
|
||||
|
||||
static JSValue _tf_api_register_imports(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv)
|
||||
{
|
||||
JSValue imports = argv[0];
|
||||
@@ -831,6 +1056,10 @@ static JSValue _tf_api_register_imports(JSContext* context, JSValueConst this_va
|
||||
{
|
||||
JS_SetPropertyStr(context, core, "globalSettingsDescriptions", JS_NewCFunction(context, _tf_ssb_globalSettingsDescriptions, "globalSettingsDescriptions", 0));
|
||||
JS_SetPropertyStr(context, core, "globalSettingsGet", JS_NewCFunction(context, _tf_ssb_globalSettingsGet, "globalSettingsGet", 1));
|
||||
|
||||
JS_SetPropertyStr(context, ssb, "addBlock", JS_NewCFunctionData(context, _tf_ssb_add_block, 1, 0, 1, &process));
|
||||
JS_SetPropertyStr(context, ssb, "removeBlock", JS_NewCFunctionData(context, _tf_ssb_remove_block, 1, 0, 1, &process));
|
||||
JS_SetPropertyStr(context, ssb, "getBlocks", JS_NewCFunctionData(context, _tf_ssb_get_blocks, 0, 0, 1, &process));
|
||||
}
|
||||
JS_FreeValue(context, administration);
|
||||
JS_FreeValue(context, permissions);
|
||||
|
||||
Reference in New Issue
Block a user