Compare commits
No commits in common. "92a74026a62175a3ad6412d3d26bca79bd0083c6" and "b04eccdbdafef70738d16dfd79f43b8864b227ed" have entirely different histories.
92a74026a6
...
b04eccdbda
@ -1040,7 +1040,7 @@ const char* tf_http_get_cookie(const char* cookie_header, const char* name)
|
|||||||
|
|
||||||
int name_start = 0;
|
int name_start = 0;
|
||||||
int equals = 0;
|
int equals = 0;
|
||||||
for (int i = 0;; i++)
|
for (int i = 0; ; i++)
|
||||||
{
|
{
|
||||||
if (cookie_header[i] == '=')
|
if (cookie_header[i] == '=')
|
||||||
{
|
{
|
||||||
@ -1048,7 +1048,9 @@ const char* tf_http_get_cookie(const char* cookie_header, const char* name)
|
|||||||
}
|
}
|
||||||
else if (cookie_header[i] == ',' || cookie_header[i] == ';' || cookie_header[i] == '\0')
|
else if (cookie_header[i] == ',' || cookie_header[i] == ';' || cookie_header[i] == '\0')
|
||||||
{
|
{
|
||||||
if (equals > name_start && strncmp(cookie_header + name_start, name, equals - name_start) == 0 && (int)strlen(name) == equals - name_start)
|
if (equals > name_start &&
|
||||||
|
strncmp(cookie_header + name_start, name, equals - name_start) == 0 &&
|
||||||
|
(int)strlen(name) == equals - name_start)
|
||||||
{
|
{
|
||||||
int length = i - equals - 1;
|
int length = i - equals - 1;
|
||||||
char* result = tf_malloc(length + 1);
|
char* result = tf_malloc(length + 1);
|
||||||
|
110
src/httpd.js.c
110
src/httpd.js.c
@ -846,11 +846,10 @@ static void _httpd_endpoint_login_file_read_callback(tf_task_t* task, const char
|
|||||||
{
|
{
|
||||||
snprintf(cookie, length + 1, k_pattern, login->session_cookie, k_refresh_interval, request->is_tls ? "Secure; " : "");
|
snprintf(cookie, length + 1, k_pattern, login->session_cookie, k_refresh_interval, request->is_tls ? "Secure; " : "");
|
||||||
}
|
}
|
||||||
const char* headers[] = {
|
const char* headers[] =
|
||||||
"Content-Type",
|
{
|
||||||
"text/html; charset=utf-8",
|
"Content-Type", "text/html; charset=utf-8",
|
||||||
"Set-Cookie",
|
"Set-Cookie", cookie ? cookie : "",
|
||||||
cookie ? cookie : "",
|
|
||||||
};
|
};
|
||||||
const char* replace_me = "$AUTH_DATA";
|
const char* replace_me = "$AUTH_DATA";
|
||||||
const char* auth = strstr(data, replace_me);
|
const char* auth = strstr(data, replace_me);
|
||||||
@ -946,7 +945,9 @@ static JSValue _authenticate_jwt(JSContext* context, const char* jwt)
|
|||||||
}
|
}
|
||||||
|
|
||||||
JSValue header_value = JS_ParseJSON(context, (const char*)header, actual_length, NULL);
|
JSValue header_value = JS_ParseJSON(context, (const char*)header, actual_length, NULL);
|
||||||
bool header_valid = _string_property_equals(context, header_value, "typ", "JWT") && _string_property_equals(context, header_value, "alg", "HS256");
|
bool header_valid =
|
||||||
|
_string_property_equals(context, header_value, "typ", "JWT") &&
|
||||||
|
_string_property_equals(context, header_value, "alg", "HS256");
|
||||||
JS_FreeValue(context, header_value);
|
JS_FreeValue(context, header_value);
|
||||||
if (!header_valid)
|
if (!header_valid)
|
||||||
{
|
{
|
||||||
@ -998,13 +999,17 @@ static bool _session_is_authenticated_as_user(JSContext* context, JSValue sessio
|
|||||||
|
|
||||||
static bool _is_name_valid(const char* name)
|
static bool _is_name_valid(const char* name)
|
||||||
{
|
{
|
||||||
if (!name || !((*name >= 'a' && *name <= 'z') || (*name >= 'A' && *name <= 'Z')))
|
if (!name ||
|
||||||
|
!((*name >= 'a' && *name <= 'z') || (*name >= 'A' && *name <= 'Z')))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
for (const char* p = name; *p; p++)
|
for (const char* p = name; *p; p++)
|
||||||
{
|
{
|
||||||
bool in_range = (*p >= 'a' && *p <= 'z') || (*p >= 'A' && *p <= 'Z') || (*p >= '0' && *p <= '9');
|
bool in_range =
|
||||||
|
(*p >= 'a' && *p <= 'z') ||
|
||||||
|
(*p >= 'A' && *p <= 'Z') ||
|
||||||
|
(*p >= '0' && *p <= '9');
|
||||||
if (!in_range)
|
if (!in_range)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
@ -1056,7 +1061,8 @@ static bool _set_account_password(JSContext* context, sqlite3* db, const char* n
|
|||||||
sqlite3_stmt* statement = NULL;
|
sqlite3_stmt* statement = NULL;
|
||||||
if (sqlite3_prepare(db, "INSERT OR REPLACE INTO properties (id, key, value) VALUES ('auth', 'user:' || ?, ?)", -1, &statement, NULL) == SQLITE_OK)
|
if (sqlite3_prepare(db, "INSERT OR REPLACE INTO properties (id, key, value) VALUES ('auth', 'user:' || ?, ?)", -1, &statement, NULL) == SQLITE_OK)
|
||||||
{
|
{
|
||||||
if (sqlite3_bind_text(statement, 1, name, -1, NULL) == SQLITE_OK && sqlite3_bind_text(statement, 2, user_string, user_length, NULL) == SQLITE_OK)
|
if (sqlite3_bind_text(statement, 1, name, -1, NULL) == SQLITE_OK &&
|
||||||
|
sqlite3_bind_text(statement, 2, user_string, user_length, NULL) == SQLITE_OK)
|
||||||
{
|
{
|
||||||
result = sqlite3_step(statement) == SQLITE_DONE;
|
result = sqlite3_step(statement) == SQLITE_DONE;
|
||||||
}
|
}
|
||||||
@ -1121,24 +1127,27 @@ static void _visit_auth_identity(const char* identity, void* user_data)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool _get_auth_private_key(tf_ssb_t* ssb, uint8_t* out_private_key)
|
static const char* _make_session_jwt(tf_ssb_t* ssb, const char* name)
|
||||||
{
|
{
|
||||||
char id[k_id_base64_len] = { 0 };
|
char id[k_id_base64_len] = { 0 };
|
||||||
tf_ssb_db_identity_visit(ssb, ":auth", _visit_auth_identity, id);
|
tf_ssb_db_identity_visit(ssb, ":auth", _visit_auth_identity, id);
|
||||||
if (*id)
|
if (!*id)
|
||||||
{
|
{
|
||||||
return tf_ssb_db_identity_get_private_key(ssb, ":auth", id, out_private_key, crypto_sign_SECRETKEYBYTES);
|
uint8_t public_key[crypto_sign_PUBLICKEYBYTES];
|
||||||
|
uint8_t private_key[crypto_sign_SECRETKEYBYTES];
|
||||||
|
if (tf_ssb_db_identity_create(ssb, ":auth", public_key, private_key))
|
||||||
|
{
|
||||||
|
tf_ssb_id_bin_to_str(id, sizeof(id), public_key);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
return tf_ssb_db_identity_create(ssb, ":auth", out_private_key + crypto_sign_PUBLICKEYBYTES, out_private_key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static const char* _make_session_jwt(tf_ssb_t* ssb, const char* name)
|
if (!*id)
|
||||||
{
|
{
|
||||||
uint8_t private_key[crypto_sign_SECRETKEYBYTES] = { 0 };
|
return NULL;
|
||||||
if (!_get_auth_private_key(ssb, private_key))
|
}
|
||||||
|
|
||||||
|
uint8_t private_key[crypto_sign_SECRETKEYBYTES];
|
||||||
|
if (!tf_ssb_db_identity_get_private_key(ssb, ":auth", id, private_key, sizeof(private_key)))
|
||||||
{
|
{
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@ -1165,7 +1174,6 @@ static const char* _make_session_jwt(tf_ssb_t* ssb, const char* name)
|
|||||||
uint8_t signature[crypto_sign_BYTES];
|
uint8_t signature[crypto_sign_BYTES];
|
||||||
unsigned long long signature_length = 0;
|
unsigned long long signature_length = 0;
|
||||||
char signature_base64[256] = { 0 };
|
char signature_base64[256] = { 0 };
|
||||||
|
|
||||||
if (crypto_sign_detached(signature, &signature_length, (const uint8_t*)payload_base64, strlen(payload_base64), private_key) == 0)
|
if (crypto_sign_detached(signature, &signature_length, (const uint8_t*)payload_base64, strlen(payload_base64), private_key) == 0)
|
||||||
{
|
{
|
||||||
sodium_bin2base64(signature_base64, sizeof(signature_base64), signature, sizeof(signature), sodium_base64_VARIANT_URLSAFE_NO_PADDING);
|
sodium_bin2base64(signature_base64, sizeof(signature_base64), signature, sizeof(signature), sodium_base64_VARIANT_URLSAFE_NO_PADDING);
|
||||||
@ -1195,7 +1203,8 @@ static const char* _get_property(tf_ssb_t* ssb, const char* id, const char* key)
|
|||||||
sqlite3_stmt* statement = NULL;
|
sqlite3_stmt* statement = NULL;
|
||||||
if (sqlite3_prepare(db, "SELECT value FROM properties WHERE id = ? AND key = ?", -1, &statement, NULL) == SQLITE_OK)
|
if (sqlite3_prepare(db, "SELECT value 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)
|
if (sqlite3_bind_text(statement, 1, id, -1, NULL) == SQLITE_OK &&
|
||||||
|
sqlite3_bind_text(statement, 2, key, -1, NULL) == SQLITE_OK)
|
||||||
{
|
{
|
||||||
if (sqlite3_step(statement) == SQLITE_ROW)
|
if (sqlite3_step(statement) == SQLITE_ROW)
|
||||||
{
|
{
|
||||||
@ -1218,7 +1227,8 @@ static bool _set_property(tf_ssb_t* ssb, const char* id, const char* key, const
|
|||||||
sqlite3_stmt* statement = NULL;
|
sqlite3_stmt* statement = NULL;
|
||||||
if (sqlite3_prepare(db, "INSERT OR REPLACE INTO properties (id, key, value) VALUES (?, ?, ?)", -1, &statement, NULL) == SQLITE_OK)
|
if (sqlite3_prepare(db, "INSERT OR REPLACE INTO properties (id, key, value) VALUES (?, ?, ?)", -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 &&
|
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)
|
sqlite3_bind_text(statement, 3, value, -1, NULL) == SQLITE_OK)
|
||||||
{
|
{
|
||||||
result = sqlite3_step(statement) == SQLITE_DONE;
|
result = sqlite3_step(statement) == SQLITE_DONE;
|
||||||
@ -1248,9 +1258,9 @@ static void _httpd_endpoint_login(tf_http_request_t* request)
|
|||||||
snprintf(url, sizeof(url), "%s%s/", request->is_tls ? "https://" : "http://", tf_http_request_get_header(request, "host"));
|
snprintf(url, sizeof(url), "%s%s/", request->is_tls ? "https://" : "http://", tf_http_request_get_header(request, "host"));
|
||||||
return_url = url;
|
return_url = url;
|
||||||
}
|
}
|
||||||
const char* headers[] = {
|
const char* headers[] =
|
||||||
"Location",
|
{
|
||||||
return_url,
|
"Location", return_url,
|
||||||
};
|
};
|
||||||
tf_http_respond(request, 303, headers, tf_countof(headers) / 2, NULL, 0);
|
tf_http_respond(request, 303, headers, tf_countof(headers) / 2, NULL, 0);
|
||||||
goto done;
|
goto done;
|
||||||
@ -1275,11 +1285,20 @@ static void _httpd_endpoint_login(tf_http_request_t* request)
|
|||||||
const char* change = _form_data_get(post_form_data, "change");
|
const char* change = _form_data_get(post_form_data, "change");
|
||||||
const char* form_register = _form_data_get(post_form_data, "register");
|
const char* form_register = _form_data_get(post_form_data, "register");
|
||||||
char account_passwd[256] = { 0 };
|
char account_passwd[256] = { 0 };
|
||||||
bool have_account = _read_account(ssb, _form_data_get(post_form_data, "name"), account_passwd, sizeof(account_passwd));
|
bool have_account = _read_account(
|
||||||
|
ssb,
|
||||||
|
_form_data_get(post_form_data, "name"),
|
||||||
|
account_passwd,
|
||||||
|
sizeof(account_passwd));
|
||||||
|
|
||||||
if (form_register && strcmp(form_register, "1") == 0)
|
if (form_register && strcmp(form_register, "1") == 0)
|
||||||
{
|
{
|
||||||
if (!have_account && _is_name_valid(account_name) && password && confirm && strcmp(password, confirm) == 0 && _register_account(ssb, account_name, password))
|
if (!have_account &&
|
||||||
|
_is_name_valid(account_name) &&
|
||||||
|
password &&
|
||||||
|
confirm &&
|
||||||
|
strcmp(password, confirm) == 0 &&
|
||||||
|
_register_account(ssb, account_name, password))
|
||||||
{
|
{
|
||||||
send_session = _make_session_jwt(ssb, account_name);
|
send_session = _make_session_jwt(ssb, account_name);
|
||||||
may_become_first_admin = true;
|
may_become_first_admin = true;
|
||||||
@ -1292,7 +1311,12 @@ static void _httpd_endpoint_login(tf_http_request_t* request)
|
|||||||
else if (change && strcmp(change, "1") == 0)
|
else if (change && strcmp(change, "1") == 0)
|
||||||
{
|
{
|
||||||
sqlite3* db = tf_ssb_acquire_db_writer(ssb);
|
sqlite3* db = tf_ssb_acquire_db_writer(ssb);
|
||||||
if (have_account && _is_name_valid(account_name) && new_password && confirm && strcmp(new_password, confirm) == 0 && _verify_password(password, account_passwd) &&
|
if (have_account &&
|
||||||
|
_is_name_valid(account_name) &&
|
||||||
|
new_password &&
|
||||||
|
confirm &&
|
||||||
|
strcmp(new_password, confirm) == 0 &&
|
||||||
|
_verify_password(password, account_passwd) &&
|
||||||
_set_account_password(context, db, account_name, new_password))
|
_set_account_password(context, db, account_name, new_password))
|
||||||
{
|
{
|
||||||
send_session = _make_session_jwt(ssb, account_name);
|
send_session = _make_session_jwt(ssb, account_name);
|
||||||
@ -1339,11 +1363,10 @@ static void _httpd_endpoint_login(tf_http_request_t* request)
|
|||||||
{
|
{
|
||||||
snprintf(cookie, length + 1, k_pattern, send_session, k_refresh_interval, request->is_tls ? "Secure; " : "");
|
snprintf(cookie, length + 1, k_pattern, send_session, k_refresh_interval, request->is_tls ? "Secure; " : "");
|
||||||
}
|
}
|
||||||
const char* headers[] = {
|
const char* headers[] =
|
||||||
"Location",
|
{
|
||||||
return_url,
|
"Location", return_url,
|
||||||
"Set-Cookie",
|
"Set-Cookie", cookie ? cookie : "",
|
||||||
cookie ? cookie : "",
|
|
||||||
};
|
};
|
||||||
tf_http_respond(request, 303, headers, tf_countof(headers) / 2, NULL, 0);
|
tf_http_respond(request, 303, headers, tf_countof(headers) / 2, NULL, 0);
|
||||||
tf_free(cookie);
|
tf_free(cookie);
|
||||||
@ -1416,7 +1439,8 @@ static void _httpd_endpoint_login(tf_http_request_t* request)
|
|||||||
JS_FreeValue(context, permissions);
|
JS_FreeValue(context, permissions);
|
||||||
|
|
||||||
login_request_t* login = tf_malloc(sizeof(login_request_t));
|
login_request_t* login = tf_malloc(sizeof(login_request_t));
|
||||||
*login = (login_request_t) {
|
*login = (login_request_t)
|
||||||
|
{
|
||||||
.request = request,
|
.request = request,
|
||||||
.name = account_name_copy,
|
.name = account_name_copy,
|
||||||
.jwt = jwt,
|
.jwt = jwt,
|
||||||
@ -1445,17 +1469,17 @@ done:
|
|||||||
|
|
||||||
static void _httpd_endpoint_logout(tf_http_request_t* request)
|
static void _httpd_endpoint_logout(tf_http_request_t* request)
|
||||||
{
|
{
|
||||||
const char* k_set_cookie = request->is_tls ? "session=; path=/; Secure; SameSite=Strict; expires=Thu, 01 Jan 1970 00:00:00 GMT; HttpOnly"
|
const char* k_set_cookie = request->is_tls ?
|
||||||
: "session=; path=/; SameSite=Strict; expires=Thu, 01 Jan 1970 00:00:00 GMT; HttpOnly";
|
"session=; path=/; Secure; SameSite=Strict; expires=Thu, 01 Jan 1970 00:00:00 GMT; HttpOnly" :
|
||||||
|
"session=; path=/; SameSite=Strict; expires=Thu, 01 Jan 1970 00:00:00 GMT; HttpOnly";
|
||||||
const char* k_location_format = "/login%s%s";
|
const char* k_location_format = "/login%s%s";
|
||||||
int length = snprintf(NULL, 0, k_location_format, request->query ? "?" : "", request->query);
|
int length = snprintf(NULL, 0, k_location_format, request->query ? "?" : "", request->query);
|
||||||
char* location = alloca(length + 1);
|
char* location = alloca(length + 1);
|
||||||
snprintf(location, length + 1, k_location_format, request->query ? "?" : "", request->query ? request->query : "");
|
snprintf(location, length + 1, k_location_format, request->query ? "?" : "", request->query ? request->query : "");
|
||||||
const char* headers[] = {
|
const char* headers[] =
|
||||||
"Set-Cookie",
|
{
|
||||||
k_set_cookie,
|
"Set-Cookie", k_set_cookie,
|
||||||
"Location",
|
"Location", location,
|
||||||
location,
|
|
||||||
};
|
};
|
||||||
tf_http_respond(request, 303, headers, tf_countof(headers) / 2, NULL, 0);
|
tf_http_respond(request, 303, headers, tf_countof(headers) / 2, NULL, 0);
|
||||||
}
|
}
|
||||||
|
10
src/ssb.db.c
10
src/ssb.db.c
@ -1060,14 +1060,8 @@ bool tf_ssb_db_identity_create(tf_ssb_t* ssb, const char* user, uint8_t* out_pub
|
|||||||
tf_ssb_generate_keys_buffer(public, sizeof(public), private, sizeof(private));
|
tf_ssb_generate_keys_buffer(public, sizeof(public), private, sizeof(private));
|
||||||
if (tf_ssb_db_identity_add(ssb, user, public, private))
|
if (tf_ssb_db_identity_add(ssb, user, public, private))
|
||||||
{
|
{
|
||||||
if (out_public_key)
|
tf_ssb_id_str_to_bin(out_public_key, public);
|
||||||
{
|
tf_ssb_id_str_to_bin(out_private_key, private);
|
||||||
tf_ssb_id_str_to_bin(out_public_key, public);
|
|
||||||
}
|
|
||||||
if (out_private_key)
|
|
||||||
{
|
|
||||||
tf_ssb_id_str_to_bin(out_private_key, private);
|
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user