*rt6S(Vck1y>XC^dIQ$nFf6bvJcy`TcCcxYq
znpVMSIymP99NxgLBv|MRPALNH-=wP~oRTDX2MA0
zB+zBjr$(q=0pQ~nt3fo2D2c{DHt`OtL83<>#oWQSNyX5&)~w$GH3cuE*3&1@U;%0i
z-jgfBAOUI(-jlOF^&Mate8^{M`<||!tUI7~5dSw;lVraILTGm}gxs2Kql#^BVM&_@02fGbnx^wf-R*RCfgW#K{FFud&)?ugW{1
zfC%?lc6mD6=c^`2tK$&!CH7~_08MZjk;XFX5vW0g+3$e4MX2HuoKu8q-U1pCa)=3s
z?gJ^S5kN?ZfG@W_R!8HUJ1b=o)yERswVW(T*{Ui7JUM}ehy~xK$_!{DLF5V&6QFIc
zdI55Y1uwJ(sPYJmrSErsJ9uG{8KB*LVQ~Ts30_##5$Fp(#$qxc6?|y-g+&OE8@#af
zM<5kEhWA+wveg-o3SQ{jeIY9Y;P;|9_u#$zokNoVmv_Z4n^9813t1TubFOhX7ER!S
zb}goNfGkcxM#TONoefQ!1}~UqK!_oW=`zHRfXDaoJO2WkDvG}aB#17^kY^~abNmL{
zPc{P`HU^Z4&_jb4Cfl8ojLEX>iJm!y7!$Z>v;ohQLRbXuF*D>TDTHO<9`j337U_W&
zZ`qv%<{!}126k^hxb^ShZ&$Jfnb_nBLR`Ym3_cA049*PR4Dk%141NqQ4E~c1xt%9}5K
+
+
+
+ Debug
+ Win32
+
+
+ Release
+ Win32
+
+
+ Debug
+ x64
+
+
+ Release
+ x64
+
+
+
+ 17.0
+ Win32Proj
+ {8e047aa8-af94-4a73-a399-80ff5caeea86}
+ dropship
+ 10.0
+
+
+
+ Application
+ true
+ v143
+ Unicode
+
+
+ Application
+ false
+ v143
+ true
+ Unicode
+
+
+ Application
+ true
+ v143
+ Unicode
+
+
+ Application
+ false
+ v143
+ true
+ Unicode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Level3
+ true
+ WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+ Use
+ pch.h
+ $(ProjectDir)src;$(ProjectDir)vendor
+ stdcpplatest
+ true
+
+
+ Console
+ true
+
+
+ taskkill /f /fi "imagename eq $(TargetFileName)"
+
+
+
+
+ Level3
+ true
+ true
+ true
+ WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+ Use
+ pch.h
+ $(ProjectDir)src;$(ProjectDir)vendor
+ stdcpplatest
+ true
+
+
+ Windows
+ true
+ true
+ true
+
+
+ taskkill /f /fi "imagename eq $(TargetFileName)"
+
+
+
+
+ Level3
+ true
+ _DEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+ Use
+ pch.h
+ $(ProjectDir)src;$(ProjectDir)vendor
+ stdcpplatest
+ true
+
+
+ Console
+ true
+ RequireAdministrator
+
+
+ taskkill /f /fi "imagename eq $(TargetFileName)"
+
+
+
+
+ Level3
+ true
+ true
+ true
+ NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+ Use
+ pch.h
+ $(ProjectDir)src;$(ProjectDir)vendor
+ stdcpplatest
+ MinSpace
+ Neither
+ Default
+ true
+
+
+ Windows
+ true
+ true
+ true
+ RequireAdministrator
+
+
+ taskkill /f /fi "imagename eq $(TargetFileName)"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Create
+ Create
+ Create
+ Create
+
+
+
+
+
+
+
+
+
+
+
+
+ NotUsing
+ NotUsing
+ NotUsing
+ NotUsing
+
+
+ NotUsing
+ NotUsing
+ NotUsing
+ NotUsing
+
+
+ NotUsing
+ NotUsing
+ NotUsing
+ NotUsing
+
+
+ NotUsing
+ NotUsing
+ NotUsing
+ NotUsing
+
+
+ NotUsing
+ NotUsing
+ NotUsing
+ NotUsing
+
+
+ NotUsing
+ NotUsing
+ NotUsing
+ NotUsing
+
+
+ NotUsing
+ NotUsing
+ NotUsing
+ NotUsing
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/dropship/dropship/dropship.vcxproj.filters b/dropship/dropship/dropship.vcxproj.filters
new file mode 100644
index 0000000..ca982a7
--- /dev/null
+++ b/dropship/dropship/dropship.vcxproj.filters
@@ -0,0 +1,218 @@
+
+
+
+
+ {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
+ cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx
+
+
+ {93995380-89BD-4b04-88EB-625FBE52EBFB}
+ h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd
+
+
+ {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
+ rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
+
+
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+
+
+ Resource Files
+
+
+
\ No newline at end of file
diff --git a/dropship/resource.h b/dropship/dropship/resource.h
similarity index 100%
rename from dropship/resource.h
rename to dropship/dropship/resource.h
diff --git a/dropship/dropship/src/App.cpp b/dropship/dropship/src/App.cpp
new file mode 100644
index 0000000..f28e91a
--- /dev/null
+++ b/dropship/dropship/src/App.cpp
@@ -0,0 +1,126 @@
+#include "pch.h"
+
+#include "App.h"
+
+extern std::unique_ptr g_updater;
+extern std::unique_ptr g_dashboard;
+extern std::unique_ptr g_firewall;
+extern std::unique_ptr g_settings;
+
+#ifdef _DEBUG
+ extern std::unique_ptr g_debug;
+#endif
+
+void App::render(bool* p_open) {
+
+#ifdef _DEBUG
+ if (g_settings) {
+ ImGui::Begin("debug");
+
+ ImGui::Text(((json) (*g_settings).getAppSettings()).dump(4).c_str());
+ ImGui::End();
+ }
+ if (g_debug) {
+ (*g_debug).render();
+ }
+#endif
+
+ static const ImGuiWindowFlags window_flags = ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoBackground | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_AlwaysAutoResize;
+ ImGui::SetNextWindowSize(ImVec2(418, 0), ImGuiCond_Once);
+ ImGui::SetNextWindowPos(ImVec2(99, 99), ImGuiCond_Once);
+ ImGui::Begin("dashboard", p_open, window_flags);
+
+ {
+ /* draw */
+
+ if (g_updater) (*g_updater).render();
+ if (g_dashboard) (*g_dashboard).render();
+ if (g_firewall) (*g_firewall).render();
+ if (g_settings) (*g_settings).render();
+ }
+
+ ImGui::End();
+}
+
+
+extern ImFont* font_subtitle;
+
+void App::renderError(std::string error) {
+
+ ImGui::PushStyleColor(ImGuiCol_WindowBg, ImVec4(0.2f, 0.2f, 0.2f, 1.0f));
+ ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1, 1, 1, 1));
+ //ImGui::SetNextWindowSize(ImVec2(418, 0), ImGuiCond_Once);
+ ImGui::Begin("failed", NULL, ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoDocking | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoResize);
+
+
+ ImGui::TextColored(ImVec4{ 1, 0.6f, 0.6f, 1 }, "app crashed");
+ ImGui::SameLine();
+ ImGui::Text("::[");
+
+ ImGui::Spacing();
+ ImGui::Spacing();
+
+ ImGui::PushFont(font_subtitle);
+ ImGui::SeparatorText("error");
+ ImGui::TextColored(ImVec4{ 1, 0.6f, 0.6f, 1 }, error.c_str());
+
+ ImGui::Spacing();
+ ImGui::Spacing();
+
+ ImGui::SeparatorText("get help");
+ //ImGui::Text("https://discord.stormy.gg/");
+ //ImGui::Text("@stormyy_ow");
+
+
+ /* discord */
+ {
+ static const ImVec4 color_button = { 0.345f, 0.396f, 0.949f, 1.0f };
+ static const ImVec4 color_button_hover = { 0.345f, 0.396f, 0.949f, 0.9f };
+ static const ImVec4 color_button_active = { 0.345f, 0.396f, 0.949f, 0.8f };
+
+ ImGui::PushStyleColor(ImGuiCol_Button, color_button);
+ ImGui::PushStyleColor(ImGuiCol_ButtonActive, color_button_active);
+ ImGui::PushStyleColor(ImGuiCol_ButtonHovered, color_button_hover);
+ {
+ if (ImGui::Button("discord")) {
+ system("start https://discord.stormy.gg");
+ }
+ ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(0, 0, 0, 1));
+ ImGui::SetItemTooltip("https://discord.stormy.gg/");
+ ImGui::PopStyleColor(1);
+
+ }
+ ImGui::PopStyleColor(3);
+ }
+
+ ImGui::SameLine();
+
+ /* twitter */
+ {
+ static const ImVec4 color_button = { 0.114f, 0.631f, 0.949f, 1.0f };
+ static const ImVec4 color_button_hover = { 0.114f, 0.631f, 0.949f, 0.9f };
+ static const ImVec4 color_button_active = { 0.114f, 0.631f, 0.949f, 0.8f };
+
+ ImGui::PushStyleColor(ImGuiCol_Button, color_button);
+ ImGui::PushStyleColor(ImGuiCol_ButtonActive, color_button_active);
+ ImGui::PushStyleColor(ImGuiCol_ButtonHovered, color_button_hover);
+ {
+ if (ImGui::Button("@stormyy_ow")) {
+ system("start https://twitter.com/stormyy_ow");
+ }
+ ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(0, 0, 0, 1));
+ ImGui::SetItemTooltip("https://twitter.com/stormyy_ow");
+ ImGui::PopStyleColor(1);
+
+ }
+ ImGui::PopStyleColor(3);
+ }
+
+ ImGui::PopFont();
+
+ ImGui::PopStyleColor(2);
+
+ ImGui::Spacing();
+
+ ImGui::End();
+}
diff --git a/dropship/dropship/src/App.h b/dropship/dropship/src/App.h
new file mode 100644
index 0000000..8eef719
--- /dev/null
+++ b/dropship/dropship/src/App.h
@@ -0,0 +1,21 @@
+#pragma once
+
+// data
+#include "components/Endpoint.h"
+// managers
+#ifdef _DEBUG
+ #include "managers/Debug.h"
+#endif
+#include "managers/Settings.h"
+#include "managers/Dashboard.h"
+
+#include "managers/Firewall.h"
+#include "managers/Update.h"
+
+
+namespace App
+{
+ void render(bool* p_open);
+
+ void renderError(std::string error);
+};
diff --git a/dropship/dropship/src/components/Endpoint.cpp b/dropship/dropship/src/components/Endpoint.cpp
new file mode 100644
index 0000000..f959ae0
--- /dev/null
+++ b/dropship/dropship/src/components/Endpoint.cpp
@@ -0,0 +1,99 @@
+#include "pch.h"
+
+#include "Endpoint.h"
+
+Endpoint2::Endpoint2(
+ std::string title,
+ std::string description,
+ std::string ip_ping,
+ bool blocked
+):
+
+ title(title),
+ description(description),
+ ip_ping(ip_ping.empty() ? std::nullopt : std::optional{ ip_ping }),
+ ping(std::make_unique>(std::nullopt)),
+ ping_ms_display(-1),
+
+ blocked(blocked),
+ blocked_desired(blocked)
+{
+ // ...
+
+ // TODO if config
+ // TODO no ping, ping once, keep pinging
+ if (this->ip_ping) {
+ this->start_pinging();
+ }
+}
+
+Endpoint2::~Endpoint2() {
+ /* */
+ this->stop_pinging();
+}
+
+
+void Endpoint2::start_pinging() {
+ try {
+ /* endpoint has no ip */
+ if (!this->ip_ping) return;
+ if (this->pinger.get() != nullptr) return;
+
+ /* ping */
+ this->pinger = std::make_unique(this->ip_ping.value(), ping);
+ this->_ping_future = std::async(std::launch::async, [&]
+ {
+ try {
+ (*(this->pinger)).start();
+ }
+ catch (const std::exception& ex) {
+ // ...
+ std::println("{}", ex.what());
+ }
+ catch (...)
+ {
+ printf("error caught!");
+ }
+ });
+ }
+ catch (const std::exception& ex) {
+ // ...
+ std::println("{}", ex.what());
+ }
+ catch (...)
+ {
+ printf("error caught!");
+ }
+}
+
+void Endpoint2::stop_pinging() {
+ if (this->pinger.get() != nullptr) {
+ (*(this->pinger.get())).stop();
+ this->_ping_future.get();
+ (this->pinger).reset();
+ }
+}
+
+std::string Endpoint2::getTitle() {
+ return this->title;
+}
+
+bool Endpoint2::getBlockDesired() {
+ return this->blocked_desired;
+}
+
+void Endpoint2::setBlockDesired(bool b) {
+ this->blocked_desired = b;;
+}
+
+/*void Endpoint2::confirm() {
+ this->blocked = this->blocked_desired;
+}*/
+
+bool Endpoint2::_getBlockedState() {
+ return this->blocked;
+}
+
+void Endpoint2::_setBlockedState(bool b) {
+ this->blocked = b;
+}
diff --git a/dropship/dropship/src/components/Endpoint.h b/dropship/dropship/src/components/Endpoint.h
new file mode 100644
index 0000000..878dec9
--- /dev/null
+++ b/dropship/dropship/src/components/Endpoint.h
@@ -0,0 +1,94 @@
+#pragma once
+
+// target windows 7+
+//#define _WIN32_WINNT_WIN7 0x0601 // Windows 7
+//#define _WIN32_WINNT = 0x0601
+
+//#define _WIN32_WINNT_WINTHRESHOLD 0x0A00 // Windows 10
+//#define _WIN32_WINNT_WIN10 0x0A00 // Windows 10
+
+//#include
+// fix me ^
+
+#include "util/ping/Pinger.h"
+
+// TODO
+// 1. firewall->blockEndpoint()
+// 2. firewall->unblockEndpoint()
+// 3. firewall->delete()
+
+// TODO
+// 1. schedule task to periodically sync firewall state
+
+struct _FirewallMeta {
+ std::string _firewall_rule_address;
+};
+
+class Endpoint2
+{
+
+ public:
+
+ Endpoint2(
+ std::string title,
+ std::string description,
+ std::string ip_ping = std::string(), // this will be converted to an std::optional<>, defaults to empty which will be converted to std::nullopt in endpoint.cpp
+ bool blocked = { false }
+ );
+ ~Endpoint2();
+
+ /* display a visual for the endpoint */
+ void render(int hue_index = 0);
+
+ /* is this endpoint blocked */
+ //bool isBlocked();
+
+ /* start pinging */
+ void start_pinging();
+
+ /* stop pinging */
+ void stop_pinging();
+
+ /* ping */
+ // void ping();
+
+ std::string getTitle();
+
+ bool getBlockDesired();
+ void setBlockDesired(bool b);
+
+ //void confirm();
+
+ bool _getBlockedState();
+ void _setBlockedState(bool b);
+
+ private:
+ /* this is the title displayed */
+ std::string title;
+
+ /* this is the description displayed */
+ std::string description;
+
+ /* optionally, specify an ip for the ping display feature */
+ std::optional ip_ping;
+
+ /* is the endpoint blocked? and what's it's desired state? */
+ bool blocked;
+ bool blocked_desired;
+
+ //union {
+ std::unique_ptr pinger;
+ std::future _ping_future;
+ //};
+
+ //int ping;
+ std::unique_ptr> ping;
+ int ping_ms_display;
+
+ /* mirror the firewall state. this could change the "isBlocked()" value */
+ //void syncFromFirewallState();
+
+ /* is this endpoint waiting for a ping? */
+ //bool isDuringPing();
+};
+
diff --git a/dropship/dropship/src/components/EndpointRender.cpp b/dropship/dropship/src/components/EndpointRender.cpp
new file mode 100644
index 0000000..aa92659
--- /dev/null
+++ b/dropship/dropship/src/components/EndpointRender.cpp
@@ -0,0 +1,149 @@
+#include "pch.h"
+
+#include "Endpoint.h"
+
+#include "images.h"
+
+extern ImFont* font_title;
+extern ImFont* font_subtitle;
+extern ImFont* font_text;
+
+void Endpoint2::render(int i) {
+
+ //throw std::runtime_error("invalid runtime variable in array");
+
+ if (*(this->ping.get())) {
+ const auto ping_ms = (*(this->ping.get())).value();
+ if (this->ping_ms_display != ping_ms)
+ {
+ static const float min_delay = 9.0f;
+ static const float max_delay = 90.0f;
+
+ if (ping_ms > 0 && this->ping_ms_display <= 0)
+ {
+ this->ping_ms_display = ping_ms;
+ }
+ else {
+ float param = fmin((float)std::abs(ping_ms - this->ping_ms_display) / 24.0f, 1.0f);
+
+ if (!(ImGui::GetFrameCount() % (int)fmax(min_delay, max_delay - (max_delay * param * half_pi)) != 0)) {
+
+
+ if (this->ping_ms_display < ping_ms)
+ this->ping_ms_display++;
+ else
+ this->ping_ms_display--;
+
+ this->ping_ms_display = std::max(0, this->ping_ms_display);
+ }
+ }
+ }
+ }
+
+ //
+ //
+
+ static const ImU32 color_text_secondary = ImGui::ColorConvertFloat4ToU32({ 1, 1, 1, .8f });
+ static const ImU32 white = ImGui::ColorConvertFloat4ToU32({ 1, 1, 1, 1.0f });
+ static const ImU32 transparent = ImGui::ColorConvertFloat4ToU32({ 1, 1, 1, 0.0f });
+
+ auto const w_list = ImGui::GetWindowDrawList();
+ static auto& style = ImGui::GetStyle();
+
+ //const auto grayed_out = this->ip_ping.value_or("").empty(); // || (endpoint._has_pinged && !(endpoint.ping > 0) && !endpoint._has_pinged_successfully);
+ static const auto grayed_out = false;
+ const auto unsynced = (this->blocked != this->blocked_desired);
+
+ // 0.4f looks quite good
+ static const ImU32 color_disabled = ImGui::ColorConvertFloat4ToU32({ .8f, .8f, .8f, 1.0f });
+ static const ImU32 color_disabled_secondary = ImGui::ColorConvertFloat4ToU32({ .88f, .88f, .88f, 1.0f });
+ static const ImU32 color_disabled_secondary_faded = ImGui::ColorConvertFloat4ToU32({ .95f, .95f, .95f, 1.0f });
+
+ const ImU32 color = grayed_out ? color_disabled : (ImU32) ImColor::HSV(1.0f - ((i + 1) / 32.0f), 0.4f, 1.0f, 1.0f);
+ const ImU32 color_secondary = grayed_out ? color_disabled_secondary : (ImU32) ImColor::HSV(1.0f - ((i + 1) / 32.0f), 0.3f, 1.0f, 1.0f);
+ const ImU32 color_secondary_faded = grayed_out ? color_disabled_secondary_faded : (ImU32) ImColor::HSV(1.0f - ((i + 1) / 32.0f), 0.2f, 1.0f, 0.4f * 1.0f);
+
+ ImGui::Dummy({ 0 ,0 });
+ ImGui::SameLine(NULL, 16);
+
+ ImGui::PushID(i);
+ ImGui::PushStyleColor(ImGuiCol_HeaderHovered, this->blocked ? color_secondary_faded : color_secondary);
+ ImGui::PushStyleColor(ImGuiCol_Header, this->blocked ? transparent : color);
+ ImGui::PushStyleColor(ImGuiCol_HeaderActive, this->blocked ? color_secondary_faded : color_secondary);
+ ImGui::PushStyleColor(ImGuiCol_NavHighlight, NULL);
+ bool action = (ImGui::Selectable("##end", &(this->blocked_desired), ImGuiSelectableFlags_SelectOnClick, { ImGui::GetContentRegionAvail().x - 16, 74 - 9 }));
+ //bool action = (ImGui::Selectable(("##" + this->title).c_str(), &(this->blocked_desired), ImGuiSelectableFlags_SelectOnClick, {ImGui::GetContentRegionAvail().x - 16, 74 - 9}));
+ ImGui::PopStyleColor(4);
+ ImGui::PopID();
+
+ auto hovered = ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup);
+
+ // background
+ if (!this->blocked) {
+ if (hovered) {
+ w_list->AddRect(ImGui::GetItemRectMin(), ImGui::GetItemRectMax(), color_secondary, 5, 0, 8);
+ }
+ else {
+ w_list->AddRectFilled(ImGui::GetItemRectMin(), ImGui::GetItemRectMax(), color, 5, NULL);
+ }
+ }
+
+ // unsynced background
+ if (unsynced)
+ {
+ const auto& color = color_secondary_faded;
+ const auto offset = (ImGui::GetFrameCount() / 4) % 40;
+ const auto offset_vec = ImVec2((float)offset, (float)offset);
+ const auto pos = ImGui::GetItemRectMin() - ImVec2(40, 40) + offset_vec;
+
+ static const auto image = _get_image("background_diagonal");
+
+ w_list->PushClipRect(ImGui::GetItemRectMin(), ImGui::GetItemRectMax(), true);
+ w_list->AddImage(image.texture, pos, pos + ImVec2((float) image.width, (float) image.height), ImVec2(0, 0), ImVec2(1, 1), this->blocked ? color_secondary_faded : color);
+ w_list->PopClipRect();
+ }
+
+ // icon
+ const auto icon_frame = ImVec2({ ImGui::GetItemRectSize().y, ImGui::GetItemRectSize().y });
+ static auto padding = ImVec2(21, 21);
+ const auto icon = unsynced ? _get_texture("icon_wall_fire") : (this->blocked ? _get_texture("icon_block") : _get_texture("icon_allow"));
+ w_list->AddImage(icon, ImGui::GetItemRectMin() + padding, ImGui::GetItemRectMin() + icon_frame - padding, ImVec2(0, 0), ImVec2(1, 1), this->blocked ? color /*color_secondary_faded*/ : color_text_secondary);
+
+ // display 1
+ auto pos = ImGui::GetItemRectMin() + ImVec2(icon_frame.x, 4) + ImVec2(-2, 0);
+ w_list->AddText(font_title, 35, pos, this->blocked ? color : white, this->title.c_str());
+
+ // display 2
+ pos += ImVec2(1, ImGui::GetItemRectSize().y - 24 - 16);
+ w_list->AddText(font_subtitle, 24, pos, this->blocked ? color_secondary : color_text_secondary, this->description.c_str());
+
+ if ((*(this->ping))) {
+
+ // display 3 / (icon wifi)
+ auto icon = _get_texture("icon_wifi");
+ static ImVec2 frame = ImVec2(26, 26);
+
+ const auto ping = (*(this->ping.get())).value();
+
+ if (ping > 120)
+ icon = _get_texture("icon_wifi_poor");
+ else if (ping > 60)
+ icon = _get_texture("icon_wifi_fair");
+ else if (ping < 0)
+ icon = _get_texture("icon_wifi_slash");
+
+ auto pos = ImGui::GetItemRectMax() - ImVec2(frame.x, ImGui::GetItemRectSize().y) + (style.FramePadding * ImVec2(-1, 1)) + ImVec2(-8, 1);
+ w_list->AddImage(icon, pos, pos + frame, ImVec2(0, 0), ImVec2(1, 1), this->blocked ? color : white);
+
+ // display 4
+ if (!(ping < 0)) {
+ auto const text = std::to_string(this->ping_ms_display);
+ auto text_size = font_subtitle->CalcTextSizeA(24, FLT_MAX, 0.0f, text.c_str());
+ auto pos = ImGui::GetItemRectMax() - style.FramePadding - text_size + ImVec2(-8, -4);
+
+ w_list->AddText(font_subtitle, 24, pos, this->blocked ? color_secondary : color_text_secondary, text.c_str());
+ }
+ }
+
+ ImGui::Spacing();
+}
diff --git a/dropship/dropship/src/components/PopupButton.cpp b/dropship/dropship/src/components/PopupButton.cpp
new file mode 100644
index 0000000..c1c5c05
--- /dev/null
+++ b/dropship/dropship/src/components/PopupButton.cpp
@@ -0,0 +1,152 @@
+#include "pch.h"
+
+#include "PopupButton.h"
+
+PopupButton::PopupButton(std::string title, std::string icon, std::vector const actions, int i, std::string tooltip):
+ _title(title),
+ _icon(icon),
+ _actions(actions),
+ _i(i),
+
+ //popup_name(title + "_popup")
+ _popup_name(title),
+ _tooltip(tooltip)
+{
+
+}
+
+void PopupButton::render2(const ImVec2& size) {
+
+ static auto& style = ImGui::GetStyle();
+ ImDrawList* list = ImGui::GetWindowDrawList();
+
+ /*const auto color_button = ImColor::HSV(0, 0.4f, 1, 1.f);
+ const auto color_button_hover = ImColor::HSV(0, 0.25f, 1, 1.f);*/
+
+ //static const ImU32 white = ImGui::ColorConvertFloat4ToU32({ 1, 1, 1, 1 });
+ //static const ImU32 color_text = ImGui::ColorConvertFloat4ToU32(style.Colors[ImGuiCol_Text]);
+
+ const ImU32 color_button = (ImU32) ImColor::HSV(1.0f - ((this->_i + 1) / 32.0f), 0.4f, 1.0f, 1.0f);
+ const ImU32 color_button_hover = (ImU32) ImColor::HSV(1.0f - ((this->_i + 1) / 32.0f), 0.3f, 1.0f, 1.0f);
+ const ImU32 color_secondary_faded = (ImU32) ImColor::HSV(1.0f - ((this->_i + 1) / 32.0f), 0.2f, 1.0f, 0.4f * 1.0f);
+
+ {
+ static const auto font = font_text;
+ static const auto font_size = font->CalcTextSizeA(24, FLT_MAX, 0.0f, this->_title.c_str());
+
+ ImGui::Dummy(size);
+ auto hovered = ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup);
+
+ /* background */
+ if (hovered)
+ list->AddRectFilled(ImGui::GetItemRectMin(), ImGui::GetItemRectMax(), color_secondary_faded, 5.0f);
+
+ const auto pos = ImGui::GetItemRectMin() + ImVec2(((ImGui::GetItemRectSize().x - font_size.x) / 2) + 10 + 4, 7);
+ list->AddText(font, 24, pos, color_button, this->_title.c_str());
+
+
+ const ImVec2 frame2 = { 20.0f, 20.0f };
+ const ImVec2 pos2 = { pos.x - frame2.x - 8.0f, pos.y + 4.0f };
+
+
+ list->AddImage((void*)_get_texture(this->_icon), pos2, pos2 + frame2, ImVec2(0, 0), ImVec2(1, 1), color_button);
+
+ }
+
+
+ if (ImGui::IsItemClicked()) {
+ if (this->_actions.size() != 1) {
+ ImGui::OpenPopup(this->_popup_name.c_str());
+ }
+ else {
+ this->_actions[0].action();
+ }
+ }
+
+ this->renderPopup();
+}
+
+const std::string& PopupButton::getTooltip() const { return this->_tooltip; }
+
+void PopupButton::render() {
+
+ ImDrawList* list = ImGui::GetWindowDrawList();
+
+ /*const auto color_button = ImColor::HSV(0, 0.4f, 1, 1.f);
+ const auto color_button_hover = ImColor::HSV(0, 0.25f, 1, 1.f);*/
+
+ const ImU32 color_button = (ImU32) ImColor::HSV(1.0f - ((this->_i + 1) / 32.0f), 0.4f, 1.0f, 1.0f);
+ const ImU32 color_button_hover = (ImU32) ImColor::HSV(1.0f - ((this->_i + 1) / 32.0f), 0.3f, 1.0f, 1.0f);
+ const ImU32 color_secondary_faded = (ImU32) ImColor::HSV(1.0f - ((this->_i + 1) / 32.0f), 0.2f, 1.0f, 0.4f * 1.0f);
+
+ //ImGui::SameLine();
+ ImGui::Dummy({ 24.0f, 24.0f });
+
+ list->AddImage((void*)_get_texture(this->_icon), ImGui::GetItemRectMin(), ImGui::GetItemRectMax(), ImVec2(0, 0), ImVec2(1, 1), ImGui::IsItemHovered() ? color_button_hover : color_button);
+
+ if (ImGui::IsItemClicked()) {
+ printf("opening %s", this->_popup_name.c_str());
+ ImGui::OpenPopup(this->_popup_name.c_str());
+ }
+
+ this->renderPopup();
+}
+
+
+void PopupButton::renderPopup() {
+
+ if (ImGui::BeginPopupModal(this->_popup_name.c_str(), NULL, ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize))
+ {
+ ImDrawList* list = ImGui::GetWindowDrawList();
+
+ // handle close
+ if (ImGui::IsMouseClicked(ImGuiMouseButton_Left) && !ImGui::IsWindowHovered() && !ImGui::IsWindowAppearing())
+ ImGui::CloseCurrentPopup();
+
+ ImGui::PushItemFlag(ImGuiItemFlags_SelectableDontClosePopup, true);
+ ImGui::PushFont(font_subtitle);
+ {
+ int i = 1;
+
+ for (auto& item : this->_actions) {
+ const ImU32 color = (ImU32) ImColor::HSV(1.0f - ((i + 1) / 32.0f), 0.4f, 1.0f, 1.0f);
+ // const ImU32 color_secondary = (ImU32) ImColor::HSV(1.0f - ((i + 1) / 32.0f), 0.3f, 1.0f, 1.0f);
+ const ImU32 color_secondary_faded = (ImU32) ImColor::HSV(1.0f - ((i + 1) / 32.0f), 0.2f, 1.0f, 0.4f * 1.0f);
+
+
+
+ ImGui::PushStyleColor(ImGuiCol_HeaderHovered, color_secondary_faded);
+ {
+ if (item.state == nullptr) {
+ if (ImGui::MenuItem(item.title.c_str(), item.description.c_str(), nullptr, !item.disabled)) item.action();
+ }
+ else {
+ bool checked = item.state();
+ // .. &checked, ..
+ if (ImGui::MenuItem(item.title.c_str(), item.description.empty() ? (checked ? "on" : "off") : (checked ? item.description.c_str() : nullptr), nullptr, !item.disabled)) item.action();
+ }
+ if (!item.tooltip.empty()) ImGui::SetItemTooltip(item.tooltip.c_str());
+ if (item.external) {
+ static auto offset = ImVec2(-8, 8);
+ static auto frame = ImVec2(18, 18);
+
+ const ImVec2 pos = ImVec2(ImGui::GetItemRectMax().x - frame.x, ImGui::GetItemRectMin().y) + offset;
+ list->AddImage(_get_texture("icon_outside_window"), pos, pos + frame, ImVec2(0, 0), ImVec2(1, 1), color);
+ }
+ }
+ ImGui::PopStyleColor();
+ i ++;
+
+ if (item.divide_next) {
+ ImGui::Spacing();
+ }
+ }
+
+ }
+ ImGui::PopFont();
+ ImGui::PopItemFlag();
+
+
+ ImGui::EndPopup();
+ }
+}
diff --git a/dropship/dropship/src/components/PopupButton.h b/dropship/dropship/src/components/PopupButton.h
new file mode 100644
index 0000000..63d9b23
--- /dev/null
+++ b/dropship/dropship/src/components/PopupButton.h
@@ -0,0 +1,47 @@
+#pragma once
+
+
+#include "images.h"
+
+extern ImFont* font_title;
+extern ImFont* font_subtitle;
+extern ImFont* font_text;
+
+struct Action {
+ std::string title;
+ std::string description;
+ std::string tooltip;
+ std::function action;
+ std::function state = { nullptr };
+
+ bool external = { false };
+ bool disabled = { false };
+
+ bool divide_next = { false };
+};
+
+class PopupButton
+{
+public:
+ PopupButton(std::string title, std::string icon, std::vector const actions, int i = 0, std::string tooltip = "");
+ void render();
+ void render2(const ImVec2& size = ImVec2(90, 28));
+
+ const std::string& getTooltip() const;
+
+ //static void renderPopups();
+
+private:
+ std::string _title;
+ std::string _icon;
+ std::string _tooltip;
+ //const ImVec2 &size;
+ int _i;
+
+ std::vector const _actions;
+
+ std::string _popup_name;
+
+ void renderPopup();
+};
+
diff --git a/dropship/src/images.cpp b/dropship/dropship/src/images.cpp
similarity index 96%
rename from dropship/src/images.cpp
rename to dropship/dropship/src/images.cpp
index 29c2add..1a86348 100644
--- a/dropship/src/images.cpp
+++ b/dropship/dropship/src/images.cpp
@@ -1,9 +1,10 @@
+#include "pch.h"
#include
#include "images.h"
#define STB_IMAGE_IMPLEMENTATION
-#include "stb_image.h"
+#include "stb_image/stb_image.h"
// #include "resource.h"
@@ -105,7 +106,7 @@ bool loadPicture(std::string title, std::string type, ID3D11ShaderResourceView**
// https://stackoverflow.com/a/28753627
// ugh.
- HRSRC resource = FindResource(NULL, title.c_str(), type.c_str());
+ HRSRC resource = FindResourceA(NULL, title.c_str(), type.c_str());
if (!resource) {
//::global_message = std::format("failed {}.{}", name, type);
@@ -119,6 +120,8 @@ bool loadPicture(std::string title, std::string type, ID3D11ShaderResourceView**
_loadPicture((unsigned char*) ::LockResource(data_handle), size, out_srv, out_width, out_height);
::FreeResource(resource);
+
+ return TRUE;
}
bool _add_texture(std::string title, std::string type)
diff --git a/dropship/src/images.h b/dropship/dropship/src/images.h
similarity index 100%
rename from dropship/src/images.h
rename to dropship/dropship/src/images.h
diff --git a/dropship/main.cpp b/dropship/dropship/src/main.cpp
similarity index 74%
rename from dropship/main.cpp
rename to dropship/dropship/src/main.cpp
index dbcd093..f85c94d 100644
--- a/dropship/main.cpp
+++ b/dropship/dropship/src/main.cpp
@@ -1,34 +1,58 @@

-// Dear ImGui: standalone example application for DirectX 11
-// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
-// Read online: https://github.com/ocornut/imgui/tree/master/docs
+/*
-#pragma comment(lib, "d3d11.lib")
+ todo
+
+ - firewall queue for async. description and blocked writes can be up to a 900ms
+ - chec file size with debug #ifed out
+ - top 500 icon
+ - patch notes instead of update button
+ - profile
+ - delete some files
-#include "imgui.h"
-#include "imgui_impl_win32.h"
-#include "imgui_impl_dx11.h"
-#include
+ stretch
+
+ -- json exceptions https://json.nlohmann.me/features/macros/#json_skip_unsupported_compiler_check
-#include
-#include
-// common
-#include "util.hpp"
+*/
+
+#include "pch.h"
+
+// data
+#include "components/Endpoint.h"
// managers
#ifdef _DEBUG
- #include "src/DebugManager.h"
+#include "managers/Debug.h"
#endif
-#include "src/FirewallManager.h"
-#include "src/DashboardManager.h"
-#include "src/AppManager.h"
+#include "managers/Settings.h"
+#include "managers/Dashboard.h"
+
+#include "managers/Firewall.h"
+#include "managers/Update.h"
+
+#include "util/watcher/window.h"
+
+// Dear ImGui: standalone example application for DirectX 11
+// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
+// Read online: https://github.com/ocornut/imgui/tree/master/docs
+
+
+#pragma comment(lib, "d3d11.lib")
+
+#include // https://stackoverflow.com/a/43832497
+
+#include "imgui-docking/imgui_impl_win32.h"
+#include "imgui-docking/imgui_impl_dx11.h"
+#include
+
+#include "App.h"
// other
-#include "src/theme.h"
+#include "theme.h"
+#include "images.h"
-// image map
-#include
// global managers structure
@@ -38,48 +62,35 @@
// Data
+class unknown_exception : public std::exception {
+ const char* what() const {
+ return "unkown exception";
+ }
+};
// globals
// TODO is this needed?
ID3D11Device* g_pd3dDevice = nullptr; // for media in browser
-OPTIONS options
-{
- #ifdef _DEBUG
- .auto_update = false,
- #else
- .auto_update = true,
- #endif
-
- // TODO implement
- ._save_settings = true,
-};
-
-AppStore __default__appStore
-{
- //._window_overlaying = "";
- .dashboard =
- {
- .title = "OW2 // DROPSHIP",
- //.heading = "Changes will be applied immediately. You do not need to keep this app open.",
- .heading = "Deselecting regions will block them permanently until you select them again.",
- //.community = "STORMY.GG/DROPSHIP",
- //.community = "DISCORD.STORMY.GG",
- .community = "@stormyy_ow",
- //.heading = "ã«ã»ã‚“ã”"
- },
- .application_open = false
-};
-AppStore appStore = __default__appStore;
+//namespace global {
#ifdef _DEBUG
- DebugManager debugManager;
+ std::unique_ptr g_debug;
#endif
-FirewallManager firewallManager;
-DashboardManager dashboardManager;
-AppManager appManager;
+
+ // testing
+ std::unique_ptr>> g_endpoints;
+ std::unique_ptr g_firewall;
+ std::unique_ptr g_dashboard;
+ std::unique_ptr g_updater;
+ std::unique_ptr g_settings;
+ std::unique_ptr g_window_watcher;
+//}
+
+
+
std::unordered_map APP_TEXTURES = { };
@@ -104,9 +115,59 @@ void CleanupRenderTarget();
LRESULT WINAPI WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
+
+void loadAssets() {
+
+#ifdef _DEBUG
+ util::timer::Timer timer("loadAssets");
+#endif
+
+ static const std::vector textures = {
+ "icon_options.png",
+ "icon_maple_leaf.png",
+ "icon_chain_slash.png",
+ "icon_bolt.png",
+ "icon_skull.png",
+ "icon_clock_undo.png",
+ "icon_heart.png",
+ "icon_outside_window.png",
+
+ "icon_wifi_slash.png",
+ "icon_wifi_poor.png",
+ "icon_wifi_fair.png",
+ "icon_wifi.png",
+
+ "icon_allow.png",
+ "icon_block.png",
+ "icon_wall_fire.png",
+
+ "icon_angle.png",
+
+ "background_app.png",
+ "background_diagonal.png",
+ };
+
+ for (std::string texture : textures)
+ _add_texture(texture.substr(0, texture.find(".")), texture.substr(texture.find(".") + 1));
+
+ std::cout << "<" << std::hex << std::this_thread::get_id() << "> loaded " << std::dec << textures.size() << " textures." << std::endl;
+}
+
+
+#ifndef _DEBUG
+
+#pragma comment(linker, "/SUBSYSTEM:windows /ENTRY:mainCRTStartup")
+
+#endif
+
// Main code
int main(int, char**)
{
+
+#ifdef _DEBUG
+ util::timer::Timer timer("start");
+#endif
+
setlocale(LC_ALL, "en_US.UTF-8");
// Create application window
@@ -202,7 +263,7 @@ int main(int, char**)
config.GlyphExtraSpacing.x = 1.0f;*/
//HRSRC resource = FindResource(NULL, L"CONFIG_REGULAR_2", L"OTF");
- HRSRC resource = FindResource(NULL, "ROBOTO_REGULAR", "OTF");
+ HRSRC resource = FindResourceA(NULL, "ROBOTO_REGULAR", "OTF");
//auto const size_pixels = 18;
auto const size_pixels = 24;
@@ -223,7 +284,7 @@ int main(int, char**)
// industry bold
{
- HRSRC resource = FindResource(NULL, "INDUSTRY_BOLD", "OTF");
+ HRSRC resource = FindResourceA(NULL, "INDUSTRY_BOLD", "OTF");
//auto const size_pixels = 28;
auto const size_pixels = 38;
@@ -243,7 +304,7 @@ int main(int, char**)
// industry medium
{
- HRSRC resource = FindResource(NULL, "INDUSTRY_MEDIUM", "OTF");
+ HRSRC resource = FindResourceA(NULL, "INDUSTRY_MEDIUM", "OTF");
//HRSRC resource = FindResource(NULL, L"CONFIG_MEDIUM_2", L"OTF");
auto const size_pixels = 20;
@@ -302,6 +363,46 @@ int main(int, char**)
*/
+ std::optional error = std::nullopt;
+
+ std::optional> assets_future = std::nullopt;
+
+ try {
+
+ // NOTE make sure these are .reset() after done. otherwise process will exist after close.
+#ifdef _DEBUG
+ g_debug = std::make_unique();
+#endif
+ g_endpoints = std::make_unique>>();
+ g_firewall = std::make_unique();
+ //g_process_watcher = std::make_unique("Overwatch.exe");
+ g_window_watcher = std::make_unique("Overwatch");
+ g_settings = std::make_unique();
+ g_dashboard = std::make_unique();
+ g_updater = std::make_unique();
+
+
+ //loadAssets();
+ assets_future = std::async(std::launch::async, loadAssets);
+ }
+ catch (const json::exception e)
+ {
+ //error = std::make_optional(e);
+ error = std::make_optional(e.what());
+ }
+ catch (const std::exception& e)
+ {
+ error = std::make_optional(e);
+ }
+ catch (...)
+ {
+ error = std::make_optional();
+ }
+
+
+#ifdef _DEBUG
+ timer.stop();
+#endif
// Main loop
bool done = false;
@@ -334,57 +435,36 @@ int main(int, char**)
ImGui_ImplWin32_NewFrame();
ImGui::NewFrame();
- // 2. Show a simple window that we create ourselves. We use a Begin/End pair to create a named window.
- {
- /*
- static float f = 0.0f;
- static int counter = 0;
-
- ImGui::Begin("Hello, world!"); // Create a window called "Hello, world!" and append into it.
-
- ImGui::Text("This is some useful text."); // Display some text (you can use a format strings too)
- ImGui::Checkbox("Demo Window", &show_demo_window); // Edit bools storing our window open/close state
- ImGui::Checkbox("Another Window", &show_another_window);
+ if (error) {
- ImGui::SliderFloat("float", &f, 0.0f, 1.0f); // Edit 1 float using a slider from 0.0f to 1.0f
- ImGui::ColorEdit3("clear color", (float*)&clear_color); // Edit 3 floats representing a color
-
- if (ImGui::Button("Button")) // Buttons return true when clicked (most widgets return true when edited/activated)
- counter++;
- ImGui::SameLine();
- ImGui::Text("counter = %d", counter);
-
- ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / io.Framerate, io.Framerate);
- ImGui::End();
- */
+ App::renderError(error.value().what());
}
+ else {
+ try {
-#ifdef _DEBUG
- debugManager.RenderUI(/* &debug_window_open */);
-#endif
-
- if (dashboard_open)
- {
- static const ImGuiWindowFlags window_flags = ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoBackground | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_AlwaysAutoResize;
- //ImGui::SetNextWindowSize(ImVec2(418, 450), ImGuiCond_Once);
- ImGui::SetNextWindowSize(ImVec2(418, 0), ImGuiCond_Once);
- //ImGui::SetNextWindowPos(ImVec2(1920 - 400 - 90, 150), ImGuiCond_Once);
- ImGui::SetNextWindowPos(ImVec2(40, 40), ImGuiCond_Once);
- ImGui::Begin("dashboard", &(dashboard_open), window_flags);
-
+ if (dashboard_open)
+ {
+ App::render(&dashboard_open);
+ }
+ }
+ catch (const json::exception& e)
{
- appManager.RenderInline();
- dashboardManager.RenderInline();
- firewallManager.RenderInline();
+ //error = std::make_optional(e);
+ error = std::make_optional(e.what());
}
-
- ImGui::End();
+ //catch (const std::exception& e)
+ //{
+ // error = e;
+ //}
+ //catch (...)
+ //{
+ // error = std::make_optional();
+ //}
}
- else
- {
- done = true;
- }
+ /* testing */
+ ImGui::ErrorCheckEndFrameRecover(nullptr);
+ ImGui::ErrorCheckEndWindowRecover(nullptr);
// Rendering
ImGui::Render();
@@ -409,17 +489,34 @@ int main(int, char**)
if (ImGui::IsPopupOpen("", ImGuiPopupFlags_AnyPopup))
// TODO fix this?
//ImGui::CloseCurrentPopup();
- ImGui::ClosePopupsOverWindow(ImGui::FindWindowByName("dashboard"), false);
+ //if (!ImGui::IsPopupOpen("updating")) {
+ ImGui::ClosePopupsOverWindow(ImGui::FindWindowByName("dashboard"), false);
+ //}
else
done = true;
}
}
}
+ if (assets_future) {
+ assets_future.value().get();
+ }
+
+#ifdef _DEBUG
+ g_debug.reset();
+#endif
+ g_endpoints.reset();
+ g_firewall.reset();
+ g_window_watcher.reset();
+ g_settings.reset();
+ g_dashboard.reset();
+ g_updater.reset();
+
/*delete font_title;
delete font_subtitle;
delete font_text;*/
+
// Cleanup
ImGui_ImplDX11_Shutdown();
ImGui_ImplWin32_Shutdown();
diff --git a/dropship/dropship/src/managers/Dashboard.cpp b/dropship/dropship/src/managers/Dashboard.cpp
new file mode 100644
index 0000000..5287f82
--- /dev/null
+++ b/dropship/dropship/src/managers/Dashboard.cpp
@@ -0,0 +1,97 @@
+#include "pch.h"
+
+#include "managers/Dashboard.h"
+
+extern std::unique_ptr g_settings;
+
+Dashboard::Dashboard()
+{
+
+ if (!g_settings) throw std::runtime_error("dashboard depends on g_settings.");
+
+ auto i = 1;
+
+ this->header_actions.push_back(std::make_unique("socials", "icon_heart", std::move(std::vector({
+ {
+ .title = "discord\n ",
+ .description = "suggestions\nhelp",
+ .action = []() { system("start https://discord.stormy.gg"); },
+ .external = true,
+ },
+ {
+ .title = "twitch",
+ .description = "stormyy_ow",
+ .action = []() { system("start https://twitch.tv/stormyy_ow"); },
+ .external = true,
+ },
+ {
+ .title = "twitter",
+ .description = "stormyy_ow",
+ .action = []() { system("start https://twitter.com/stormyy_ow"); },
+ .external = true,
+ },
+ {
+ .title = "github\n ",
+ .description = "guide\ncode",
+ .action = []() { system("start https://github.com/stowmyy/dropship"); },
+ .external = true,
+ },
+ })), i++));
+
+ this->header_actions.push_back(std::make_unique("options", "icon_options", std::move(std::vector({
+ {
+ .title = "auto update",
+ .description = "",
+ .action = [this]() { (*g_settings).toggleOptionAutoUpdate(); },
+ .state = [this]() { return (*g_settings).getAppSettings().options.auto_update; },
+ .external = false,
+ },
+ {
+ .title = "ping servers",
+ //.description = "constantly",
+ .description = "",
+ .action = [this]() { (*g_settings).toggleOptionPingServers(); },
+ .state = [this]() { return (*g_settings).getAppSettings().options.ping_servers; },
+ .external = false,
+
+ //.disabled = true,
+ .divide_next = true,
+ },
+ {
+ .title = "network settings",
+ .tooltip = "windowsdefender://network",
+ .action = []() { system("start windowsdefender://network"); },
+ .external = true,
+ },
+ {
+ .title = "firewall rules",
+ .tooltip = "wf.msc",
+ .action = []() { system("start wf.msc"); },
+ .external = true,
+ },
+ })), i++));
+
+ this->header_actions.push_back(std::make_unique("unblock", "icon_clock_undo", std::move(std::vector({
+ {
+ .action = [this]() { (*g_settings).unblockAll(); },
+ }
+ })), i++, "Unblocks all servers\n\nIf you are ever failing to connect\nto a server, quickly clicking this\nwill prevent a competitive ban"));
+
+ //(*(this->header_actions)).insert((*(this->header_actions)).end(), {
+ // std::make_shared("socials", "icon_heart"),
+ // std::make_shared("options", "icon_options")
+ //});
+
+ //for (int i = 0; i < (*header_actions).size(); i++) {
+ // printf("xx %d\n", i);
+ //}
+
+}
+
+Dashboard::~Dashboard()
+{
+ /*for (auto& b : (this->header_actions)) {
+ delete b;
+ }*/
+}
+
diff --git a/dropship/dropship/src/managers/Dashboard.h b/dropship/dropship/src/managers/Dashboard.h
new file mode 100644
index 0000000..4f89795
--- /dev/null
+++ b/dropship/dropship/src/managers/Dashboard.h
@@ -0,0 +1,27 @@
+#pragma once
+
+
+#include "components/Endpoint.h"
+#include "components/PopupButton.h"
+
+#include "managers/Settings.h"
+#include "util/watcher/window.h"
+
+//const PopupButton header_actions[2] = { "Volvo", "BMW", "Ford", "Mazda" };aaaaaa
+
+class Dashboard
+{
+public:
+ Dashboard();
+ ~Dashboard();
+ void render(/* bool* p_open */);
+
+private:
+
+ bool footer = { false };
+
+ //std::vector const header_actions;
+ //std::vector header_actions;
+ std::vector> header_actions;
+ //std::unique_ptr>> const& header_actions;
+};
\ No newline at end of file
diff --git a/dropship/dropship/src/managers/DashboardRender.cpp b/dropship/dropship/src/managers/DashboardRender.cpp
new file mode 100644
index 0000000..dac17e3
--- /dev/null
+++ b/dropship/dropship/src/managers/DashboardRender.cpp
@@ -0,0 +1,162 @@
+#include "pch.h"
+
+#include "Dashboard.h"
+
+
+extern std::unique_ptr>> g_endpoints;
+extern std::unique_ptr g_settings;
+extern std::unique_ptr g_window_watcher;
+
+#include "images.h"
+
+extern ImFont* font_title;
+extern ImFont* font_subtitle;
+extern ImFont* font_text;
+
+
+void renderBackground() {
+ static const ImU32 white = ImGui::ColorConvertFloat4ToU32({ 1, 1, 1, 1 });
+ ImVec2 const windowPos = ImGui::GetWindowPos();
+ ImVec2 const windowSize = ImGui::GetWindowSize();
+ ImDrawList* bg_list = ImGui::GetBackgroundDrawList();
+
+ // background texture
+ {
+ // TODO dark mode if deactivated?
+ bg_list->AddRectFilled(windowPos, windowPos + ImGui::GetWindowSize(), white, 9);
+ bg_list->AddImageRounded(_get_texture("background_app"), windowPos, windowPos + ImVec2(windowSize.x, std::min(windowSize.y, 699.0f)), ImVec2(0, 0), ImVec2(1, 1), white, 9);
+ }
+}
+
+void renderButtons(std::vector>& buttons) {
+ /*for (auto& button : buttons) {
+ (*button).render();
+ ImGui::SameLine();
+ }
+ ImGui::NewLine();*/
+
+ static auto &style = ImGui::GetStyle();
+
+ static const auto width = (ImGui::GetContentRegionAvail().x / buttons.size()) - ((style.ItemSpacing.x / 2.0f) * (buttons.size() - 1));
+
+ for (auto& button : buttons) {
+ (*button).render2({ width, 40 });
+ if (!(*button).getTooltip().empty()) ImGui::SetItemTooltip((*button).getTooltip().c_str());
+ ImGui::SameLine();
+ }
+ ImGui::NewLine();
+}
+
+void renderHeader(std::string title, std::string description) {
+
+ static auto& style = ImGui::GetStyle();
+ ImDrawList* list = ImGui::GetWindowDrawList();
+ const auto widgetPos = ImGui::GetCursorScreenPos();
+
+ auto const size = 24;
+ static const ImU32 color_text = ImGui::ColorConvertFloat4ToU32(style.Colors[ImGuiCol_Text]);
+
+ // dashboard copy
+ ImGui::BeginGroup();
+ {
+ list->AddText(font_title, font_title->FontSize, widgetPos - ImVec2(1, 0), color_text, title.c_str());
+ ImGui::Dummy({ 0, font_title->FontSize - 6 });
+
+ //ImGui::Bullet();
+ ImGui::TextWrapped(description.c_str());
+ }
+ ImGui::EndGroup();
+
+ //ImGui::Spacing();
+}
+
+void renderEndpoints() {
+ ImGui::BeginChild("endpoints_scrollable", ImVec2(ImGui::GetContentRegionAvail().x, 500), false);
+ {
+ ImGui::Spacing();
+ for (int i = 0; i < (*g_endpoints).size(); i++) {
+ (*(*g_endpoints)[i]).render(i);
+
+ if (ImGui::IsItemActivated()) {
+ //printf("%s\n", (*(*endpoints)[i]).getTitle().c_str());
+
+ //(*settings_m).syncEndpoint((*endpoints)[i]);
+
+ if ((*(*g_endpoints)[i]).getBlockDesired()) {
+ (*g_settings).addBlockedEndpoint((*(*g_endpoints)[i]).getTitle());
+ }
+ else {
+ (*g_settings).removeBlockedEndpoint((*(*g_endpoints)[i]).getTitle());
+ }
+
+ }
+ }
+ }
+ ImGui::EndChild();
+}
+
+void renderFooter(bool* open) {
+
+ static auto& style = ImGui::GetStyle();
+ ImDrawList* list = ImGui::GetWindowDrawList();
+
+ static const ImU32 white = ImGui::ColorConvertFloat4ToU32({ 1, 1, 1, 1 });
+ static const ImU32 color_text = ImGui::ColorConvertFloat4ToU32(style.Colors[ImGuiCol_Text]);
+
+ ImGui::Dummy({ ImGui::GetContentRegionAvail().x, ImGui::GetFont()->FontSize + (style.FramePadding.y * 2) });
+ list->AddRectFilled(ImGui::GetItemRectMin(), ImGui::GetItemRectMax(), white, 5);
+ list->AddText(ImGui::GetItemRectMin() + style.FramePadding + ImVec2(2, 0), color_text, "Advanced");
+
+ static ImVec2 frame = ImVec2(24, 24);
+ auto const pos = ImVec2(ImGui::GetItemRectMax() - frame - style.FramePadding);
+ auto const uv_min = !*open ? ImVec2(0, 0) : ImVec2(0, 1);
+ auto const uv_max = !*open ? ImVec2(1, 1) : ImVec2(1, 0);
+ list->AddImage(_get_texture("icon_angle"), pos, pos + frame, uv_min, uv_max, color_text);
+
+ if (ImGui::IsItemClicked())
+ *open = !*open;
+
+ if (*open)
+ {
+ ImGui::BeginGroup();
+ {
+ ImGui::Indent(style.FramePadding.x);
+ {
+ ImGui::Text("Available in a future update.");
+ // static bool test;
+ // ToggleButton("test", &test);
+ }
+ ImGui::Unindent();
+ }
+ ImGui::EndGroup();
+
+ }
+}
+
+void Dashboard::render() {
+
+ /* background */
+ renderBackground();
+
+ /* header */
+ renderHeader(
+ "OW2 // DROPSHIP",
+ "Deselecting regions will block them permanently until you select them again."
+ );
+
+ if (g_settings)
+ {
+ (*g_settings).renderWaitingStatus();
+ }
+
+ renderButtons(this->header_actions);
+
+ /* endpoints */
+ renderEndpoints();
+
+ /* footer */
+ renderFooter(&(this->footer));
+}
+
+
+
diff --git a/dropship/src/DebugManager.cpp b/dropship/dropship/src/managers/Debug.cpp
similarity index 77%
rename from dropship/src/DebugManager.cpp
rename to dropship/dropship/src/managers/Debug.cpp
index 5a2e58d..3ece55a 100644
--- a/dropship/src/DebugManager.cpp
+++ b/dropship/dropship/src/managers/Debug.cpp
@@ -1,12 +1,12 @@
+#include "pch.h"
-#include "imgui.h"
+#include "Debug.h"
-#include "DebugManager.h"
-#include
-#include
+extern ImFont* font_subtitle;
-void DebugManager::_imgui_debug_status_text(bool happy, std::string text)
+
+void Debug::_imgui_debug_status_text(bool happy, std::string text)
{
if (happy)
{
@@ -22,7 +22,7 @@ void DebugManager::_imgui_debug_status_text(bool happy, std::string text)
ImGui::Text(text.c_str());
}
-DebugManager::DebugManager() : items({}), demo_window_open(false)
+Debug::Debug() : items({}), demo_window_open(false)
{
//::global_message = done ? "done cover_browser.jpg" : "D: failed.";
@@ -33,24 +33,23 @@ DebugManager::DebugManager() : items({}), demo_window_open(false)
// items.push_back(fmt);
//}
-void DebugManager::print(std::string text)
+void Debug::print(std::string text)
{
items.push_back(text);
printf(std::format("{0}\n", text).c_str());
}
-void DebugManager::RenderUI(/* bool* p_open */)
+void Debug::render(/* bool* p_open */)
{
#ifdef _DEBUG
-
{
ImGuiWindowFlags window_flags = ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoResize;
ImGui::Begin("debug", NULL, window_flags);
ImGui::SetWindowSize(ImVec2(432, 400), ImGuiCond_Once);
ImGui::SetWindowPos(ImVec2(800, 600), ImGuiCond_Once);
-
+ ImGui::SeparatorText("demo");
// ImGui::ShowDemoWindow adds ~0.5mb to exe
if (ImGui::Button("demo")) demo_window_open = true;
if (demo_window_open)
@@ -64,6 +63,5 @@ void DebugManager::RenderUI(/* bool* p_open */)
ImGui::End();
}
-
- #endif
+#endif
}
diff --git a/dropship/src/DebugManager.h b/dropship/dropship/src/managers/Debug.h
similarity index 62%
rename from dropship/src/DebugManager.h
rename to dropship/dropship/src/managers/Debug.h
index fbb9166..338b718 100644
--- a/dropship/src/DebugManager.h
+++ b/dropship/dropship/src/managers/Debug.h
@@ -2,14 +2,13 @@
#include "images.h"
-#include
-#include
-class DebugManager
+class Debug
{
+
public:
- DebugManager();
- void RenderUI(/* bool* p_open */);
+ Debug();
+ void render(/* bool* p_open */);
void print(std::string text);
static void _imgui_debug_status_text(bool happy, std::string text);
@@ -20,5 +19,5 @@ class DebugManager
};
-extern DebugManager debugManager;
+//extern DebugManager debugManager;
diff --git a/dropship/dropship/src/managers/Firewall.cpp b/dropship/dropship/src/managers/Firewall.cpp
new file mode 100644
index 0000000..8c5c5de
--- /dev/null
+++ b/dropship/dropship/src/managers/Firewall.cpp
@@ -0,0 +1,213 @@
+#include "pch.h"
+
+#include "Firewall.h"
+
+Firewall::Firewall()
+{
+ // Initialize COM.
+ this->_coInitilizeSuccess = SUCCEEDED(CoInitialize(0));
+
+ if (!(this->_coInitilizeSuccess)) {
+ throw std::runtime_error("windows firewall: CoInitialize failed");
+ }
+
+ // TODO ensure rule exists
+ this->_validateRules();
+
+ this->_queryNetworkStatus();
+
+ // TODO legacy
+
+
+ /*
+
+ legacy: always remove stormy.gg/dropship
+ new group name: stormy/dropship
+
+ legacy: always remove stormy.gg/dropship
+ new group name: stormy/dropship
+
+ legacy: always remove stormy.gg/dropship
+ new group name: stormy/dropship
+
+ legacy: always remove stormy.gg/dropship
+ new group name: stormy/dropship
+
+ */
+
+}
+
+Firewall::~Firewall() {
+ // Uninitialize COM.
+ if (this->_coInitilizeSuccess) {
+ CoUninitialize();
+ }
+}
+
+void Firewall::_queryNetworkStatus() {
+
+#ifdef _DEBUG
+ //util::timer::Timer timer ("_queryNetworkStatus");
+#endif
+
+ //this->_network_information = std::make_optional(util::win_network::queryNetwork());
+ this->_network_information = util::win_network::queryNetwork();
+
+}
+
+void Firewall::tryWriteSettingsToFirewall(std::string data, std::string block) {
+
+ println("storage: {} / 1024", data.length());
+
+ util::win_firewall::forFirewallRulesInGroup(this->__group_name, [&data, &block](const CComPtr& FwRule, const CComPtr& rules) {
+
+ CComBSTR description (data.c_str());
+ if (SUCCEEDED(FwRule->put_Description(description)))
+ {
+ printf("description write successful\n");
+ }
+
+
+ /*
+ . if no blocks, unblock and set scope to ""
+ . if blocks, concat and block
+
+ */
+
+ if (block.empty()) {
+ println("nothing blocked, unblocking..");
+
+ if (FAILED(FwRule->put_Enabled(VARIANT_FALSE)))
+ {
+ printf("unblock failed\n");
+ }
+ }
+ else {
+
+ CComBSTR blocked_addresses (block.c_str());
+
+ if (FAILED(FwRule->put_RemoteAddresses(blocked_addresses)))
+ {
+ printf("block addresses failed\n");
+ }
+ else {
+ /* !important make sure remote addresses are not blank. */
+ /* !important otherwise this blocks all internet traffic permanently */
+ if (FAILED(FwRule->put_Enabled(VARIANT_TRUE)))
+ {
+ printf("block failed\n");
+ }
+ }
+ }
+
+
+ });
+}
+
+std::optional Firewall::tryFetchSettingsFromFirewall() {
+
+ std::optional loaded_settings = std::nullopt;
+
+ util::win_firewall::forFirewallRulesInGroup(this->__group_name, [&loaded_settings](const CComPtr& FwRule, const CComPtr& rules) {
+
+ //USES_CONVERSION;
+ CComBSTR description;
+ if (SUCCEEDED(FwRule->get_Description(&description)) && description)
+ {
+
+ /*const auto ws = std::wstring(description, SysStringLen(description));
+ std::string s(ws.begin(), ws.end());*/
+
+ // web std::string sTarget = OLE2A(bstrSource);
+
+ CW2A s (description);
+
+ loaded_settings = std::make_optional(s);
+
+ println("patch chars: {}/1024", description.ByteLength());
+ }
+ });
+
+
+ return loaded_settings;
+}
+
+
+/*
+ .. currently, ensure a single rule exists
+ .. in future, may want to ensure a single out and single in rule exist
+*/
+void Firewall::_validateRules() {
+
+#ifdef _DEBUG
+ util::timer::Timer timer("_validateRules");
+#endif
+
+ int c = 0;
+
+ /* legacy */
+ {
+ /* delete all stormy.gg/dropship blocks */
+ util::win_firewall::forFirewallRulesInGroup(this->__group_name_legacy, [&c](const CComPtr& FwRule, const CComPtr& FwRules) {
+ CComBSTR ruleName;
+ FwRule->get_Name(&ruleName);
+ FwRules->Remove(ruleName);
+ });
+ }
+
+ util::win_firewall::forFirewallRulesInGroup(this->__group_name, [&c](const CComPtr& FwRule, const CComPtr& rules) {
+ c ++;
+ });
+
+ if (c != 1) {
+ // delete all rules
+ util::win_firewall::forFirewallRulesInGroup(this->__group_name, [&c](const CComPtr& FwRule, const CComPtr& FwRules) {
+ CComBSTR ruleName;
+ if (FAILED(FwRule->get_Name(&ruleName)) && ruleName)
+ {
+ printf("failed to get rule name\n");
+ }
+ if (FAILED(FwRules->Remove(ruleName)))
+ {
+ printf("failed to delete rule\n");
+ };
+ });
+
+
+ // add single rule
+ util::win_firewall::firewallRulesPredicate([this](const CComPtr& FwRules)
+ {
+ CComBSTR rule_name ("stormy/dropship");
+ CComBSTR group_name (this->__group_name);
+ //CComBSTR remote_addresses ("");
+ NET_FW_RULE_DIRECTION_ dir = NET_FW_RULE_DIR_OUT;
+ NET_FW_PROFILE_TYPE2_ profile = NET_FW_PROFILE2_ALL;
+
+ CComPtr pFwRule;
+ if (FAILED(CoCreateInstance(__uuidof(NetFwRule), nullptr, CLSCTX_INPROC_SERVER, __uuidof(INetFwRule), (void**)&pFwRule)))
+ {
+ printf("CoCreateInstance for Firewall Rule failed \n");
+ }
+
+ // Populate the Firewall Rule object
+ pFwRule->put_Name(rule_name);
+ //pFwRule->put_Description(bstrRuleDescription);
+ //pFwRule->put_ApplicationName(bstrRuleApplication);
+ pFwRule->put_Protocol(NET_FW_IP_PROTOCOL_ANY);
+ //pFwRule->put_RemoteAddresses(remote_addresses);
+ pFwRule->put_Direction(dir);
+ pFwRule->put_Grouping(group_name);
+ pFwRule->put_Profiles(profile);
+ pFwRule->put_Action(NET_FW_ACTION_BLOCK);
+ pFwRule->put_Enabled(VARIANT_FALSE);
+
+ // Add the Firewall Rule
+ if (FAILED(FwRules->Add(pFwRule)))
+ {
+ printf("Firewall Rule Add failed: \n");
+ }
+
+ else printf("Firewall Rule Added\n");
+ });
+ }
+}
diff --git a/dropship/dropship/src/managers/Firewall.h b/dropship/dropship/src/managers/Firewall.h
new file mode 100644
index 0000000..10ac3ce
--- /dev/null
+++ b/dropship/dropship/src/managers/Firewall.h
@@ -0,0 +1,51 @@
+#pragma once
+
+#include "util/win/win_firewall/windows_firewall.h"
+#include "util/win/win_network/windows_network.h"
+
+using json = nlohmann::json;
+
+class Firewall
+{
+
+ /* consts */
+ private:
+ inline static const char* __group_name { "stormy/dropship" };
+ inline static const char* __group_name_legacy { "stormy.gg/dropship" };
+
+ inline static const char* __win_net_fw_popup_name { "firewall_network_profile_wizard" };
+ inline static const char* __win_net_fw_manual_popup_name { "how_to_fix" };
+
+ //static constexpr auto __network_query_timeout { 2s };
+ static const auto __network_query_delay_s { 2 };
+ //static const auto __win_net_fw_popup_close_delay { 2 };
+
+
+ public:
+
+ Firewall();
+ ~Firewall();
+
+ void render();
+
+ void tryWriteSettingsToFirewall(std::string data, std::string block);
+ std::optional tryFetchSettingsFromFirewall();
+
+ private:
+
+ bool __win_net_fw_popup_ignored { false };
+
+ bool _coInitilizeSuccess;
+ //std::optional _network_information; // note; optional not needed, takes <10ms
+ util::win_network::NetworkInformation _network_information;
+ double _network_information_updated_frametime { 0. };
+
+ private:
+
+ /* fetch network status */
+ /* timeout:2s*/
+ void _queryNetworkStatus(); // auto timeout = __network_query_timeout
+
+ void _validateRules();
+};
+
diff --git a/dropship/dropship/src/managers/FirewallRender.cpp b/dropship/dropship/src/managers/FirewallRender.cpp
new file mode 100644
index 0000000..936bb99
--- /dev/null
+++ b/dropship/dropship/src/managers/FirewallRender.cpp
@@ -0,0 +1,137 @@
+#include "pch.h"
+
+#include "Firewall.h"
+
+
+
+void Firewall::render() {
+
+ /*if (this->_network_information) {
+
+ }
+
+ ImGui::Text("waiting for network information");*/
+
+
+ bool close__win_net_fw_popup = false;
+
+
+ // if done during IsWindowAppearing() it's visually offset. band-aid here.
+ /*if (!ImGui::IsWindowAppearing() && this->_network_information_updated_frametime == 0.)
+ if (!this->_network_information.connected_networks_are_enabled_in_firewall)
+ if (!ImGui::IsPopupOpen(this->__win_net_fw_popup_name)) ImGui::OpenPopup(this->__win_net_fw_popup_name);*/
+
+
+ if (!this->__win_net_fw_popup_ignored) {
+
+ if (ImGui::GetTime() > this->_network_information_updated_frametime + this->__network_query_delay_s) {
+ this->_queryNetworkStatus();
+ this->_network_information_updated_frametime = ImGui::GetTime();
+
+ /* connected to a network that's not covered in firewall */
+ if (!this->_network_information.connected_networks_are_enabled_in_firewall) {
+ if (!ImGui::IsPopupOpen(this->__win_net_fw_popup_name))
+ {
+ ImGui::OpenPopup(this->__win_net_fw_popup_name);
+ }
+ }
+ else {
+ close__win_net_fw_popup = true;
+ }
+ }
+
+ bool not_quit = true;
+ if (ImGui::BeginPopupModal(this->__win_net_fw_popup_name, ¬_quit, ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize)) {
+
+ if (close__win_net_fw_popup) {
+ ImGui::CloseCurrentPopup();
+ }
+
+ ImGui::Text("To block servers, dropship needs Windows \nFirewall to be enabled");
+
+ /* vpn note */
+ if (this->_network_information.connected_networks_count > 1)
+ {
+ //ImGui::SeparatorText("note");
+ ImGui::BulletText("Multiple networks detected. If you are\nusing a VPN, turning it off may fix\nthis problem");
+ }
+
+ static const NET_FW_PROFILE_TYPE2_ profiles [3] = { NET_FW_PROFILE2_DOMAIN, NET_FW_PROFILE2_PUBLIC, NET_FW_PROFILE2_PRIVATE };
+ static const char* names [3] = { "domain", "public", "private" };
+
+ /* network notes */
+ for (int i = 0; i < 3; i ++)
+ {
+ auto& p = profiles[i];
+ auto& n = names[i];
+
+ if ((this->_network_information.network_profiles_connected & p) && !(this->_network_information.firewall_profiles_enabled & p))
+ {
+ ImGui::BulletText("This device is connected to a %s\nnetwork, but %s networks are not\nenabled in windows firewall", n, n);
+ }
+ }
+
+ ImGui::Spacing();
+
+ //ImGui::Text("This will turn on Windows Firewall");
+
+ ImGui::Spacing();
+
+ /* network actions */
+ for (int i = 0; i < 3; i++)
+ {
+ auto& p = profiles[i];
+ auto& n = names[i];
+
+ if ((this->_network_information.network_profiles_connected & p) && !(this->_network_information.firewall_profiles_enabled & p))
+ {
+ if (ImGui::Button(std::format("Turn on for {} networks", n).c_str(), {ImGui::GetContentRegionAvail().x, 0})) {
+ util::win_net_fw::enableFirewallForNetworkProfile(p);
+ }
+ }
+ }
+
+ /*ImGui::BeginDisabled();
+ if (ImGui::Button("turn on firewall for private networks", { ImGui::GetContentRegionAvail().x, 0 })) {
+ not_quit = false;
+ }
+ ImGui::EndDisabled();*/
+
+ ImGui::PushStyleColor(ImGuiCol_Text, { 0, 0, 0, 0.4f });
+ ImGui::PushStyleColor(ImGuiCol_Button, { 0, 0, 0, 0.0f });
+ ImGui::PushStyleColor(ImGuiCol_ButtonHovered, { 0, 0, 0, 0.04f });
+ ImGui::PushStyleColor(ImGuiCol_ButtonActive, { 0, 0, 0, 0.09f });
+ {
+ if (ImGui::Button("Network settings", { ImGui::GetContentRegionAvail().x, 0 })) {
+
+ // option 01
+ //system("%systemroot%\\system32\\control.exe /name Microsoft.WindowsFirewall");
+
+ // option 02
+ system("start windowsdefender://network");
+
+ ImGui::OpenPopup(this->__win_net_fw_manual_popup_name);
+ }
+ }
+ ImGui::PopStyleColor(4);
+
+
+ /* manual fix modal */
+ if (ImGui::BeginPopupModal(this->__win_net_fw_manual_popup_name, NULL, ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize)) {
+
+ ImGui::Text("Tap the [Turn on] button next to the network\nthat says (active)");
+
+ if (ImGui::Button("done", { ImGui::GetContentRegionAvail().x, 0 })) {
+ ImGui::CloseCurrentPopup();
+ }
+ }
+
+ ImGui::EndPopup();
+ }
+
+ if (!not_quit)
+ {
+ this->__win_net_fw_popup_ignored = true;
+ }
+ }
+}
diff --git a/dropship/dropship/src/managers/Settings.cpp b/dropship/dropship/src/managers/Settings.cpp
new file mode 100644
index 0000000..9de802d
--- /dev/null
+++ b/dropship/dropship/src/managers/Settings.cpp
@@ -0,0 +1,424 @@
+#include "pch.h"
+
+#include "Settings.h"
+
+
+extern std::unique_ptr>> g_endpoints;
+extern std::unique_ptr g_firewall;
+extern std::unique_ptr g_window_watcher;
+
+extern ImFont* font_subtitle;
+
+namespace dropship::settings {
+ void to_json(json& j, const dropship_app_settings& p) {
+
+
+
+ j = json {
+ {"options", {
+ { "auto_update", p.options.auto_update },
+ { "ping_servers", p.options.ping_servers },
+ }},
+ {"config", {
+ { "blocked_endpoints", p.config.blocked_endpoints },
+ }},
+ };
+ }
+
+ json strip_diff_dropship_app_settings(const json& j_default, const json& j) {
+
+ json result;
+
+ // web https://json.nlohmann.me/features/json_pointer/
+
+ /* types that support equality */
+ const std::array /**/ compare
+ {
+ /* bool */
+ "/options/auto_update"_json_pointer,
+ "/options/ping_servers"_json_pointer,
+
+ /* vector */
+ "/config/blocked_endpoints"_json_pointer,
+ };
+
+ for (auto& p : compare)
+ if (j.contains(p) && j_default.at(p) != j.at(p))
+ result[p] = j.at(p);
+
+ return result;
+ }
+
+
+ void from_json(const json& j, dropship_app_settings& p) {
+ if (j.contains("/options/auto_update"_json_pointer)) j.at("/options/auto_update"_json_pointer).get_to(p.options.auto_update);
+ if (j.contains("/options/ping_servers"_json_pointer)) j.at("/options/ping_servers"_json_pointer).get_to(p.options.ping_servers);
+
+ if (j.contains("/config/blocked_endpoints"_json_pointer)) j.at("/config/blocked_endpoints"_json_pointer).get_to(p.config.blocked_endpoints);
+ }
+}
+
+
+
+
+const dropship::settings::dropship_app_settings& Settings::getAppSettings()
+{
+ return this->_dropship_app_settings;
+};
+
+
+std::string Settings::getAllBlockedAddresses() {
+
+ std::string result;
+
+ if (this->_dropship_app_settings.config.blocked_endpoints.empty()) return result;
+
+ std::set blocked_servers;
+
+ /* note this causes weird crash. */
+ /*for (auto& e : this->_dropship_app_settings.config.blocked_endpoints)
+ {
+ auto& endpoint = this->__ow2_endpoints.at(e);
+
+ for (auto s : endpoint.blocked_servers)
+ {
+ blocked_servers.insert(s);
+ }
+ }
+
+ for (auto& s : blocked_servers)
+ {
+ auto& server = this->__ow2_servers.at(s);
+ result += server.block;
+ result += ',';
+ }*/
+
+ //if (!result.empty())
+ //{
+ // result = result.substr(0, result.length() - 1);
+ //}
+
+ for (auto& e : this->_dropship_app_settings.config.blocked_endpoints)
+ {
+ auto& endpoint = this->__ow2_endpoints.at(e);
+
+ for (auto s : endpoint.blocked_servers)
+ {
+ auto& server = this->__ow2_servers.at(s);
+ result += server.block;
+ result += ',';
+ }
+ }
+
+
+ result.pop_back();
+
+ // throws errors
+ //println("blocking {}", result);
+
+ return result;
+
+}
+
+
+
+std::optional Settings::readStoragePatch__win_firewall() {
+
+#ifdef _DEBUG
+ util::timer::Timer timer("readStoragePatch__win_firewall");
+#endif
+
+ std::optional result = std::nullopt;
+
+ auto loaded_settings = (*g_firewall).tryFetchSettingsFromFirewall();
+ if (loaded_settings)
+ {
+
+ try {
+ //result = std::make_optional(loaded_settings.value());
+ result = std::make_optional(json::from_msgpack(loaded_settings.value()));
+ println("loaded patch: {}", result.value().dump(4));
+ }
+ catch (json::exception& e) {
+ println("json error: {}", e.what());
+ }
+ }
+
+ return result;
+}
+
+void Settings::tryLoadSettingsFromStorage() {
+ auto loaded_settings = this->readStoragePatch();
+ if (loaded_settings) {
+
+ try {
+ json settings = this->__default_dropship_app_settings;
+
+ //settings.merge_patch(loaded_settings.value());
+
+ /* merge obects: false */
+ settings.update(loaded_settings.value(), false);
+
+ this->_dropship_app_settings = settings;
+ }
+ catch (json::exception& e) {
+ println("tryLoadSettingsFromStorage() json error: {}", e.what());
+ }
+ }
+}
+
+
+/* note: windows firewall has a 1024 description */
+void Settings::tryWriteSettingsToStorage(bool force) {
+
+#ifdef _DEBUG
+ util::timer::Timer timer("tryWriteSettingsToStorage");
+#endif
+
+ const auto game_open = g_window_watcher && (*g_window_watcher).isActive();
+ if (game_open && !force)
+ {
+ //this->_waiting_for_config_write = true;
+ auto any = false;
+ for (auto& e : (*g_endpoints)) {
+ if ((*e).getBlockDesired() != (*e)._getBlockedState()) { any = true; };
+ }
+ this->_waiting_for_config_write = any;
+ }
+ else if (force && this->_waiting_for_config_write)
+ {
+ this->_waiting_for_config_write = false;
+ }
+
+ if (!this->_waiting_for_config_write || force)
+ {
+ // calculate diff
+ /*auto diff = json::diff(this->__default_dropship_app_settings, this->_dropship_app_settings);
+ println("diff: {}", diff.dump(4));*/
+
+ json stripped = dropship::settings::strip_diff_dropship_app_settings(this->__default_dropship_app_settings, this->_dropship_app_settings);
+
+ if (stripped.is_null())
+ {
+ stripped = this->__default_dropship_app_settings;
+ }
+
+ // throws error
+ //println("writing: {}", stripped.dump(4));
+
+ /* note: diff calcuated in to_json defined above */
+ auto packed = json::to_msgpack(stripped);
+ std::string s(packed.begin(), packed.end());
+
+ (*g_firewall).tryWriteSettingsToFirewall(s, this->getAllBlockedAddresses());
+
+
+ // TODO if not failed
+ for (auto& endpoint : (*g_endpoints)) {
+ (*endpoint)._setBlockedState(this->_dropship_app_settings.config.blocked_endpoints.contains((*endpoint).getTitle()));
+ }
+
+
+ //std::basic_string_view packed_sv (packed.data(), packed.size());
+ //std::string packed_s{ packed_sv };
+ //auto s = std::string_view(packed);
+
+ //(*g_firewall).tryWriteSettingsToFirewall(s);
+
+ //printf("packed: <%s>\n", s.c_str());
+ }
+
+ else
+ {
+ println("waiting for game close");
+ }
+
+}
+
+//json mergeSettings(const json& a, const json& b) {
+//
+// println("a {}", a.dump(4));
+// println("b {}", b.dump(4));
+//
+// throw std::runtime_error("xd");
+//
+// /* calculate diff */
+// json merge_patch = a;
+//
+// //merge_patch.merge_patch(b);
+// for (auto& b : a.flatten()) {
+// println("ac: {}", b.dump(4));
+// }
+//
+// println("merge: {}", merge_patch.dump(4));
+//
+// //a.merge_patch(b);
+//
+// return a;
+//}
+
+
+
+std::optional Settings::readStoragePatch() {
+ return this->readStoragePatch__win_firewall();
+}
+
+
+Settings::Settings() {
+
+ if (!g_endpoints) throw std::runtime_error("settings depends on g_endpoints.");
+ if (!g_firewall) throw std::runtime_error("settings depends on g_firewall.");
+
+
+ this->tryLoadSettingsFromStorage();
+
+ /*
+ 1. grab settings from firewall manager
+ 2. if failed, show failed and use default settings.
+
+ */
+
+ (*g_endpoints).reserve(this->__ow2_endpoints.size());
+
+ for (auto& [key, e] : this->__ow2_endpoints)
+ {
+ auto blocked = this->_dropship_app_settings.config.blocked_endpoints.contains(key);
+
+ (*g_endpoints).push_back(std::make_shared(
+ key,
+ e.description,
+ this->_dropship_app_settings.options.ping_servers ? e.ip_ping : "",
+ blocked
+ ));
+ }
+
+
+ /*std::cout << "__ow2_ranges: " << __ow2_servers.dump(4) << std::endl;
+ std::cout << "__ow2_ranges: " << __ow2_ranges.dump(4) << std::endl;
+ std::cout << "__ow2_endpoints: " << __ow2_endpoints.dump(4) << std::endl;
+ std::cout << "__default: " << __default.dump(4) << std::endl;*/
+
+}
+
+Settings::~Settings() {
+
+
+ printf("destructor");
+}
+
+void Settings::unblockAll() {
+ for (auto& endpoint : (*g_endpoints)) {
+ (*endpoint).setBlockDesired(false);
+ }
+ this->_dropship_app_settings.config.blocked_endpoints.clear();
+ this->tryWriteSettingsToStorage(true); // force
+}
+
+void Settings::toggleOptionAutoUpdate() {
+ this->_dropship_app_settings.options.auto_update = !this->_dropship_app_settings.options.auto_update;
+ this->tryWriteSettingsToStorage();
+}
+
+void Settings::toggleOptionPingServers() {
+ this->_dropship_app_settings.options.ping_servers = !this->_dropship_app_settings.options.ping_servers;
+ this->tryWriteSettingsToStorage();
+}
+
+
+// todo std::unordered_set
+void Settings::addBlockedEndpoint(std::string endpoint_title) {
+
+ auto [_position, hasBeenInserted] = this->_dropship_app_settings.config.blocked_endpoints.insert(endpoint_title);
+
+ if (hasBeenInserted)
+ {
+ this->tryWriteSettingsToStorage();
+ }
+
+}
+
+// todo std::unordered_set
+void Settings::removeBlockedEndpoint(std::string endpoint_title) {
+
+ auto const num_removed = this->_dropship_app_settings.config.blocked_endpoints.erase(endpoint_title);
+
+ if (num_removed > 0)
+ {
+ this->tryWriteSettingsToStorage();
+ }
+
+}
+
+void Settings::render() {
+ if (g_window_watcher) {
+
+ const auto game_open = (*g_window_watcher).isActive();
+
+ // pause config writes when game is open
+ if (game_open) {
+ //this->_waiting_for_config_write = true;
+ }
+
+ // trigger a write when game is closed
+ else
+ {
+ if (this->_waiting_for_config_write)
+ {
+ this->_waiting_for_config_write = false;
+ this->tryWriteSettingsToStorage();
+ }
+ }
+
+ }
+}
+
+void Settings::renderWaitingStatus()
+{
+ if (g_window_watcher) {
+
+ if (this->_waiting_for_config_write)
+ {
+ //static auto& style = ImGui::GetStyle();
+ ImDrawList* list = ImGui::GetWindowDrawList();
+
+ static const ImU32 white = ImGui::ColorConvertFloat4ToU32({ 1, 1, 1, 1 });
+
+ static const auto color = ImGui::ColorConvertFloat4ToU32({ .4f, .4f, .4f, 1.0f });
+ // static const auto color_2 = ImGui::ColorConvertFloat4ToU32({ 0, 0, 0, 0.6f });
+ static const std::string text = "GAME RESTART REQUIRED";
+ //static const std::string text = "GAME SHUT DOWN REQUIRED";
+
+ static const auto font = font_subtitle;
+ static const auto font_size = font->CalcTextSizeA(font_subtitle->FontSize, FLT_MAX, 0.0f, text.c_str());
+
+
+ ImGui::Dummy({ ImGui::GetContentRegionAvail().x, font_size.y + 16 });
+
+ list->AddRectFilled(ImGui::GetItemRectMin(), ImGui::GetItemRectMax(), color, 5.0f);
+
+ {
+ static const auto color = ImGui::ColorConvertFloat4ToU32({ 1, 1, 1, 0.09f });
+ const auto pos = ImGui::GetItemRectMin();
+
+ static const auto image = _get_image("background_diagonal");
+
+ list->PushClipRect(ImGui::GetItemRectMin(), ImGui::GetItemRectMax(), true);
+ list->AddImage(image.texture, pos, pos + ImVec2((float)image.width, (float)image.height), ImVec2(0, 0), ImVec2(1, 1), color);
+ list->PopClipRect();
+ }
+
+ const auto pos = ImGui::GetItemRectMin() + ImVec2((ImGui::GetItemRectSize().x - font_size.x) / 2, 8 - 2);
+ list->AddText(font_subtitle, font_subtitle->FontSize, pos, white, text.c_str());
+
+ }
+
+ /*static auto& style = ImGui::GetStyle();
+ ImGui::PushStyleColor(ImGuiCol_Text, style.Colors[ImGuiCol_TextDisabled]);
+ ImGui::TextWrapped("Click Unblock if not connecting");
+ ImGui::PopStyleColor();*/
+ }
+
+ else {
+ ImGui::TextDisabled("Do not block servers with game open");
+ }
+}
diff --git a/dropship/dropship/src/managers/Settings.h b/dropship/dropship/src/managers/Settings.h
new file mode 100644
index 0000000..a3e027b
--- /dev/null
+++ b/dropship/dropship/src/managers/Settings.h
@@ -0,0 +1,186 @@
+#pragma once
+
+
+#include "components/Endpoint.h"
+
+#include "managers/Firewall.h"
+#include "util/watcher/window.h"
+
+#include "images.h"
+
+using json = nlohmann::json;
+// web https://github.com/nlohmann/json
+
+
+namespace dropship::settings {
+
+ struct unique_server {
+ const std::string block;
+ };
+
+
+ struct unique_endpoint {
+ const std::string description;
+ const std::string ip_ping { "" };
+ std::set blocked_servers;
+
+ };
+
+ /* note - always update to_json and from_json if new options are added */
+ struct dropship_app_settings {
+ struct _dropship_app_settings__options {
+ bool auto_update { false };
+ bool ping_servers { true };
+ };
+ _dropship_app_settings__options options;
+
+ struct _dropship_app_settings__config {
+ std::set blocked_endpoints;
+ };
+ _dropship_app_settings__config config;
+ };
+
+ void to_json(json& j, const dropship_app_settings& p);
+
+ void from_json(const json& j, dropship_app_settings& p);
+
+ /* custom so i only store changes in firewall */
+ json strip_diff_dropship_app_settings(const json& j_default, const json& j);
+};
+
+// todo
+/* static const std::unordered_map __ow2_servers {
+ { "ord1", { .block = "24.105.40.0-24.105.47.255,64.224.0.0/21,8.34.210.0/24" } },
+ { "guw2", { .block = "35.247.0.0/17,35.236.0.0/17" } },
+ { "lax1", { .block = "24.105.8.0-24.105.15.255,34.124.0.0/21" } },
+ { "las1", { .block = "64.224.24.0/23" } },
+}; */
+
+
+
+
+class Settings
+{
+ /* consts */
+ private:
+
+ const std::map __ow2_servers {
+ { "_tmp_na/central", { .block = "24.105.40.0-24.105.47.255,64.224.0.0/21,8.34.210.0/24,8.34.212.0/22,8.34.216.0/22,8.35.192.0/21,23.236.48.0/20,23.251.144.0/20,34.0.225.0/24,34.16.0.0/17,34.27.0.0/16,34.28.0.0/14,34.33.0.0/16,34.41.0.0/16,34.42.0.0/16,34.44.0.0/15,34.46.0.0/16,34.66.0.0/15,34.68.0.0/14,34.72.0.0/16,34.118.200.0/21,34.121.0.0/16,34.122.0.0/15,34.128.32.0/22,34.132.0.0/14,34.136.0.0/16,34.153.48.0/21,34.153.240.0/21,34.157.84.0/23,34.157.96.0/20,34.157.212.0/23,34.157.224.0/20,34.170.0.0/15,34.172.0.0/15,34.177.52.0/22,35.184.0.0/16,35.188.0.0/17,35.188.128.0/18,35.188.192.0/19,35.192.0.0/15,35.194.0.0/18,35.202.0.0/16,35.206.64.0/18,35.208.0.0/15,35.220.64.0/19,35.222.0.0/15,35.224.0.0/15,35.226.0.0/16,35.232.0.0/16,35.238.0.0/15,35.242.96.0/19,104.154.16.0/20,104.154.32.0/19,104.154.64.0/19,104.154.96.0/20,104.154.113.0/24,104.154.114.0/23,104.154.116.0/22,104.154.120.0/23,104.154.128.0/17,104.155.128.0/18,104.197.0.0/16,104.198.16.0/20,104.198.32.0/19,104.198.64.0/20,104.198.128.0/17,107.178.208.0/20,108.59.80.0/21,130.211.112.0/20,130.211.128.0/18,130.211.192.0/19,130.211.224.0/20,146.148.32.0/19,146.148.64.0/19,146.148.96.0/20,162.222.176.0/21,173.255.112.0/21,199.192.115.0/24,199.223.232.0/22,199.223.236.0/24,34.22.0.0/19,35.186.0.0/17,35.186.128.0/20,35.206.32.0/19,35.220.46.0/24,35.242.46.0/24,107.167.160.0/20,108.59.88.0/21,173.255.120.0/21" } },
+ { "_tmp_na/west", { .block = "64.224.24.0/23,24.105.8.0-24.105.15.255,35.247.0.0/17,35.236.0.0/17,35.235.64.0/18,34.102.0.0/17,34.94.0.0/16,34.19.0.0/17,34.82.0.0/15,34.105.0.0/17,34.118.192.0/21,34.127.0.0/17,34.145.0.0/17,34.157.112.0/21,34.157.240.0/21,34.168.0.0/15,35.185.192.0/18,35.197.0.0/17,35.199.144.0/20,35.199.160.0/19,35.203.128.0/18,35.212.128.0/17,35.220.48.0/21,35.227.128.0/18,35.230.0.0/17,35.233.128.0/17,35.242.48.0/21,35.243.32.0/21,35.247.0.0/17,104.196.224.0/19,104.198.0.0/20,104.198.96.0/20,104.199.112.0/20,34.20.128.0/17,34.94.0.0/16,34.102.0.0/17,34.104.64.0/21,34.108.0.0/16,34.118.248.0/23,35.215.64.0/18,35.220.47.0/24,35.235.64.0/18,35.236.0.0/17,35.242.47.0/24,35.243.0.0/21,34.22.32.0/19,34.104.52.0/24,34.106.0.0/16,34.127.180.0/24,35.217.64.0/18,35.220.31.0/24,35.242.31.0/24,34.16.128.0/17,34.104.72.0/22,34.118.240.0/22,34.124.8.0/22,34.125.0.0/16,35.219.128.0/18,34.124.0.0/21,34.37.0.0/16,34.128.46.0/23,34.128.62.0/23,34.53.0.0/17" } },
+ { "_tmp_na/east", { .block = "34.124.0.0/21,35.236.192.0-35.236.255.255,35.199.0.0-35.199.63.255,34.86.0.0-34.86.255.255,35.245.0.0-35.245.255.255,35.186.160.0-35.186.191.255,34.145.128.0-34.145.255.255,34.150.128.0-34.150.255.255,34.85.128.0-34.85.255.255,34.23.0.0/16,34.24.0.0/15,34.26.0.0/16,34.73.0.0/16,34.74.0.0/15,34.98.128.0/21,34.118.250.0/23,34.138.0.0/15,34.148.0.0/16,35.185.0.0/17,35.190.128.0/18,35.196.0.0/16,35.207.0.0/18,35.211.0.0/16,35.220.0.0/20,35.227.0.0/17,35.229.16.0/20,35.229.32.0/19,35.229.64.0/18,35.231.0.0/16,35.237.0.0/16,35.242.0.0/20,35.243.128.0/17,104.196.0.0/18,104.196.65.0/24,104.196.66.0/23,104.196.68.0/22,104.196.96.0/19,104.196.128.0/18,104.196.192.0/19,162.216.148.0/22,34.21.0.0/17,34.85.128.0/17,34.86.0.0/16,34.104.60.0/23,34.104.124.0/23,34.118.252.0/23,34.124.60.0/23,34.127.188.0/23,34.145.128.0/17,34.150.128.0/17,34.157.0.0/21,34.157.16.0/20,34.157.128.0/21,34.157.144.0/20,35.186.160.0/19,35.188.224.0/19,35.194.64.0/19,35.199.0.0/18,35.212.0.0/17,35.220.60.0/22,35.221.0.0/18,35.230.160.0/19,35.234.176.0/20,35.236.192.0/18,35.242.60.0/22,35.243.40.0/21,35.245.0.0/16,34.157.32.0/22,34.157.160.0/22,34.162.0.0/16,34.104.56.0/23,34.127.184.0/23,34.161.0.0/16,35.206.10.0/23,34.152.72.0/21,34.177.40.0/21,34.48.0.0/16,34.1.16.0/20" } },
+ { "_tmp_europe", { .block = "64.224.26.0/23,104.155.0.0/17,104.199.0.0/18,104.199.66.0/23,104.199.68.0/22,104.199.72.0/21,104.199.80.0/20,104.199.96.0/20,130.211.48.0/20,130.211.64.0/19,130.211.96.0/20,146.148.112.0/20,146.148.16.0/20,146.148.2.0/23,146.148.4.0/22,146.148.8.0/21,192.158.28.0/22,23.251.128.0/20,34.104.110.0/23,34.104.112.0/23,34.104.126.0/23,34.104.96.0/21,34.105.128.0/17,34.107.0.0/17,34.118.244.0/22,34.118.254.0/23,34.124.32.0/21,34.124.46.0/23,34.124.48.0/23,34.124.62.0/23,34.127.186.0/23,34.140.0.0/16,34.141.0.0/17,34.141.128.0/17,34.142.0.0/17,34.147.0.0/17,34.147.128.0/17,34.154.0.0/16,34.155.0.0/16,34.157.12.0/22,34.157.136.0/23,34.157.140.0/22,34.157.168.0/22,34.157.176.0/20,34.157.208.0/23,34.157.220.0/22,34.157.36.0/22,34.157.40.0/22,34.157.48.0/20,34.157.8.0/23,34.157.80.0/23,34.157.92.0/22,34.159.0.0/16,34.163.0.0/16,34.65.0.0/16,34.76.0.0/14,34.88.0.0/16,34.89.0.0/17,34.89.128.0/17,34.90.0.0/15,35.187.0.0/17,35.187.160.0/19,35.189.192.0/18,35.189.64.0/18,35.190.192.0/19,35.195.0.0/16,35.197.192.0/18,35.198.128.0/18,35.198.64.0/18,35.203.210.0/23,35.203.212.0/22,35.203.216.0/22,35.203.232.0/21,35.204.0.0/16,35.205.0.0/16,35.206.128.0/18,35.207.128.0/18,35.207.64.0/18,35.210.0.0/16,35.214.0.0/17,35.214.128.0/17,35.216.128.0/17,35.217.0.0/18,35.219.224.0/19,35.220.16.0/23,35.220.18.0/23,35.220.20.0/22,35.220.26.0/24,35.220.44.0/24,35.220.96.0/19,35.228.0.0/16,35.230.128.0/19,35.233.0.0/17,35.234.128.0/19,35.234.160.0/20,35.234.64.0/18,35.235.216.0/21,35.235.32.0/20,35.235.48.0/20,35.240.0.0/17,35.241.128.0/17,35.242.128.0/18,35.242.16.0/23,35.242.18.0/23,35.242.192.0/18,35.242.20.0/22,35.242.26.0/24,35.242.44.0/24,35.242.64.0/19,35.246.0.0/17,35.246.128.0/17,5.42.168.0-5.42.175.255,5.42.184.0-5.42.191.255,8.34.208.0/23,8.34.211.0/24,8.34.220.0/22,34.22.128.0/17,34.104.116.0/22,34.116.128.0/17,34.118.0.0/17,34.124.52.0/22,34.157.44.0/23,34.157.172.0/23,34.164.0.0/16,34.175.0.0/16,34.22.112.0/20,34.17.0.0/16,34.157.124.0/23,34.157.250.0/23,34.0.160.0/19,34.157.121.0/24,34.157.249.0/24,34.0.192.0/19,34.0.240.0/20,34.34.128.0/18,34.38.0.0/16,34.32.0.0/17,34.152.80.0/23,34.177.36.0/23,34.39.0.0/17,34.128.52.0/22,34.0.224.0/24,34.0.226.0/24,34.40.0.0/17,34.32.128.0/17,34.34.0.0/17,34.1.0.0/20,34.1.160.0/20,34.1.224.0/19,34.153.38.0/24,34.153.230.0/24" } },
+ { "_tmp_japan", { .block = "34.85.0.0-34.85.127.255,34.84.0.0-34.84.255.255,35.190.224.0-35.190.239.255,35.194.96.0-35.194.255.255,35.221.64.0-35.221.255.255,34.146.0.0-34.146.255.255,34.84.0.0/16,34.85.0.0/17,34.104.62.0/23,34.104.128.0/17,34.127.190.0/23,34.146.0.0/16,34.157.64.0/20,34.157.164.0/22,34.157.192.0/20,35.187.192.0/19,35.189.128.0/19,35.190.224.0/20,35.194.96.0/19,35.200.0.0/17,35.213.0.0/17,35.220.56.0/22,35.221.64.0/18,35.230.240.0/20,35.242.56.0/22,35.243.64.0/18,104.198.80.0/20,104.198.112.0/20,34.97.0.0/16,34.104.49.0/24,34.127.177.0/24,35.217.128.0/17,35.220.45.0/24,35.242.45.0/24,35.243.56.0/21" } },
+ { "_tmp_australia", { .block = "158.115.196.0/23,37.244.42.0-37.244.42.255,34.87.192.0/18,34.104.104.0/23,34.116.64.0/18,34.124.40.0/23,34.151.64.0/18,34.151.128.0/18,35.189.0.0/18,35.197.160.0/19,35.201.0.0/19,35.213.192.0/18,35.220.41.0/24,35.234.224.0/20,35.242.41.0/24,35.244.64.0/18,34.104.122.0/23,34.124.58.0/23,34.126.192.0/20,34.129.0.0/16,34.0.16.0/20,34.40.128.0/17,34.128.36.0/24,34.128.48.0/24,34.1.176.0/20" } },
+ { "_tmp_south_korea", { .block = "202.9.66.0/23,34.64.0.0-34.64.255.255,117.52.0.0-117.52.255.255,121.254.0.0-121.254.255.255,34.0.96.0/19,34.64.32.0/19,34.64.64.0/22,34.64.68.0/22,34.64.72.0/21,34.64.80.0/20,34.64.96.0/19,34.64.128.0/22,34.64.132.0/22,34.64.136.0/21,34.64.144.0/20,34.64.160.0/19,34.64.192.0/18,35.216.0.0/17,34.22.64.0/19,34.22.96.0/20,34.47.64.0/18,34.50.0.0/18" } },
+ { "_tmp_singapore", { .block = "34.124.0.0-34.124.255.255,34.124.42.0-34.124.43.255,34.142.128.0-34.142.255.255,35.185.176.0-35.185.191.255,35.186.144.0-35.186.159.255,35.247.128.0-35.247.191.255,34.87.0.0-34.87.191.255,34.143.128.0-34.143.255.255,34.124.128.0-34.124.255.255,34.126.64.0-34.126.191.255,35.240.128.0-35.240.255.255,35.198.192.0-35.198.255.255,34.21.128.0-34.21.255.255,34.104.58.0-34.104.59.255,34.124.41.0-34.124.42.255,34.157.82.0-34.157.83.255,34.157.88.0-34.157.89.255,34.157.210.0-34.157.211.255,35.187.224.0-35.187.255.255,35.197.128.0-35.197.159.255,35.213.128.0-35.213.191.255,35.220.24.0-35.220.25.255,35.234.192.0-35.234.207.255,35.242.24.0-35.242.25.255,34.126.128.0/18,34.87.128.0/18,34.21.128.0/17,34.87.0.0/17,34.87.128.0/18,34.104.58.0/23,34.104.106.0/23,34.124.42.0/23,34.124.128.0/17,34.126.64.0/18,34.126.128.0/18,34.142.128.0/17,34.143.128.0/17,34.157.82.0/23,34.157.88.0/23,34.157.210.0/23,35.185.176.0/20,35.186.144.0/20,35.187.224.0/19,35.197.128.0/19,35.198.192.0/18,35.213.128.0/18,35.220.24.0/23,35.234.192.0/20,35.240.128.0/17,35.242.24.0/23,35.247.128.0/18,34.101.18.0/24,34.101.20.0/22,34.101.24.0/22,34.101.32.0/19,34.101.64.0/18,34.101.128.0/17,34.128.64.0/18,35.219.0.0/17,34.128.44.0/23,34.128.60.0/23,34.1.128.0/20,34.1.192.0/20,34.153.40.0/23,34.153.232.0/23" } },
+ { "_tmp_taiwan", { .block = "5.42.160.0-5.42.160.255,35.221.128.0/17,34.80.0.0/15,34.137.0.0/16,35.185.128.0/19,35.185.160.0/20,35.187.144.0/20,35.189.160.0/19,35.194.128.0/17,35.201.128.0/17,35.206.192.0/18,35.220.32.0/21,35.229.128.0/17,35.234.0.0/18,35.235.16.0/20,35.236.128.0/18,35.242.32.0/21,104.155.192.0/19,104.155.224.0/20,104.199.128.0/18,104.199.192.0/19,104.199.224.0/20,104.199.242.0/23,104.199.244.0/22,104.199.248.0/21,107.167.176.0/20,130.211.240.0/20" } },
+ { "_tmp_brazil", { .block = "34.95.128.0/17,34.104.80.0/21,34.124.16.0/21,34.151.0.0/18,34.151.192.0/18,35.198.0.0/18,35.199.64.0/18,35.215.192.0/18,35.220.40.0/24,35.235.0.0/20,35.242.40.0/24,35.247.192.0/18,34.104.50.0/23,34.127.178.0/23,34.176.0.0/16,34.95.208.0/20,34.39.128.0/17,35.199.96.0/20" } },
+ { "_tmp_middle_east", { .block = "157.175.0.0-157.175.255.255,15.185.0.0-15.185.255.255,15.184.0.0-15.184.255.255,16.24.0.0/16,34.1.48.0/20,34.152.84.0/23,34.166.0.0/16,34.177.48.0/23,34.1.32.0/20,34.18.0.0/16,34.157.126.0/23,34.157.252.0/23,34.0.64.0/19,34.157.90.0/23,34.157.216.0/23,34.165.0.0/16,34.1.48.0/20,34.177.48.0/23,34.0.64.0/19,34.157.90.0/23,34.157.216.0/23,34.165.0.0/16" } },
+ };
+
+ const std::map __ow2_endpoints {
+ { "NA - CENTRAL" , {
+ .description = "ORD1 and GUW2",
+ .ip_ping = "137.221.69.29",
+ .blocked_servers = { "_tmp_na/central" },
+ }},
+ { "NA - WEST" , {
+ .description = "LAX1 and LAS1",
+ .ip_ping = "137.221.68.83",
+ .blocked_servers = { "_tmp_na/west" },
+ }},
+
+ { "EUROPE" , {
+ .description = "AMS1 and CDG1", // Amsterdam, Paris
+ .ip_ping = "137.221.78.69",
+ .blocked_servers = { "_tmp_europe" },
+ }},
+
+ { "JAPAN" , {
+ .description = "GTK1", // Tokyo
+ .ip_ping = "52.94.8.94",
+ .blocked_servers = { "_tmp_japan" },
+ }},
+
+ { "SOUTH KOREA" , {
+ .description = "ICN1", // Seoul
+ .ip_ping = "137.221.65.65",
+ .blocked_servers = { "_tmp_south_korea" },
+ }},
+
+ { "AUSTRALIA" , {
+ .description = "SYD2", // Sydney
+ .ip_ping = "137.221.85.67",
+ .blocked_servers = { "_tmp_australia" },
+ }},
+
+ { "SINGAPORE" , {
+ .description = "GSG1",
+ .ip_ping = "35.71.118.14",
+ .blocked_servers = { "_tmp_singapore" },
+ }},
+
+ { "TAIWAN" , {
+ .description = "TPE1", // Taipei
+ .ip_ping = "35.229.225.152",
+ .blocked_servers = { "_tmp_taiwan" },
+ }},
+
+ { "BRAZIL" , {
+ .description = "GBR1",
+ .ip_ping = "52.94.7.202",
+ .blocked_servers = { "_tmp_brazil" },
+ }},
+
+ { "MIDDLE EAST" , {
+ .description = "GMEC2",
+ .ip_ping = "13.248.66.130",
+ .blocked_servers = { "_tmp_middle_east" },
+ }},
+ };
+
+ const dropship::settings::dropship_app_settings __default_dropship_app_settings;
+
+ dropship::settings::dropship_app_settings _dropship_app_settings;
+
+ public:
+
+ Settings();
+ ~Settings();
+
+ const dropship::settings::dropship_app_settings& getAppSettings();
+
+ /* will not do anything on error */
+ void tryLoadSettingsFromStorage();
+
+ /* will not do anything on error */
+ void tryWriteSettingsToStorage(bool force = false);
+
+ void render();
+
+ void renderWaitingStatus();
+
+
+ public:
+
+ void unblockAll();
+
+ void toggleOptionAutoUpdate();
+
+ void toggleOptionPingServers();
+
+ void addBlockedEndpoint(std::string endpoint_title);
+ void removeBlockedEndpoint(std::string endpoint_title);
+
+ //void syncEndpoint(std::shared_ptr endpoint);
+
+ private:
+
+ [[nodiscard]] std::optional readStoragePatch__win_firewall();
+ [[nodiscard]] std::optional readStoragePatch();
+
+ [[nodiscard]] std::string getAllBlockedAddresses();
+
+ bool _waiting_for_config_write { false };
+};
+
\ No newline at end of file
diff --git a/dropship/dropship/src/managers/Update.cpp b/dropship/dropship/src/managers/Update.cpp
new file mode 100644
index 0000000..a550919
--- /dev/null
+++ b/dropship/dropship/src/managers/Update.cpp
@@ -0,0 +1,323 @@
+#include "pch.h"
+
+#include "Update.h"
+
+extern std::unique_ptr g_settings;
+
+//extern OPTIONS options;
+//
+//extern AppStore appStore;
+//extern AppStore __default__appStore;
+
+extern ImFont* font_subtitle;
+
+
+// static const std::string message = "STORMY.GG/DROPSHIP";
+
+// download uri
+// https://github.com/stowmyy/dropship/releases/latest/download/dropship.exe
+
+std::wstring _get_exe_path() {
+ /*TCHAR _path[MAX_PATH] = { 0 };
+ ::GetModuleFileName(NULL, _path, MAX_PATH);
+ return std::string(_path);*/
+
+ wchar_t _path[MAX_PATH];
+ ::GetModuleFileNameW(NULL, _path, MAX_PATH);
+
+ return std::wstring(_path);
+}
+
+std::string _get_file_sha512(std::wstring _path) {
+ /*std::string _hash = sw::sha512::file(_path.c_str());
+ std::transform(_hash.begin(), _hash.end(), _hash.begin(), ::tolower);
+ return _hash;*/
+
+ std::ifstream fs;
+ fs.open(_path.c_str(), (std::ios::in | std::ios::binary));
+ sw::detail::basic_sha512::str_t s = sw::sha512::calculate(fs);
+ fs.close();
+
+ std::string _hash = s;
+ std::transform(_hash.begin(), _hash.end(), _hash.begin(), ::tolower);
+ return _hash;
+}
+
+
+// TODO ZoeResult CalculateFileSHA256(const utf8string& file_path, Options* opt, utf8string& str_hash);
+// TODO ZoeResult CalculateFileSHA256(const utf8string& file_path, Options* opt, utf8string& str_hash);
+// TODO ZoeResult CalculateFileSHA256(const utf8string& file_path, Options* opt, utf8string& str_hash);
+// TODO ZoeResult CalculateFileSHA256(const utf8string& file_path, Options* opt, utf8string& str_hash);
+void Updater::getMeta() {
+ /* get .exe metadata */
+ const auto path = _get_exe_path();
+ const auto hash = _get_file_sha512(path);
+
+ //std::println("path: {}\nhash: {}", path, hash);
+
+ this->__exe_path = path;
+ this->__exe_hash = hash;
+}
+
+/* downloads the new version hash from github */
+std::string _fetch_update_sha512() {
+ std::string update_hash = util::win_download::_download_txt(__UPDATE_VERSION_URI);
+ return update_hash;
+}
+
+bool Updater::checkForUpdate() {
+ std::string update_hash = _fetch_update_sha512();
+ std::transform(update_hash.begin(), update_hash.end(), update_hash.begin(), ::tolower);
+ trim(update_hash);
+
+ std::println("update hash: {}", update_hash);
+
+ if (update_hash.length() != this->__exe_hash.length()) {
+ throw std::runtime_error("bad version");
+ }
+
+ return (this->__exe_hash != update_hash);
+}
+
+void Updater::update() {
+
+ this->update_future = std::async(std::launch::async, [&] {
+ try {
+
+ this->progress = 0.0f;
+ this->downloading = true;
+ this->version = "downloading new version";
+
+ std::filesystem::path _downloaded_path;
+ util::win_download::download_file(__UPDATE_EXE_URI, "dropship.exe", &(this->progress), NULL, &_downloaded_path);
+ this->downloading = false;
+ this->version = "updating application";
+
+ const auto tmp = std::filesystem::path(this->__exe_path + L".old");
+ const auto dst = std::filesystem::path(this->__exe_path);
+
+ // std::filesystem::temp_directory_path().append("dropship").append("dropship.exe);
+
+
+ {
+ std::filesystem::rename(dst, tmp);
+ //std::filesystem::copy(_downloaded_path, dst);
+ std::filesystem::rename(_downloaded_path, dst);
+ static char buffer[512];
+ strcpy_s(buffer, dst.string().c_str());
+
+
+ /* CreateProcess API initialization */
+ STARTUPINFOA siStartupInfo;
+ PROCESS_INFORMATION piProcessInfo;
+ memset(&siStartupInfo, 0, sizeof(siStartupInfo));
+ memset(&piProcessInfo, 0, sizeof(piProcessInfo));
+ siStartupInfo.cb = sizeof(siStartupInfo);
+
+ ::CreateProcessA(buffer, // application name/path
+ NULL, // command line (optional)
+ NULL, // no process attributes (default)
+ NULL, // default security attributes
+ false,
+ CREATE_DEFAULT_ERROR_MODE | CREATE_NEW_CONSOLE,
+ NULL, // default env
+ NULL, // default working dir
+ &siStartupInfo,
+ &piProcessInfo);
+
+ ::TerminateProcess(GetCurrentProcess(), 0);
+ ::ExitProcess(0); // exit this process
+
+ // this does not return.
+ }
+ }
+ catch (const std::exception& e)
+ {
+ this->version = std::format("UPDATE FAILED ({})", e.what());
+ this->update_available = false;
+ }
+ catch (...)
+ {
+ this->version = "UPDATE FAILED (unknown error)";
+ this->update_available = false;
+ }
+ });
+}
+
+Updater::Updater():
+ description("@stormyy_ow")
+{
+ if (!g_settings) throw std::runtime_error("updater depends on g_settings");
+
+ this->version_future = std::async(std::launch::async, [&] {
+ try {
+ /* get .exe path and hash */
+ this->getMeta();
+ this->version = this->__exe_hash.substr(0, 9);
+
+ // TODO: delete this in a future version. it's only here for older versions.
+ /* !deprecated */
+ {
+ std::filesystem::path _tmp_path = std::filesystem::path(this->__exe_path + L".old"); // gets path of old exe
+ if (std::filesystem::exists(_tmp_path)) {
+ std::filesystem::remove(_tmp_path);
+ }
+ }
+
+ /* fetch new hash and compare */
+ if (this->checkForUpdate()) {
+ //this->version = "UPDATE AVAILABLE";
+ this->update_available = true;
+
+ std::println("auto update: {}", (*g_settings).getAppSettings().options.auto_update);
+
+ // todo settings
+ if ((*g_settings).getAppSettings().options.auto_update)
+ {
+ #ifndef _DEBUG
+ this->update();
+ #endif
+ }
+ }
+ }
+ catch (const std::exception& e)
+ {
+ this->version = std::format("VERSION FAILED ({})", e.what());
+ this->update_available = false;
+ }
+ catch (...)
+ {
+ this->version = "VERSION FAILED (unknown error)";
+ this->update_available = false;
+ }
+ });
+}
+
+Updater::~Updater() {
+ if (this->version_future.valid()) this->version_future.get();
+ if (this->update_future.valid()) this->update_future.get();
+}
+
+void Updater::render()
+{
+
+ if (!ImGui::IsWindowAppearing()) {
+ if (downloading && !ImGui::IsPopupOpen("updating")) {
+ ImGui::OpenPopup("updating");
+ }
+ else if (!update_available && ImGui::IsPopupOpen("updating")) {
+ //ImGui::CloseCurrentPopup();
+ ImGui::ClosePopupsOverWindow(ImGui::FindWindowByName("dashboard"), false);
+ }
+ }
+
+ ImGui::CloseCurrentPopup();
+ static const auto list = ImGui::GetWindowDrawList();
+ static const auto &style = ImGui::GetStyle();
+
+ static const auto width = ImGui::GetContentRegionAvail().x;
+
+
+ // version
+ {
+ static const auto color_text = ImGui::ColorConvertFloat4ToU32({ .8f, .8f, .8f, style.Alpha });
+ list->AddText(font_subtitle, 14, ImGui::GetCursorScreenPos(), color_text, this->version.c_str());
+ //if (this->downloadState.active)
+ {
+ const auto width_text = font_subtitle->CalcTextSizeA(14, FLT_MAX, 0.0f, this->description.c_str());
+ list->AddText(font_subtitle, 14, ImGui::GetCursorScreenPos() + ImVec2(ImGui::GetContentRegionAvail().x - width_text.x, 0), color_text, this->description.c_str());
+ }
+ ImGui::Dummy({ 0, 4 });
+ }
+
+ //if (this->display)
+ {
+ //static const auto color_background = ImGui::ColorConvertFloat4ToU32({ 1, 1, 1, 1 });
+ static const auto color_progress_downloading_background = ImColor::HSV(0 / 14.0f, 0.2f, 1.0f, 0.4f * style.Alpha);
+ static const auto color_progress_downloading = ImColor::HSV(0 / 14.0f, 0.4f, 1.0f, style.Alpha);
+
+ static const auto color_progress_background = ImColor::HSV(0.0f, 0.0f, 0.9f, style.Alpha);
+ // static const auto color_progress = ImColor::HSV(fmod( - 0.02f, 1.0f) / 14.0f, 0.0f, 1.0f, style.Alpha);
+
+
+ if (this->downloading)
+ {
+ //list->AddRectFilled(ImGui::GetItemRectMin(), ImGui::GetItemRectMax(), color_background, 5);
+ ImGui::Dummy({ 0, 0 });
+
+ //const auto pos = ImVec2(0, 0) + ImGui::GetWindowPos() + style.WindowPadding;
+ const auto pos = ImGui::GetCursorScreenPos();
+ const auto width_progress = (((width * this->progress) > (9.0f)) ? (width * this->progress) : (9.0f));
+
+
+ list->AddRectFilled(pos, pos + ImVec2(width, 9), color_progress_downloading_background, 5);
+ list->AddRectFilled(pos, pos + ImVec2(width_progress, 9), color_progress_downloading, 5);
+
+ ImGui::Dummy({ width, 9 });
+ }
+ else
+ {
+ // list->AddRectFilled(pos, pos + ImVec2(width, 9), color_progress_background, 5);
+ }
+ }
+
+ ImGui::Spacing();
+
+ {
+ if (this->update_available && !(*g_settings).getAppSettings().options.auto_update) {
+ ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0, 0, 0, 0.09f));
+ ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(0, 0, 0, 0.3f));
+ ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(0, 0, 0, 0.2f));
+ {
+ if (ImGui::Button("Update available", { ImGui::GetContentRegionAvail().x, 0 })) {
+ this->update();
+ }
+ ImGui::SetItemTooltip("Click to download an update");
+ }
+ ImGui::PopStyleColor(3);
+ }
+
+ if (ImGui::BeginPopupModal("updating", NULL, ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoDocking | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoBackground))
+ {
+ ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1, 1, 1, 1));
+ {
+ ImGui::Text("updating");
+ }
+ ImGui::PopStyleColor();
+ ImGui::EndPopup();
+ }
+ }
+
+
+
+ // ImGui::Text("DOWNLOADING APP UPDATE");
+
+ // ImGui::SeparatorText("downloading app update");
+
+ /*const auto pos = ImVec2(0, 0) + ImGui::GetWindowPos() + style.WindowPadding;
+
+ static const auto color_text = ImGui::ColorConvertFloat4ToU32(style.Colors[ImGuiCol_Text]);
+
+ list->AddRectFilled(pos, pos + ImVec2(width, 40), color_background, 5);
+
+ list->AddRectFilled(pos, pos + ImVec2(width, 9), color_progress_background, 5);
+ list->AddRectFilled(pos, pos + ImVec2(width_progress, 9), color_progress, 5);
+
+ list->AddText(pos + ImVec2(0, style.ItemSpacing.y), color_text, "DOWNLOADING APP UPDATE");*/
+
+ #ifdef _DEBUG
+ {
+ ImGui::Begin("debug");
+ if (ImGui::CollapsingHeader("update.h", ImGuiTreeNodeFlags_None))
+ {
+ ImGui::Checkbox("downloading", &(this->downloading));
+
+ ImGui::SliderFloat("progress", (&this->progress), 0.0f, 1.0f);
+ }
+
+
+ ImGui::End();
+ }
+ #endif
+
+}
\ No newline at end of file
diff --git a/dropship/dropship/src/managers/Update.h b/dropship/dropship/src/managers/Update.h
new file mode 100644
index 0000000..c5b81a4
--- /dev/null
+++ b/dropship/dropship/src/managers/Update.h
@@ -0,0 +1,62 @@
+#pragma once
+
+#include
+
+#include "managers/Settings.h"
+
+#include "util/sha512.hh"
+
+#include "util/win/win_download/download_file.h"
+
+// TODO use zoe and remove from project
+#include "util/win/win_download/download_txt.h"
+
+#include "util/trim.h"
+
+const std::string __UPDATE_VERSION_URI = "https://github.com/stowmyy/dropship/releases/latest/download/version.txt";
+const std::string __UPDATE_EXE_URI = "https://github.com/stowmyy/dropship/releases/latest/download/dropship.exe";
+
+//struct AppDownloadState
+//{
+// bool active; // is updating
+// bool downloading; // is currently downloading a file
+// float progress;
+// std::string status;
+// std::string appVersion;
+//};
+
+class Updater
+{
+ public:
+ Updater();
+ ~Updater();
+ void render(/* bool* p_open */);
+
+ private:
+
+ // todo
+ //inline static const char* __updating_popup_name { "#updating" };
+
+ //bool display;
+ bool downloading;
+ float progress;
+ std::string version;
+ std::string description;
+
+ bool update_available;
+
+
+ //AppDownloadState downloadState;
+ void getMeta();
+ bool checkForUpdate();
+ void update();
+
+ std::future update_future;
+ std::future version_future;
+
+ std::wstring __exe_path;
+ std::string __exe_hash;
+};
+
+//extern UpdateManager updateManager;
+
diff --git a/dropship/dropship/src/pch.cpp b/dropship/dropship/src/pch.cpp
new file mode 100644
index 0000000..1d9f38c
--- /dev/null
+++ b/dropship/dropship/src/pch.cpp
@@ -0,0 +1 @@
+#include "pch.h"
diff --git a/dropship/dropship/src/pch.h b/dropship/dropship/src/pch.h
new file mode 100644
index 0000000..41f1443
--- /dev/null
+++ b/dropship/dropship/src/pch.h
@@ -0,0 +1,43 @@
+#pragma once
+
+//#define _WIN32_WINNT = 0x0601
+
+#define half_pi 1.57079632679
+#define NOMINMAX
+
+#include
+using std::println;
+#include
+
+
+#include
+#include
+#include
+#include
+
+using namespace std::chrono_literals;
+
+
+// data structures
+#include
+#include
+#include
+
+// imgui
+#define IMGUI_DEFINE_MATH_OPERATORS // https://github.com/ocornut/imgui/issues/2832
+#include "imgui-docking/imgui.h"
+#include "imgui-docking/imgui_internal.h" // ClosePopupsOverWindow, pushitemflag, popitemflag
+
+// json
+#include "json/json.hpp"
+
+// Windows API
+# define WIN32_LEAN_AND_MEAN
+#include
+// TODO which one? for ccomptr
+#include
+//#include
+
+
+// util
+#include "util/timer/timer.h";
diff --git a/dropship/src/theme.cpp b/dropship/dropship/src/theme.cpp
similarity index 84%
rename from dropship/src/theme.cpp
rename to dropship/dropship/src/theme.cpp
index e994c2e..6eb4d35 100644
--- a/dropship/src/theme.cpp
+++ b/dropship/dropship/src/theme.cpp
@@ -1,6 +1,8 @@
+#include "pch.h"
+#define IMGUI_DEFINE_MATH_OPERATORS // https://github.com/ocornut/imgui/issues/2832
-# include "imgui.h"
+# include "imgui-docking/imgui.h"
# include "theme.h"
void setTheme(THEME theme)
@@ -60,11 +62,16 @@ void setTheme(THEME theme)
style.ItemSpacing = { 10, 10 };
- style.DisabledAlpha = 0.4;
+ style.DisabledAlpha = 0.4f;
+
+ //style.Colors[ImGuiCol_Button] = { 0, 0, 0, 0.8f };
+ //style.Colors[ImGuiCol_ButtonHovered] = { 0, 0, 0, 0.7f };
+ //style.Colors[ImGuiCol_ButtonActive] = { 0, 0, 0, 0.6f };
+
+ style.Colors[ImGuiCol_Button] = { 0, 0, 0, 0.09f };
+ style.Colors[ImGuiCol_ButtonHovered] = { 0, 0, 0, 0.14f };
+ style.Colors[ImGuiCol_ButtonActive] = { 0, 0, 0, 0.2f };
- style.Colors[ImGuiCol_Button] = { 0, 0, 0, 0.8f };
- style.Colors[ImGuiCol_ButtonHovered] = { 0, 0, 0, 0.7f };
- style.Colors[ImGuiCol_ButtonActive] = { 0, 0, 0, 0.6f };
if (theme == dark)
{
diff --git a/dropship/src/theme.h b/dropship/dropship/src/theme.h
similarity index 98%
rename from dropship/src/theme.h
rename to dropship/dropship/src/theme.h
index 6d63d6c..e5907d7 100644
--- a/dropship/src/theme.h
+++ b/dropship/dropship/src/theme.h
@@ -1,7 +1,5 @@
#pragma once
-#include "imgui_internal.h"
-
enum THEME {
dark,
diff --git a/dropship/dropship/src/util/color.h b/dropship/dropship/src/util/color.h
new file mode 100644
index 0000000..70f9022
--- /dev/null
+++ b/dropship/dropship/src/util/color.h
@@ -0,0 +1,3 @@
+#pragma once
+
+//static inline ImU32 color(int i);
diff --git a/dropship/dropship/src/util/ping/Pinger.cpp b/dropship/dropship/src/util/ping/Pinger.cpp
new file mode 100644
index 0000000..b487308
--- /dev/null
+++ b/dropship/dropship/src/util/ping/Pinger.cpp
@@ -0,0 +1,47 @@
+#include "pch.h"
+
+#include "Pinger.h"
+
+namespace util::ping {
+
+ Pinger::Pinger(std::string ip, std::unique_ptr> const& ping) :
+ io_context(std::make_unique()),
+ pinger(std::make_unique(*io_context.get(), ip.c_str(), ping)
+ ) {
+ /* this->ping() */
+ }
+
+ Pinger::~Pinger() {
+ }
+
+
+ void Pinger::start() {
+ try {
+ (*io_context).run();
+ }
+ catch (std::exception& e)
+ {
+ std::cerr << "Exception: " << e.what() << std::endl;
+ }
+ }
+
+ void Pinger::stop() {
+ try {
+ (*io_context).stop();
+ }
+ catch (std::exception& e)
+ {
+ std::cerr << "Exception: " << e.what() << std::endl;
+ }
+ }
+
+ void Pinger::ping() {
+ try {
+ (*io_context).run_one();
+ }
+ catch (std::exception& e)
+ {
+ std::cerr << "Exception: " << e.what() << std::endl;
+ }
+ }
+}
diff --git a/dropship/dropship/src/util/ping/Pinger.h b/dropship/dropship/src/util/ping/Pinger.h
new file mode 100644
index 0000000..e2adde8
--- /dev/null
+++ b/dropship/dropship/src/util/ping/Pinger.h
@@ -0,0 +1,23 @@
+#pragma once
+
+#include "asio/asio.h"
+
+namespace util::ping {
+
+ class Pinger
+ {
+ public:
+
+ Pinger(std::string ip, std::unique_ptr> const& ping);
+ ~Pinger();
+
+ void start();
+ void stop();
+
+ void ping();
+
+ private:
+ std::unique_ptr io_context;
+ std::unique_ptr pinger;
+ };
+}
\ No newline at end of file
diff --git a/dropship/dropship/src/util/ping/asio/asio.cpp b/dropship/dropship/src/util/ping/asio/asio.cpp
new file mode 100644
index 0000000..b8b481d
--- /dev/null
+++ b/dropship/dropship/src/util/ping/asio/asio.cpp
@@ -0,0 +1,117 @@
+#include "pch.h"
+
+#include "asio.h"
+
+AsioPinger::AsioPinger(asio::io_context& io_context, const char* destination, std::unique_ptr> const& ping)
+ : resolver_(io_context), socket_(io_context, icmp::v4()),
+ timer_(io_context), sequence_number_(0), num_replies_(0),
+
+ ping(ping)
+{
+ destination_ = *resolver_.resolve(icmp::v4(), destination, "").begin();
+
+ start_send();
+ start_receive();
+}
+
+void AsioPinger::start_send()
+{
+ std::string body("\"Hello!\" from Asio ping.");
+
+ // Create an ICMP header for an echo request.
+ icmp_header echo_request;
+ echo_request.type(icmp_header::echo_request);
+ echo_request.code(0);
+ echo_request.identifier(get_identifier());
+ echo_request.sequence_number(++sequence_number_);
+ compute_checksum(echo_request, body.begin(), body.end());
+
+ // Encode the request packet.
+ asio::streambuf request_buffer;
+ std::ostream os(&request_buffer);
+ os << echo_request << body;
+
+ // Send the request.
+ time_sent_ = steady_timer::clock_type::now();
+ socket_.send_to(request_buffer.data(), destination_);
+
+ // Wait up to five seconds for a reply.
+ num_replies_ = 0;
+ timer_.expires_at(time_sent_ + chrono::seconds(5));
+ timer_.async_wait(std::bind(&AsioPinger::handle_timeout, this));
+}
+
+void AsioPinger::handle_timeout()
+{
+ if (num_replies_ == 0)
+ {
+ //std::cout << "Request timed out" << std::endl;
+ *(this->ping) = std::optional{ -1 };
+ }
+
+ // Requests must be sent no less than one second apart.
+ timer_.expires_at(time_sent_ + chrono::seconds(4));
+ timer_.async_wait(std::bind(&AsioPinger::start_send, this));
+
+}
+
+void AsioPinger::start_receive()
+{
+ // Discard any data already in the buffer.
+ reply_buffer_.consume(reply_buffer_.size());
+
+ // Wait for a reply. We prepare the buffer to receive up to 64KB.
+ socket_.async_receive(reply_buffer_.prepare(65536),
+ std::bind(&AsioPinger::handle_receive, this, std::placeholders::_2));
+}
+
+void AsioPinger::handle_receive(std::size_t length)
+{
+ // The actual number of bytes received is committed to the buffer so that we
+ // can extract it using a std::istream object.
+ reply_buffer_.commit(length);
+
+ // Decode the reply packet.
+ std::istream is(&reply_buffer_);
+ ipv4_header ipv4_hdr;
+ icmp_header icmp_hdr;
+ is >> ipv4_hdr >> icmp_hdr;
+
+ // We can receive all ICMP packets received by the host, so we need to
+ // filter out only the echo replies that match the our identifier and
+ // expected sequence number.
+ if (is && icmp_hdr.type() == icmp_header::echo_reply
+ && icmp_hdr.identifier() == get_identifier()
+ && icmp_hdr.sequence_number() == sequence_number_)
+ {
+ // If this is the first reply, interrupt the five second timeout.
+ if (num_replies_++ == 0)
+ timer_.cancel();
+
+ // Print out some information about the reply packet.
+ chrono::steady_clock::time_point now = chrono::steady_clock::now();
+ chrono::steady_clock::duration elapsed = now - time_sent_;
+ auto ping = chrono::duration_cast(elapsed).count();
+ /*std::cout << length - ipv4_hdr.header_length()
+ << " bytes from " << ipv4_hdr.source_address()
+ << ": icmp_seq=" << icmp_hdr.sequence_number()
+ << ", ttl=" << ipv4_hdr.time_to_live()
+ << ", time="
+ << ping
+ << std::endl;*/
+
+ //*(this->ping) = ping;
+ *(this->ping) = std::optional{ ping };
+ }
+
+ start_receive();
+}
+
+unsigned short AsioPinger::get_identifier()
+{
+#if defined(ASIO_WINDOWS)
+ return static_cast(::GetCurrentProcessId());
+#else
+ return static_cast(::getpid());
+#endif
+}
diff --git a/dropship/dropship/src/util/ping/asio/asio.h b/dropship/dropship/src/util/ping/asio/asio.h
new file mode 100644
index 0000000..aee0e8b
--- /dev/null
+++ b/dropship/dropship/src/util/ping/asio/asio.h
@@ -0,0 +1,40 @@
+#pragma once
+
+#include
+#include
+#include
+#include
+
+#include "icmp_header.hpp"
+#include "ipv4_header.hpp"
+
+using asio::ip::icmp;
+using asio::steady_timer;
+namespace chrono = asio::chrono;
+
+class AsioPinger
+{
+public:
+ //AsioPinger(const AsioPinger&) = delete;
+ //AsioPinger& operator= (const AsioPinger&) = delete;
+
+ AsioPinger(asio::io_context& io_context, const char* destination, std::unique_ptr> const& ping);
+
+private:
+ void start_send();
+ void handle_timeout();
+ void start_receive();
+ void handle_receive(std::size_t length);
+ static unsigned short get_identifier();
+
+ icmp::resolver resolver_;
+ icmp::endpoint destination_;
+ icmp::socket socket_;
+ steady_timer timer_;
+ unsigned short sequence_number_;
+ chrono::steady_clock::time_point time_sent_;
+ asio::streambuf reply_buffer_;
+ std::size_t num_replies_;
+
+ std::unique_ptr> const& ping;
+};
diff --git a/dropship/dropship/src/util/ping/asio/icmp_header.hpp b/dropship/dropship/src/util/ping/asio/icmp_header.hpp
new file mode 100644
index 0000000..369511c
--- /dev/null
+++ b/dropship/dropship/src/util/ping/asio/icmp_header.hpp
@@ -0,0 +1,94 @@
+//
+// icmp_header.hpp
+// ~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ICMP_HEADER_HPP
+#define ICMP_HEADER_HPP
+
+#include
+#include
+#include
+
+// ICMP header for both IPv4 and IPv6.
+//
+// The wire format of an ICMP header is:
+//
+// 0 8 16 31
+// +---------------+---------------+------------------------------+ ---
+// | | | | ^
+// | type | code | checksum | |
+// | | | | |
+// +---------------+---------------+------------------------------+ 8 bytes
+// | | | |
+// | identifier | sequence number | |
+// | | | v
+// +-------------------------------+------------------------------+ ---
+
+class icmp_header
+{
+public:
+ enum { echo_reply = 0, destination_unreachable = 3, source_quench = 4,
+ redirect = 5, echo_request = 8, time_exceeded = 11, parameter_problem = 12,
+ timestamp_request = 13, timestamp_reply = 14, info_request = 15,
+ info_reply = 16, address_request = 17, address_reply = 18 };
+
+ icmp_header() { std::fill(rep_, rep_ + sizeof(rep_), 0); }
+
+ unsigned char type() const { return rep_[0]; }
+ unsigned char code() const { return rep_[1]; }
+ unsigned short checksum() const { return decode(2, 3); }
+ unsigned short identifier() const { return decode(4, 5); }
+ unsigned short sequence_number() const { return decode(6, 7); }
+
+ void type(unsigned char n) { rep_[0] = n; }
+ void code(unsigned char n) { rep_[1] = n; }
+ void checksum(unsigned short n) { encode(2, 3, n); }
+ void identifier(unsigned short n) { encode(4, 5, n); }
+ void sequence_number(unsigned short n) { encode(6, 7, n); }
+
+ friend std::istream& operator>>(std::istream& is, icmp_header& header)
+ { return is.read(reinterpret_cast(header.rep_), 8); }
+
+ friend std::ostream& operator<<(std::ostream& os, const icmp_header& header)
+ { return os.write(reinterpret_cast(header.rep_), 8); }
+
+private:
+ unsigned short decode(int a, int b) const
+ { return (rep_[a] << 8) + rep_[b]; }
+
+ void encode(int a, int b, unsigned short n)
+ {
+ rep_[a] = static_cast(n >> 8);
+ rep_[b] = static_cast(n & 0xFF);
+ }
+
+ unsigned char rep_[8];
+};
+
+template
+void compute_checksum(icmp_header& header,
+ Iterator body_begin, Iterator body_end)
+{
+ unsigned int sum = (header.type() << 8) + header.code()
+ + header.identifier() + header.sequence_number();
+
+ Iterator body_iter = body_begin;
+ while (body_iter != body_end)
+ {
+ sum += (static_cast(*body_iter++) << 8);
+ if (body_iter != body_end)
+ sum += static_cast(*body_iter++);
+ }
+
+ sum = (sum >> 16) + (sum & 0xFFFF);
+ sum += (sum >> 16);
+ header.checksum(static_cast(~sum));
+}
+
+#endif // ICMP_HEADER_HPP
diff --git a/dropship/dropship/src/util/ping/asio/ipv4_header.hpp b/dropship/dropship/src/util/ping/asio/ipv4_header.hpp
new file mode 100644
index 0000000..c1fd30f
--- /dev/null
+++ b/dropship/dropship/src/util/ping/asio/ipv4_header.hpp
@@ -0,0 +1,102 @@
+//
+// ipv4_header.hpp
+// ~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef IPV4_HEADER_HPP
+#define IPV4_HEADER_HPP
+
+#include
+#include
+
+// Packet header for IPv4.
+//
+// The wire format of an IPv4 header is:
+//
+// 0 8 16 31
+// +-------+-------+---------------+------------------------------+ ---
+// | | | | | ^
+// |version|header | type of | total length in bytes | |
+// | (4) | length| service | | |
+// +-------+-------+---------------+-+-+-+------------------------+ |
+// | | | | | | |
+// | identification |0|D|M| fragment offset | |
+// | | |F|F| | |
+// +---------------+---------------+-+-+-+------------------------+ |
+// | | | | |
+// | time to live | protocol | header checksum | 20 bytes
+// | | | | |
+// +---------------+---------------+------------------------------+ |
+// | | |
+// | source IPv4 address | |
+// | | |
+// +--------------------------------------------------------------+ |
+// | | |
+// | destination IPv4 address | |
+// | | v
+// +--------------------------------------------------------------+ ---
+// | | ^
+// | | |
+// / options (if any) / 0 - 40
+// / / bytes
+// | | |
+// | | v
+// +--------------------------------------------------------------+ ---
+
+class ipv4_header
+{
+public:
+ ipv4_header() { std::fill(rep_, rep_ + sizeof(rep_), 0); }
+
+ unsigned char version() const { return (rep_[0] >> 4) & 0xF; }
+ unsigned short header_length() const { return (rep_[0] & 0xF) * 4; }
+ unsigned char type_of_service() const { return rep_[1]; }
+ unsigned short total_length() const { return decode(2, 3); }
+ unsigned short identification() const { return decode(4, 5); }
+ bool dont_fragment() const { return (rep_[6] & 0x40) != 0; }
+ bool more_fragments() const { return (rep_[6] & 0x20) != 0; }
+ unsigned short fragment_offset() const { return decode(6, 7) & 0x1FFF; }
+ unsigned int time_to_live() const { return rep_[8]; }
+ unsigned char protocol() const { return rep_[9]; }
+ unsigned short header_checksum() const { return decode(10, 11); }
+
+ asio::ip::address_v4 source_address() const
+ {
+ asio::ip::address_v4::bytes_type bytes
+ = { { rep_[12], rep_[13], rep_[14], rep_[15] } };
+ return asio::ip::address_v4(bytes);
+ }
+
+ asio::ip::address_v4 destination_address() const
+ {
+ asio::ip::address_v4::bytes_type bytes
+ = { { rep_[16], rep_[17], rep_[18], rep_[19] } };
+ return asio::ip::address_v4(bytes);
+ }
+
+ friend std::istream& operator>>(std::istream& is, ipv4_header& header)
+ {
+ is.read(reinterpret_cast(header.rep_), 20);
+ if (header.version() != 4)
+ is.setstate(std::ios::failbit);
+ std::streamsize options_length = header.header_length() - 20;
+ if (options_length < 0 || options_length > 40)
+ is.setstate(std::ios::failbit);
+ else
+ is.read(reinterpret_cast(header.rep_) + 20, options_length);
+ return is;
+ }
+
+private:
+ unsigned short decode(int a, int b) const
+ { return (rep_[a] << 8) + rep_[b]; }
+
+ unsigned char rep_[60];
+};
+
+#endif // IPV4_HEADER_HPP
diff --git a/dropship/dropship/src/util/ping/asio/ping.cpp b/dropship/dropship/src/util/ping/asio/ping.cpp
new file mode 100644
index 0000000..6b3f230
--- /dev/null
+++ b/dropship/dropship/src/util/ping/asio/ping.cpp
@@ -0,0 +1,160 @@
+//
+// ping.cpp
+// ~~~~~~~~
+//
+// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+#include
+#include
+#include
+#include
+
+#include "icmp_header.hpp"
+#include "ipv4_header.hpp"
+
+using asio::ip::icmp;
+using asio::steady_timer;
+namespace chrono = asio::chrono;
+
+class pinger
+{
+public:
+ pinger(asio::io_context& io_context, const char* destination)
+ : resolver_(io_context), socket_(io_context, icmp::v4()),
+ timer_(io_context), sequence_number_(0), num_replies_(0)
+ {
+ destination_ = *resolver_.resolve(icmp::v4(), destination, "").begin();
+
+ start_send();
+ start_receive();
+ }
+
+private:
+ void start_send()
+ {
+ std::string body("\"Hello!\" from Asio ping.");
+
+ // Create an ICMP header for an echo request.
+ icmp_header echo_request;
+ echo_request.type(icmp_header::echo_request);
+ echo_request.code(0);
+ echo_request.identifier(get_identifier());
+ echo_request.sequence_number(++sequence_number_);
+ compute_checksum(echo_request, body.begin(), body.end());
+
+ // Encode the request packet.
+ asio::streambuf request_buffer;
+ std::ostream os(&request_buffer);
+ os << echo_request << body;
+
+ // Send the request.
+ time_sent_ = steady_timer::clock_type::now();
+ socket_.send_to(request_buffer.data(), destination_);
+
+ // Wait up to five seconds for a reply.
+ num_replies_ = 0;
+ timer_.expires_at(time_sent_ + chrono::seconds(5));
+ timer_.async_wait(std::bind(&pinger::handle_timeout, this));
+ }
+
+ void handle_timeout()
+ {
+ if (num_replies_ == 0)
+ std::cout << "Request timed out" << std::endl;
+
+ // Requests must be sent no less than one second apart.
+ timer_.expires_at(time_sent_ + chrono::seconds(1));
+ timer_.async_wait(std::bind(&pinger::start_send, this));
+ }
+
+ void start_receive()
+ {
+ // Discard any data already in the buffer.
+ reply_buffer_.consume(reply_buffer_.size());
+
+ // Wait for a reply. We prepare the buffer to receive up to 64KB.
+ socket_.async_receive(reply_buffer_.prepare(65536),
+ std::bind(&pinger::handle_receive, this, std::placeholders::_2));
+ }
+
+ void handle_receive(std::size_t length)
+ {
+ // The actual number of bytes received is committed to the buffer so that we
+ // can extract it using a std::istream object.
+ reply_buffer_.commit(length);
+
+ // Decode the reply packet.
+ std::istream is(&reply_buffer_);
+ ipv4_header ipv4_hdr;
+ icmp_header icmp_hdr;
+ is >> ipv4_hdr >> icmp_hdr;
+
+ // We can receive all ICMP packets received by the host, so we need to
+ // filter out only the echo replies that match the our identifier and
+ // expected sequence number.
+ if (is && icmp_hdr.type() == icmp_header::echo_reply
+ && icmp_hdr.identifier() == get_identifier()
+ && icmp_hdr.sequence_number() == sequence_number_)
+ {
+ // If this is the first reply, interrupt the five second timeout.
+ if (num_replies_++ == 0)
+ timer_.cancel();
+
+ // Print out some information about the reply packet.
+ chrono::steady_clock::time_point now = chrono::steady_clock::now();
+ chrono::steady_clock::duration elapsed = now - time_sent_;
+ std::cout << length - ipv4_hdr.header_length()
+ << " bytes from " << ipv4_hdr.source_address()
+ << ": icmp_seq=" << icmp_hdr.sequence_number()
+ << ", ttl=" << ipv4_hdr.time_to_live()
+ << ", time="
+ << chrono::duration_cast(elapsed).count()
+ << std::endl;
+ }
+
+ start_receive();
+ }
+
+ static unsigned short get_identifier()
+ {
+#if defined(ASIO_WINDOWS)
+ return static_cast(::GetCurrentProcessId());
+#else
+ return static_cast(::getpid());
+#endif
+ }
+
+ icmp::resolver resolver_;
+ icmp::endpoint destination_;
+ icmp::socket socket_;
+ steady_timer timer_;
+ unsigned short sequence_number_;
+ chrono::steady_clock::time_point time_sent_;
+ asio::streambuf reply_buffer_;
+ std::size_t num_replies_;
+};
+
+int main(int argc, char* argv[])
+{
+ try
+ {
+ if (argc != 2)
+ {
+ std::cerr << "Usage: ping " << std::endl;
+#if !defined(ASIO_WINDOWS)
+ std::cerr << "(You may need to run this program as root.)" << std::endl;
+#endif
+ return 1;
+ }
+
+ asio::io_context io_context;
+ pinger p(io_context, argv[1]);
+ io_context.run();
+ }
+ catch (std::exception& e)
+ {
+ std::cerr << "Exception: " << e.what() << std::endl;
+ }
+}
diff --git a/dropship/dropship/src/util/ping/tcp.hpp b/dropship/dropship/src/util/ping/tcp.hpp
new file mode 100644
index 0000000..6310606
--- /dev/null
+++ b/dropship/dropship/src/util/ping/tcp.hpp
@@ -0,0 +1,64 @@
+#pragma once
+
+#include
+#include
+
+#include "../vendor/clsocket/ActiveSocket.h" // Include header for active socket object definition
+
+
+std::optional _tcp_ping(std::string destination, uint16 port, CSimpleSocket::CSocketType type = CSimpleSocket::SocketTypeTcp) {
+ CActiveSocket socket(type); // Instantiate active socket object (defaults to TCP).
+ char time[50];
+
+ memset(&time, 0, 50);
+
+ //--------------------------------------------------------------------------
+ // Initialize our socket object
+ //--------------------------------------------------------------------------
+ socket.Initialize();
+
+
+ std::chrono::time_point start = std::chrono::steady_clock::now();
+
+
+ //--------------------------------------------------------------------------
+ // Create a connection to the time server so that data can be sent
+ // and received.
+ //--------------------------------------------------------------------------
+ if (socket.Open(destination.c_str(), port))
+ {
+ //----------------------------------------------------------------------
+ // Send a requtest the server requesting the current time.
+ //----------------------------------------------------------------------
+
+ const auto ping = "Ping : Request (8)\n";
+ if (socket.Send((const uint8*) ping, sizeof(ping)))
+ {
+ //----------------------------------------------------------------------
+ // Receive response from the server.
+ //----------------------------------------------------------------------
+ socket.Receive(32);
+ memcpy(&time, socket.GetData(), 28);
+ printf("%s\n", time);
+
+ //----------------------------------------------------------------------
+ // Close the connection.
+ //----------------------------------------------------------------------
+ socket.Close();
+
+ std::chrono::time_point end = std::chrono::steady_clock::now();
+ std::chrono::milliseconds diff = std::chrono::duration_cast(end - start);
+
+ return std::optional{ (int)diff.count() };
+ }
+
+
+ socket.Receive();
+ printf("\nno\n");
+
+
+ //return std::optional{ socket.GetTotalTimeMs() };
+ }
+
+ return std::nullopt;
+}
\ No newline at end of file
diff --git a/dropship/src/sha512.hh b/dropship/dropship/src/util/sha512.hh
similarity index 100%
rename from dropship/src/sha512.hh
rename to dropship/dropship/src/util/sha512.hh
diff --git a/dropship/dropship/src/util/timer/timer.cpp b/dropship/dropship/src/util/timer/timer.cpp
new file mode 100644
index 0000000..6ff6952
--- /dev/null
+++ b/dropship/dropship/src/util/timer/timer.cpp
@@ -0,0 +1,36 @@
+#include "pch.h"
+
+#include "timer.h"
+
+
+namespace util::timer {
+
+ Timer::Timer(const char* name):
+ _name(name),
+ _stopped(false)
+ {
+ this->_start_time_point = std::chrono::high_resolution_clock::now();
+ }
+
+ Timer::~Timer() {
+ if (!this->_stopped)
+ {
+ this->stop();
+ }
+ }
+
+ void Timer::stop() {
+ auto end_time_point = std::chrono::high_resolution_clock::now();
+
+ this->_stopped = true;
+
+ //auto duration = duration_cast(end_time_point - this->_start_time_point);
+ auto duration = duration_cast(end_time_point - this->_start_time_point).count() * 0.001f;
+
+ // web https://stackoverflow.com/a/54062826
+
+ println("\x1B[33mduration \x1B[93m{}\x1B[33m: \x1B[93m{:.2f}ms\033[0m", this->_name, duration);
+
+ }
+
+}
diff --git a/dropship/dropship/src/util/timer/timer.h b/dropship/dropship/src/util/timer/timer.h
new file mode 100644
index 0000000..bbb11e4
--- /dev/null
+++ b/dropship/dropship/src/util/timer/timer.h
@@ -0,0 +1,32 @@
+#pragma once
+
+// web https://youtu.be/YbYV8rRo9_A?t=606
+
+
+#ifdef _DEBUG
+ #include "managers/Debug.h"
+#endif
+
+
+namespace util::timer {
+
+ /*struct ProfileResult {
+ const char* name;
+ float duration_ms;
+ };*/
+
+ class Timer {
+
+ public:
+ Timer(const char* name);
+ ~Timer();
+
+ void stop();
+
+ private:
+ const char* _name;
+ std::chrono::time_point _start_time_point;
+ bool _stopped;
+ };
+
+}
diff --git a/dropship/dropship/src/util/trim.h b/dropship/dropship/src/util/trim.h
new file mode 100644
index 0000000..983c5ff
--- /dev/null
+++ b/dropship/dropship/src/util/trim.h
@@ -0,0 +1,45 @@
+#pragma once
+
+// web https://stackoverflow.com/questions/216823/how-to-trim-a-stdstring
+
+#include
+#include
+#include
+
+// trim from start (in place)
+inline void ltrim(std::string& s) {
+ s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](unsigned char ch) {
+ return !std::isspace(ch);
+ }));
+}
+
+// trim from end (in place)
+inline void rtrim(std::string& s) {
+ s.erase(std::find_if(s.rbegin(), s.rend(), [](unsigned char ch) {
+ return !std::isspace(ch);
+ }).base(), s.end());
+}
+
+// trim from both ends (in place)
+inline void trim(std::string& s) {
+ rtrim(s);
+ ltrim(s);
+}
+
+// trim from start (copying)
+inline std::string ltrim_copy(std::string s) {
+ ltrim(s);
+ return s;
+}
+
+// trim from end (copying)
+inline std::string rtrim_copy(std::string s) {
+ rtrim(s);
+ return s;
+}
+
+// trim from both ends (copying)
+inline std::string trim_copy(std::string s) {
+ trim(s);
+ return s;
+}
diff --git a/dropship/dropship/src/util/watcher/process.cpp b/dropship/dropship/src/util/watcher/process.cpp
new file mode 100644
index 0000000..5e8264a
--- /dev/null
+++ b/dropship/dropship/src/util/watcher/process.cpp
@@ -0,0 +1,55 @@
+#include "pch.h"
+
+#include "process.h"
+
+
+
+/**
+ * gets the bitmap data for a module icon from a running process
+ *
+ * @param processId id of process to examine
+ * @param module within process `processId` to extract icon from executable
+ * @return int process id. returns 0 if not found
+ */
+int find_process(std::wstring procname)
+{
+
+ /*
+ FIND A PROCESS WITH NAME
+ @https://cocomelonc.github.io/pentest/2021/09/29/findmyprocess.html
+
+ - ..
+ */
+ HANDLE hSnapshot;
+ PROCESSENTRY32 pe;
+ int pid = 0;
+ BOOL hResult;
+
+ // snapshot of all processes in the system
+ hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
+ if (INVALID_HANDLE_VALUE == hSnapshot) return 0;
+
+ // initializing size: needed for using Process32First
+ pe.dwSize = sizeof(PROCESSENTRY32);
+
+ // info about first process encountered in a system snapshot
+ hResult = Process32First(hSnapshot, &pe);
+
+ // retrieve information about the processes
+ // and exit if unsuccessful
+ while (hResult) {
+ // if we find the process: return process ID
+
+ // std::wcout << pe.szExeFile << L" != " << procname.c_str() << std::endl;
+
+ if (wcscmp(procname.c_str(), pe.szExeFile) == 0) {
+ pid = pe.th32ProcessID;
+ break;
+ }
+ hResult = Process32Next(hSnapshot, &pe);
+ }
+
+ // closes an open handle (CreateToolhelp32Snapshot)
+ CloseHandle(hSnapshot);
+ return pid;
+}
diff --git a/dropship/dropship/src/util/watcher/process.h b/dropship/dropship/src/util/watcher/process.h
new file mode 100644
index 0000000..bed50c6
--- /dev/null
+++ b/dropship/dropship/src/util/watcher/process.h
@@ -0,0 +1,6 @@
+#pragma once
+
+#include // find_process
+
+int find_process(std::string procname);
+
diff --git a/dropship/dropship/src/util/watcher/window.cpp b/dropship/dropship/src/util/watcher/window.cpp
new file mode 100644
index 0000000..2f80c11
--- /dev/null
+++ b/dropship/dropship/src/util/watcher/window.cpp
@@ -0,0 +1,149 @@
+#include "pch.h"
+
+#include "window.h"
+
+/* functional */
+namespace util::watcher::window {
+ std::optional<::HWND> findWindow(std::string& window_name) {
+ std::optional<::HWND> match = std::nullopt;
+
+ for (::HWND hwnd = ::GetTopWindow(NULL); hwnd != NULL; hwnd = GetNextWindow(hwnd, GW_HWNDNEXT)) {
+ int length = GetWindowTextLength(hwnd);
+ if (length == 0) continue;
+
+ char* title = new char[length + 1];
+ {
+ ::GetWindowTextA(hwnd, title, length + 1);
+
+ if (strcmp(title, window_name.c_str()) == 0)
+ {
+ // std::cout << "HWND: " << hwnd << " Title: " << s_title << std::endl;
+ match = std::make_optional<::HWND>(hwnd);
+ break;
+ }
+ }
+ delete[] title;
+ }
+
+ return match;
+ }
+
+ bool isWindowOpen(std::string& window_name) {
+ auto window = findWindow(window_name);
+ return window && ::IsWindow(window.value());
+ }
+}
+
+namespace util::watcher::window {
+
+ WindowWatcher::WindowWatcher(std::string window_name) :
+ _window_name(window_name)
+ {
+ this->start();
+ }
+
+ WindowWatcher::~WindowWatcher() {
+ this->stop();
+ }
+
+ bool WindowWatcher::isActive() { return this->_window_open; }
+
+ void WindowWatcher::stop() {
+ this->_watching = false;
+ this->__watcher_future_condition_variable.notify_all();
+ if (this->_watcher_future.valid()) this->_watcher_future.get();
+ }
+
+ void WindowWatcher::start() {
+ this->_watching = true;
+
+ this->_watcher_future = std::async(std::launch::async, [this] {
+ try {
+ while (this->_watching) {
+
+ auto open = util::watcher::window::isWindowOpen(this->_window_name);
+ if (this->_window_open != open) {
+ this->_window_open = open;
+ }
+
+ std::unique_lock lock(this->__watcher_future_condition_variable_mutex);
+ /* alternative: extra condition on notify
+ *
+ if (cv.wait_for(lk, watcher_delay, [this] { return !this->watching; }))
+ {
+ println("early exit");
+ }
+ else
+ {
+ println("no early exit");
+ }
+ */
+
+ /* wait for notification
+ *
+ auto res = cv.wait_for(lk, this->watcher_delay);
+ if (res == std::cv_status::timeout) {
+ println("no early exit");
+ }
+ else if (res == std::cv_status::no_timeout) {
+ println("early exit");
+ }
+ */
+ //this->__watcher_future_condition_variable.wait_for(lock, this->watcher_delay);
+ this->__watcher_future_condition_variable.wait_for(lock, watcher_delay, [this] { return !this->_watching; });
+ }
+ }
+ catch (const std::exception& e)
+ {
+ std::println("watcher error: {}", e.what());
+ this->stop();
+ // todo notify
+ }
+ catch (...)
+ {
+ std::println("watcher error: {}", "unknown");
+ this->stop();
+ // todo notify
+ }
+ });
+ }
+}
+
+/*
+ bool __previous__application_open = appStore.application_open;
+
+ static const std::string process_name = "Overwatch.exe";
+ static const std::string module_name = "Overwatch.exe";
+
+ int pid = find_process(process_name);
+ HWND window = find_window("Overwatch");
+
+ appStore.application_open = window;
+ this->processes["Overwatch.exe"].on = window;
+ this->processes["Overwatch.exe"].window = window;
+
+ if (__previous__application_open && !appStore.application_open)
+ {
+ // V2 COMMENTED
+ std::jthread([&]() {
+ firewallManager.sync(&(this->endpoints));
+ }).detach();
+
+ appStore.dashboard.heading = __default__appStore.dashboard.heading;
+
+ this->game_restart_required = false;
+ }
+
+ if (!__previous__application_open && appStore.application_open)
+ {
+ // appStore.dashboard.heading = "Blocking new servers won't take effect until Overwatch is restarted.";
+ }
+
+ if (this->processes[process_name].icon.texture == nullptr)
+ {
+ // just prints stuff for now
+ get_module(pid, module_name);
+
+ loadPicture("process_icon_overwatch", "png", &(this->processes[process_name].icon.texture), &(this->processes[process_name].icon.width), &(this->processes[process_name].icon.height));
+ }
+*/
diff --git a/dropship/dropship/src/util/watcher/window.h b/dropship/dropship/src/util/watcher/window.h
new file mode 100644
index 0000000..fa9291d
--- /dev/null
+++ b/dropship/dropship/src/util/watcher/window.h
@@ -0,0 +1,38 @@
+#pragma once
+
+#include // IsWindow()
+
+namespace util::watcher::window {
+
+ /* functional */
+ std::optional findWindow(std::string& window_name);
+ bool isWindowOpen();
+
+ /* class */
+ class WindowWatcher
+ {
+ /* consts */
+ private:
+ static constexpr auto watcher_delay = 900ms;
+
+ public:
+ WindowWatcher(std::string window_name);
+ ~WindowWatcher();
+ bool isActive();
+
+ private:
+ void start();
+ void stop();
+
+ private:
+ std::string _window_name;
+
+ bool _window_open { false };
+ bool _watching;
+
+ /* worker */
+ std::future _watcher_future;
+ std::mutex __watcher_future_condition_variable_mutex;
+ std::condition_variable __watcher_future_condition_variable;
+ };
+}
diff --git a/dropship/dropship/src/util/win/win_download/download_file.cpp b/dropship/dropship/src/util/win/win_download/download_file.cpp
new file mode 100644
index 0000000..3fe80ad
--- /dev/null
+++ b/dropship/dropship/src/util/win/win_download/download_file.cpp
@@ -0,0 +1,74 @@
+#include "pch.h"
+
+#include "download_file.h"
+
+
+namespace util::win_download {
+
+ void download_file(std::string uri, std::string filename, float* progress, std::string* data, std::filesystem::path* path)
+ {
+ std::filesystem::path _path = std::filesystem::temp_directory_path().append("dropship");
+
+ if (!std::filesystem::is_directory(_path) || !std::filesystem::exists(_path)) {
+ std::filesystem::create_directory(_path);
+ }
+
+ _path.append(filename);
+
+ if (std::filesystem::exists(_path))
+ std::filesystem::remove(_path);
+
+ std::string _path_name = _path.string();
+
+ DeleteUrlCacheEntryA(_path_name.c_str());
+
+ printf("downloading: %s\n", _path_name.c_str());
+
+ _downloading _progress(progress);
+ if (URLDownloadToFileA(NULL, uri.c_str(), _path_name.c_str(), 0, &_progress) != S_OK)
+ {
+ printf("download failed\n");
+ throw DownloadException("download failed");
+ }
+ else
+ {
+ printf("download worked\n");
+
+ if (data != nullptr)
+ {
+
+ *data = get_file_contents(_path_name.c_str());
+ }
+
+ if (path != nullptr)
+ {
+ *path = _path;
+ }
+
+ // std::filesystem::hash_value
+
+ //system(std::format("Get-FileHash {0} -Algorithm SHA512 | Select-Object -ExpandProperty Hash | Out-File {1}.comp", filePath.string(), filePath.string()).c_str());
+
+ //std::filesystem::
+ }
+ }
+
+
+ std::string get_file_contents(const char* filename) {
+ /*std::ifstream in(filename, std::ios::in | std::ios::binary);
+ if (in)
+ {
+ return(std::string((std::istreambuf_iterator(in)), std::istreambuf_iterator()));
+ }*/
+
+ std::string s; //string
+ std::fstream f; //file stream
+ f.open(filename); //open your word list
+ std::getline(f, s); //get line from f (your word list) and put it in s (the string)
+
+ f.close();
+
+ return s;
+ }
+
+}
diff --git a/dropship/dropship/src/util/win/win_download/download_file.h b/dropship/dropship/src/util/win/win_download/download_file.h
new file mode 100644
index 0000000..0da5909
--- /dev/null
+++ b/dropship/dropship/src/util/win/win_download/download_file.h
@@ -0,0 +1,132 @@
+#pragma once
+
+#include
+
+#include // must be included before hack.h as SAL annotations
+#include // collide with GCC's standard library implmentation
+
+#include // collide with GCC's standard library implmentation
+
+#include "urlmon.h" // copied into project folder (from Windows SDK)
+// along with the import library and an empty "msxml.h" file
+
+
+#pragma comment( lib, "urlmon.lib" )
+#pragma comment(lib, "wininet.Lib" )
+
+//IBindStatusCallback _downloading()
+
+#include // MinGW does provide this (needed for DeleteUrlCacheEntry)
+#include
+#include
+
+#pragma comment (lib, "urlmon.lib")
+
+#include
+#include
+
+namespace util::win_download {
+
+ void download_file(std::string uri, std::string filename, float* progress, std::string* data = nullptr, std::filesystem::path* path = nullptr);
+
+ std::string get_file_contents(const char* filename);
+
+ namespace {
+
+ class DownloadException : public std::exception {
+ private:
+ std::string message;
+
+ public:
+ DownloadException(const char* msg)
+ : message(msg)
+ {
+ }
+
+ // Override the what() method to return our message
+ const char* what() const throw()
+ {
+ return message.c_str();
+ }
+ };
+
+
+ class _downloading : public IBindStatusCallback
+ {
+ private:
+ //float download_progress = 0.0f; // 0.0f = 1.0f
+
+ float* p_progress = nullptr;
+
+ public:
+ _downloading(float* progress) : p_progress(progress) {}
+
+ ~_downloading() { }
+
+ // This one is called by URLDownloadToFile
+ STDMETHOD(OnProgress)(/* [in] */ ULONG ulProgress, /* [in] */ ULONG ulProgressMax, /* [in] */ ULONG ulStatusCode, /* [in] */ LPCWSTR wszStatusText)
+ {
+ std::cout << "Downloaded " << ulProgress << " of " << ulProgressMax << " byte(s), " << " Status Code = " << ulStatusCode << std::endl;
+
+ if (ulProgressMax > 0)
+ {
+ *(this->p_progress) = (float)((double)ulProgress / (double)ulProgressMax);
+ }
+
+ return S_OK;
+ }
+
+ // The rest don't do anything...
+ STDMETHOD(OnStartBinding)(/* [in] */ DWORD dwReserved, /* [in] */ IBinding __RPC_FAR* pib)
+ {
+ return E_NOTIMPL;
+ }
+
+ STDMETHOD(GetPriority)(/* [out] */ LONG __RPC_FAR* pnPriority)
+ {
+ return E_NOTIMPL;
+ }
+
+ STDMETHOD(OnLowResource)(/* [in] */ DWORD reserved)
+ {
+ return E_NOTIMPL;
+ }
+
+ STDMETHOD(OnStopBinding)(/* [in] */ HRESULT hresult, /* [unique][in] */ LPCWSTR szError)
+ {
+ return E_NOTIMPL;
+ }
+
+ STDMETHOD(GetBindInfo)(/* [out] */ DWORD __RPC_FAR* grfBINDF, /* [unique][out][in] */ BINDINFO __RPC_FAR* pbindinfo)
+ {
+ return E_NOTIMPL;
+ }
+
+ STDMETHOD(OnDataAvailable)(/* [in] */ DWORD grfBSCF, /* [in] */ DWORD dwSize, /* [in] */ FORMATETC __RPC_FAR* pformatetc, /* [in] */ STGMEDIUM __RPC_FAR* pstgmed)
+ {
+ return E_NOTIMPL;
+ }
+
+ STDMETHOD(OnObjectAvailable)(/* [in] */ REFIID riid, /* [iid_is][in] */ IUnknown __RPC_FAR* punk)
+ {
+ return E_NOTIMPL;
+ }
+
+ // IUnknown stuff
+ STDMETHOD_(ULONG, AddRef)()
+ {
+ return 0;
+ }
+
+ STDMETHOD_(ULONG, Release)()
+ {
+ return 0;
+ }
+
+ STDMETHOD(QueryInterface)(/* [in] */ REFIID riid, /* [iid_is][out] */ void __RPC_FAR* __RPC_FAR* ppvObject)
+ {
+ return E_NOTIMPL;
+ }
+ };
+ }
+}
diff --git a/dropship/dropship/src/util/win/win_download/download_text.cpp b/dropship/dropship/src/util/win/win_download/download_text.cpp
new file mode 100644
index 0000000..823a539
--- /dev/null
+++ b/dropship/dropship/src/util/win/win_download/download_text.cpp
@@ -0,0 +1,61 @@
+#include "pch.h"
+
+#include "download_txt.h"
+
+namespace util::win_download {
+
+
+ namespace {
+ struct ComInit
+ {
+ HRESULT hr;
+ ComInit() : hr(::CoInitialize(nullptr)) {}
+ ~ComInit() { if (SUCCEEDED(hr)) ::CoUninitialize(); }
+ };
+ }
+
+
+ std::string _download_txt(std::string _uri) {
+
+ std::string _result;
+
+ //std::wstring uri = __string_to_LPCWSTR(_uri);
+ std::wstring uri = std::wstring(_uri.begin(), _uri.end());
+
+ ComInit init;
+
+ // use CComPtr so you don't have to manually call Release()
+ CComPtr pStream;
+
+ // Open the HTTP request.
+ HRESULT hr = URLOpenBlockingStreamW(nullptr, uri.c_str(), &pStream, 0, nullptr);
+ if (FAILED(hr))
+ {
+ //std::cout << "ERROR: Could not connect. HRESULT: 0x" << std::hex << hr << std::dec << "\n";
+ throw std::runtime_error("could not connect");
+ }
+
+ // Download the response and write it to stdout.
+ char buffer[4096];
+ do
+ {
+ DWORD bytesRead = 0;
+ hr = pStream->Read(buffer, sizeof(buffer), &bytesRead);
+
+ if (bytesRead > 0)
+ {
+ //std::cout.write(buffer, bytesRead);
+ _result.append(buffer, bytesRead);
+ }
+ } while (SUCCEEDED(hr) && hr != S_FALSE);
+
+ if (FAILED(hr))
+ {
+ //std::cout << "ERROR: Download failed. HRESULT: 0x" << std::hex << hr << std::dec << "\n";
+ throw std::runtime_error("download failed");
+ }
+
+ return _result;
+ };
+
+}
diff --git a/dropship/dropship/src/util/win/win_download/download_txt.h b/dropship/dropship/src/util/win/win_download/download_txt.h
new file mode 100644
index 0000000..74ba96f
--- /dev/null
+++ b/dropship/dropship/src/util/win/win_download/download_txt.h
@@ -0,0 +1,29 @@
+#pragma once
+
+// web https://stackoverflow.com/a/44029974
+// web https://github.com/elddy/Windows-NTAPI-Injector/blob/c4f545e27a885bc7d53c4dc303eaab80f2d1d803/NativeInjection/Download_shellcode.h
+
+#include
+#include // URLOpenBlockingStreamW()
+//#include // CComPtr
+//#include
+#pragma comment( lib, "Urlmon.lib" )
+
+#include
+#include
+
+/* // web https://www.geeksforgeeks.org/convert-stdstring-to-lpcwstr-in-c/
+inline LPCWSTR __string_to_LPCWSTR(std::string s) {
+ // Initializing an object of wstring
+ std::wstring ws = std::wstring(s.begin(), s.end());
+
+ // Applying c_str() method on temp
+ LPCWSTR wideString = ws.c_str();
+ return wideString;
+} */
+
+namespace util::win_download {
+
+ std::string _download_txt(std::string _uri);
+
+}
diff --git a/dropship/dropship/src/util/win/win_firewall/windows_firewall.cpp b/dropship/dropship/src/util/win/win_firewall/windows_firewall.cpp
new file mode 100644
index 0000000..9b47ccd
--- /dev/null
+++ b/dropship/dropship/src/util/win/win_firewall/windows_firewall.cpp
@@ -0,0 +1,303 @@
+#include "pch.h"
+
+#include "windows_firewall.h"
+
+
+namespace util::win_firewall {
+
+ // predicate returns void and takes arguments by reference. second argument for removing rules.
+ void forFirewallRulesInGroup(std::string _target_groupName, std::function&, const CComPtr&)> predicate)
+ {
+ HRESULT hr;
+
+ // Retrieve INetFwPolicy2
+ CComPtr pNetFwPolicy2;
+ hr = pNetFwPolicy2.CoCreateInstance(__uuidof(NetFwPolicy2));
+ if (FAILED(hr))
+ {
+ wprintf(L"CoCreateInstance failed: 0x%08lx\n", hr);
+ return;
+ }
+
+ // Retrieve INetFwRules
+ CComPtr pFwRules;
+ hr = pNetFwPolicy2->get_Rules(&pFwRules);
+ if (FAILED(hr))
+ {
+ wprintf(L"get_Rules failed: 0x%08lx\n", hr);
+ return;
+ }
+
+ // Obtain the number of Firewall rules
+ long fwRuleCount;
+ hr = pFwRules->get_Count(&fwRuleCount);
+ if (FAILED(hr))
+ {
+ wprintf(L"get_Count failed: 0x%08lx\n", hr);
+ return;
+ }
+
+ wprintf(L"The number of rules in the Windows Firewall are %d\n", fwRuleCount);
+
+ // Iterate through all of the rules in pFwRules
+ CComPtr pEnumerator;
+ hr = pFwRules->get__NewEnum(&pEnumerator);
+ if (FAILED(hr))
+ {
+ wprintf(L"get__NewEnum failed: 0x%08lx\n", hr);
+ return;
+ }
+
+ CComPtr pVariant;
+ hr = pEnumerator.QueryInterface(&pVariant);
+ if (FAILED(hr))
+ {
+ wprintf(L"get__NewEnum failed to produce IEnumVariant: 0x%08lx\n", hr);
+ return;
+ }
+
+ ULONG cFetched = 0;
+ for (CComVariant var; pVariant->Next(1, &var, &cFetched) == S_OK; var.Clear())
+ {
+ CComPtr pFwRule;
+ if (SUCCEEDED(var.ChangeType(VT_DISPATCH)) &&
+ SUCCEEDED(V_DISPATCH(&var)->QueryInterface(IID_PPV_ARGS(&pFwRule))))
+ {
+
+ CComBSTR target_groupName(_target_groupName.c_str());
+ CComBSTR groupName;
+ if (SUCCEEDED(pFwRule->get_Grouping(&groupName)) && groupName)
+ {
+ if (groupName == target_groupName)
+ {
+ predicate(pFwRule, pFwRules);
+ }
+ }
+ }
+ }
+
+ }
+
+ void firewallRulesPredicate(std::function&)> predicate) {
+ HRESULT hr;
+
+ // Retrieve INetFwPolicy2
+ CComPtr pNetFwPolicy2;
+ hr = pNetFwPolicy2.CoCreateInstance(__uuidof(NetFwPolicy2));
+ if (FAILED(hr))
+ {
+ wprintf(L"CoCreateInstance failed: 0x%08lx\n", hr);
+ return;
+ }
+
+ // Retrieve INetFwRules
+ CComPtr pFwRules;
+ hr = pNetFwPolicy2->get_Rules(&pFwRules);
+ if (FAILED(hr))
+ {
+ wprintf(L"get_Rules failed: 0x%08lx\n", hr);
+ return;
+ }
+
+ predicate(pFwRules);
+ }
+}
+
+
+/*
+
+
+// Output properties of a Firewall rule
+void DumpFWRulesInCollection(INetFwRule* FwRule)
+{
+ wprintf(L"---------------------------------------------\n");
+
+ CComBSTR name;
+ if (SUCCEEDED(FwRule->get_Name(&name)) && name)
+ {
+ PrintLocalizableString(L"Name: ", name);
+ }
+
+ CComBSTR description;
+ if (SUCCEEDED(FwRule->get_Description(&description)) && description)
+ {
+ PrintLocalizableString(L"Description: ", description);
+ }
+
+ CComBSTR applicationName;
+ if (SUCCEEDED(FwRule->get_ApplicationName(&applicationName)) && applicationName)
+ {
+ wprintf(L"Application Name: %ls\n", static_cast(applicationName));
+ }
+
+ CComBSTR serviceName;
+ if (SUCCEEDED(FwRule->get_ServiceName(&serviceName)) && serviceName)
+ {
+ wprintf(L"Service Name: %ls\n", static_cast(serviceName));
+ }
+
+ long protocolNumber = 0;
+ if (SUCCEEDED(FwRule->get_Protocol(&protocolNumber)))
+ {
+ // Try to convert the protocol number to a name, for readability.
+ PCSTR protocolName = nullptr;
+
+ // This special value means "any protocol".
+ if (protocolNumber == NET_FW_IP_PROTOCOL_ANY)
+ {
+ protocolName = "Any";
+ }
+ else
+ {
+ protoent* ent = getprotobynumber(protocolNumber);
+ if (ent)
+ {
+ protocolName = ent->p_name;
+ }
+ }
+ if (protocolName)
+ {
+ wprintf(L"IP Protocol: %d (%hs)\n", protocolNumber, protocolName);
+ }
+ else
+ {
+ wprintf(L"IP Protocol: %d\n", protocolNumber);
+ }
+
+ if (protocolNumber != IP_PROTOCOL_ICMP4 && protocolNumber != IP_PROTOCOL_ICMP6)
+ {
+ CComBSTR localPorts;
+ if (SUCCEEDED(FwRule->get_LocalPorts(&localPorts)) && localPorts)
+ {
+ wprintf(L"Local Ports: %ls\n", static_cast(localPorts));
+ }
+
+ CComBSTR remotePorts;
+ if (SUCCEEDED(FwRule->get_RemotePorts(&remotePorts)) && remotePorts)
+ {
+ wprintf(L"Remote Ports: %ls\n", static_cast(remotePorts));
+ }
+ }
+ else
+ {
+ CComBSTR icmpTypesAndCodes;
+ if (SUCCEEDED(FwRule->get_IcmpTypesAndCodes(&icmpTypesAndCodes)) && icmpTypesAndCodes)
+ {
+ wprintf(L"ICMP TypeCode: %ls\n", static_cast(icmpTypesAndCodes));
+ }
+ }
+ }
+
+CComBSTR localAddresses;
+if (SUCCEEDED(FwRule->get_LocalAddresses(&localAddresses)) && localAddresses)
+{
+ wprintf(L"LocalAddresses: %ls\n", static_cast(localAddresses));
+}
+
+CComBSTR remoteAddresses;
+if (SUCCEEDED(FwRule->get_RemoteAddresses(&remoteAddresses)) && remoteAddresses)
+{
+ wprintf(L"RemoteAddresses: %ls\n", static_cast(remoteAddresses));
+}
+
+long lProfileBitmask = 0;
+if (SUCCEEDED(FwRule->get_Profiles(&lProfileBitmask)))
+{
+ // The returned bitmask can have more than 1 bit set if multiple profiles
+ // are active or current at the same time
+ static const struct ProfileMapElement
+ {
+ NET_FW_PROFILE_TYPE2 Id;
+ LPCWSTR Name;
+ } ProfileMap[3] = {
+ { NET_FW_PROFILE2_DOMAIN, L"Domain" },
+ { NET_FW_PROFILE2_PRIVATE, L"Private" },
+ { NET_FW_PROFILE2_PUBLIC, L"Public" },
+ };
+
+ for (ProfileMapElement const& entry : ProfileMap)
+ {
+ if (lProfileBitmask & entry.Id)
+ {
+ wprintf(L"Profile: %ls\n", entry.Name);
+ }
+ }
+}
+
+NET_FW_RULE_DIRECTION fwDirection;
+if (SUCCEEDED(FwRule->get_Direction(&fwDirection)))
+{
+ switch (fwDirection)
+ {
+ case NET_FW_RULE_DIR_IN:
+ wprintf(L"Direction: In\n");
+ break;
+
+ case NET_FW_RULE_DIR_OUT:
+ wprintf(L"Direction: Out\n");
+ break;
+ }
+}
+
+NET_FW_ACTION fwAction;
+if (SUCCEEDED(FwRule->get_Action(&fwAction)))
+{
+ switch (fwAction)
+ {
+ case NET_FW_ACTION_BLOCK:
+ wprintf(L"Action: Block\n");
+ break;
+
+ case NET_FW_ACTION_ALLOW:
+ wprintf(L"Action: Allow\n");
+ break;
+ }
+}
+
+CComVariant InterfaceArray;
+if (SUCCEEDED(FwRule->get_Interfaces(&InterfaceArray)))
+{
+ if (InterfaceArray.vt == (VT_VARIANT | VT_ARRAY))
+ {
+ SAFEARRAY* pSa = NULL;
+
+ pSa = InterfaceArray.parray;
+
+ for (long index = pSa->rgsabound->lLbound; index < (long)pSa->rgsabound->cElements; index++)
+ {
+ CComVariant InterfaceString;
+ if (SUCCEEDED(SafeArrayGetElement(pSa, &index, &InterfaceString)) &&
+ (InterfaceString.vt == VT_BSTR))
+ {
+ wprintf(L"Interfaces: %ls\n", InterfaceString.bstrVal);
+ }
+ }
+ }
+}
+
+CComBSTR interfaceTypes;
+if (SUCCEEDED(FwRule->get_InterfaceTypes(&interfaceTypes)) && interfaceTypes)
+{
+ wprintf(L"Interface Types: %ls\n", static_cast(interfaceTypes));
+}
+
+VARIANT_BOOL enabled;
+if (SUCCEEDED(FwRule->get_Enabled(&enabled)))
+{
+ wprintf(L"Enabled: %ls\n", enabled ? L"TRUE" : L"FALSE");
+}
+
+CComBSTR grouping;
+if (SUCCEEDED(FwRule->get_Grouping(&grouping)) && grouping)
+{
+ PrintLocalizableString(L"Grouping: ", grouping);
+}
+
+if (SUCCEEDED(FwRule->get_EdgeTraversal(&enabled)))
+{
+ wprintf(L"Edge Traversal: %ls\n", enabled ? L"TRUE" : L"FALSE");
+}
+}
+
+
+*/
diff --git a/dropship/dropship/src/util/win/win_firewall/windows_firewall.h b/dropship/dropship/src/util/win/win_firewall/windows_firewall.h
new file mode 100644
index 0000000..2f17646
--- /dev/null
+++ b/dropship/dropship/src/util/win/win_firewall/windows_firewall.h
@@ -0,0 +1,32 @@
+#pragma once
+
+
+#include // INetFwPolicy2
+
+//#include
+//#include
+//#include // for getprotocolbyname
+
+
+#define IP_PROTOCOL_ICMP4 1
+#define IP_PROTOCOL_ICMP6 58
+
+// TODO remove
+//#include // for SHLoadIndirectString
+
+/*
+
+ !! QUARANTINE ZONE !!
+
+ there is a lot of win32 stuff in this one file.
+ • the official windows examples have massive memory leaks and are bad.
+ • thus one uses ccomptr to avoid memory leaks: https://github.com/microsoft/Windows-classic-samples/blob/44d192fd7ec6f2422b7d023891c5f805ada2c811/Samples/Win7Samples/security/windowsfirewall/enumeratefirewallrules/EnumerateFirewallRules.cpp
+
+*/
+
+namespace util::win_firewall {
+
+ void forFirewallRulesInGroup(std::string _target_groupName, std::function&, const CComPtr&)> predicate);
+
+ void firewallRulesPredicate(std::function&)> predicate);
+}
diff --git a/dropship/dropship/src/util/win/win_net_fw.cpp b/dropship/dropship/src/util/win/win_net_fw.cpp
new file mode 100644
index 0000000..22ccd0c
--- /dev/null
+++ b/dropship/dropship/src/util/win/win_net_fw.cpp
@@ -0,0 +1,42 @@
+#include "pch.h"
+
+#include "win_net_fw.h"
+
+
+namespace util::win_net_fw {
+
+ namespace {
+
+ /* get network firewall policy */
+ CComPtr getNetworkFirewallPolicy()
+ {
+
+ CComPtr pNetFwPolicy2;
+ if (FAILED(pNetFwPolicy2.CoCreateInstance(__uuidof(NetFwPolicy2)))) throw std::runtime_error("failed to get network firewall policy");
+
+ return pNetFwPolicy2;
+ }
+
+ }
+
+ /* gets firewall enabled for network type */
+ bool isFirewallEnabledForNetworkProfile(NET_FW_PROFILE_TYPE2 profile)
+ {
+
+ auto pNetFwPolicy2 = getNetworkFirewallPolicy();
+
+ VARIANT_BOOL fwEnabled;
+ if (FAILED(pNetFwPolicy2->get_FirewallEnabled(profile, &fwEnabled))) throw std::runtime_error("failed to query firewall state for network profile");
+
+ return (fwEnabled != VARIANT_FALSE);
+ }
+
+ void enableFirewallForNetworkProfile(NET_FW_PROFILE_TYPE2 profile)
+ {
+
+ auto pNetFwPolicy2 = getNetworkFirewallPolicy();
+ if (FAILED(pNetFwPolicy2->put_FirewallEnabled(profile, VARIANT_TRUE))) throw std::runtime_error("failed to enable firewall for network profile");
+
+ }
+
+}
diff --git a/dropship/dropship/src/util/win/win_net_fw.h b/dropship/dropship/src/util/win/win_net_fw.h
new file mode 100644
index 0000000..e775159
--- /dev/null
+++ b/dropship/dropship/src/util/win/win_net_fw.h
@@ -0,0 +1,19 @@
+#pragma once
+
+//#include "util/win/win_firewall/windows_firewall.h";
+//#include "util/win/win_network/windows_network.h";
+
+#include // INetFwPolicy2
+
+
+namespace util::win_net_fw {
+
+ namespace {
+ CComPtr getNetworkFirewallPolicy();
+ }
+
+ bool isFirewallEnabledForNetworkProfile(NET_FW_PROFILE_TYPE2 profile);
+
+ void enableFirewallForNetworkProfile(NET_FW_PROFILE_TYPE2 profile);
+
+}
diff --git a/dropship/dropship/src/util/win/win_network/windows_network.cpp b/dropship/dropship/src/util/win/win_network/windows_network.cpp
new file mode 100644
index 0000000..461cafc
--- /dev/null
+++ b/dropship/dropship/src/util/win/win_network/windows_network.cpp
@@ -0,0 +1,114 @@
+#include "pch.h"
+
+#include "windows_network.h"
+
+namespace util::win_network {
+
+
+ NetworkInformation queryNetwork() {
+
+ NetworkInformation output;
+
+ {
+ int total_netcount = 0;
+
+ long total_connectedNetworkProfileBitmask = 0x0;
+ long total_networkProfilesEnabledInFirewallBitmask = 0x0;
+
+ // https://learn.microsoft.com/en-us/windows/win32/api/objbase/ne-objbase-coinit#remarks
+ // CoInitializeEx(NULL, COINIT_MULTITHREADED)
+
+ /* pNetworkListManager */
+ CComPtr pNetworkListManager;
+ if (FAILED(pNetworkListManager.CoCreateInstance(CLSID_NetworkListManager))) throw std::runtime_error("failed creating windows network instance");
+
+ /* network iterator */
+ CComPtr pEnumerator;
+ if (FAILED(pNetworkListManager->GetNetworks(NLM_ENUM_NETWORK_CONNECTED, &pEnumerator))) throw std::runtime_error("failed querying connected networks");
+
+ /* network item */
+ CComPtr pVariant;
+ if (FAILED(pEnumerator.QueryInterface(&pVariant))) throw std::runtime_error("failed querying network enumerator");
+
+ /* iterate networks */
+ for (CComVariant var; pVariant->Next(1, &var, nullptr) == S_OK; var.Clear())
+ {
+
+ /* query network*/
+ CComPtr pINetwork;
+ if (FAILED(var.ChangeType(VT_DISPATCH))) throw std::runtime_error("failed to change dispatch type");
+ if (FAILED(V_DISPATCH(&var)->QueryInterface(IID_PPV_ARGS(&pINetwork)))) throw std::runtime_error("failed to query network");
+
+ total_netcount ++;
+
+ /*
+ CComBSTR
+ CComBSTR
+
+ BSTR bstrVal;
+ if (SUCCEEDED(pINetwork->GetName(&bstrVal)))
+ {
+ wprintf(L" \"%s\"\n", bstrVal);
+ }*/
+
+ /*VARIANT_BOOL booVal;
+ if (SUCCEEDED(pINetwork->get_IsConnectedToInternet(&booVal)))
+ {
+ printf(booVal ? "connected\n" : "disconnected\n");
+ }*/
+
+ /* network profile */
+ NLM_NETWORK_CATEGORY network_cat;
+ if (FAILED(pINetwork->GetCategory(&network_cat))) throw std::runtime_error("failed to query network category");
+
+ if (network_cat == NLM_NETWORK_CATEGORY_PRIVATE) total_connectedNetworkProfileBitmask |= NET_FW_PROFILE2_PRIVATE;
+ else if (network_cat == NLM_NETWORK_CATEGORY_PUBLIC) total_connectedNetworkProfileBitmask |= NET_FW_PROFILE2_PUBLIC;
+ else if (network_cat == NLM_NETWORK_CATEGORY_DOMAIN_AUTHENTICATED) total_connectedNetworkProfileBitmask |= NET_FW_PROFILE2_DOMAIN;
+ else throw std::runtime_error("unknown network category detected");
+ }
+
+ if (util::win_net_fw::isFirewallEnabledForNetworkProfile(NET_FW_PROFILE2_PRIVATE)) total_networkProfilesEnabledInFirewallBitmask |= NET_FW_PROFILE2_PRIVATE;
+ if (util::win_net_fw::isFirewallEnabledForNetworkProfile(NET_FW_PROFILE2_PUBLIC)) total_networkProfilesEnabledInFirewallBitmask |= NET_FW_PROFILE2_PUBLIC;
+ if (util::win_net_fw::isFirewallEnabledForNetworkProfile(NET_FW_PROFILE2_DOMAIN)) total_networkProfilesEnabledInFirewallBitmask |= NET_FW_PROFILE2_DOMAIN;
+
+ //
+ //
+ // TODO replace with //hr = this->pNetFwPolicy2->get_CurrentProfileTypes(&(this->current_network_profile_type_bitmask));
+ //
+ //
+
+ /*
+ • at least one network profile is enabled in firewall
+ • all networks connected to are enabled in firewall
+ */
+ bool connected_networks_are_enabled_in_firewall =
+ total_networkProfilesEnabledInFirewallBitmask != 0x0
+ && ((total_networkProfilesEnabledInFirewallBitmask & total_connectedNetworkProfileBitmask) == total_connectedNetworkProfileBitmask)
+ ;
+
+ double _updated_at = 0.0;
+
+ if (ImGui::GetCurrentContext() != nullptr && ImGui::GetTime())
+ {
+ _updated_at = ImGui::GetTime();
+ }
+
+ //this->networkInfo = { netcount, connectedNetworkProfileBitmask, total_networkProfilesEnabledInFirewallBitmask, connected_networks_are_enabled_in_firewall, _updated_at };
+
+ output = {
+ .connected_networks_count = total_netcount,
+ .network_profiles_connected = total_connectedNetworkProfileBitmask,
+ .firewall_profiles_enabled = total_networkProfilesEnabledInFirewallBitmask,
+ .connected_networks_are_enabled_in_firewall = connected_networks_are_enabled_in_firewall,
+ };
+
+ /*if (this->networkInfo.connected_networks == 0 && ImGui::GetCurrentContext() != nullptr)
+ {
+ ImGui::OpenPopup("offline");
+ }*/
+ }
+
+ return output;
+ }
+
+}
diff --git a/dropship/dropship/src/util/win/win_network/windows_network.h b/dropship/dropship/src/util/win/win_network/windows_network.h
new file mode 100644
index 0000000..230c538
--- /dev/null
+++ b/dropship/dropship/src/util/win/win_network/windows_network.h
@@ -0,0 +1,35 @@
+#pragma once
+
+#include // INetworkListManager
+//#include // NET_FW_PROFILE_TYPE2_
+
+#include "util/win/win_net_fw.h"
+
+namespace util::win_network {
+
+ struct NetworkInformation
+ {
+ // number of networks connected to. 2 may indicate vpn.
+ // networks may be disconnected from internet.
+ int connected_networks_count;
+
+ // (bitmask & NET_FW_PROFILE2_PRIVATE) if any connected networks are PRIVATE
+ // (bitmask & NET_FW_PROFILE2_PUBLIC) if any connected networks are PUBLIC
+ // (bitmask & NET_FW_PROFILE2_DOMAIN) if any connected networks are DOMAIN
+ // (bitmask & NET_FW_PROFILE2_ALL) if any connected networks are DOMAIN, PUBLIC, or PRIVATE
+
+ long network_profiles_connected;
+ long firewall_profiles_enabled;
+
+ // is there a mismatch? ex. are they connected to a private network, but the private firewall profile is disabled?
+ bool connected_networks_are_enabled_in_firewall;
+
+ // imgui timer;
+ //double _updated_at;
+ };
+
+ NetworkInformation queryNetwork();
+
+}
+
+
diff --git a/dropship/dropship/vendor/asio/asio.hpp b/dropship/dropship/vendor/asio/asio.hpp
new file mode 100644
index 0000000..25cee47
--- /dev/null
+++ b/dropship/dropship/vendor/asio/asio.hpp
@@ -0,0 +1,205 @@
+//
+// asio.hpp
+// ~~~~~~~~
+//
+// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_HPP
+#define ASIO_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/any_completion_executor.hpp"
+#include "asio/any_completion_handler.hpp"
+#include "asio/any_io_executor.hpp"
+#include "asio/append.hpp"
+#include "asio/as_tuple.hpp"
+#include "asio/associated_allocator.hpp"
+#include "asio/associated_cancellation_slot.hpp"
+#include "asio/associated_executor.hpp"
+#include "asio/associated_immediate_executor.hpp"
+#include "asio/associator.hpp"
+#include "asio/async_result.hpp"
+#include "asio/awaitable.hpp"
+#include "asio/basic_datagram_socket.hpp"
+#include "asio/basic_deadline_timer.hpp"
+#include "asio/basic_file.hpp"
+#include "asio/basic_io_object.hpp"
+#include "asio/basic_random_access_file.hpp"
+#include "asio/basic_raw_socket.hpp"
+#include "asio/basic_readable_pipe.hpp"
+#include "asio/basic_seq_packet_socket.hpp"
+#include "asio/basic_serial_port.hpp"
+#include "asio/basic_signal_set.hpp"
+#include "asio/basic_socket.hpp"
+#include "asio/basic_socket_acceptor.hpp"
+#include "asio/basic_socket_iostream.hpp"
+#include "asio/basic_socket_streambuf.hpp"
+#include "asio/basic_stream_file.hpp"
+#include "asio/basic_stream_socket.hpp"
+#include "asio/basic_streambuf.hpp"
+#include "asio/basic_waitable_timer.hpp"
+#include "asio/basic_writable_pipe.hpp"
+#include "asio/bind_allocator.hpp"
+#include "asio/bind_cancellation_slot.hpp"
+#include "asio/bind_executor.hpp"
+#include "asio/bind_immediate_executor.hpp"
+#include "asio/buffer.hpp"
+#include "asio/buffer_registration.hpp"
+#include "asio/buffered_read_stream_fwd.hpp"
+#include "asio/buffered_read_stream.hpp"
+#include "asio/buffered_stream_fwd.hpp"
+#include "asio/buffered_stream.hpp"
+#include "asio/buffered_write_stream_fwd.hpp"
+#include "asio/buffered_write_stream.hpp"
+#include "asio/buffers_iterator.hpp"
+#include "asio/cancel_after.hpp"
+#include "asio/cancel_at.hpp"
+#include "asio/cancellation_signal.hpp"
+#include "asio/cancellation_state.hpp"
+#include "asio/cancellation_type.hpp"
+#include "asio/co_composed.hpp"
+#include "asio/co_spawn.hpp"
+#include "asio/completion_condition.hpp"
+#include "asio/compose.hpp"
+#include "asio/composed.hpp"
+#include "asio/connect.hpp"
+#include "asio/connect_pipe.hpp"
+#include "asio/consign.hpp"
+#include "asio/coroutine.hpp"
+#include "asio/deadline_timer.hpp"
+#include "asio/defer.hpp"
+#include "asio/deferred.hpp"
+#include "asio/default_completion_token.hpp"
+#include "asio/detached.hpp"
+#include "asio/dispatch.hpp"
+#include "asio/error.hpp"
+#include "asio/error_code.hpp"
+#include "asio/execution.hpp"
+#include "asio/execution/allocator.hpp"
+#include "asio/execution/any_executor.hpp"
+#include "asio/execution/blocking.hpp"
+#include "asio/execution/blocking_adaptation.hpp"
+#include "asio/execution/context.hpp"
+#include "asio/execution/context_as.hpp"
+#include "asio/execution/executor.hpp"
+#include "asio/execution/invocable_archetype.hpp"
+#include "asio/execution/mapping.hpp"
+#include "asio/execution/occupancy.hpp"
+#include "asio/execution/outstanding_work.hpp"
+#include "asio/execution/prefer_only.hpp"
+#include "asio/execution/relationship.hpp"
+#include "asio/executor.hpp"
+#include "asio/executor_work_guard.hpp"
+#include "asio/file_base.hpp"
+#include "asio/generic/basic_endpoint.hpp"
+#include "asio/generic/datagram_protocol.hpp"
+#include "asio/generic/raw_protocol.hpp"
+#include "asio/generic/seq_packet_protocol.hpp"
+#include "asio/generic/stream_protocol.hpp"
+#include "asio/handler_continuation_hook.hpp"
+#include "asio/high_resolution_timer.hpp"
+#include "asio/immediate.hpp"
+#include "asio/io_context.hpp"
+#include "asio/io_context_strand.hpp"
+#include "asio/io_service.hpp"
+#include "asio/io_service_strand.hpp"
+#include "asio/ip/address.hpp"
+#include "asio/ip/address_v4.hpp"
+#include "asio/ip/address_v4_iterator.hpp"
+#include "asio/ip/address_v4_range.hpp"
+#include "asio/ip/address_v6.hpp"
+#include "asio/ip/address_v6_iterator.hpp"
+#include "asio/ip/address_v6_range.hpp"
+#include "asio/ip/network_v4.hpp"
+#include "asio/ip/network_v6.hpp"
+#include "asio/ip/bad_address_cast.hpp"
+#include "asio/ip/basic_endpoint.hpp"
+#include "asio/ip/basic_resolver.hpp"
+#include "asio/ip/basic_resolver_entry.hpp"
+#include "asio/ip/basic_resolver_iterator.hpp"
+#include "asio/ip/basic_resolver_query.hpp"
+#include "asio/ip/host_name.hpp"
+#include "asio/ip/icmp.hpp"
+#include "asio/ip/multicast.hpp"
+#include "asio/ip/resolver_base.hpp"
+#include "asio/ip/resolver_query_base.hpp"
+#include "asio/ip/tcp.hpp"
+#include "asio/ip/udp.hpp"
+#include "asio/ip/unicast.hpp"
+#include "asio/ip/v6_only.hpp"
+#include "asio/is_applicable_property.hpp"
+#include "asio/is_contiguous_iterator.hpp"
+#include "asio/is_executor.hpp"
+#include "asio/is_read_buffered.hpp"
+#include "asio/is_write_buffered.hpp"
+#include "asio/local/basic_endpoint.hpp"
+#include "asio/local/connect_pair.hpp"
+#include "asio/local/datagram_protocol.hpp"
+#include "asio/local/seq_packet_protocol.hpp"
+#include "asio/local/stream_protocol.hpp"
+#include "asio/multiple_exceptions.hpp"
+#include "asio/packaged_task.hpp"
+#include "asio/placeholders.hpp"
+#include "asio/posix/basic_descriptor.hpp"
+#include "asio/posix/basic_stream_descriptor.hpp"
+#include "asio/posix/descriptor.hpp"
+#include "asio/posix/descriptor_base.hpp"
+#include "asio/posix/stream_descriptor.hpp"
+#include "asio/post.hpp"
+#include "asio/prefer.hpp"
+#include "asio/prepend.hpp"
+#include "asio/query.hpp"
+#include "asio/random_access_file.hpp"
+#include "asio/read.hpp"
+#include "asio/read_at.hpp"
+#include "asio/read_until.hpp"
+#include "asio/readable_pipe.hpp"
+#include "asio/recycling_allocator.hpp"
+#include "asio/redirect_error.hpp"
+#include "asio/registered_buffer.hpp"
+#include "asio/require.hpp"
+#include "asio/require_concept.hpp"
+#include "asio/serial_port.hpp"
+#include "asio/serial_port_base.hpp"
+#include "asio/signal_set.hpp"
+#include "asio/signal_set_base.hpp"
+#include "asio/socket_base.hpp"
+#include "asio/static_thread_pool.hpp"
+#include "asio/steady_timer.hpp"
+#include "asio/strand.hpp"
+#include "asio/stream_file.hpp"
+#include "asio/streambuf.hpp"
+#include "asio/system_context.hpp"
+#include "asio/system_error.hpp"
+#include "asio/system_executor.hpp"
+#include "asio/system_timer.hpp"
+#include "asio/this_coro.hpp"
+#include "asio/thread.hpp"
+#include "asio/thread_pool.hpp"
+#include "asio/time_traits.hpp"
+#include "asio/use_awaitable.hpp"
+#include "asio/use_future.hpp"
+#include "asio/uses_executor.hpp"
+#include "asio/version.hpp"
+#include "asio/wait_traits.hpp"
+#include "asio/windows/basic_object_handle.hpp"
+#include "asio/windows/basic_overlapped_handle.hpp"
+#include "asio/windows/basic_random_access_handle.hpp"
+#include "asio/windows/basic_stream_handle.hpp"
+#include "asio/windows/object_handle.hpp"
+#include "asio/windows/overlapped_handle.hpp"
+#include "asio/windows/overlapped_ptr.hpp"
+#include "asio/windows/random_access_handle.hpp"
+#include "asio/windows/stream_handle.hpp"
+#include "asio/writable_pipe.hpp"
+#include "asio/write.hpp"
+#include "asio/write_at.hpp"
+
+#endif // ASIO_HPP
diff --git a/dropship/dropship/vendor/asio/asio/any_completion_executor.hpp b/dropship/dropship/vendor/asio/asio/any_completion_executor.hpp
new file mode 100644
index 0000000..650ff7b
--- /dev/null
+++ b/dropship/dropship/vendor/asio/asio/any_completion_executor.hpp
@@ -0,0 +1,336 @@
+//
+// any_completion_executor.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_ANY_COMPLETION_EXECUTOR_HPP
+#define ASIO_ANY_COMPLETION_EXECUTOR_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#if defined(ASIO_USE_TS_EXECUTOR_AS_DEFAULT)
+# include "asio/executor.hpp"
+#else // defined(ASIO_USE_TS_EXECUTOR_AS_DEFAULT)
+# include "asio/execution.hpp"
+#endif // defined(ASIO_USE_TS_EXECUTOR_AS_DEFAULT)
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+
+#if defined(ASIO_USE_TS_EXECUTOR_AS_DEFAULT)
+
+typedef executor any_completion_executor;
+
+#else // defined(ASIO_USE_TS_EXECUTOR_AS_DEFAULT)
+
+/// Polymorphic executor type for use with I/O objects.
+/**
+ * The @c any_completion_executor type is a polymorphic executor that supports
+ * the set of properties required for the execution of completion handlers. It
+ * is defined as the execution::any_executor class template parameterised as
+ * follows:
+ * @code execution::any_executor<
+ * execution::prefer_only,
+ * execution::prefer_only
+ * execution::prefer_only,
+ * execution::prefer_only
+ * > @endcode
+ */
+class any_completion_executor :
+#if defined(GENERATING_DOCUMENTATION)
+ public execution::any_executor<...>
+#else // defined(GENERATING_DOCUMENTATION)
+ public execution::any_executor<
+ execution::prefer_only