mirror of
https://github.com/SapphireServer/Sapphire.git
synced 2025-05-23 18:17:46 +00:00
Use proper KDF (Argon2) to hash password
VS2015, linux is not tested yet.
This commit is contained in:
parent
0eeeb020eb
commit
cf283d61e5
3 changed files with 130 additions and 99 deletions
|
@ -30,6 +30,7 @@ if(UNIX)
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
else()
|
else()
|
||||||
|
add_definitions(-DSODIUM_STATIC)
|
||||||
add_definitions(-D_WIN32_WINNT=0x601)
|
add_definitions(-D_WIN32_WINNT=0x601)
|
||||||
add_definitions(-D_CRT_SECURE_NO_WARNINGS)
|
add_definitions(-D_CRT_SECURE_NO_WARNINGS)
|
||||||
include_directories("${CMAKE_CURRENT_SOURCE_DIR}/../../libraries/external/MySQL/")
|
include_directories("${CMAKE_CURRENT_SOURCE_DIR}/../../libraries/external/MySQL/")
|
||||||
|
@ -57,10 +58,13 @@ endif()
|
||||||
|
|
||||||
|
|
||||||
include_directories(${Boost_INCLUDE_DIR})
|
include_directories(${Boost_INCLUDE_DIR})
|
||||||
|
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../../libraries/external/libsodium/include)
|
||||||
|
|
||||||
link_directories(${BOOST_LIBRARYDIR})
|
link_directories(${BOOST_LIBRARYDIR})
|
||||||
link_directories(${SERVER_COMMON_DIR})
|
link_directories(${SERVER_COMMON_DIR})
|
||||||
link_directories(${CMAKE_CURRENT_SOURCE_DIR}/../../libraries/sapphire/datReader)
|
link_directories(${CMAKE_CURRENT_SOURCE_DIR}/../../libraries/sapphire/datReader)
|
||||||
|
link_directories(${CMAKE_CURRENT_SOURCE_DIR}/../../libraries/external/libsodium/x64/Release/v141/static)
|
||||||
|
|
||||||
|
|
||||||
if(CMAKE_SIZEOF_VOID_P EQUAL 4)
|
if(CMAKE_SIZEOF_VOID_P EQUAL 4)
|
||||||
# 32 bit link
|
# 32 bit link
|
||||||
|
@ -89,7 +93,7 @@ set_target_properties(server_rest PROPERTIES
|
||||||
if (UNIX)
|
if (UNIX)
|
||||||
target_link_libraries (server_rest Common xivdat pthread mysqlclient dl z)
|
target_link_libraries (server_rest Common xivdat pthread mysqlclient dl z)
|
||||||
else()
|
else()
|
||||||
target_link_libraries (server_rest Common xivdat libmysql zlib1)
|
target_link_libraries (server_rest Common xivdat libmysql zlib1 libsodium)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
target_link_libraries( server_rest ${Boost_LIBRARIES} ${Boost_LIBRARIES} )
|
target_link_libraries( server_rest ${Boost_LIBRARIES} ${Boost_LIBRARIES} )
|
||||||
|
|
|
@ -13,6 +13,8 @@
|
||||||
#include <boost/shared_ptr.hpp>
|
#include <boost/shared_ptr.hpp>
|
||||||
#include <boost/make_shared.hpp>
|
#include <boost/make_shared.hpp>
|
||||||
|
|
||||||
|
#include <sodium.h>
|
||||||
|
|
||||||
extern Core::Db::Database g_database;
|
extern Core::Db::Database g_database;
|
||||||
|
|
||||||
Core::Network::SapphireAPI::SapphireAPI()
|
Core::Network::SapphireAPI::SapphireAPI()
|
||||||
|
@ -27,7 +29,7 @@ Core::Network::SapphireAPI::~SapphireAPI()
|
||||||
|
|
||||||
bool Core::Network::SapphireAPI::login( const std::string& username, const std::string& pass, std::string& sId )
|
bool Core::Network::SapphireAPI::login( const std::string& username, const std::string& pass, std::string& sId )
|
||||||
{
|
{
|
||||||
std::string query = "SELECT account_id FROM accounts WHERE account_name = '" + username + "' AND account_pass = '" + pass + "';";
|
std::string query = "SELECT account_id, account_pass FROM accounts WHERE account_name = '" + username + "';";
|
||||||
|
|
||||||
// check if a user with that name / password exists
|
// check if a user with that name / password exists
|
||||||
auto pQR = g_database.query( query );
|
auto pQR = g_database.query( query );
|
||||||
|
@ -35,6 +37,15 @@ bool Core::Network::SapphireAPI::login( const std::string& username, const std::
|
||||||
if( !pQR )
|
if( !pQR )
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
// id is assumed to be verified with SQL
|
||||||
|
// check password here
|
||||||
|
auto const accountPass = pQR->fetch()[1].getString();
|
||||||
|
if ( crypto_pwhash_argon2i_str_verify( accountPass, pass.c_str(), pass.length()) != 0 )
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// user found, proceed
|
// user found, proceed
|
||||||
int32_t accountId = pQR->fetch()[0].getUInt32();
|
int32_t accountId = pQR->fetch()[0].getUInt32();
|
||||||
|
|
||||||
|
@ -73,14 +84,14 @@ bool Core::Network::SapphireAPI::login( const std::string& username, const std::
|
||||||
|
|
||||||
bool Core::Network::SapphireAPI::insertSession( const uint32_t& accountId, std::string& sId )
|
bool Core::Network::SapphireAPI::insertSession( const uint32_t& accountId, std::string& sId )
|
||||||
{
|
{
|
||||||
// create session for the new sessionid and store to sessionlist
|
// create session for the new sessionid and store to sessionlist
|
||||||
auto pSession = boost::make_shared< Session >();
|
auto pSession = boost::make_shared< Session >();
|
||||||
pSession->setAccountId( accountId );
|
pSession->setAccountId( accountId );
|
||||||
pSession->setSessionId( (uint8_t *)sId.c_str() );
|
pSession->setSessionId( (uint8_t *)sId.c_str() );
|
||||||
|
|
||||||
m_sessionMap[sId] = pSession;
|
m_sessionMap[sId] = pSession;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -98,11 +109,19 @@ bool Core::Network::SapphireAPI::createAccount( const std::string& username, con
|
||||||
pQR = g_database.query( "SELECT MAX(account_id) FROM accounts;" );
|
pQR = g_database.query( "SELECT MAX(account_id) FROM accounts;" );
|
||||||
int32_t accountId = pQR->fetch()[0].getUInt32() + 1;
|
int32_t accountId = pQR->fetch()[0].getUInt32() + 1;
|
||||||
|
|
||||||
|
|
||||||
|
char hash[crypto_pwhash_STRBYTES];
|
||||||
|
if (crypto_pwhash_argon2i_str(hash, pass.c_str(), pass.length(), crypto_pwhash_OPSLIMIT_INTERACTIVE, crypto_pwhash_MEMLIMIT_INTERACTIVE) != 0)
|
||||||
|
{
|
||||||
|
// Failed to allocate memory
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// store the account to the db
|
// store the account to the db
|
||||||
g_database.execute( "INSERT INTO accounts (account_Id, account_name, account_pass, account_created) VALUE(%i, '%s', '%s', %i);",
|
g_database.execute( "INSERT INTO accounts (account_Id, account_name, account_pass, account_created) VALUE(%i, '%s', '%s', %i);",
|
||||||
accountId,
|
accountId,
|
||||||
username.c_str(),
|
username.c_str(),
|
||||||
pass.c_str(),
|
hash,
|
||||||
time( NULL ) );
|
time( NULL ) );
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -29,6 +29,8 @@
|
||||||
#include "SapphireAPI.h"
|
#include "SapphireAPI.h"
|
||||||
|
|
||||||
|
|
||||||
|
#include <sodium.h>
|
||||||
|
|
||||||
Core::Logger g_log;
|
Core::Logger g_log;
|
||||||
Core::Db::Database g_database;
|
Core::Db::Database g_database;
|
||||||
Core::Data::ExdData g_exdData;
|
Core::Data::ExdData g_exdData;
|
||||||
|
@ -173,6 +175,12 @@ int main(int argc, char* argv[])
|
||||||
g_log.info( "Compiled: " __DATE__ " " __TIME__ );
|
g_log.info( "Compiled: " __DATE__ " " __TIME__ );
|
||||||
g_log.info( "===========================================================" );
|
g_log.info( "===========================================================" );
|
||||||
|
|
||||||
|
if ( sodium_init() == -1 )
|
||||||
|
{
|
||||||
|
g_log.fatal("Failed to initialize libsodium");
|
||||||
|
}
|
||||||
|
g_log.info("Initialized libsodium");
|
||||||
|
|
||||||
if (!loadSettings(argc, argv))
|
if (!loadSettings(argc, argv))
|
||||||
{
|
{
|
||||||
throw std::exception();
|
throw std::exception();
|
||||||
|
@ -279,7 +287,7 @@ int main(int argc, char* argv[])
|
||||||
std::string sId = pt.get<string>( "sId" );
|
std::string sId = pt.get<string>( "sId" );
|
||||||
std::string secret = pt.get<string>( "secret" );
|
std::string secret = pt.get<string>( "secret" );
|
||||||
std::string name = pt.get<string>( "name" );
|
std::string name = pt.get<string>( "name" );
|
||||||
|
|
||||||
// reloadConfig();
|
// reloadConfig();
|
||||||
|
|
||||||
int32_t accountId = g_sapphireAPI.checkSession( sId );
|
int32_t accountId = g_sapphireAPI.checkSession( sId );
|
||||||
|
@ -352,36 +360,36 @@ int main(int argc, char* argv[])
|
||||||
};
|
};
|
||||||
|
|
||||||
server.resource["^/sapphire-api/lobby/insertSession"]["POST"] = [&]( shared_ptr<HttpServer::Response> response, shared_ptr<HttpServer::Request> request ) {
|
server.resource["^/sapphire-api/lobby/insertSession"]["POST"] = [&]( shared_ptr<HttpServer::Response> response, shared_ptr<HttpServer::Request> request ) {
|
||||||
print_request_info( request );
|
print_request_info( request );
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
using namespace boost::property_tree;
|
using namespace boost::property_tree;
|
||||||
ptree pt;
|
ptree pt;
|
||||||
read_json( request->content, pt );
|
read_json( request->content, pt );
|
||||||
|
|
||||||
std::string sId = pt.get<string>( "sId" );
|
std::string sId = pt.get<string>( "sId" );
|
||||||
uint32_t accountId = pt.get<uint32_t>( "accountId" );
|
uint32_t accountId = pt.get<uint32_t>( "accountId" );
|
||||||
std::string secret = pt.get<string>( "secret" );
|
std::string secret = pt.get<string>( "secret" );
|
||||||
|
|
||||||
// reloadConfig();
|
// reloadConfig();
|
||||||
|
|
||||||
if( m_pConfig->getValue< std::string >( "Settings.General.ServerSecret" ) != secret ) {
|
if( m_pConfig->getValue< std::string >( "Settings.General.ServerSecret" ) != secret ) {
|
||||||
std::string json_string = "{\"result\":\"invalid_secret\"}";
|
std::string json_string = "{\"result\":\"invalid_secret\"}";
|
||||||
*response << "HTTP/1.1 403\r\nContent-Length: " << json_string.length() << "\r\n\r\n" << json_string;
|
*response << "HTTP/1.1 403\r\nContent-Length: " << json_string.length() << "\r\n\r\n" << json_string;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
g_sapphireAPI.insertSession( accountId, sId );
|
g_sapphireAPI.insertSession( accountId, sId );
|
||||||
std::string json_string = "{\"result\":\"success\"}";
|
std::string json_string = "{\"result\":\"success\"}";
|
||||||
*response << "HTTP/1.1 200\r\nContent-Length: " << json_string.length() << "\r\n\r\n" << json_string;
|
*response << "HTTP/1.1 200\r\nContent-Length: " << json_string.length() << "\r\n\r\n" << json_string;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch( exception& e )
|
catch( exception& e )
|
||||||
{
|
{
|
||||||
*response << "HTTP/1.1 500\r\n\r\n";
|
*response << "HTTP/1.1 500\r\n\r\n";
|
||||||
g_log.error( e.what() );
|
g_log.error( e.what() );
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -589,88 +597,88 @@ int main(int argc, char* argv[])
|
||||||
};
|
};
|
||||||
|
|
||||||
server.resource["^(/frontier-api/ffxivsupport/view/get_init)(.*)"]["GET"] = [&]( shared_ptr<HttpServer::Response> response, shared_ptr<HttpServer::Request> request ) {
|
server.resource["^(/frontier-api/ffxivsupport/view/get_init)(.*)"]["GET"] = [&]( shared_ptr<HttpServer::Response> response, shared_ptr<HttpServer::Request> request ) {
|
||||||
print_request_info( request );
|
print_request_info( request );
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
auto web_root_path = boost::filesystem::canonical( "web" );
|
auto web_root_path = boost::filesystem::canonical( "web" );
|
||||||
auto path = boost::filesystem::canonical( web_root_path / "news.xml" );
|
auto path = boost::filesystem::canonical( web_root_path / "news.xml" );
|
||||||
//Check if path is within web_root_path
|
//Check if path is within web_root_path
|
||||||
if( distance( web_root_path.begin(), web_root_path.end() ) > distance( path.begin(), path.end() ) ||
|
if( distance( web_root_path.begin(), web_root_path.end() ) > distance( path.begin(), path.end() ) ||
|
||||||
!equal( web_root_path.begin(), web_root_path.end(), path.begin() ) )
|
!equal( web_root_path.begin(), web_root_path.end(), path.begin() ) )
|
||||||
throw invalid_argument( "path must be within root path" );
|
throw invalid_argument( "path must be within root path" );
|
||||||
if( !( boost::filesystem::exists( path ) && boost::filesystem::is_regular_file( path ) ) )
|
if( !( boost::filesystem::exists( path ) && boost::filesystem::is_regular_file( path ) ) )
|
||||||
throw invalid_argument( "file does not exist" );
|
throw invalid_argument( "file does not exist" );
|
||||||
|
|
||||||
std::string cache_control, etag;
|
std::string cache_control, etag;
|
||||||
|
|
||||||
// Uncomment the following line to enable Cache-Control
|
// Uncomment the following line to enable Cache-Control
|
||||||
// cache_control="Cache-Control: max-age=86400\r\n";
|
// cache_control="Cache-Control: max-age=86400\r\n";
|
||||||
|
|
||||||
auto ifs = make_shared<ifstream>();
|
auto ifs = make_shared<ifstream>();
|
||||||
ifs->open( path.string(), ifstream::in | ios::binary | ios::ate );
|
ifs->open( path.string(), ifstream::in | ios::binary | ios::ate );
|
||||||
|
|
||||||
if( *ifs )
|
if( *ifs )
|
||||||
{
|
{
|
||||||
auto length = ifs->tellg();
|
auto length = ifs->tellg();
|
||||||
ifs->seekg( 0, ios::beg );
|
ifs->seekg( 0, ios::beg );
|
||||||
|
|
||||||
*response << "HTTP/1.1 200 OK\r\n" << cache_control << etag << "Content-Length: " << length << "\r\n\r\n";
|
*response << "HTTP/1.1 200 OK\r\n" << cache_control << etag << "Content-Length: " << length << "\r\n\r\n";
|
||||||
default_resource_send( server, response, ifs );
|
default_resource_send( server, response, ifs );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
throw invalid_argument( "could not read file" );
|
throw invalid_argument( "could not read file" );
|
||||||
}
|
}
|
||||||
catch( exception& e )
|
catch( exception& e )
|
||||||
{
|
{
|
||||||
*response << "HTTP/1.1 500\r\n\r\n";
|
*response << "HTTP/1.1 500\r\n\r\n";
|
||||||
g_log.error( e.what() );
|
g_log.error( e.what() );
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
server.resource["^(/frontier-api/ffxivsupport/information/get_headline_all)(.*)"]["GET"] = [&]( shared_ptr<HttpServer::Response> response, shared_ptr<HttpServer::Request> request ) {
|
server.resource["^(/frontier-api/ffxivsupport/information/get_headline_all)(.*)"]["GET"] = [&]( shared_ptr<HttpServer::Response> response, shared_ptr<HttpServer::Request> request ) {
|
||||||
print_request_info( request );
|
print_request_info( request );
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
auto web_root_path = boost::filesystem::canonical( "web" );
|
auto web_root_path = boost::filesystem::canonical( "web" );
|
||||||
auto path = boost::filesystem::canonical( web_root_path / "headlines.xml" );
|
auto path = boost::filesystem::canonical( web_root_path / "headlines.xml" );
|
||||||
//Check if path is within web_root_path
|
//Check if path is within web_root_path
|
||||||
if( distance( web_root_path.begin(), web_root_path.end() ) > distance( path.begin(), path.end() ) ||
|
if( distance( web_root_path.begin(), web_root_path.end() ) > distance( path.begin(), path.end() ) ||
|
||||||
!equal( web_root_path.begin(), web_root_path.end(), path.begin() ) )
|
!equal( web_root_path.begin(), web_root_path.end(), path.begin() ) )
|
||||||
throw invalid_argument( "path must be within root path" );
|
throw invalid_argument( "path must be within root path" );
|
||||||
if( !( boost::filesystem::exists( path ) && boost::filesystem::is_regular_file( path ) ) )
|
if( !( boost::filesystem::exists( path ) && boost::filesystem::is_regular_file( path ) ) )
|
||||||
throw invalid_argument( "file does not exist" );
|
throw invalid_argument( "file does not exist" );
|
||||||
|
|
||||||
std::string cache_control, etag;
|
std::string cache_control, etag;
|
||||||
|
|
||||||
// Uncomment the following line to enable Cache-Control
|
// Uncomment the following line to enable Cache-Control
|
||||||
// cache_control="Cache-Control: max-age=86400\r\n";
|
// cache_control="Cache-Control: max-age=86400\r\n";
|
||||||
|
|
||||||
auto ifs = make_shared<ifstream>();
|
auto ifs = make_shared<ifstream>();
|
||||||
ifs->open( path.string(), ifstream::in | ios::binary | ios::ate );
|
ifs->open( path.string(), ifstream::in | ios::binary | ios::ate );
|
||||||
|
|
||||||
if( *ifs )
|
if( *ifs )
|
||||||
{
|
{
|
||||||
auto length = ifs->tellg();
|
auto length = ifs->tellg();
|
||||||
ifs->seekg( 0, ios::beg );
|
ifs->seekg( 0, ios::beg );
|
||||||
|
|
||||||
*response << "HTTP/1.1 200 OK\r\n" << cache_control << etag << "Content-Length: " << length << "\r\n\r\n";
|
*response << "HTTP/1.1 200 OK\r\n" << cache_control << etag << "Content-Length: " << length << "\r\n\r\n";
|
||||||
default_resource_send( server, response, ifs );
|
default_resource_send( server, response, ifs );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
throw invalid_argument( "could not read file" );
|
throw invalid_argument( "could not read file" );
|
||||||
}
|
}
|
||||||
catch( exception& e )
|
catch( exception& e )
|
||||||
{
|
{
|
||||||
*response << "HTTP/1.1 500\r\n\r\n";
|
*response << "HTTP/1.1 500\r\n\r\n";
|
||||||
g_log.error( e.what() );
|
g_log.error( e.what() );
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
//Default GET-example. If no other matches, this anonymous function will be called.
|
//Default GET-example. If no other matches, this anonymous function will be called.
|
||||||
//Will respond with content in the web/-directory, and its subdirectories.
|
//Will respond with content in the web/-directory, and its subdirectories.
|
||||||
//Default file: index.html
|
//Default file: index.html
|
||||||
//Can for instance be used to retrieve an HTML 5 client that uses REST-resources on this server
|
//Can for instance be used to retrieve an HTML 5 client that uses REST-resources on this server
|
||||||
|
@ -723,7 +731,7 @@ int main(int argc, char* argv[])
|
||||||
|
|
||||||
//Wait for server to start so that the client can connect
|
//Wait for server to start so that the client can connect
|
||||||
this_thread::sleep_for( chrono::seconds( 1 ) );
|
this_thread::sleep_for( chrono::seconds( 1 ) );
|
||||||
|
|
||||||
server_thread.join();
|
server_thread.join();
|
||||||
g_log.info( "Started REST server at port " + std::to_string( server.config.port ) );
|
g_log.info( "Started REST server at port " + std::to_string( server.config.port ) );
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue