mirror of
https://github.com/WarmUpTill/SceneSwitcher.git
synced 2026-03-21 17:34:57 -05:00
Implement proper timestamp validation for Twitch messages
This commit is contained in:
parent
d892298995
commit
70bbc7cdac
3
.gitmodules
vendored
3
.gitmodules
vendored
|
|
@ -28,3 +28,6 @@
|
||||||
[submodule "deps/libusb"]
|
[submodule "deps/libusb"]
|
||||||
path = deps/libusb
|
path = deps/libusb
|
||||||
url = https://github.com/libusb/libusb.git
|
url = https://github.com/libusb/libusb.git
|
||||||
|
[submodule "deps/date"]
|
||||||
|
path = deps/date
|
||||||
|
url = https://github.com/HowardHinnant/date.git
|
||||||
|
|
|
||||||
1
deps/date
vendored
Submodule
1
deps/date
vendored
Submodule
|
|
@ -0,0 +1 @@
|
||||||
|
Subproject commit 5bdb7e6f31fac909c090a46dbd9fea27b6e609a4
|
||||||
|
|
@ -30,6 +30,31 @@ if(NOT ZLIB_FOUND)
|
||||||
return()
|
return()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
set(DATE_LIB_DIR "${ADVSS_SOURCE_DIR}/deps/date")
|
||||||
|
if(EXISTS "${DATE_LIB_DIR}/CMakeLists.txt")
|
||||||
|
set(BUILD_TZ_LIB ON)
|
||||||
|
if(OS_WINDOWS)
|
||||||
|
if(CURL_FOUND AND TARGET CURL::libcurl)
|
||||||
|
get_target_property(CURL_INCLUDE_DIR CURL::libcurl
|
||||||
|
INTERFACE_INCLUDE_DIRECTORIES)
|
||||||
|
add_subdirectory("${DATE_LIB_DIR}" "${DATE_LIB_DIR}/build"
|
||||||
|
EXCLUDE_FROM_ALL)
|
||||||
|
target_include_directories(date-tz PRIVATE "${CURL_INCLUDE_DIR}")
|
||||||
|
set(VERIFY_TWITCH_TIMESTAMPS ON)
|
||||||
|
else()
|
||||||
|
message(WARNING "CURL not found - not verifying Twitch timestamps")
|
||||||
|
endif()
|
||||||
|
else()
|
||||||
|
add_subdirectory("${DATE_LIB_DIR}" "${DATE_LIB_DIR}/build" EXCLUDE_FROM_ALL)
|
||||||
|
target_compile_options(date-tz PUBLIC -Wno-error=conversion
|
||||||
|
-Wno-error=shadow)
|
||||||
|
set(VERIFY_TWITCH_TIMESTAMPS ON)
|
||||||
|
endif()
|
||||||
|
else()
|
||||||
|
message(WARNING "date lib not found in \"${DATE_LIB_DIR}\"!\n"
|
||||||
|
"Twitch timestamps will not be checked!")
|
||||||
|
endif()
|
||||||
|
|
||||||
# --- End of section ---
|
# --- End of section ---
|
||||||
|
|
||||||
add_library(${PROJECT_NAME} MODULE)
|
add_library(${PROJECT_NAME} MODULE)
|
||||||
|
|
@ -76,6 +101,14 @@ set_target_properties(${PROJECT_NAME} PROPERTIES PREFIX "")
|
||||||
target_include_directories(${PROJECT_NAME} PRIVATE "${CPP_HTTPLIB_DIR}/"
|
target_include_directories(${PROJECT_NAME} PRIVATE "${CPP_HTTPLIB_DIR}/"
|
||||||
"${OPENSSL_INCLUDE_DIR}")
|
"${OPENSSL_INCLUDE_DIR}")
|
||||||
target_link_libraries(${PROJECT_NAME} PRIVATE ${OPENSSL_LIBRARIES} ZLIB::ZLIB)
|
target_link_libraries(${PROJECT_NAME} PRIVATE ${OPENSSL_LIBRARIES} ZLIB::ZLIB)
|
||||||
|
if(DEFINED VERIFY_TWITCH_TIMESTAMPS)
|
||||||
|
target_compile_definitions(${PROJECT_NAME} PRIVATE VERIFY_TIMESTAMPS=1)
|
||||||
|
target_link_libraries(${PROJECT_NAME} PRIVATE date::date-tz)
|
||||||
|
if(OS_WINDOWS)
|
||||||
|
target_link_libraries(${PROJECT_NAME} PRIVATE CURL::libcurl)
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
install_advss_plugin(${PROJECT_NAME})
|
install_advss_plugin(${PROJECT_NAME})
|
||||||
if(OS_WINDOWS)
|
if(OS_WINDOWS)
|
||||||
# Couldn't really find a better way to install runtime dependencies for
|
# Couldn't really find a better way to install runtime dependencies for
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,10 @@
|
||||||
|
|
||||||
#include <log-helper.hpp>
|
#include <log-helper.hpp>
|
||||||
|
|
||||||
|
#ifdef VERIFY_TIMESTAMPS
|
||||||
|
#include "date/tz.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace advss {
|
namespace advss {
|
||||||
|
|
||||||
using websocketpp::lib::placeholders::_1;
|
using websocketpp::lib::placeholders::_1;
|
||||||
|
|
@ -237,15 +241,43 @@ void EventSub::OnOpen(connection_hdl)
|
||||||
|
|
||||||
static bool isValidTimestamp(const std::string ×tamp)
|
static bool isValidTimestamp(const std::string ×tamp)
|
||||||
{
|
{
|
||||||
std::tm tm = {};
|
#ifdef VERIFY_TIMESTAMPS
|
||||||
std::istringstream ss(timestamp);
|
// Example input: 2023-07-19T14:56:51.634234626Z
|
||||||
ss >> std::get_time(&tm, "%Y-%m-%dT%H:%M:%S.%fZ");
|
try {
|
||||||
auto tp = std::chrono::system_clock::from_time_t(std::mktime(&tm));
|
// Discard the nanosecond part
|
||||||
tp += std::chrono::hours(1); // UTC
|
static constexpr size_t dotPos = 19;
|
||||||
std::chrono::system_clock::time_point currentTime =
|
std::string trimmed = timestamp.substr(0, dotPos);
|
||||||
std::chrono::system_clock::now();
|
auto tzStart = timestamp.find_first_of("Z+-", dotPos);
|
||||||
auto diff = currentTime - tp;
|
trimmed = timestamp.substr(0, dotPos);
|
||||||
return diff <= std::chrono::minutes(10);
|
if (tzStart != std::string::npos) {
|
||||||
|
trimmed += timestamp.substr(tzStart);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::istringstream in(trimmed);
|
||||||
|
date::sys_time<std::chrono::seconds> parsedTime;
|
||||||
|
in >> date::parse("%FT%TZ", parsedTime);
|
||||||
|
if (in.fail()) {
|
||||||
|
blog(LOG_WARNING, "failed to parse timestamp %s",
|
||||||
|
timestamp.c_str());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto now = date::zoned_time{date::current_zone(),
|
||||||
|
std::chrono::system_clock::now()}
|
||||||
|
.get_sys_time();
|
||||||
|
|
||||||
|
auto duration = now - parsedTime;
|
||||||
|
// Clocks might be off by a bit, so allow negative values also
|
||||||
|
return duration <= std::chrono::minutes(10) &&
|
||||||
|
duration >= std::chrono::minutes(-1);
|
||||||
|
} catch (const std::exception &e) {
|
||||||
|
blog(LOG_WARNING, "%s: %s", __func__, e.what());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
// Just assume timestamps are always valid
|
||||||
|
return true;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
bool EventSub::IsValidMessageID(const std::string &id)
|
bool EventSub::IsValidMessageID(const std::string &id)
|
||||||
|
|
@ -288,7 +320,8 @@ void EventSub::OnMessage(connection_hdl, EventSubWSClient::message_ptr message)
|
||||||
obs_data_get_string(metadata, "message_timestamp");
|
obs_data_get_string(metadata, "message_timestamp");
|
||||||
if (!isValidTimestamp(timestamp)) {
|
if (!isValidTimestamp(timestamp)) {
|
||||||
blog(LOG_WARNING,
|
blog(LOG_WARNING,
|
||||||
"Discarding Twitch EventSub with invalid timestamp");
|
"Discarding Twitch EventSub with invalid timestamp %s",
|
||||||
|
timestamp.c_str());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
std::string id = obs_data_get_string(metadata, "message_id");
|
std::string id = obs_data_get_string(metadata, "message_id");
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user