Add an option to disable account registation, and fix use of a JSContext from the wrong thread along the way.
Some checks are pending
Build Tilde Friends / Build-All (push) Waiting to run
Some checks are pending
Build Tilde Friends / Build-All (push) Waiting to run
This commit is contained in:
parent
e38ff99607
commit
bfb3d8b8a2
@ -79,6 +79,11 @@ const k_global_settings = {
|
||||
default_value: false,
|
||||
description: 'Enable discovery of, sharing of, and connecting to internet peer strangers, including announcing this instance.',
|
||||
},
|
||||
account_registration: {
|
||||
type: 'boolean',
|
||||
default_value: true,
|
||||
description: 'Allow registration of new accounts.',
|
||||
},
|
||||
};
|
||||
|
||||
let gGlobalSettings = {
|
||||
|
@ -1484,27 +1484,39 @@ static void _httpd_endpoint_login_work(tf_ssb_t* ssb, void* user_data)
|
||||
|
||||
if (form_register && strcmp(form_register, "1") == 0)
|
||||
{
|
||||
if (!have_account && _is_name_valid(account_name) && password && confirm && strcmp(password, confirm) == 0 &&
|
||||
tf_ssb_db_register_account(ssb, account_name, password))
|
||||
bool registered = false;
|
||||
if (!have_account && _is_name_valid(account_name) && password && confirm && strcmp(password, confirm) == 0)
|
||||
{
|
||||
tf_free((void*)send_session);
|
||||
send_session = _make_session_jwt(ssb, account_name);
|
||||
may_become_first_admin = true;
|
||||
sqlite3* db = tf_ssb_acquire_db_writer(ssb);
|
||||
registered = tf_ssb_db_register_account(tf_ssb_get_loop(ssb), db, context, account_name, password);
|
||||
tf_ssb_release_db_writer(ssb, db);
|
||||
if (registered)
|
||||
{
|
||||
tf_free((void*)send_session);
|
||||
send_session = _make_session_jwt(ssb, account_name);
|
||||
may_become_first_admin = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
if (!registered)
|
||||
{
|
||||
login_error = "Error registering account.";
|
||||
}
|
||||
}
|
||||
else if (change && strcmp(change, "1") == 0)
|
||||
{
|
||||
if (have_account && _is_name_valid(account_name) && new_password && confirm && strcmp(new_password, confirm) == 0 && _verify_password(password, account_passwd) &&
|
||||
tf_ssb_db_set_account_password(ssb, account_name, new_password))
|
||||
bool set = false;
|
||||
if (have_account && _is_name_valid(account_name) && new_password && confirm && strcmp(new_password, confirm) == 0 && _verify_password(password, account_passwd))
|
||||
{
|
||||
tf_free((void*)send_session);
|
||||
send_session = _make_session_jwt(ssb, account_name);
|
||||
sqlite3* db = tf_ssb_acquire_db_writer(ssb);
|
||||
set = tf_ssb_db_set_account_password(tf_ssb_get_loop(ssb), db, context, account_name, new_password);
|
||||
tf_ssb_release_db_writer(ssb, db);
|
||||
if (set)
|
||||
{
|
||||
tf_free((void*)send_session);
|
||||
send_session = _make_session_jwt(ssb, account_name);
|
||||
}
|
||||
}
|
||||
else
|
||||
if (!set)
|
||||
{
|
||||
login_error = "Error changing password.";
|
||||
}
|
||||
|
92
src/ssb.db.c
92
src/ssb.db.c
@ -1644,14 +1644,13 @@ bool tf_ssb_db_get_account_password_hash(tf_ssb_t* ssb, const char* name, char*
|
||||
return result;
|
||||
}
|
||||
|
||||
bool tf_ssb_db_set_account_password(tf_ssb_t* ssb, const char* name, const char* password)
|
||||
bool tf_ssb_db_set_account_password(uv_loop_t* loop, sqlite3* db, JSContext* context, const char* name, const char* password)
|
||||
{
|
||||
JSContext* context = tf_ssb_get_context(ssb);
|
||||
bool result = false;
|
||||
static const int k_salt_length = 12;
|
||||
|
||||
char buffer[16];
|
||||
size_t bytes = uv_random(tf_ssb_get_loop(ssb), &(uv_random_t) { 0 }, buffer, sizeof(buffer), 0, NULL) == 0 ? sizeof(buffer) : 0;
|
||||
size_t bytes = uv_random(loop, &(uv_random_t) { 0 }, buffer, sizeof(buffer), 0, NULL) == 0 ? sizeof(buffer) : 0;
|
||||
char output[7 + 22 + 1];
|
||||
char* salt = crypt_gensalt_rn("$2b$", k_salt_length, buffer, bytes, output, sizeof(output));
|
||||
char hash_output[7 + 22 + 31 + 1];
|
||||
@ -1663,7 +1662,6 @@ bool tf_ssb_db_set_account_password(tf_ssb_t* ssb, const char* name, const char*
|
||||
size_t user_length = 0;
|
||||
const char* user_string = JS_ToCStringLen(context, &user_length, user_json);
|
||||
|
||||
sqlite3* db = tf_ssb_acquire_db_writer(ssb);
|
||||
sqlite3_stmt* statement = NULL;
|
||||
if (sqlite3_prepare(db, "INSERT OR REPLACE INTO properties (id, key, value) VALUES ('auth', 'user:' || ?, ?)", -1, &statement, NULL) == SQLITE_OK)
|
||||
{
|
||||
@ -1673,7 +1671,6 @@ bool tf_ssb_db_set_account_password(tf_ssb_t* ssb, const char* name, const char*
|
||||
}
|
||||
sqlite3_finalize(statement);
|
||||
}
|
||||
tf_ssb_release_db_writer(ssb, db);
|
||||
|
||||
JS_FreeCString(context, user_string);
|
||||
JS_FreeValue(context, user_json);
|
||||
@ -1681,47 +1678,70 @@ bool tf_ssb_db_set_account_password(tf_ssb_t* ssb, const char* name, const char*
|
||||
return result;
|
||||
}
|
||||
|
||||
bool tf_ssb_db_register_account(tf_ssb_t* ssb, const char* name, const char* password)
|
||||
static bool _tf_ssb_db_get_global_setting_bool(sqlite3* db, const char* name, bool default_value)
|
||||
{
|
||||
bool result = default_value;
|
||||
sqlite3_stmt* statement;
|
||||
if (sqlite3_prepare(db, "SELECT json_extract(value, '$.' || ?) FROM properties WHERE id = 'core' AND key = 'settings'", -1, &statement, NULL) == SQLITE_OK)
|
||||
{
|
||||
if (sqlite3_bind_text(statement, 1, name, -1, NULL) == SQLITE_OK)
|
||||
{
|
||||
if (sqlite3_step(statement) == SQLITE_ROW && sqlite3_column_type(statement, 0) != SQLITE_NULL)
|
||||
{
|
||||
result = sqlite3_column_int(statement, 0) != 0;
|
||||
}
|
||||
}
|
||||
sqlite3_finalize(statement);
|
||||
}
|
||||
else
|
||||
{
|
||||
tf_printf("prepare failed: %s\n", sqlite3_errmsg(db));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool tf_ssb_db_register_account(uv_loop_t* loop, sqlite3* db, JSContext* context, const char* name, const char* password)
|
||||
{
|
||||
bool result = false;
|
||||
JSContext* context = tf_ssb_get_context(ssb);
|
||||
JSValue users_array = JS_UNDEFINED;
|
||||
|
||||
sqlite3* db = tf_ssb_acquire_db_writer(ssb);
|
||||
sqlite3_stmt* statement = NULL;
|
||||
if (sqlite3_prepare(db, "SELECT value FROM properties WHERE id = 'auth' AND key = 'users'", -1, &statement, NULL) == SQLITE_OK)
|
||||
bool registration_allowed = _tf_ssb_db_get_global_setting_bool(db, "account_registration", true);
|
||||
if (registration_allowed)
|
||||
{
|
||||
if (sqlite3_step(statement) == SQLITE_ROW)
|
||||
sqlite3_stmt* statement = NULL;
|
||||
if (sqlite3_prepare(db, "SELECT value FROM properties WHERE id = 'auth' AND key = 'users'", -1, &statement, NULL) == SQLITE_OK)
|
||||
{
|
||||
users_array = JS_ParseJSON(context, (const char*)sqlite3_column_text(statement, 0), sqlite3_column_bytes(statement, 0), NULL);
|
||||
if (sqlite3_step(statement) == SQLITE_ROW)
|
||||
{
|
||||
users_array = JS_ParseJSON(context, (const char*)sqlite3_column_text(statement, 0), sqlite3_column_bytes(statement, 0), NULL);
|
||||
}
|
||||
sqlite3_finalize(statement);
|
||||
}
|
||||
sqlite3_finalize(statement);
|
||||
}
|
||||
if (JS_IsUndefined(users_array))
|
||||
{
|
||||
users_array = JS_NewArray(context);
|
||||
}
|
||||
int length = tf_util_get_length(context, users_array);
|
||||
JS_SetPropertyUint32(context, users_array, length, JS_NewString(context, name));
|
||||
|
||||
JSValue json = JS_JSONStringify(context, users_array, JS_NULL, JS_NULL);
|
||||
JS_FreeValue(context, users_array);
|
||||
size_t value_length = 0;
|
||||
const char* value = JS_ToCStringLen(context, &value_length, json);
|
||||
if (sqlite3_prepare(db, "INSERT OR REPLACE INTO properties (id, key, value) VALUES ('auth', 'users', ?)", -1, &statement, NULL) == SQLITE_OK)
|
||||
{
|
||||
if (sqlite3_bind_text(statement, 1, value, value_length, NULL) == SQLITE_OK)
|
||||
if (JS_IsUndefined(users_array))
|
||||
{
|
||||
tf_printf("added user to properties\n");
|
||||
result = sqlite3_step(statement) == SQLITE_DONE;
|
||||
users_array = JS_NewArray(context);
|
||||
}
|
||||
sqlite3_finalize(statement);
|
||||
}
|
||||
JS_FreeCString(context, value);
|
||||
JS_FreeValue(context, json);
|
||||
tf_ssb_release_db_writer(ssb, db);
|
||||
int length = tf_util_get_length(context, users_array);
|
||||
JS_SetPropertyUint32(context, users_array, length, JS_NewString(context, name));
|
||||
|
||||
result = result && tf_ssb_db_set_account_password(ssb, name, password);
|
||||
JSValue json = JS_JSONStringify(context, users_array, JS_NULL, JS_NULL);
|
||||
JS_FreeValue(context, users_array);
|
||||
size_t value_length = 0;
|
||||
const char* value = JS_ToCStringLen(context, &value_length, json);
|
||||
if (sqlite3_prepare(db, "INSERT OR REPLACE INTO properties (id, key, value) VALUES ('auth', 'users', ?)", -1, &statement, NULL) == SQLITE_OK)
|
||||
{
|
||||
if (sqlite3_bind_text(statement, 1, value, value_length, NULL) == SQLITE_OK)
|
||||
{
|
||||
tf_printf("added user to properties\n");
|
||||
result = sqlite3_step(statement) == SQLITE_DONE;
|
||||
}
|
||||
sqlite3_finalize(statement);
|
||||
}
|
||||
JS_FreeCString(context, value);
|
||||
JS_FreeValue(context, json);
|
||||
}
|
||||
|
||||
result = result && tf_ssb_db_set_account_password(loop, db, context, name, password);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
12
src/ssb.db.h
12
src/ssb.db.h
@ -360,21 +360,25 @@ bool tf_ssb_db_get_account_password_hash(tf_ssb_t* ssb, const char* name, char*
|
||||
|
||||
/**
|
||||
** Insert or update a user's hashed password in the database.
|
||||
** @param ssb The SSB instance.
|
||||
** @param loop The event loop.
|
||||
** @param db A DB writer.
|
||||
** @param context A JS context.
|
||||
** @param name The username.
|
||||
** @param password The raw password.
|
||||
** @return true if the hash of the password was successfully stored.
|
||||
*/
|
||||
bool tf_ssb_db_set_account_password(tf_ssb_t* ssb, const char* name, const char* password);
|
||||
bool tf_ssb_db_set_account_password(uv_loop_t* loop, sqlite3* db, JSContext* context, const char* name, const char* password);
|
||||
|
||||
/**
|
||||
** Add a user account to the database.
|
||||
** @param ssb The SSB instance.
|
||||
** @param loop The event loop.
|
||||
** @param db A DB writer.
|
||||
** @param context A JS context.
|
||||
** @param name The username to add.
|
||||
** @param password The user's raw password.
|
||||
** @return true If the user was added successfully.
|
||||
*/
|
||||
bool tf_ssb_db_register_account(tf_ssb_t* ssb, const char* name, const char* password);
|
||||
bool tf_ssb_db_register_account(uv_loop_t* loop, sqlite3* db, JSContext* context, const char* name, const char* password);
|
||||
|
||||
/**
|
||||
** Get an entry from the properties table.
|
||||
|
Loading…
Reference in New Issue
Block a user