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

View file

@ -148,6 +148,15 @@ bool sosc::Packet::Check(int region_count, ...) const {
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 {
*packet = std::string(8, 0);
(*packet)[0] = 0xB0;

View file

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

View file

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

View file

@ -7,6 +7,8 @@
#include <vector>
#include <map>
#include <iostream>
#include "string.hpp"
namespace sosc {
@ -23,7 +25,7 @@ struct Field {
explicit Field
(const std::string& name, kType type = STRING)
: name(name), type(type) {}
bool Test() const;
bool Test(const std::string& value) const;
std::string name;
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 delimiter, int count)
{
std::string assembled;
std::stringstream ss;
int bounds = (count == -1)
? parts.size()
: std::min<int>(count, parts.size());
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

View file

@ -11,11 +11,12 @@ static struct {
bool sosc::db::init_databases(std::string* error) {
if(_ctx.ready)
return true;
_ctx.ready = true;
sqlite3_open(":memory:", &_ctx.mem_db);
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(
"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(error != nullptr)
*error = "HARD DB: RECORDED MIGRATION COUNT TOO HIGH";
_ctx.ready = false;
return false;
}
int id;
Query insertMigration(
"INSERT INTO MIGRATIONS (ID, SQL_HASH, DATE_RAN) "
"VALUES (?, ?, NOW())"
"VALUES (?, ?, DATETIME('NOW'))"
);
Query getMigration("SELECT SQL_HASH FROM MIGRATIONS WHERE 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(error != nullptr)
*error = "HARD DB: MIGRATION RECORDS NOT CONTINUOUS";
_ctx.ready = false;
return false;
}
@ -56,6 +59,7 @@ bool sosc::db::init_databases(std::string* error) {
if(hash != cgc::sha1(_hard_db_sql[id])) {
if(error != nullptr)
*error = "HARD DB: MIGRATION SQL HASH MISMATCH";
_ctx.ready = 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) {
if(!_ctx.ready)
return;
if(!this->open)
if(this->open)
this->Close();
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)
this->open = true;
else
throw std::runtime_error(sqlite3_errmsg(this->database));
}
void sosc::db::Query::BindDouble(double value, int i) {

View file

@ -4,6 +4,7 @@
#include "sqlite/sqlite3.h"
#include "utils/time.hpp"
#include "crypto/sha1.hpp"
#include "common.hpp"
#include <vector>
#include <string>
@ -86,7 +87,7 @@ private:
};
// 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);
void close_databases();
}}

View file

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

View file

@ -7,44 +7,50 @@ static struct {
/** MASTERCLIENTPOOL CODE **/
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(
"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(
"INSERT INTO `USERS` "
"(`USERNAME`, `PASS_HASH`, `EMAIL`, `ACTIVATED`, `JOINED`) "
"VALUES (?, ?, ?, 0, CURRENT_TIMESTAMP)"
));
#define QRY_USER_NAME_EXISTS 2
#define QRY_USER_NAME_EXISTS 3
queries->push_back(new db::Query(
"SELECT COUNT(*) FROM `USERS` "
"WHERE LOWER(`USERNAME`) = LOWER(?)"
));
#define QRY_USER_GET_PWD_HASH 3
#define QRY_USER_GET_PWD_HASH 4
queries->push_back(new db::Query(
"SELECT `ID`, `PASS_HASH` FROM `USERS` "
"WHERE LOWER(`USERNAME`) = LOWER(?)"
));
#define QRY_USER_GENERATE_KEY 4
#define QRY_USER_GENERATE_KEY 5
queries->push_back(new db::Query(
"INSERT OR IGNORE INTO `USER_KEYS` "
"(`ID`, `SECRET`) VALUES (?, RANDOMBLOB(128))"
));
#define QRY_USER_GET_KEY 5
#define QRY_USER_GET_KEY 6
queries->push_back(new db::Query(
"SELECT `SECRET` FROM `USER_KEYS` "
"WHERE `ID` = ?"
));
#define QRY_USER_CHECK_KEY 6
#define QRY_USER_CHECK_KEY 7
queries->push_back(new db::Query(
"SELECT COUNT(*) FROM `USER_KEYS` "
"WHERE `ID` = ? AND `SECRET` = ?"
@ -88,14 +94,85 @@ bool sosc::MasterClient::ProcessLogin(Packet &pck) {
return true;
if(!pck.Check(2, PCK_ANY, PCK_ANY))
return false;
pck.TrimRegions();
db::ResultSet* results = nullptr;
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;
}
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;
}

View file

@ -152,23 +152,23 @@ bool sosc::MasterIntra::Authentication(sosc::Packet& pck) {
}
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) {
this->sock.Send(
Packet(kNegativeAck, { packetId , net::htonv(errorCode) })
Packet(kNegativeAck, { packet_id , net::htonv(error_code) })
);
return true;
} else {
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(
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) {
using namespace sosc;
if(argc < 2)
return -1;
ini::File* config;
try {
@ -105,7 +103,7 @@ int main(int argc, char **argv) {
poolinfo_t info;
configure_poolinfo(&_ctx.default_info, (*config)["defaults"][0]);
if((*config)["master"]["run master"]) {
if((*config)["general"]["run master"]) {
if(!config->HasSection("master to client") ||
!config->HasSection("master to slave"))
{
@ -122,13 +120,13 @@ int main(int argc, char **argv) {
configure_poolinfo(&info, (*config)["master to slave"][0]);
_ctx.master_intra = new master_intra_ctx;
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]);
_ctx.master_client = new master_client_ctx;
master_client_start(
(uint16_t)(*config)["master"]["client port"], info
(uint16_t)(*config)["master to client"]["port"], info
);
}