ZaStoGram_desktop/Telegram/SourceFiles/tests/test_mtproxy_client_hello.cpp
loop-uh be3315b3b2 Refactor proxy connection and endpoint health management
- Replace endpoint cooldown tracking with centralized EndpointHealth system for MTProxy attempts
- Add multi-profile ClientHello builder with Chrome Modern (validated), Android Chrome, and other profiles
- Implement SeekFramePolicy for video seeking (AtOrAfter/AtOrBefore/Nearest)
- Enhance proxy status with terminal reasons, attempt tracking, and severity levels
- Add ConnectionNotice for WSS unavailability recommendations
- Change default proxy port to fixed 1353
- Implement delayed ClientHello sending with connection pattern spacing
- Update terminology from 'JA4 fingerprint' to 'ClientHello profile'
- Add comprehensive test coverage for new systems
2026-07-04 18:48:54 +03:00

71 lines
2.1 KiB
C++

/*
This file is part of Telegram Desktop,
the official desktop application for the Telegram messaging service.
For license and copyright information please follow this link:
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#include "mtproto/proxy/mtproxy/client_hello_builder.h"
#include "mtproto/proxy/mtproxy/client_hello_facts.h"
#include "mtproto/proxy/mtproxy/client_hello_profile.h"
#include "base/bytes.h"
#include <QtCore/QByteArray>
#include <QtCore/QString>
#include <cstdio>
#include <optional>
namespace {
[[nodiscard]] int Fail(const char *message) {
std::fprintf(stderr, "%s\n", message);
return 1;
}
[[nodiscard]] bytes::const_span AsBytes(const QByteArray &value) {
return bytes::make_span(value.constData(), value.size());
}
} // namespace
int main(int, char *[]) {
const auto domain = QByteArray("ja4-capture.test");
const auto key = QByteArray::fromHex("00112233445566778899aabbccddeeff");
const auto &profile = MTP::details::ClientHelloProfile(
MTP::ProxyTlsProfile::ChromeModern);
if (profile.validation != MTP::details::ClientHelloProfileValidation::Validated
|| !profile.expectedJa4[0]) {
return Fail("ChromeModern profile is not validated.");
}
auto options = MTP::details::ClientHelloGenerationOptions();
options.deterministic = true;
const auto rules = MTP::details::PrepareClientHelloRules(
MTP::ProxyTlsProfile::ChromeModern);
const auto hello = MTP::details::PrepareClientHello(
rules,
AsBytes(domain),
AsBytes(key),
MTP::ProxyTlsProfile::ChromeModern,
std::nullopt,
options);
if (hello.data.isEmpty() || hello.digest.size() != 32) {
return Fail("ChromeModern ClientHello was not generated.");
}
const auto facts = MTP::details::ComputeClientHelloFacts(hello.data);
if (!facts) {
return Fail("ChromeModern ClientHello facts were not parsed.");
}
if (!facts->hasSni || facts->firstAlpn != QByteArray("h2")) {
return Fail("ChromeModern ClientHello core facts drifted.");
}
const auto ja4 = MTP::details::ComputeClientHelloJa4(*facts);
if (ja4 != QString::fromLatin1(profile.expectedJa4)) {
return Fail("ChromeModern ClientHello JA4 drifted.");
}
return 0;
}