Skip to content

Commit

Permalink
Added API support
Browse files Browse the repository at this point in the history
  • Loading branch information
SMJSGaming committed Jul 2, 2024
1 parent 70d0c72 commit e16bbfd
Show file tree
Hide file tree
Showing 47 changed files with 821 additions and 547 deletions.
5 changes: 3 additions & 2 deletions TODO
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,11 @@ Alpha 3 Todo:
☐ @high Add a send button
☐ @critical Add a pause/resume button
☐ @high Add more keybinds
✔ @low Add modding API support @done(24-07-02 15:10)
☐ @high Add mod request support
Release Todo:
☐ Add inputs to the json code block
# TODO: Figure out wtf I meant by this
☐ Add a format to original in the converters
☐ Add a formatted text to original in the converters
Nice To Haves:
☐ Custom theme support
☐ Do some lobbying to push the Geode team to add a request event
File renamed without changes.
5 changes: 5 additions & 0 deletions mod.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@
"version": "v0.2.3-alpha.2",
"id": "smjs.gdintercept",
"name": "GDIntercept",
"api": {
"include": [
"include/*.hpp"
]
},
"developers": [
"SMJSGaming",
"RobTop"
Expand Down
87 changes: 87 additions & 0 deletions proxy/HttpInfo.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
#include <Geode/Geode.hpp>
#include <Geode/utils/web.hpp>
#include "../lib/json.hpp"
#include "converters/Converter.hpp"
#include "converters/FormToJson.hpp"
#include "converters/BinaryToRaw.hpp"
#include "converters/RobTopToJson.hpp"

namespace proxy {
#define GETTER(type, name, capital_name) \
public: \
type get##capital_name() const { return m_##name; } \
private: \
type m_##name;

using namespace geode::prelude;
using namespace nlohmann;

struct HttpInfo {
enum Origin {
GD,
GD_CDN,
ROBTOP_GAMES,
NEWGROUNDS,
GEODE,
OTHER
};

enum Protocol {
HTTP,
HTTPS,
UNKNOWN_PROTOCOL
};

enum ContentType {
FORM,
JSON,
XML,
ROBTOP,
BINARY,
UNKNOWN_CONTENT
};

typedef std::pair<ContentType, std::string> content;

std::string stringifyProtocol() const;
std::string stringifyMethod() const;
std::string stringifyQuery() const;
std::string stringifyHeaders() const;
content getBodyContent(const bool raw = true);
content getResponseContent(const bool raw = true);
void resetCache();
private:
static converters::FormToJson formToJson;
static converters::RobTopToJson robtopToJson;
static converters::BinaryToRaw binaryToRaw;

GETTER(Origin, origin, Origin)
GETTER(Protocol, protocol, Protocol)
GETTER(CCHttpRequest::HttpRequestType, method, Method)
GETTER(std::string, url, Url)
GETTER(std::string, host, Host)
GETTER(std::string, path, Path)
GETTER(json, query, Query)
GETTER(json, headers, Headers)
GETTER(std::string, body, Body)
GETTER(ContentType, bodyContentType, BodyContentType)
GETTER(int, statusCode, StatusCode)
GETTER(std::string, response, Response)
GETTER(ContentType, responseContentType, ResponseContentType)
content m_simplifiedBodyCache;
content m_simplifiedResponseCache;

HttpInfo(CCHttpRequest* request);
HttpInfo(web::WebRequest* request, const std::string& method, const std::string& url);
content getContent(const bool raw, const ContentType originalContentType, const std::string& original, content& cache);
content simplifyContent(const content& content);
ContentType determineContentType(const std::string& content, const bool isBody = false);
bool isDomain(const std::string& domain);
void determineOrigin();
void parseUrl(const std::string& url);

friend struct ProxyHandler;
};

#undef GETTER
}
66 changes: 66 additions & 0 deletions proxy/Proxy.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
#pragma once

#include <Geode/Geode.hpp>
#include "HttpInfo.hpp"

namespace proxy {
using namespace geode::prelude;

enum SourceFilter {
GD,
GD_CDN,
ROBTOP_GAMES,
NEWGROUNDS,
GEODE,
OTHER,
ALL
};

struct ProxyEvent : public Event {
ProxyEvent(HttpInfo* info);
HttpInfo* getRequest() const;
protected:
HttpInfo* m_info;
};

struct RequestEvent : public ProxyEvent {
RequestEvent(HttpInfo* info);
};

struct ResponseEvent : public ProxyEvent {
ResponseEvent(HttpInfo* info);
HttpInfo::content getResponse(const bool raw = true) const;
};

template <typename T>
concept proxy_event = std::is_base_of_v<ProxyEvent, T>;

template<proxy_event T>
struct ProxyFilter : public EventFilter<T> {
ProxyFilter(const SourceFilter source = ALL) : m_source(source) { };
ProxyFilter(const SourceFilter source, const std::initializer_list<std::string>& urls) : m_source(source), m_urls(urls) { };
ListenerResult handle(MiniFunction<ListenerResult(T*)> callback, T* event) {
if (
(m_urls.empty() || std::find(m_urls.begin(), m_urls.end(), event->getRequest()->getUrl()) != m_urls.end()) &&
(m_source == ALL || as<int>(m_source) == as<int>(event->getRequest()->getOrigin()))
) {
return callback(event);
} else {
return ListenerResult::Propagate;
}
}
protected:
SourceFilter m_source;
std::vector<std::string> m_urls;
};

struct RequestFilter : public ProxyFilter<RequestEvent> {
RequestFilter(const SourceFilter source = ALL);
RequestFilter(const SourceFilter source, const std::initializer_list<std::string>& urls);
};

struct ResponseFilter : public ProxyFilter<ResponseEvent> {
ResponseFilter(const SourceFilter source = ALL);
ResponseFilter(const SourceFilter source, const std::initializer_list<std::string>& urls);
};
}
11 changes: 11 additions & 0 deletions proxy/converters/BinaryToRaw.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#pragma once

#include "Converter.hpp"

namespace proxy::converters {
// What can I say? I like it raw
struct BinaryToRaw : public Converter<std::string> {
bool canConvert(const std::string& path, const std::string& original) override;
std::string convert(const std::string& path, const std::string& original) override;
};
}
23 changes: 23 additions & 0 deletions proxy/converters/Converter.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#pragma once

#include <Geode/Geode.hpp>
#include "../../lib/json.hpp"

namespace proxy::converters {
using namespace geode::prelude;
using namespace nlohmann;

bool isInt(const std::string& str);
bool isNumber(const std::string& str);
bool isBool(const std::string& str);
bool isNull(const std::string& str);
bool isString(const std::string& str);
bool isJson(const std::string& str);
json getPrimitiveJsonType(const std::string& key, const std::string& str);

template<typename T>
struct Converter {
virtual bool canConvert(const std::string& path, const std::string& original) = 0;
virtual T convert(const std::string& path, const std::string& original) = 0;
};
}
10 changes: 10 additions & 0 deletions proxy/converters/FormToJson.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#pragma once

#include "Converter.hpp"

namespace proxy::converters {
struct FormToJson : public Converter<json> {
bool canConvert(const std::string& path, const std::string& original) override;
json convert(const std::string& path, const std::string& original) override;
};
}
49 changes: 49 additions & 0 deletions proxy/converters/RobTopToJson.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
#pragma once

#include "Converter.hpp"

namespace proxy::converters {
struct RobTopToJson : public Converter<json> {
bool canConvert(const std::string& path, const std::string& original) override;
json convert(const std::string& path, const std::string& original) override;
private:
enum ObjectType {
OBJECT,
ARRAY
};

enum SeparatorType {
KEY_VALUE,
TUPLE
};

// The only reason why const char* is involved here is because std::string basically sees everything as a string ctor so overloading with it was almost impossible
struct ObjParser {
ObjParser(const char* delimiter, const char* entryDelimiter = "");
ObjParser(const std::vector<std::string>& tupleKeys, const char* delimiter = "", const char* entryDelimiter = "");
virtual json parse(const std::string& str) const;
private:
ObjectType m_bodyType;
SeparatorType m_separatorType;
std::string m_delimiter;
std::string m_entryDelimiter;
std::vector<std::string> m_tupleKeys;

static std::vector<std::string> split(const std::string& str, const std::string& delimiter);

json parseEntry(const std::string& str) const;
};

struct Parser : public ObjParser {
Parser(const char* delimiter, const std::vector<std::tuple<std::string, ObjParser>>& metadataKeys = {});
Parser(const std::vector<std::string>& tupleKeys, const char* delimiter = "", const std::vector<std::tuple<std::string, ObjParser>>& metadataKeys = {});
Parser(const char* delimiter, const char* entryDelimiter, const std::vector<std::tuple<std::string, ObjParser>>& metadataKeys = {});
Parser(const std::vector<std::string>& tupleKeys, const char* delimiter, const char* entryDelimiter, const std::vector<std::tuple<std::string, ObjParser>>& metadataKeys = {});
json parse(const std::string& str) const override;
private:
std::vector<std::tuple<std::string, ObjParser>> m_metadata;
};

static const std::unordered_map<std::string, Parser> parsers;
};
}
13 changes: 13 additions & 0 deletions src/include.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#include "include.hpp"

std::vector<ProxyHandler*> context::CACHED_PROXIES;

void context::registerRequest(ProxyHandler* proxy) {
if (!Mod::get()->getSettingValue<bool>("remember-requests") && CACHED_PROXIES.size() > 0) {
delete CACHED_PROXIES.at(0);

CACHED_PROXIES.resize(0);
}

CACHED_PROXIES.insert(CACHED_PROXIES.begin(), proxy);
}
12 changes: 10 additions & 2 deletions src/include.hpp
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
#pragma once

#include <Geode/Geode.hpp>
#include "lib/json.hpp"
#include "../lib/json.hpp"
#include "../proxy/Proxy.hpp"
#include "proxy/ProxyHandler.hpp"

using namespace geode::prelude;
using namespace proxy;
using namespace nlohmann;
using namespace geode::prelude;

#define PADDING 5.0f
#define FULL_OPACITY 0xFF
Expand All @@ -30,4 +33,9 @@ constexpr ccColor4B BROWN_4B({ 0xA0, 0x54, 0x34, FULL_OPACITY });
constexpr ccColor3B DARK_BROWN_3B({ 0x82, 0x40, 0x21 });
constexpr ccColor4B DARK_BROWN_4B({ 0x82, 0x40, 0x21, FULL_OPACITY });

namespace context {
extern std::vector<ProxyHandler*> CACHED_PROXIES;
void registerRequest(ProxyHandler* proxy);
}

#define OPT(expr) if (auto _opt_ = expr) _opt_
37 changes: 29 additions & 8 deletions src/main.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
#include <Geode/loader/SettingEvent.hpp>
#include "include.hpp"
#include "objects/HttpInfo.hpp"
#include "scenes/InterceptPopup.hpp"

#ifdef GEODE_IS_WINDOWS
Expand Down Expand Up @@ -49,14 +48,32 @@
#endif

$execute {
new EventListener([=](RequestEvent* event) {
if (Mod::get()->getSettingValue<bool>("log-requests")) {
HttpInfo* request = event->getRequest();

log::info("Sending request:\nMethod: {}\nProtocol: {}\nHost: {}\nPath: {}\nQuery: {}\nHeaders: {}\nBody: {}",
request->stringifyMethod(),
request->stringifyProtocol(),
request->getHost(),
request->getPath(),
request->stringifyQuery(),
request->stringifyHeaders(),
request->getBodyContent(false).second
);
}

return ListenerResult::Propagate;
}, RequestFilter());

listenForSettingChanges("remember-requests", +[](const bool value) {
if (!value) {
for (size_t i = 1; i < HttpInfo::requests.size(); i++) {
delete HttpInfo::requests.at(i);
for (size_t i = 1; i < context::CACHED_PROXIES.size(); i++) {
delete context::CACHED_PROXIES.at(i);
}

if (HttpInfo::requests.size() > 1) {
HttpInfo::requests.resize(1);
if (context::CACHED_PROXIES.size() > 1) {
context::CACHED_PROXIES.resize(1);
}

OPT(InterceptPopup::get())->reload();
Expand All @@ -65,13 +82,17 @@

listenForSettingChanges("cache", +[](const bool value) {
if (!value) {
for (HttpInfo* request : HttpInfo::requests) {
request->resetCache();
for (ProxyHandler* proxy : context::CACHED_PROXIES) {
proxy->getInfo()->resetCache();
}
}
});

listenForAllSettingChanges(+[](SettingValue* event) {
OPT(InterceptPopup::get())->reload();
std::vector<std::string> blacklist({ "remember-requests", "cache" });

if (std::find(blacklist.begin(), blacklist.end(), event->getKey()) == blacklist.end()) {
OPT(InterceptPopup::get())->reload();
}
});
}
Loading

0 comments on commit e16bbfd

Please sign in to comment.