satori bad

This commit is contained in:
malloc 2018-11-14 16:26:44 -06:00
parent cfcdcc4cd4
commit 6ed3adfb87
13 changed files with 172 additions and 59 deletions

View file

@ -181,8 +181,8 @@ Communication between the master server and clients will be done over a WebSocke
</tr> </tr>
<tr style="border-bottom: 2px solid;"> <tr style="border-bottom: 2px solid;">
<td class="center">2</td> <td class="center">2</td>
<td>Message</td> <td>Error Code</td>
<td>String</td> <td>Packed Unsigned Short</td>
<td>&not;R<sub>1</sub></td> <td>&not;R<sub>1</sub></td>
</tr> </tr>
<tr> <tr>
@ -213,8 +213,8 @@ Communication between the master server and clients will be done over a WebSocke
</tr> </tr>
<tr> <tr>
<td class="center">2</td> <td class="center">2</td>
<td>Message</td> <td>Error Code</td>
<td>String</td> <td>Packed Unsigned Short</td>
</tr> </tr>
</table> </table>
@ -354,12 +354,7 @@ TODO: MAKE THIS SECTION NOT LOOK LIKE SHIT
### Master / Slave ### Master / Slave
#### M -> S (ID 2) #### M -> S (ID 1)
0x100: KEY SIZE WAS INCORRECT
0x101: COULD NOT PARSE KEY
#### M -> S (ID 4)
0x100: MAX AUTH ATTEMPTS REACHED 0x100: MAX AUTH ATTEMPTS REACHED
0x101: LICENSE DATA INCORRECT 0x101: LICENSE DATA INCORRECT
@ -370,4 +365,22 @@ TODO: MAKE THIS SECTION NOT LOOK LIKE SHIT
### Master / Client ### Master / Client
#### M -> C (ID 0)
0x100: MAX AUTH ATTEMPTS REACHED
0x101: USERNAME DOES NOT EXIST
0x102: PASSWORD INCORRECT
#### M -> C (ID 1)
0x000: OK
0x100: USERNAME TAKEN
0x101: EMAIL TAKEN
0x102: PASSWORD TOO WEAK
### Slave / Client ### Slave / Client

View file

@ -148,6 +148,15 @@ bool sosc::Packet::Check(int region_count, ...) const {
return true; return true;
} }
void sosc::Packet::TrimRegions(const std::vector<uint32_t>& ids) {
if(ids.size() == 0)
for(uint32_t id = 0; id < this->regions.size(); ++id)
str::trim(&this->regions[id]);
else
for(auto id : ids)
str::trim(&this->regions[id]);
}
std::string* sosc::Packet::ToString(std::string* packet) const { std::string* sosc::Packet::ToString(std::string* packet) const {
*packet = std::string(8, 0); *packet = std::string(8, 0);
(*packet)[0] = 0xB0; (*packet)[0] = 0xB0;

View file

@ -35,6 +35,7 @@ public:
int Parse(const std::string& data, std::string* extra = nullptr); int Parse(const std::string& data, std::string* extra = nullptr);
bool Check(int region_count, ...) const; bool Check(int region_count, ...) const;
void TrimRegions(const std::vector<uint32_t>& ids = {});
inline void SetId(uint8_t id) { inline void SetId(uint8_t id) {
this->id = id; this->id = id;

View file

@ -1,20 +1,20 @@
#include "ini.hpp" #include "ini.hpp"
using namespace sosc::ini; using namespace sosc::ini;
bool Field::Test() const { bool Field::Test(const std::string& value) const {
try { try {
switch(type) { switch(type) {
case INT32: case INT32:
(int32_t)File::Proxy(name); (int32_t)File::Proxy(value);
break; break;
case UINT32: case UINT32:
(uint32_t)File::Proxy(name); (uint32_t)File::Proxy(value);
break; break;
case DOUBLE: case DOUBLE:
(double)File::Proxy(name); (double)File::Proxy(value);
break; break;
case BOOL: case BOOL:
(bool)File::Proxy(name); (bool)File::Proxy(value);
break; break;
} }
@ -100,13 +100,14 @@ File* File::Open
for(auto& section : (*ini)[rule.name].sections) { for(auto& section : (*ini)[rule.name].sections) {
for(auto &field : rule.required_fields) { for(auto &field : rule.required_fields) {
if(section.values.count(str::tolower(field.name)) == 0) std::string field_name = str::tolower(field.name);
if(section.values.count(field_name) == 0)
throw LoadError(ini, -1, str::join({ throw LoadError(ini, -1, str::join({
"Required field '", field.name, "' in section '", "Required field '", field.name, "' in section '",
rule.name, "' not found." rule.name, "' not found."
})); }));
if(!field.Test()) if(!field.Test(section.values.at(field_name)))
throw LoadError(ini, -1, str::join({ throw LoadError(ini, -1, str::join({
"Field '", field.name, "' in section '",rule.name, "' " "Field '", field.name, "' in section '",rule.name, "' "
"cannot be casted to requested type." "cannot be casted to requested type."
@ -121,15 +122,16 @@ File* File::Open
std::runtime_error File::LoadError std::runtime_error File::LoadError
(File* file, int line, const std::string &error) (File* file, int line, const std::string &error)
{ {
delete file; std::string msg;
if(line > 0) if(line > 0)
return std::runtime_error(str::join( msg = str::join(
{"LOAD ERROR IN '", file->filename, "' L", TOSTR(line), ": ", error} {"LOAD ERROR IN '", file->filename, "' L", TOSTR(line), ": ", error}
)); );
else else
return std::runtime_error(str::join( msg = str::join({"LOAD ERROR IN '", file->filename, "': ", error});
{"LOAD ERROR IN '", file->filename, "': ", error}
)); delete file;
throw std::runtime_error(msg);
} }
bool File::HasSection(std::string name) const { bool File::HasSection(std::string name) const {

View file

@ -7,6 +7,8 @@
#include <vector> #include <vector>
#include <map> #include <map>
#include <iostream>
#include "string.hpp" #include "string.hpp"
namespace sosc { namespace sosc {
@ -23,7 +25,7 @@ struct Field {
explicit Field explicit Field
(const std::string& name, kType type = STRING) (const std::string& name, kType type = STRING)
: name(name), type(type) {} : name(name), type(type) {}
bool Test() const; bool Test(const std::string& value) const;
std::string name; std::string name;
kType type; kType type;

View file

@ -88,15 +88,15 @@ std::string sosc::str::join(const std::vector<std::string>& parts,
std::string sosc::str::join(const std::vector<std::string>& parts, std::string sosc::str::join(const std::vector<std::string>& parts,
std::string delimiter, int count) std::string delimiter, int count)
{ {
std::string assembled; std::stringstream ss;
int bounds = (count == -1) int bounds = (count == -1)
? parts.size() ? parts.size()
: std::min<int>(count, parts.size()); : std::min<int>(count, parts.size());
for(int i = 0; i < bounds; ++i) for(int i = 0; i < bounds; ++i)
assembled += (i == 0 ? "" : delimiter) + parts[i]; ss << (i == 0 ? "" : delimiter) + parts[i];
return assembled; return ss.str();
} }
bool sosc::str::starts bool sosc::str::starts

View file

@ -11,11 +11,12 @@ static struct {
bool sosc::db::init_databases(std::string* error) { bool sosc::db::init_databases(std::string* error) {
if(_ctx.ready) if(_ctx.ready)
return true; return true;
_ctx.ready = true;
sqlite3_open(":memory:", &_ctx.mem_db); sqlite3_open(":memory:", &_ctx.mem_db);
sqlite3_exec(_ctx.mem_db, _mem_db_sql, nullptr, nullptr, nullptr); sqlite3_exec(_ctx.mem_db, _mem_db_sql, nullptr, nullptr, nullptr);
sqlite3_open("scape.db", &_ctx.hard_db); sqlite3_open(SOSC_RESC("scape.db").c_str(), &_ctx.hard_db);
int32_t migrationsExist = db::Query::ScalarInt32( int32_t migrationsExist = db::Query::ScalarInt32(
"SELECT COUNT(*) FROM SQLITE_MASTER WHERE TBL_NAME = 'MIGRATIONS'" "SELECT COUNT(*) FROM SQLITE_MASTER WHERE TBL_NAME = 'MIGRATIONS'"
@ -27,13 +28,14 @@ bool sosc::db::init_databases(std::string* error) {
if(lastMig > _hard_db_sql.size()) { if(lastMig > _hard_db_sql.size()) {
if(error != nullptr) if(error != nullptr)
*error = "HARD DB: RECORDED MIGRATION COUNT TOO HIGH"; *error = "HARD DB: RECORDED MIGRATION COUNT TOO HIGH";
_ctx.ready = false;
return false; return false;
} }
int id; int id;
Query insertMigration( Query insertMigration(
"INSERT INTO MIGRATIONS (ID, SQL_HASH, DATE_RAN) " "INSERT INTO MIGRATIONS (ID, SQL_HASH, DATE_RAN) "
"VALUES (?, ?, NOW())" "VALUES (?, ?, DATETIME('NOW'))"
); );
Query getMigration("SELECT SQL_HASH FROM MIGRATIONS WHERE ID = ?"); Query getMigration("SELECT SQL_HASH FROM MIGRATIONS WHERE ID = ?");
for(id = 0; id < _hard_db_sql.size(); ++id) { for(id = 0; id < _hard_db_sql.size(); ++id) {
@ -44,6 +46,7 @@ bool sosc::db::init_databases(std::string* error) {
if(id < lastMig) { if(id < lastMig) {
if(error != nullptr) if(error != nullptr)
*error = "HARD DB: MIGRATION RECORDS NOT CONTINUOUS"; *error = "HARD DB: MIGRATION RECORDS NOT CONTINUOUS";
_ctx.ready = false;
return false; return false;
} }
@ -56,6 +59,7 @@ bool sosc::db::init_databases(std::string* error) {
if(hash != cgc::sha1(_hard_db_sql[id])) { if(hash != cgc::sha1(_hard_db_sql[id])) {
if(error != nullptr) if(error != nullptr)
*error = "HARD DB: MIGRATION SQL HASH MISMATCH"; *error = "HARD DB: MIGRATION SQL HASH MISMATCH";
_ctx.ready = false;
return false; return false;
} }
} }
@ -106,7 +110,7 @@ sosc::db::Query::Query(const std::string& query, int db) : results(this) {
void sosc::db::Query::SetQuery(const std::string &query, int db) { void sosc::db::Query::SetQuery(const std::string &query, int db) {
if(!_ctx.ready) if(!_ctx.ready)
return; return;
if(!this->open) if(this->open)
this->Close(); this->Close();
this->database = db == DB_USE_MEMORY ? _ctx.mem_db : _ctx.hard_db; this->database = db == DB_USE_MEMORY ? _ctx.mem_db : _ctx.hard_db;
@ -120,6 +124,8 @@ void sosc::db::Query::SetQuery(const std::string &query, int db) {
if(status == SQLITE_OK) if(status == SQLITE_OK)
this->open = true; this->open = true;
else
throw std::runtime_error(sqlite3_errmsg(this->database));
} }
void sosc::db::Query::BindDouble(double value, int i) { void sosc::db::Query::BindDouble(double value, int i) {

View file

@ -4,6 +4,7 @@
#include "sqlite/sqlite3.h" #include "sqlite/sqlite3.h"
#include "utils/time.hpp" #include "utils/time.hpp"
#include "crypto/sha1.hpp" #include "crypto/sha1.hpp"
#include "common.hpp"
#include <vector> #include <vector>
#include <string> #include <string>
@ -86,7 +87,7 @@ private:
}; };
// THE FOLLOWING ARE NOT THREAD SAFE !! // THE FOLLOWING ARE NOT THREAD SAFE !!
// CALL THEM ONLY WHEN MASTER POOL IS INACTIVE // CALL THEM ONLY WHEN MASTER POOLS ARE INACTIVE
bool init_databases(std::string* error); bool init_databases(std::string* error);
void close_databases(); void close_databases();
}} }}

View file

@ -5,8 +5,8 @@
#include "sock/scapesock.hpp" #include "sock/scapesock.hpp"
#include "sock/pool.hpp" #include "sock/pool.hpp"
#include "crypto/bcrypt.hpp"
#include "db/database.hpp" #include "db/database.hpp"
#include "ctx/master.hpp" #include "ctx/master.hpp"
#include <vector> #include <vector>
@ -27,7 +27,11 @@ public:
~MasterClient() { this->Close(); }; ~MasterClient() { this->Close(); };
private: private:
bool ProcessLogin(Packet& pck); bool ProcessLogin(Packet& pck);
bool LoginError(uint16_t error_code);
bool ProcessRegistration(Packet& pck); bool ProcessRegistration(Packet& pck);
bool RegistrationError(uint16_t error_code);
bool ListServers(Packet& pck); bool ListServers(Packet& pck);
enum MasterToClientId { enum MasterToClientId {
@ -79,9 +83,9 @@ private:
bool StatusUpdate(Packet& pck); bool StatusUpdate(Packet& pck);
bool AuthenticationFailure bool AuthenticationFailure
(const std::string& packetId, uint16_t errorCode); (const std::string& packet_id, uint16_t error_code);
bool NotAuthorized(const std::string& packetId); bool NotAuthorized(const std::string& packet_id);
enum SlaveToMasterId { enum SlaveToMasterId {
kAuthentication = 0, kAuthentication = 0,

View file

@ -7,44 +7,50 @@ static struct {
/** MASTERCLIENTPOOL CODE **/ /** MASTERCLIENTPOOL CODE **/
void sosc::MasterClientPool::SetupQueries(db::Queries *queries) { void sosc::MasterClientPool::SetupQueries(db::Queries *queries) {
#define QRY_USER_REG_CHECK 0 #define QRY_USER_NAME_REG_CHECK 0
queries->push_back(new db::Query( queries->push_back(new db::Query(
"SELECT COUNT(*) FROM `USERS` " "SELECT COUNT(*) FROM `USERS` "
"WHERE `USERNAME` = ? OR `EMAIL` = ?" "WHERE `USERNAME` = ?"
)); ));
#define QRY_USER_REGISTER 1 #define QRY_USER_MAIL_REG_CHECK 1
queries->push_back(new db::Query(
"SELECT COUNT(*) FROM `USERS` "
"WHERE `USERNAME` = ?"
));
#define QRY_USER_REGISTER 2
queries->push_back(new db::Query( queries->push_back(new db::Query(
"INSERT INTO `USERS` " "INSERT INTO `USERS` "
"(`USERNAME`, `PASS_HASH`, `EMAIL`, `ACTIVATED`, `JOINED`) " "(`USERNAME`, `PASS_HASH`, `EMAIL`, `ACTIVATED`, `JOINED`) "
"VALUES (?, ?, ?, 0, CURRENT_TIMESTAMP)" "VALUES (?, ?, ?, 0, CURRENT_TIMESTAMP)"
)); ));
#define QRY_USER_NAME_EXISTS 2 #define QRY_USER_NAME_EXISTS 3
queries->push_back(new db::Query( queries->push_back(new db::Query(
"SELECT COUNT(*) FROM `USERS` " "SELECT COUNT(*) FROM `USERS` "
"WHERE LOWER(`USERNAME`) = LOWER(?)" "WHERE LOWER(`USERNAME`) = LOWER(?)"
)); ));
#define QRY_USER_GET_PWD_HASH 3 #define QRY_USER_GET_PWD_HASH 4
queries->push_back(new db::Query( queries->push_back(new db::Query(
"SELECT `ID`, `PASS_HASH` FROM `USERS` " "SELECT `ID`, `PASS_HASH` FROM `USERS` "
"WHERE LOWER(`USERNAME`) = LOWER(?)" "WHERE LOWER(`USERNAME`) = LOWER(?)"
)); ));
#define QRY_USER_GENERATE_KEY 4 #define QRY_USER_GENERATE_KEY 5
queries->push_back(new db::Query( queries->push_back(new db::Query(
"INSERT OR IGNORE INTO `USER_KEYS` " "INSERT OR IGNORE INTO `USER_KEYS` "
"(`ID`, `SECRET`) VALUES (?, RANDOMBLOB(128))" "(`ID`, `SECRET`) VALUES (?, RANDOMBLOB(128))"
)); ));
#define QRY_USER_GET_KEY 5 #define QRY_USER_GET_KEY 6
queries->push_back(new db::Query( queries->push_back(new db::Query(
"SELECT `SECRET` FROM `USER_KEYS` " "SELECT `SECRET` FROM `USER_KEYS` "
"WHERE `ID` = ?" "WHERE `ID` = ?"
)); ));
#define QRY_USER_CHECK_KEY 6 #define QRY_USER_CHECK_KEY 7
queries->push_back(new db::Query( queries->push_back(new db::Query(
"SELECT COUNT(*) FROM `USER_KEYS` " "SELECT COUNT(*) FROM `USER_KEYS` "
"WHERE `ID` = ? AND `SECRET` = ?" "WHERE `ID` = ? AND `SECRET` = ?"
@ -88,14 +94,85 @@ bool sosc::MasterClient::ProcessLogin(Packet &pck) {
return true; return true;
if(!pck.Check(2, PCK_ANY, PCK_ANY)) if(!pck.Check(2, PCK_ANY, PCK_ANY))
return false; return false;
pck.TrimRegions();
db::ResultSet* results = nullptr;
db::Query* query = this->queries->at(QRY_USER_NAME_EXISTS); db::Query* query = this->queries->at(QRY_USER_NAME_EXISTS);
query->Reset();
query->BindText(pck[0], 0);
if(query->ScalarInt32() == 0)
return LoginError(0x101);
query = this->queries->at(QRY_USER_GET_PWD_HASH);
query->Reset();
query->BindText(pck[0], 0);
results = query->GetResults();
results->Step();
int64_t user_id = results->GetInt64(0);
if(!cgc::bcrypt_check(pck[1], results->GetText(1)))
return LoginError(0x102);
query = this->queries->at(QRY_USER_GENERATE_KEY);
query->Reset();
query->BindInt64(user_id, 0);
query->NonQuery();
query = this->queries->at(QRY_USER_GET_KEY);
query->Reset();
query->BindInt64(user_id, 0);
auto secret = query->ScalarBlob();
this->sock.Send(Packet(kLoginResponse, {"\1", secret}));
this->authed = true;
return true; return true;
} }
bool sosc::MasterClient::ProcessRegistration(Packet &pck) { bool sosc::MasterClient::LoginError(uint16_t error_code) {
if(++this->auth_attempts < MAX_AUTH_ATTEMPTS) {
this->sock.Send(
Packet(kLoginResponse, {"\0", HTONUS(error_code)})
);
return true;
} else {
return this->Close(
Packet(kLoginResponse, {"\0", HTONUS(0x100)})
);
}
}
bool sosc::MasterClient::ProcessRegistration(Packet &pck) {
if(!pck.Check(3, PCK_ANY, PCK_ANY, PCK_ANY))
return false;
pck.TrimRegions();
db::Query* query = this->queries->at(QRY_USER_NAME_REG_CHECK);
query->Reset();
query->BindText(pck[0], 0);
if(query->ScalarInt32() > 0)
return RegistrationError(0x100);
query = this->queries->at(QRY_USER_MAIL_REG_CHECK);
query->Reset();
query->BindText(pck[2], 0);
if(query->ScalarInt32() > 0)
return RegistrationError(0x101);
query = this->queries->at(QRY_USER_REGISTER);
query->Reset();
query->BindText(pck[0], 0);
query->BindText(cgc::bcrypt_hash(pck[1]), 1);
query->BindText(pck[2], 2);
query->NonQuery();
this->sock.Send(Packet(kRegisterResponse, {"\1", 0x000}));
return true;
}
bool sosc::MasterClient::RegistrationError(uint16_t error_code) {
this->sock.Send(
Packet(kRegisterResponse, {"\0", HTONUS(error_code)})
);
return true; return true;
} }

View file

@ -152,23 +152,23 @@ bool sosc::MasterIntra::Authentication(sosc::Packet& pck) {
} }
bool sosc::MasterIntra::AuthenticationFailure bool sosc::MasterIntra::AuthenticationFailure
(const std::string& packetId, uint16_t errorCode) (const std::string& packet_id, uint16_t error_code)
{ {
if(++this->auth_attempts < MAX_AUTH_ATTEMPTS) { if(++this->auth_attempts < MAX_AUTH_ATTEMPTS) {
this->sock.Send( this->sock.Send(
Packet(kNegativeAck, { packetId , net::htonv(errorCode) }) Packet(kNegativeAck, { packet_id , net::htonv(error_code) })
); );
return true; return true;
} else { } else {
return this->Close( return this->Close(
Packet(kNegativeAck, { packetId, net::htonv<uint16_t>(0x100) }) Packet(kNegativeAck, { packet_id, net::htonv<uint16_t>(0x100) })
); );
} }
} }
bool sosc::MasterIntra::NotAuthorized(const std::string& packetId) { bool sosc::MasterIntra::NotAuthorized(const std::string& packet_id) {
return this->Close( return this->Close(
Packet(kNegativeAck, { packetId, net::htonv<uint16_t>(0x200) }) Packet(kNegativeAck, { packet_id, net::htonv<uint16_t>(0x200) })
); );
} }

View file

@ -65,8 +65,6 @@ void configure_poolinfo(sosc::poolinfo_t* info,
int main(int argc, char **argv) { int main(int argc, char **argv) {
using namespace sosc; using namespace sosc;
if(argc < 2)
return -1;
ini::File* config; ini::File* config;
try { try {
@ -105,7 +103,7 @@ int main(int argc, char **argv) {
poolinfo_t info; poolinfo_t info;
configure_poolinfo(&_ctx.default_info, (*config)["defaults"][0]); configure_poolinfo(&_ctx.default_info, (*config)["defaults"][0]);
if((*config)["master"]["run master"]) { if((*config)["general"]["run master"]) {
if(!config->HasSection("master to client") || if(!config->HasSection("master to client") ||
!config->HasSection("master to slave")) !config->HasSection("master to slave"))
{ {
@ -122,13 +120,13 @@ int main(int argc, char **argv) {
configure_poolinfo(&info, (*config)["master to slave"][0]); configure_poolinfo(&info, (*config)["master to slave"][0]);
_ctx.master_intra = new master_intra_ctx; _ctx.master_intra = new master_intra_ctx;
master_intra_start( master_intra_start(
(uint16_t)(*config)["master"]["intra port"], info (uint16_t)(*config)["master to slave"]["port"], info
); );
configure_poolinfo(&info, (*config)["master to client"][0]); configure_poolinfo(&info, (*config)["master to client"][0]);
_ctx.master_client = new master_client_ctx; _ctx.master_client = new master_client_ctx;
master_client_start( master_client_start(
(uint16_t)(*config)["master"]["client port"], info (uint16_t)(*config)["master to client"]["port"], info
); );
} }