Compare commits

...

15 Commits

Author SHA1 Message Date
Lion Kortlepel e25f2b0382 add test error to current build 2021-10-10 01:20:46 +02:00
Lion Kortlepel e91fee7186 more less compiler mad making yes
anon is my accomplice
2021-10-10 01:08:26 +02:00
Lion Kortlepel bfe9cfd41b dont make the compiler mad, now 2021-10-10 01:07:14 +02:00
Lion Kortlepel d4f40ca889 force crash 2021-10-10 00:58:10 +02:00
Lion Kortlepel d0431c0b9d Use v2 api 2021-09-27 15:46:37 +02:00
Lion Kortlepel 0961f86662 Add heartbeat-api-v API version header 2021-09-27 15:46:37 +02:00
Lion Kortlepel 7f2ca025f8 Start using new heartbeat response format 2021-09-27 15:46:37 +02:00
Lion Kortlepel 2355327c21 CMake: Fix typo in SANITIZE codepath 2021-09-15 17:55:34 +02:00
Lion Kortlepel 3837e101e2 CMake: Use gzipped debug info on linux 2021-09-15 17:55:34 +02:00
Lion Kortlepel fa19ba08e3 Sentry: Properly store DSN 2021-09-15 17:55:34 +02:00
Lion Kortlepel 57d0eb735e Add cryptography header for the future 2021-09-15 17:55:34 +02:00
Lion Kortlepel 15704abf6c Http, Heartbeat: Process status < 0 differently, report as "Invalid
Response Code"
2021-09-15 17:55:34 +02:00
Lion Kortlepel 6883c96d33 Http: Add Sentry error breadcrumbs on internal https POST errors 2021-09-15 17:55:34 +02:00
Lion Kortlepel f632606d76 Heartbeat: Dont report 200 + INVALID_KEY to Sentry 2021-09-15 17:55:34 +02:00
Lion Kortlepel c70ada2926 Config: private by default 2021-09-15 17:55:34 +02:00
9 changed files with 208 additions and 34 deletions
+2 -2
View File
@@ -32,10 +32,10 @@ if (WIN32)
elseif (UNIX) elseif (UNIX)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Wpedantic -static-libstdc++") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Wpedantic -static-libstdc++")
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -O0 -g") set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -O0 -g")
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O2 -s -fno-builtin") set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O2 -gz -fno-builtin")
if (SANITIZE) if (SANITIZE)
message(STATUS "sanitize is ON") message(STATUS "sanitize is ON")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLanAGS} -fsanitize=undefined,thread") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=undefined,thread")
endif (SANITIZE) endif (SANITIZE)
endif () endif ()
+4
View File
@@ -1,3 +1,7 @@
# v2.3.3
- CHANGED servers to be private by default
# v2.3.2 # v2.3.2
- ADDED Ctrl+C causes a graceful shutdown on windows (did already on linux) - ADDED Ctrl+C causes a graceful shutdown on windows (did already on linux)
+6 -1
View File
@@ -27,7 +27,7 @@ public:
, Resource("Resources") , Resource("Resources")
, MapName("/levels/gridmap_v2/info.json") , MapName("/levels/gridmap_v2/info.json")
, MaxPlayers(10) , MaxPlayers(10)
, Private(false) , Private(true)
, MaxCars(1) , MaxCars(1)
, DebugModeEnabled(false) , DebugModeEnabled(false)
, Port(30814) , Port(30814)
@@ -87,6 +87,7 @@ void RegisterThread(const std::string& str);
#define KB 1024 #define KB 1024
#define MB (KB * 1024) #define MB (KB * 1024)
#define SSU_UNRAW SECRET_SENTRY_URL
#define _file_basename std::filesystem::path(__FILE__).filename().string() #define _file_basename std::filesystem::path(__FILE__).filename().string()
#define _line std::to_string(__LINE__) #define _line std::to_string(__LINE__)
@@ -112,9 +113,11 @@ void RegisterThread(const std::string& str);
#else #else
#define _this_location (ThreadName() + _file_basename + ":" + _line + " ") #define _this_location (ThreadName() + _file_basename + ":" + _line + " ")
#endif #endif
#define SU_RAW SSU_UNRAW
#else // !defined(DEBUG) #else // !defined(DEBUG)
#define SU_RAW RAWIFY(SSU_UNRAW)
#define _this_location (ThreadName()) #define _this_location (ThreadName())
#endif // defined(DEBUG) #endif // defined(DEBUG)
@@ -150,3 +153,5 @@ void LogChatMessage(const std::string& name, int id, const std::string& msg);
#define Biggest 30000 #define Biggest 30000
std::string Comp(std::string Data); std::string Comp(std::string Data);
std::string DeComp(std::string Compressed); std::string DeComp(std::string Compressed);
#define S_DSN SU_RAW
+114
View File
@@ -0,0 +1,114 @@
// Copyright Anonymous275 8/11/2020
#pragma once
#include <array>
#include <cstdarg>
#include <string>
namespace Crypto {
constexpr auto time = __TIME__;
constexpr auto seed = static_cast<int>(time[7]) + static_cast<int>(time[6]) * 10 + static_cast<int>(time[4]) * 60 + static_cast<int>(time[3]) * 600 + static_cast<int>(time[1]) * 3600 + static_cast<int>(time[0]) * 36000;
// 1988, Stephen Park and Keith Miller
// "Random Number Generators: Good Ones Are Hard To Find", considered as "minimal standard"
// Park-Miller 31 bit pseudo-random number generator, implemented with G. Carta's optimisation:
// with 32-bit math and without division
template <int N>
struct RandomGenerator {
private:
static constexpr unsigned a = 16807; // 7^5
static constexpr unsigned m = 2147483647; // 2^31 - 1
static constexpr unsigned s = RandomGenerator<N - 1>::value;
static constexpr unsigned lo = a * (s & 0xFFFFu); // Multiply lower 16 bits by 16807
static constexpr unsigned hi = a * (s >> 16u); // Multiply higher 16 bits by 16807
static constexpr unsigned lo2 = lo + ((hi & 0x7FFFu) << 16u); // Combine lower 15 bits of hi with lo's upper bits
static constexpr unsigned hi2 = hi >> 15u; // Discard lower 15 bits of hi
static constexpr unsigned lo3 = lo2 + hi;
public:
static constexpr unsigned max = m;
static constexpr unsigned value = lo3 > m ? lo3 - m : lo3;
};
template <>
struct RandomGenerator<0> {
static constexpr unsigned value = seed;
};
template <int N, int M>
struct RandomInt {
static constexpr auto value = RandomGenerator<N + 1>::value % M;
};
template <int N>
struct RandomChar {
static const char value = static_cast<char>(1 + RandomInt<N, 0x7F - 1>::value);
};
template <size_t N, int K, typename Char>
struct MangleString {
private:
const char _key;
std::array<Char, N + 1> _encrypted;
constexpr Char enc(Char c) const {
return c ^ _key;
}
Char dec(Char c) const {
return c ^ _key;
}
public:
template <size_t... Is>
constexpr MangleString(const Char* str, std::index_sequence<Is...>)
: _key(RandomChar<K>::value)
, _encrypted { enc(str[Is])... } { }
decltype(auto) decrypt() {
for (size_t i = 0; i < N; ++i) {
_encrypted[i] = dec(_encrypted[i]);
}
_encrypted[N] = '\0';
return _encrypted.data();
}
};
static auto w_printf = [](const char* fmt, ...) {
va_list args;
va_start(args, fmt);
vprintf(fmt, args);
va_end(args);
};
static auto w_printf_s = [](const char* fmt, ...) {
va_list args;
va_start(args, fmt);
vprintf(fmt, args);
va_end(args);
};
static auto w_sprintf_s = [](char* buf, size_t buf_size, const char* fmt, ...) {
va_list args;
va_start(args, fmt);
vsprintf(buf, fmt, args);
va_end(args);
};
static auto w_sprintf_s_ret = [](char* buf, size_t buf_size, const char* fmt, ...) {
int ret;
va_list args;
va_start(args, fmt);
ret = vsprintf(buf, fmt, args);
va_end(args);
return ret;
};
#define XOR_C(s) [] { constexpr Crypto::MangleString< sizeof(s)/sizeof(char) - 1, __COUNTER__, char > expr( s, std::make_index_sequence< sizeof(s)/sizeof(char) - 1>() ); return expr; }().decrypt()
#define XOR_W(s) [] { constexpr Crypto::MangleString< sizeof(s)/sizeof(wchar_t) - 1, __COUNTER__, wchar_t > expr( s, std::make_index_sequence< sizeof(s)/sizeof(wchar_t) - 1>() ); return expr; }().decrypt()
#define RAWIFY(s) XOR_C(s)
}
+1
View File
@@ -2,6 +2,7 @@
#include "commandline/commandline.h" #include "commandline/commandline.h"
#include "TLuaFile.h" #include "TLuaFile.h"
#include "Cryptography.h"
#include <atomic> #include <atomic>
#include <fstream> #include <fstream>
+3
View File
@@ -127,6 +127,7 @@ std::string Http::POST(const std::string& host, const std::string& target, const
bool ok = try_connect_with_protocol(tcp::v4()); bool ok = try_connect_with_protocol(tcp::v4());
if (!ok) { if (!ok) {
Application::Console().Write("[ERROR] failed to resolve or connect in POST " + host + target); Application::Console().Write("[ERROR] failed to resolve or connect in POST " + host + target);
Sentry.AddErrorBreadcrumb("failed to resolve or connect to " + host + target, __FILE__, std::to_string(__LINE__)); // FIXME: this is ugly.
return "-1"; return "-1";
} }
//} //}
@@ -202,12 +203,14 @@ std::string Http::POST(const std::string& host, const std::string& target, const
} catch (const std::exception& e) { } catch (const std::exception& e) {
Application::Console().Write(e.what()); Application::Console().Write(e.what());
Sentry.AddErrorBreadcrumb(e.what(), __FILE__, std::to_string(__LINE__)); // FIXME: this is ugly.
return "-1"; return "-1";
} }
} }
// RFC 2616, RFC 7231 // RFC 2616, RFC 7231
static std::map<size_t, const char*> Map = { static std::map<size_t, const char*> Map = {
{ -1, "Invalid Response Code"},
{ 100, "Continue" }, { 100, "Continue" },
{ 101, "Switching Protocols" }, { 101, "Switching Protocols" },
{ 102, "Processing" }, { 102, "Processing" },
+65 -23
View File
@@ -3,8 +3,12 @@
#include "Client.h" #include "Client.h"
#include "Http.h" #include "Http.h"
//#include "SocketIO.h" //#include "SocketIO.h"
#include <rapidjson/document.h>
#include <rapidjson/rapidjson.h>
#include <sstream> #include <sstream>
namespace json = rapidjson;
void THeartbeatThread::operator()() { void THeartbeatThread::operator()() {
RegisterThread("Heartbeat"); RegisterThread("Heartbeat");
std::string Body; std::string Body;
@@ -36,50 +40,88 @@ void THeartbeatThread::operator()() {
Body += "&pps=" + Application::PPS(); Body += "&pps=" + Application::PPS();
auto SentryReportError = [&](const std::string& transaction, int status) { auto SentryReportError = [&](const std::string& transaction, int status) {
if (status < 0) {
status = 0;
}
auto Lock = Sentry.CreateExclusiveContext(); auto Lock = Sentry.CreateExclusiveContext();
Sentry.SetContext("heartbeat", Sentry.SetContext("heartbeat",
{ { "response-body", T }, { { "response-body", T },
{ "request-body", Body } }); { "request-body", Body } });
Sentry.SetTransaction(transaction); Sentry.SetTransaction(transaction);
trace("sending log to sentry: " + std::to_string(status) + " for " + transaction);
Sentry.Log(SentryLevel::Error, "default", Http::Status::ToString(status) + " (" + std::to_string(status) + ")"); Sentry.Log(SentryLevel::Error, "default", Http::Status::ToString(status) + " (" + std::to_string(status) + ")");
}; };
auto Target = "/heartbeat"; auto Target = "/heartbeat";
int ResponseCode = -1; int ResponseCode = -1;
T = Http::POST(Application::GetBackendHostname(), Target, {}, Body, false, &ResponseCode); const std::vector<std::string> Urls = {
Application::GetBackendHostname(),
Application::GetBackup1Hostname(),
Application::GetBackup2Hostname(),
};
if (T.substr(0, 2) != "20" || ResponseCode != 200) { json::Document Doc;
trace("got " + T + " from backend"); bool Ok = false;
SentryReportError(Application::GetBackendHostname() + Target, ResponseCode); for (const auto& Url : Urls) {
T = Http::POST(Url, Target, { { "api-v", "2" } }, Body, false, &ResponseCode);
trace(T);
Doc.Parse(T.data(), T.size());
if (Doc.HasParseError() || !Doc.IsObject()) {
error("Backend response failed to parse as valid json");
debug("Response was: `" + T + "`");
Sentry.SetContext("JSON Response", { { "reponse", T } });
SentryReportError(Url + Target, ResponseCode);
} else if (ResponseCode != 200) {
SentryReportError(Url + Target, ResponseCode);
} else {
// all ok
Ok = true;
break;
}
std::this_thread::sleep_for(std::chrono::milliseconds(500)); std::this_thread::sleep_for(std::chrono::milliseconds(500));
T = Http::POST(Application::GetBackup1Hostname(), Target, {}, Body, false, &ResponseCode); }
if (T.substr(0, 2) != "20" || ResponseCode != 200) { std::string Status {};
SentryReportError(Application::GetBackup1Hostname() + Target, ResponseCode); std::string Code {};
std::this_thread::sleep_for(std::chrono::milliseconds(500)); std::string Message {};
T = Http::POST(Application::GetBackup2Hostname(), Target, {}, Body, false, &ResponseCode); const auto StatusKey = "status";
if (T.substr(0, 2) != "20" || ResponseCode != 200) { const auto CodeKey = "code";
warn("Backend system refused server! Server will not show in the public server list."); const auto MessageKey = "msg";
isAuth = false;
SentryReportError(Application::GetBackup2Hostname() + Target, ResponseCode); if (Ok) {
} if (Doc.HasMember(StatusKey) && Doc[StatusKey].IsString()) {
Status = Doc[StatusKey].GetString();
} else {
Sentry.SetContext("JSON Response", { { StatusKey, "invalid string / missing" } });
Ok = false;
}
if (Doc.HasMember(CodeKey) && Doc[CodeKey].IsString()) {
Code = Doc[CodeKey].GetString();
} else {
Sentry.SetContext("JSON Response", { { CodeKey, "invalid string / missing" } });
Ok = false;
}
if (Doc.HasMember(MessageKey) && Doc[MessageKey].IsString()) {
Message = Doc[MessageKey].GetString();
} else {
Sentry.SetContext("JSON Response", { { MessageKey, "invalid string / missing" } });
Ok = false;
}
if (!Ok) {
error("Missing/invalid json members in backend response");
Sentry.LogError("Missing/invalid json members in backend response", __FILE__, std::to_string(__LINE__));
} }
} }
if (!isAuth) { if (Ok && !isAuth) {
if (T == "2000") { if (Status == "2000") {
info(("Authenticated!")); info(("Authenticated!"));
isAuth = true; isAuth = true;
} else if (T == "200") { } else if (Status == "200") {
info(("Resumed authenticated session!")); info(("Resumed authenticated session!"));
isAuth = true; isAuth = true;
} else {
if (Message.empty()) {
Message = "Backend didn't provide a reason";
}
error("Backend REFUSED the auth key. " + Message);
} }
} }
//SocketIO::Get().SetAuthenticated(isAuth);
} }
} }
+3 -8
View File
@@ -1,22 +1,17 @@
#include "TSentry.h" #include "TSentry.h"
#include "Common.h" #include "Common.h"
#include <cstring>
#include <sentry.h> #include <sentry.h>
#include <sstream> #include <sstream>
// compile-time length of a string/array
template <size_t N>
constexpr size_t ConstexprLength(char const (&)[N]) {
return N - 1;
}
TSentry::TSentry() { TSentry::TSentry() {
if constexpr (ConstexprLength(SECRET_SENTRY_URL) == 0) { if (std::strlen(S_DSN) == 0) {
mValid = false; mValid = false;
} else { } else {
mValid = true; mValid = true;
sentry_options_t* options = sentry_options_new(); sentry_options_t* options = sentry_options_new();
sentry_options_set_dsn(options, SECRET_SENTRY_URL); sentry_options_set_dsn(options, S_DSN);
sentry_options_set_debug(options, false); // needs to always be false sentry_options_set_debug(options, false); // needs to always be false
sentry_options_set_symbolize_stacktraces(options, true); sentry_options_set_symbolize_stacktraces(options, true);
auto ReleaseString = "BeamMP-Server@" + Application::ServerVersion(); auto ReleaseString = "BeamMP-Server@" + Application::ServerVersion();
+10
View File
@@ -54,6 +54,16 @@ int main(int argc, char** argv) try {
Application::Console().InitializeLuaConsole(LuaEngine); Application::Console().InitializeLuaConsole(LuaEngine);
Application::CheckForUpdates(); Application::CheckForUpdates();
Sentry.LogError("test error", __FILE__, std::to_string(__LINE__));
error("goodbye, crashing now");
volatile int* a = nullptr;
// oh boy
*a = -0;
a[318008]++;
// bye now
abort();
// TODO: replace // TODO: replace
while (!Shutdown) { while (!Shutdown) {
std::this_thread::sleep_for(std::chrono::milliseconds(50)); std::this_thread::sleep_for(std::chrono::milliseconds(50));