Compare commits
3 Commits
c29378c2f8
...
7997a739ab
Author | SHA1 | Date | |
---|---|---|---|
7997a739ab | |||
248b258413 | |||
0423ed7fb4 |
@ -222,7 +222,7 @@ async function socket(request, response, client) {
|
||||
} else if (message.action == 'setActiveIdentity') {
|
||||
process.setActiveIdentity(message.identity);
|
||||
} else if (message.action == 'createIdentity') {
|
||||
process.createIdentity();
|
||||
await process.createIdentity();
|
||||
} else if (message.message == 'tfrpc') {
|
||||
if (message.id && g_calls[message.id]) {
|
||||
if (message.error !== undefined) {
|
||||
|
@ -472,7 +472,7 @@ async function getProcessBlob(blobId, key, options) {
|
||||
process.credentials.session.name &&
|
||||
process.credentials.session.name !== 'guest'
|
||||
) {
|
||||
let id = ssb.createIdentity(process.credentials.session.name);
|
||||
let id = await ssb.createIdentity(process.credentials.session.name);
|
||||
await process.sendIdentities();
|
||||
broadcastAppEventToUser(
|
||||
process?.credentials?.session?.name,
|
||||
|
@ -320,31 +320,90 @@ static JSValue _database_remove(JSContext* context, JSValueConst this_val, int a
|
||||
return JS_UNDEFINED;
|
||||
}
|
||||
|
||||
typedef struct _database_get_all_t
|
||||
{
|
||||
const char* id;
|
||||
const char* key;
|
||||
size_t key_length;
|
||||
char** out_values;
|
||||
size_t* out_lengths;
|
||||
int out_values_length;
|
||||
JSValue promise[2];
|
||||
} database_get_all_t;
|
||||
|
||||
static void _database_get_all_work(tf_ssb_t* ssb, void* user_data)
|
||||
{
|
||||
database_get_all_t* work = user_data;
|
||||
sqlite3_stmt* statement;
|
||||
sqlite3* db = tf_ssb_acquire_db_reader(ssb);
|
||||
if (sqlite3_prepare(db, "SELECT key FROM properties WHERE id = ?", -1, &statement, NULL) == SQLITE_OK)
|
||||
{
|
||||
if (sqlite3_bind_text(statement, 1, work->id, -1, NULL) == SQLITE_OK)
|
||||
{
|
||||
while (sqlite3_step(statement) == SQLITE_ROW)
|
||||
{
|
||||
work->out_values = tf_resize_vec(work->out_values, sizeof(char*) * (work->out_values_length + 1));
|
||||
work->out_lengths = tf_resize_vec(work->out_lengths, sizeof(size_t) * (work->out_values_length + 1));
|
||||
size_t length = sqlite3_column_bytes(statement, 0);
|
||||
char* data = tf_malloc(length + 1);
|
||||
memcpy(data, sqlite3_column_text(statement, 0), length);
|
||||
data[length] = '\0';
|
||||
work->out_values[work->out_values_length] = data;
|
||||
work->out_lengths[work->out_values_length] = length;
|
||||
work->out_values_length++;
|
||||
}
|
||||
}
|
||||
sqlite3_finalize(statement);
|
||||
}
|
||||
tf_ssb_release_db_reader(ssb, db);
|
||||
}
|
||||
|
||||
static void _database_get_all_after_work(tf_ssb_t* ssb, int status, void* user_data)
|
||||
{
|
||||
database_get_all_t* work = user_data;
|
||||
JSContext* context = tf_ssb_get_context(ssb);
|
||||
JSValue result = JS_NewArray(context);
|
||||
;
|
||||
for (int i = 0; i < work->out_values_length; i++)
|
||||
{
|
||||
JS_SetPropertyUint32(context, result, i, JS_NewStringLen(context, work->out_values[i], work->out_lengths[i]));
|
||||
tf_free((void*)work->out_values[i]);
|
||||
}
|
||||
JSValue error = JS_Call(context, work->promise[0], JS_UNDEFINED, 1, &result);
|
||||
tf_util_report_error(context, error);
|
||||
JS_FreeValue(context, error);
|
||||
JS_FreeValue(context, result);
|
||||
JS_FreeValue(context, work->promise[0]);
|
||||
JS_FreeValue(context, work->promise[1]);
|
||||
tf_free(work->out_values);
|
||||
tf_free(work->out_lengths);
|
||||
tf_free(work);
|
||||
}
|
||||
|
||||
static JSValue _database_get_all(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv)
|
||||
{
|
||||
JSValue array = JS_UNDEFINED;
|
||||
JSValue result = JS_UNDEFINED;
|
||||
database_t* database = JS_GetOpaque(this_val, _database_class_id);
|
||||
if (database)
|
||||
{
|
||||
sqlite3_stmt* statement;
|
||||
tf_ssb_t* ssb = tf_task_get_ssb(database->task);
|
||||
sqlite3* db = tf_ssb_acquire_db_reader(ssb);
|
||||
if (sqlite3_prepare(db, "SELECT key, value FROM properties WHERE id = ?1", -1, &statement, NULL) == SQLITE_OK)
|
||||
{
|
||||
if (sqlite3_bind_text(statement, 1, database->id, -1, NULL) == SQLITE_OK)
|
||||
{
|
||||
array = JS_NewArray(context);
|
||||
uint32_t index = 0;
|
||||
while (sqlite3_step(statement) == SQLITE_ROW)
|
||||
{
|
||||
JS_SetPropertyUint32(context, array, index++, JS_NewStringLen(context, (const char*)sqlite3_column_text(statement, 0), sqlite3_column_bytes(statement, 0)));
|
||||
}
|
||||
}
|
||||
sqlite3_finalize(statement);
|
||||
}
|
||||
tf_ssb_release_db_reader(ssb, db);
|
||||
|
||||
size_t length;
|
||||
const char* key = JS_ToCStringLen(context, &length, argv[0]);
|
||||
database_get_all_t* work = tf_malloc(sizeof(database_get_all_t) + strlen(database->id) + 1 + length + 1);
|
||||
*work = (database_get_all_t) {
|
||||
.id = (const char*)(work + 1),
|
||||
.key = (const char*)(work + 1) + strlen(database->id) + 1,
|
||||
.key_length = length,
|
||||
};
|
||||
memcpy((char*)work->id, database->id, strlen(database->id) + 1);
|
||||
memcpy((char*)work->key, key, length + 1);
|
||||
JS_FreeCString(context, key);
|
||||
|
||||
tf_ssb_run_work(ssb, _database_get_all_work, _database_get_all_after_work, work);
|
||||
result = JS_NewPromiseCapability(context, work->promise);
|
||||
}
|
||||
return array;
|
||||
return result;
|
||||
}
|
||||
|
||||
static JSValue _database_get_like(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv)
|
||||
|
188
src/httpd.js.c
188
src/httpd.js.c
@ -37,7 +37,7 @@
|
||||
|
||||
const int64_t k_refresh_interval = 1ULL * 7 * 24 * 60 * 60 * 1000;
|
||||
|
||||
static JSValue _authenticate_jwt(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 const char* _make_session_jwt(tf_ssb_t* ssb, const char* name);
|
||||
static const char* _make_set_session_cookie_header(tf_http_request_t* request, const char* session_cookie);
|
||||
@ -330,7 +330,7 @@ static JSValue _httpd_websocket_upgrade(JSContext* context, JSValueConst this_va
|
||||
|
||||
tf_ssb_t* ssb = tf_task_get_ssb(tf_task_get(context));
|
||||
const char* session = tf_http_get_cookie(tf_http_request_get_header(request, "cookie"), "session");
|
||||
JSValue jwt = _authenticate_jwt(context, session);
|
||||
JSValue jwt = _authenticate_jwt(ssb, context, session);
|
||||
tf_free((void*)session);
|
||||
JSValue name = !JS_IsUndefined(jwt) ? JS_GetPropertyStr(context, jwt, "name") : JS_UNDEFINED;
|
||||
const char* name_string = !JS_IsUndefined(name) ? JS_ToCString(context, name) : NULL;
|
||||
@ -508,7 +508,7 @@ static JSValue _httpd_auth_query(JSContext* context, JSValueConst this_val, int
|
||||
JSValue cookie = JS_GetPropertyStr(context, headers, "cookie");
|
||||
const char* cookie_string = JS_ToCString(context, cookie);
|
||||
const char* session = tf_http_get_cookie(cookie_string, "session");
|
||||
JSValue entry = _authenticate_jwt(context, session);
|
||||
JSValue entry = _authenticate_jwt(ssb, context, session);
|
||||
tf_free((void*)session);
|
||||
JS_FreeCString(context, cookie_string);
|
||||
JS_FreeValue(context, cookie);
|
||||
@ -1094,14 +1094,17 @@ const char* _form_data_get(const char** form_data, const char* key)
|
||||
typedef struct _login_request_t
|
||||
{
|
||||
tf_http_request_t* request;
|
||||
const char* session_cookie;
|
||||
JSValue jwt;
|
||||
const char* name;
|
||||
const char* error;
|
||||
const char* settings;
|
||||
const char* code_of_conduct;
|
||||
bool have_administrator;
|
||||
bool session_is_new;
|
||||
|
||||
char location_header[1024];
|
||||
const char* set_cookie_header;
|
||||
|
||||
int pending;
|
||||
} login_request_t;
|
||||
|
||||
static const char* _make_set_session_cookie_header(tf_http_request_t* request, const char* session_cookie)
|
||||
@ -1116,18 +1119,29 @@ static const char* _make_set_session_cookie_header(tf_http_request_t* request, c
|
||||
return cookie;
|
||||
}
|
||||
|
||||
static void _login_release(login_request_t* login)
|
||||
{
|
||||
int ref_count = --login->pending;
|
||||
if (ref_count == 0)
|
||||
{
|
||||
tf_free((void*)login->name);
|
||||
tf_free((void*)login->code_of_conduct);
|
||||
tf_free((void*)login->set_cookie_header);
|
||||
tf_free(login);
|
||||
}
|
||||
}
|
||||
|
||||
static void _httpd_endpoint_login_file_read_callback(tf_task_t* task, const char* path, int result, const void* data, void* user_data)
|
||||
{
|
||||
login_request_t* login = user_data;
|
||||
tf_http_request_t* request = login->request;
|
||||
if (result >= 0)
|
||||
{
|
||||
const char* cookie = _make_set_session_cookie_header(request, login->session_cookie);
|
||||
const char* headers[] = {
|
||||
"Content-Type",
|
||||
"text/html; charset=utf-8",
|
||||
"Set-Cookie",
|
||||
cookie ? cookie : "",
|
||||
login->set_cookie_header ? login->set_cookie_header : "",
|
||||
};
|
||||
const char* replace_me = "$AUTH_DATA";
|
||||
const char* auth = strstr(data, replace_me);
|
||||
@ -1161,7 +1175,6 @@ static void _httpd_endpoint_login_file_read_callback(tf_task_t* task, const char
|
||||
{
|
||||
tf_http_respond(request, 200, headers, tf_countof(headers) / 2, data, result);
|
||||
}
|
||||
tf_free((void*)cookie);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -1169,10 +1182,7 @@ static void _httpd_endpoint_login_file_read_callback(tf_task_t* task, const char
|
||||
tf_http_respond(request, 404, NULL, 0, k_payload, strlen(k_payload));
|
||||
}
|
||||
tf_http_request_unref(request);
|
||||
tf_free((void*)login->name);
|
||||
tf_free((void*)login->code_of_conduct);
|
||||
tf_free((void*)login->session_cookie);
|
||||
tf_free(login);
|
||||
_login_release(login);
|
||||
}
|
||||
|
||||
static bool _string_property_equals(JSContext* context, JSValue object, const char* name, const char* value)
|
||||
@ -1185,7 +1195,7 @@ static bool _string_property_equals(JSContext* context, JSValue object, const ch
|
||||
return equals;
|
||||
}
|
||||
|
||||
static JSValue _authenticate_jwt(JSContext* context, const char* jwt)
|
||||
static JSValue _authenticate_jwt(tf_ssb_t* ssb, JSContext* context, const char* jwt)
|
||||
{
|
||||
if (!jwt)
|
||||
{
|
||||
@ -1226,8 +1236,6 @@ static JSValue _authenticate_jwt(JSContext* context, const char* jwt)
|
||||
return JS_UNDEFINED;
|
||||
}
|
||||
|
||||
tf_task_t* task = tf_task_get(context);
|
||||
tf_ssb_t* ssb = tf_task_get_ssb(task);
|
||||
char public_key_b64[k_id_base64_len] = { 0 };
|
||||
tf_ssb_whoami(ssb, public_key_b64, sizeof(public_key_b64));
|
||||
|
||||
@ -1343,32 +1351,6 @@ static bool _verify_password(const char* password, const char* hash)
|
||||
return out_hash && strcmp(hash, out_hash) == 0;
|
||||
}
|
||||
|
||||
static void _httpd_endpoint_login_get_code_of_conduct_work(tf_ssb_t* ssb, void* user_data)
|
||||
{
|
||||
login_request_t* login = user_data;
|
||||
login->settings = tf_ssb_db_get_property(ssb, "core", "settings");
|
||||
}
|
||||
|
||||
static void _httpd_endpoint_login_get_code_of_conduct_after_work(tf_ssb_t* ssb, int status, void* user_data)
|
||||
{
|
||||
login_request_t* login = user_data;
|
||||
if (login->settings)
|
||||
{
|
||||
JSContext* context = tf_ssb_get_context(ssb);
|
||||
JSValue settings_value = JS_ParseJSON(context, login->settings, strlen(login->settings), NULL);
|
||||
JSValue code_of_conduct_value = JS_GetPropertyStr(context, settings_value, "code_of_conduct");
|
||||
const char* code_of_conduct = JS_ToCString(context, code_of_conduct_value);
|
||||
const char* result = tf_strdup(code_of_conduct);
|
||||
JS_FreeCString(context, code_of_conduct);
|
||||
JS_FreeValue(context, code_of_conduct_value);
|
||||
JS_FreeValue(context, settings_value);
|
||||
tf_free((void*)login->settings);
|
||||
login->settings = NULL;
|
||||
login->code_of_conduct = result;
|
||||
}
|
||||
tf_file_read(login->request->user_data, "core/auth.html", _httpd_endpoint_login_file_read_callback, login);
|
||||
}
|
||||
|
||||
static bool _make_administrator_if_first(tf_ssb_t* ssb, const char* account_name_copy, bool may_become_first_admin)
|
||||
{
|
||||
JSContext* context = tf_ssb_get_context(ssb);
|
||||
@ -1442,30 +1424,32 @@ static bool _make_administrator_if_first(tf_ssb_t* ssb, const char* account_name
|
||||
return have_administrator;
|
||||
}
|
||||
|
||||
static void _httpd_endpoint_login(tf_http_request_t* request)
|
||||
static void _httpd_endpoint_login_work(tf_ssb_t* ssb, void* user_data)
|
||||
{
|
||||
tf_task_t* task = request->user_data;
|
||||
JSContext* context = tf_task_get_context(task);
|
||||
tf_ssb_t* ssb = tf_task_get_ssb(task);
|
||||
login_request_t* login = user_data;
|
||||
tf_http_request_t* request = login->request;
|
||||
|
||||
JSMallocFunctions funcs = { 0 };
|
||||
tf_get_js_malloc_functions(&funcs);
|
||||
JSRuntime* runtime = JS_NewRuntime2(&funcs, NULL);
|
||||
JSContext* context = JS_NewContext(runtime);
|
||||
|
||||
const char* session = tf_http_get_cookie(tf_http_request_get_header(request, "cookie"), "session");
|
||||
const char** form_data = _form_data_decode(request->query, request->query ? strlen(request->query) : 0);
|
||||
const char* account_name_copy = NULL;
|
||||
JSValue jwt = _authenticate_jwt(context, session);
|
||||
JSValue jwt = _authenticate_jwt(ssb, context, session);
|
||||
|
||||
if (_session_is_authenticated_as_user(context, jwt))
|
||||
{
|
||||
const char* return_url = _form_data_get(form_data, "return");
|
||||
char url[1024];
|
||||
if (!return_url)
|
||||
if (return_url)
|
||||
{
|
||||
snprintf(url, sizeof(url), "%s%s/", request->is_tls ? "https://" : "http://", tf_http_request_get_header(request, "host"));
|
||||
return_url = url;
|
||||
snprintf(login->location_header, sizeof(login->location_header), "%s", return_url);
|
||||
}
|
||||
else
|
||||
{
|
||||
snprintf(login->location_header, sizeof(login->location_header), "%s%s/", request->is_tls ? "https://" : "http://", tf_http_request_get_header(request, "host"));
|
||||
}
|
||||
const char* headers[] = {
|
||||
"Location",
|
||||
return_url,
|
||||
};
|
||||
tf_http_respond(request, 303, headers, tf_countof(headers) / 2, NULL, 0);
|
||||
goto done;
|
||||
}
|
||||
|
||||
@ -1544,40 +1528,46 @@ static void _httpd_endpoint_login(tf_http_request_t* request)
|
||||
if (session_is_new && _form_data_get(form_data, "return") && !login_error)
|
||||
{
|
||||
const char* return_url = _form_data_get(form_data, "return");
|
||||
char url[1024];
|
||||
if (!return_url)
|
||||
if (return_url)
|
||||
{
|
||||
snprintf(url, sizeof(url), "%s%s/", request->is_tls ? "https://" : "http://", tf_http_request_get_header(request, "host"));
|
||||
return_url = url;
|
||||
snprintf(login->location_header, sizeof(login->location_header), "%s", return_url);
|
||||
}
|
||||
const char* cookie = _make_set_session_cookie_header(request, send_session);
|
||||
const char* headers[] = {
|
||||
"Location",
|
||||
return_url,
|
||||
"Set-Cookie",
|
||||
cookie ? cookie : "",
|
||||
};
|
||||
tf_http_respond(request, 303, headers, tf_countof(headers) / 2, NULL, 0);
|
||||
tf_free((void*)cookie);
|
||||
else
|
||||
{
|
||||
snprintf(login->location_header, sizeof(login->location_header), "%s%s/", request->is_tls ? "https://" : "http://", tf_http_request_get_header(request, "host"));
|
||||
}
|
||||
login->set_cookie_header = _make_set_session_cookie_header(request, send_session);
|
||||
tf_free((void*)send_session);
|
||||
}
|
||||
else
|
||||
{
|
||||
tf_http_request_ref(request);
|
||||
|
||||
login_request_t* login = tf_malloc(sizeof(login_request_t));
|
||||
*login = (login_request_t) {
|
||||
.request = request,
|
||||
.name = account_name_copy,
|
||||
.jwt = jwt,
|
||||
.error = login_error,
|
||||
.session_cookie = send_session,
|
||||
.session_is_new = session_is_new,
|
||||
.have_administrator = have_administrator,
|
||||
};
|
||||
login->name = account_name_copy;
|
||||
login->error = login_error;
|
||||
login->set_cookie_header = _make_set_session_cookie_header(request, send_session);
|
||||
tf_free((void*)send_session);
|
||||
login->session_is_new = session_is_new;
|
||||
login->have_administrator = have_administrator;
|
||||
login->settings = tf_ssb_db_get_property(ssb, "core", "settings");
|
||||
|
||||
if (login->settings)
|
||||
{
|
||||
JSValue settings_value = JS_ParseJSON(context, login->settings, strlen(login->settings), NULL);
|
||||
JSValue code_of_conduct_value = JS_GetPropertyStr(context, settings_value, "code_of_conduct");
|
||||
const char* code_of_conduct = JS_ToCString(context, code_of_conduct_value);
|
||||
const char* result = tf_strdup(code_of_conduct);
|
||||
JS_FreeCString(context, code_of_conduct);
|
||||
JS_FreeValue(context, code_of_conduct_value);
|
||||
JS_FreeValue(context, settings_value);
|
||||
tf_free((void*)login->settings);
|
||||
login->settings = NULL;
|
||||
login->code_of_conduct = result;
|
||||
}
|
||||
|
||||
login->pending++;
|
||||
tf_file_read(login->request->user_data, "core/auth.html", _httpd_endpoint_login_file_read_callback, login);
|
||||
|
||||
tf_ssb_run_work(ssb, _httpd_endpoint_login_get_code_of_conduct_work, _httpd_endpoint_login_get_code_of_conduct_after_work, login);
|
||||
jwt = JS_UNDEFINED;
|
||||
account_name_copy = NULL;
|
||||
}
|
||||
|
||||
@ -1586,6 +1576,44 @@ done:
|
||||
tf_free(form_data);
|
||||
tf_free((void*)account_name_copy);
|
||||
JS_FreeValue(context, jwt);
|
||||
|
||||
JS_FreeContext(context);
|
||||
JS_FreeRuntime(runtime);
|
||||
}
|
||||
|
||||
static void _httpd_endpoint_login_after_work(tf_ssb_t* ssb, int status, void* user_data)
|
||||
{
|
||||
login_request_t* login = user_data;
|
||||
if (login->pending == 1)
|
||||
{
|
||||
tf_http_request_t* request = login->request;
|
||||
if (*login->location_header)
|
||||
{
|
||||
const char* headers[] = {
|
||||
"Location",
|
||||
login->location_header,
|
||||
"Set-Cookie",
|
||||
login->set_cookie_header ? login->set_cookie_header : "",
|
||||
};
|
||||
tf_http_respond(request, 303, headers, tf_countof(headers) / 2, NULL, 0);
|
||||
}
|
||||
tf_http_request_unref(request);
|
||||
}
|
||||
_login_release(login);
|
||||
}
|
||||
|
||||
static void _httpd_endpoint_login(tf_http_request_t* request)
|
||||
{
|
||||
tf_task_t* task = request->user_data;
|
||||
tf_http_request_ref(request);
|
||||
|
||||
tf_ssb_t* ssb = tf_task_get_ssb(task);
|
||||
login_request_t* login = tf_malloc(sizeof(login_request_t));
|
||||
*login = (login_request_t) {
|
||||
.request = request,
|
||||
};
|
||||
login->pending++;
|
||||
tf_ssb_run_work(ssb, _httpd_endpoint_login_work, _httpd_endpoint_login_after_work, login);
|
||||
}
|
||||
|
||||
static void _httpd_endpoint_logout(tf_http_request_t* request)
|
||||
|
89
src/ssb.js.c
89
src/ssb.js.c
@ -30,35 +30,80 @@ static JSClassID _tf_ssb_classId;
|
||||
|
||||
static JSValue _tf_ssb_appendMessageWithIdentity(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv);
|
||||
|
||||
typedef struct _create_identity_t
|
||||
{
|
||||
char id[k_id_base64_len];
|
||||
bool error_add;
|
||||
bool error_too_many;
|
||||
JSValue promise[2];
|
||||
char user[];
|
||||
} create_identity_t;
|
||||
|
||||
static void _tf_ssb_create_identity_work(tf_ssb_t* ssb, void* user_data)
|
||||
{
|
||||
create_identity_t* work = user_data;
|
||||
int count = tf_ssb_db_identity_get_count_for_user(ssb, work->user);
|
||||
if (count < 16)
|
||||
{
|
||||
char public[k_id_base64_len - 1];
|
||||
char private[512];
|
||||
tf_ssb_generate_keys_buffer(public, sizeof(public), private, sizeof(private));
|
||||
if (tf_ssb_db_identity_add(ssb, work->user, public, private))
|
||||
{
|
||||
snprintf(work->id, sizeof(work->id), "@%s", public);
|
||||
}
|
||||
else
|
||||
{
|
||||
work->error_add = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
work->error_too_many = true;
|
||||
}
|
||||
}
|
||||
|
||||
static void _tf_ssb_create_identity_after_work(tf_ssb_t* ssb, int status, void* user_data)
|
||||
{
|
||||
JSContext* context = tf_ssb_get_context(ssb);
|
||||
JSValue result = JS_UNDEFINED;
|
||||
create_identity_t* work = user_data;
|
||||
if (work->error_too_many)
|
||||
{
|
||||
result = JS_ThrowInternalError(context, "Too many identities for user.");
|
||||
}
|
||||
else if (work->error_add)
|
||||
{
|
||||
result = JS_ThrowInternalError(context, "Unable to add identity.");
|
||||
}
|
||||
else
|
||||
{
|
||||
result = JS_NewString(context, work->id);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
static JSValue _tf_ssb_createIdentity(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv)
|
||||
{
|
||||
tf_ssb_t* ssb = JS_GetOpaque(this_val, _tf_ssb_classId);
|
||||
JSValue result = JS_UNDEFINED;
|
||||
if (ssb)
|
||||
{
|
||||
const char* user = JS_ToCString(context, argv[0]);
|
||||
int count = tf_ssb_db_identity_get_count_for_user(ssb, user);
|
||||
if (count < 16)
|
||||
{
|
||||
char public[512];
|
||||
char private[512];
|
||||
tf_ssb_generate_keys_buffer(public, sizeof(public), private, sizeof(private));
|
||||
if (tf_ssb_db_identity_add(ssb, user, public, private))
|
||||
{
|
||||
char id[513];
|
||||
snprintf(id, sizeof(id), "@%s", public);
|
||||
result = JS_NewString(context, id);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = JS_ThrowInternalError(context, "Unable to add identity.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
result = JS_ThrowInternalError(context, "Too many identities for user.");
|
||||
}
|
||||
size_t length = 0;
|
||||
const char* user = JS_ToCStringLen(context, &length, argv[0]);
|
||||
create_identity_t* work = tf_malloc(sizeof(create_identity_t) + length + 1);
|
||||
*work = (create_identity_t) { 0 };
|
||||
memcpy(work->user, user, length + 1);
|
||||
JS_FreeCString(context, user);
|
||||
result = JS_NewPromiseCapability(context, work->promise);
|
||||
tf_ssb_run_work(ssb, _tf_ssb_create_identity_work, _tf_ssb_create_identity_after_work, work);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
@ -279,7 +279,7 @@ static void _test_database(const tf_test_options_t* options)
|
||||
" await db.set('c', 3);\n"
|
||||
"\n"
|
||||
" var expected = ['a', 'b', 'c'];\n"
|
||||
" var have = db.getAll();\n"
|
||||
" var have = await db.getAll();\n"
|
||||
" for (var i = 0; i < have.length; i++) {\n"
|
||||
" var item = have[i];\n"
|
||||
" if (expected.indexOf(item) == -1) {\n"
|
||||
|
@ -42,20 +42,19 @@ try:
|
||||
|
||||
driver.switch_to.frame(driver.find_element(By.ID, 'document'))
|
||||
wait.until(expected_conditions.presence_of_element_located((By.LINK_TEXT, 'identity'))).click()
|
||||
driver.switch_to.default_content()
|
||||
|
||||
wait.until(expected_conditions.presence_of_element_located((By.ID, 'content')))
|
||||
|
||||
# StaleElementReferenceException
|
||||
while True:
|
||||
try:
|
||||
driver.switch_to.default_content()
|
||||
wait.until(expected_conditions.presence_of_element_located((By.ID, 'content')))
|
||||
driver.switch_to.frame(wait.until(expected_conditions.presence_of_element_located((By.ID, 'document'))))
|
||||
wait.until(expected_conditions.presence_of_element_located((By.ID, 'create_id'))).click()
|
||||
driver.switch_to.alert.accept()
|
||||
break
|
||||
except:
|
||||
pass
|
||||
|
||||
wait.until(expected_conditions.presence_of_element_located((By.ID, 'create_id'))).click()
|
||||
driver.switch_to.alert.accept()
|
||||
# StaleElementReferenceException
|
||||
while True:
|
||||
try:
|
||||
|
Loading…
Reference in New Issue
Block a user