Auth Cookie Support (#285)

* Auth cookie support

* Add config option for auth cookie support

* Safe handling of TEGid/auth_id strings

* Fix bad size calculation due to pointer cast

* Expiration timestamp instead of valid bit

* Change setting to "allowed auth methods"

This allows plaintext password auth to be disabled altogether

* PR feedback
This commit is contained in:
2024-09-17 20:41:48 -07:00
committed by GitHub
parent 52833f7fb3
commit a6eb0e2349
10 changed files with 185 additions and 36 deletions

View File

@@ -5,7 +5,7 @@
#include <string>
#include <vector>
#define DATABASE_VERSION 4
#define DATABASE_VERSION 5
namespace Database {
@@ -53,6 +53,10 @@ namespace Database {
void updateAccountLevel(int accountId, int accountLevel);
// return true if cookie is valid for the account.
// invalidates the stored cookie afterwards
bool checkCookie(int accountId, const char *cookie);
// interface for the /ban command
bool banPlayer(int playerId, std::string& reason);
bool unbanPlayer(int playerId);

View File

@@ -98,6 +98,55 @@ void Database::updateAccountLevel(int accountId, int accountLevel) {
sqlite3_finalize(stmt);
}
bool Database::checkCookie(int accountId, const char *tryCookie) {
std::lock_guard<std::mutex> lock(dbCrit);
const char* sql_get = R"(
SELECT Cookie
FROM Auth
WHERE AccountID = ? AND Expires > ?;
)";
const char* sql_invalidate = R"(
UPDATE Auth
SET Expires = 0
WHERE AccountID = ?;
)";
sqlite3_stmt* stmt;
sqlite3_prepare_v2(db, sql_get, -1, &stmt, NULL);
sqlite3_bind_int(stmt, 1, accountId);
sqlite3_bind_int(stmt, 2, getTimestamp());
int rc = sqlite3_step(stmt);
if (rc != SQLITE_ROW) {
sqlite3_finalize(stmt);
return false;
}
const char *cookie = reinterpret_cast<const char*>(sqlite3_column_text(stmt, 0));
if (strlen(cookie) != strlen(tryCookie)) {
sqlite3_finalize(stmt);
return false;
}
/*
* since cookies are immediately invalidated, we don't need to be concerned about
* timing-related side channel attacks, so strcmp is fine here
*/
bool match = (strcmp(cookie, tryCookie) == 0);
sqlite3_finalize(stmt);
sqlite3_prepare_v2(db, sql_invalidate, -1, &stmt, NULL);
sqlite3_bind_int(stmt, 1, accountId);
rc = sqlite3_step(stmt);
sqlite3_finalize(stmt);
if (rc != SQLITE_DONE)
std::cout << "[WARN] Database fail on checkCookie(): " << sqlite3_errmsg(db) << std::endl;
return match;
}
void Database::updateSelected(int accountId, int slot) {
std::lock_guard<std::mutex> lock(dbCrit);