mirror of
https://github.com/vale981/tdesktop
synced 2025-03-06 02:01:40 -05:00
Sync local time with HTTP 'Date' header value.
This commit is contained in:
parent
c894ce30c4
commit
68b1024dd4
24 changed files with 356 additions and 55 deletions
|
@ -24,11 +24,13 @@ ConfigLoader::ConfigLoader(
|
|||
not_null<Instance*> instance,
|
||||
const QString &phone,
|
||||
RPCDoneHandlerPtr onDone,
|
||||
RPCFailHandlerPtr onFail)
|
||||
RPCFailHandlerPtr onFail,
|
||||
Fn<void(TimeId)> updateHttpUnixtime)
|
||||
: _instance(instance)
|
||||
, _phone(phone)
|
||||
, _doneHandler(onDone)
|
||||
, _failHandler(onFail) {
|
||||
, _failHandler(onFail)
|
||||
, _updateHttpUnixtime(updateHttpUnixtime) {
|
||||
_enumDCTimer.setCallback([this] { enumerate(); });
|
||||
_specialEnumTimer.setCallback([this] { sendSpecialRequest(); });
|
||||
}
|
||||
|
@ -129,7 +131,7 @@ void ConfigLoader::createSpecialLoader() {
|
|||
int port,
|
||||
bytes::const_span secret) {
|
||||
addSpecialEndpoint(dcId, ip, port, secret);
|
||||
}, _phone);
|
||||
}, _updateHttpUnixtime, _phone);
|
||||
}
|
||||
|
||||
void ConfigLoader::addSpecialEndpoint(
|
||||
|
|
|
@ -25,7 +25,8 @@ public:
|
|||
not_null<Instance*> instance,
|
||||
const QString &phone,
|
||||
RPCDoneHandlerPtr onDone,
|
||||
RPCFailHandlerPtr onFail);
|
||||
RPCFailHandlerPtr onFail,
|
||||
Fn<void(TimeId)> updateHttpUnixtime);
|
||||
~ConfigLoader();
|
||||
|
||||
void load();
|
||||
|
@ -69,6 +70,7 @@ private:
|
|||
|
||||
RPCDoneHandlerPtr _doneHandler;
|
||||
RPCFailHandlerPtr _failHandler;
|
||||
Fn<void(TimeId)> _updateHttpUnixtime;
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -379,6 +379,9 @@ void ConnectionPrivate::appendTestConnection(
|
|||
connect(weak, &AbstractConnection::disconnected, [=] {
|
||||
onDisconnected(weak);
|
||||
});
|
||||
connect(weak, &AbstractConnection::syncTimeRequest, [=] {
|
||||
_instance->syncHttpUnixtime();
|
||||
});
|
||||
|
||||
InvokeQueued(_testConnections.back().data, [=] {
|
||||
weak->connectToServer(ip, port, protocolSecret, getProtocolDcId());
|
||||
|
@ -1332,7 +1335,7 @@ void ConnectionPrivate::waitConnectedFailed() {
|
|||
_waitForConnected = std::min(maxTimeout, 2 * _waitForConnected);
|
||||
}
|
||||
|
||||
doDisconnect();
|
||||
connectingTimedOut();
|
||||
restarted = true;
|
||||
|
||||
DEBUG_LOG(("MTP Info: immediate restart!"));
|
||||
|
@ -1343,6 +1346,13 @@ void ConnectionPrivate::waitBetterFailed() {
|
|||
confirmBestConnection();
|
||||
}
|
||||
|
||||
void ConnectionPrivate::connectingTimedOut() {
|
||||
for (const auto &connection : _testConnections) {
|
||||
connection.data->timedOut();
|
||||
}
|
||||
doDisconnect();
|
||||
}
|
||||
|
||||
void ConnectionPrivate::doDisconnect() {
|
||||
destroyAllConnections();
|
||||
|
||||
|
|
|
@ -152,6 +152,7 @@ private:
|
|||
int priority = 0;
|
||||
};
|
||||
void connectToServer(bool afterConfig = false);
|
||||
void connectingTimedOut();
|
||||
void doDisconnect();
|
||||
void restart();
|
||||
void finishAndDestroy();
|
||||
|
|
|
@ -165,7 +165,10 @@ ConnectionPointer AbstractConnection::Create(
|
|||
const ProxyData &proxy) {
|
||||
auto result = [&] {
|
||||
if (protocol == DcOptions::Variants::Tcp) {
|
||||
return ConnectionPointer::New<TcpConnection>(thread, proxy);
|
||||
return ConnectionPointer::New<TcpConnection>(
|
||||
instance,
|
||||
thread,
|
||||
proxy);
|
||||
} else {
|
||||
return ConnectionPointer::New<HttpConnection>(thread, proxy);
|
||||
}
|
||||
|
|
|
@ -75,6 +75,8 @@ public:
|
|||
int port,
|
||||
const bytes::vector &protocolSecret,
|
||||
int16 protocolDcId) = 0;
|
||||
virtual void timedOut() {
|
||||
}
|
||||
virtual bool isConnected() const = 0;
|
||||
virtual bool usingHttpWait() {
|
||||
return false;
|
||||
|
@ -122,6 +124,8 @@ signals:
|
|||
void connected();
|
||||
void disconnected();
|
||||
|
||||
void syncTimeRequest();
|
||||
|
||||
protected:
|
||||
BuffersQueue _receivedQueue; // list of received packets, not processed yet
|
||||
bool _sentEncrypted = false;
|
||||
|
|
|
@ -237,13 +237,17 @@ auto TcpConnection::Protocol::Create(bytes::const_span secret)
|
|||
Unexpected("Secret bytes in TcpConnection::Protocol::Create.");
|
||||
}
|
||||
|
||||
TcpConnection::TcpConnection(QThread *thread, const ProxyData &proxy)
|
||||
TcpConnection::TcpConnection(
|
||||
not_null<Instance*> instance,
|
||||
QThread *thread,
|
||||
const ProxyData &proxy)
|
||||
: AbstractConnection(thread, proxy)
|
||||
, _instance(instance)
|
||||
, _checkNonce(rand_value<MTPint128>()) {
|
||||
}
|
||||
|
||||
ConnectionPointer TcpConnection::clone(const ProxyData &proxy) {
|
||||
return ConnectionPointer::New<TcpConnection>(thread(), proxy);
|
||||
return ConnectionPointer::New<TcpConnection>(_instance, thread(), proxy);
|
||||
}
|
||||
|
||||
void TcpConnection::ensureAvailableInBuffer(int amount) {
|
||||
|
@ -554,7 +558,8 @@ void TcpConnection::connectToServer(
|
|||
_socket = AbstractSocket::Create(
|
||||
thread(),
|
||||
secret,
|
||||
ToNetworkProxy(_proxy));
|
||||
ToNetworkProxy(_proxy),
|
||||
[=] { return _instance->httpUnixtime(); });
|
||||
_protocolDcId = protocolDcId;
|
||||
|
||||
_socket->connected(
|
||||
|
@ -577,6 +582,11 @@ void TcpConnection::connectToServer(
|
|||
socketError();
|
||||
}, _lifetime);
|
||||
|
||||
_socket->syncTimeRequests(
|
||||
) | rpl::start_with_next([=] {
|
||||
emit syncTimeRequest();
|
||||
}, _lifetime);
|
||||
|
||||
_socket->connectToHost(_address, _port);
|
||||
}
|
||||
|
||||
|
@ -628,6 +638,12 @@ void TcpConnection::socketPacket(bytes::const_span bytes) {
|
|||
}
|
||||
}
|
||||
|
||||
void TcpConnection::timedOut() {
|
||||
if (_socket) {
|
||||
_socket->timedOut();
|
||||
}
|
||||
}
|
||||
|
||||
bool TcpConnection::isConnected() const {
|
||||
return (_status == Status::Ready);
|
||||
}
|
||||
|
|
|
@ -17,7 +17,10 @@ class AbstractSocket;
|
|||
|
||||
class TcpConnection : public AbstractConnection {
|
||||
public:
|
||||
TcpConnection(QThread *thread, const ProxyData &proxy);
|
||||
TcpConnection(
|
||||
not_null<Instance*> instance,
|
||||
QThread *thread,
|
||||
const ProxyData &proxy);
|
||||
|
||||
ConnectionPointer clone(const ProxyData &proxy) override;
|
||||
|
||||
|
@ -30,6 +33,7 @@ public:
|
|||
int port,
|
||||
const bytes::vector &protocolSecret,
|
||||
int16 protocolDcId) override;
|
||||
void timedOut() override;
|
||||
bool isConnected() const override;
|
||||
bool requiresExtendedPadding() const override;
|
||||
|
||||
|
@ -63,6 +67,7 @@ private:
|
|||
return *reinterpret_cast<uint32*>(ch);
|
||||
}
|
||||
|
||||
const not_null<Instance*> _instance;
|
||||
std::unique_ptr<AbstractSocket> _socket;
|
||||
bool _connectionStarted = false;
|
||||
|
||||
|
|
|
@ -16,9 +16,10 @@ namespace internal {
|
|||
std::unique_ptr<AbstractSocket> AbstractSocket::Create(
|
||||
not_null<QThread*> thread,
|
||||
const bytes::vector &secret,
|
||||
const QNetworkProxy &proxy) {
|
||||
const QNetworkProxy &proxy,
|
||||
Fn<int32()> unixtime) {
|
||||
if (secret.size() >= 21 && secret[0] == bytes::type(0xEE)) {
|
||||
return std::make_unique<TlsSocket>(thread, secret, proxy);
|
||||
return std::make_unique<TlsSocket>(thread, secret, proxy, unixtime);
|
||||
} else {
|
||||
return std::make_unique<TcpSocket>(thread, proxy);
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#pragma once
|
||||
|
||||
#include "base/bytes.h"
|
||||
#include "base/basic_types.h"
|
||||
|
||||
namespace MTP {
|
||||
namespace internal {
|
||||
|
@ -17,7 +18,8 @@ public:
|
|||
static std::unique_ptr<AbstractSocket> Create(
|
||||
not_null<QThread*> thread,
|
||||
const bytes::vector &secret,
|
||||
const QNetworkProxy &proxy);
|
||||
const QNetworkProxy &proxy,
|
||||
Fn<int32()> unixtime);
|
||||
|
||||
explicit AbstractSocket(not_null<QThread*> thread) {
|
||||
moveToThread(thread);
|
||||
|
@ -36,8 +38,12 @@ public:
|
|||
[[nodiscard]] rpl::producer<> error() const {
|
||||
return _error.events();
|
||||
}
|
||||
[[nodiscard]] rpl::producer<> syncTimeRequests() const {
|
||||
return _syncTimeRequests.events();
|
||||
}
|
||||
|
||||
virtual void connectToHost(const QString &address, int port) = 0;
|
||||
virtual void timedOut() = 0;
|
||||
[[nodiscard]] virtual bool isConnected() = 0;
|
||||
[[nodiscard]] virtual bool hasBytesAvailable() = 0;
|
||||
[[nodiscard]] virtual int64 read(bytes::span buffer) = 0;
|
||||
|
@ -52,6 +58,7 @@ protected:
|
|||
rpl::event_stream<> _disconnected;
|
||||
rpl::event_stream<> _readyRead;
|
||||
rpl::event_stream<> _error;
|
||||
rpl::event_stream<> _syncTimeRequests;
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -42,31 +42,36 @@ public:
|
|||
void setGoodProxyDomain(const QString &host, const QString &ip);
|
||||
void suggestMainDcId(DcId mainDcId);
|
||||
void setMainDcId(DcId mainDcId);
|
||||
DcId mainDcId() const;
|
||||
[[nodiscard]] DcId mainDcId() const;
|
||||
|
||||
void setKeyForWrite(DcId dcId, const AuthKeyPtr &key);
|
||||
AuthKeysList getKeysForWrite() const;
|
||||
[[nodiscard]] AuthKeysList getKeysForWrite() const;
|
||||
void addKeysForDestroy(AuthKeysList &&keys);
|
||||
|
||||
not_null<DcOptions*> dcOptions();
|
||||
[[nodiscard]] not_null<DcOptions*> dcOptions();
|
||||
|
||||
// Thread safe.
|
||||
QString deviceModel() const;
|
||||
QString systemVersion() const;
|
||||
[[nodiscard]] QString deviceModel() const;
|
||||
[[nodiscard]] QString systemVersion() const;
|
||||
|
||||
// Main thread.
|
||||
void requestConfig();
|
||||
void requestConfigIfOld();
|
||||
void requestCDNConfig();
|
||||
void setUserPhone(const QString &phone);
|
||||
void badConfigurationError();
|
||||
|
||||
// Thread safe.
|
||||
void syncHttpUnixtime();
|
||||
[[nodiscard]] int32 httpUnixtime() const;
|
||||
|
||||
void restart();
|
||||
void restart(ShiftedDcId shiftedDcId);
|
||||
int32 dcstate(ShiftedDcId shiftedDcId = 0);
|
||||
QString dctransport(ShiftedDcId shiftedDcId = 0);
|
||||
[[nodiscard]] int32 dcstate(ShiftedDcId shiftedDcId = 0);
|
||||
[[nodiscard]] QString dctransport(ShiftedDcId shiftedDcId = 0);
|
||||
void ping();
|
||||
void cancel(mtpRequestId requestId);
|
||||
int32 state(mtpRequestId requestId); // < 0 means waiting for such count of ms
|
||||
[[nodiscard]] int32 state(mtpRequestId requestId); // < 0 means waiting for such count of ms
|
||||
void killSession(ShiftedDcId shiftedDcId);
|
||||
void killSession(std::unique_ptr<internal::Session> session);
|
||||
void stopSession(ShiftedDcId shiftedDcId);
|
||||
|
@ -123,9 +128,6 @@ public:
|
|||
bool isKeysDestroyer() const {
|
||||
return (_mode == Instance::Mode::KeysDestroyer);
|
||||
}
|
||||
bool isSpecialConfigRequester() const {
|
||||
return (_mode == Instance::Mode::SpecialConfigRequester);
|
||||
}
|
||||
|
||||
void scheduleKeyDestroy(ShiftedDcId shiftedDcId);
|
||||
void performKeyDestroy(ShiftedDcId shiftedDcId);
|
||||
|
@ -166,6 +168,7 @@ private:
|
|||
void clearCallbacks(const std::vector<RPCCallbackClear> &ids);
|
||||
|
||||
void checkDelayedRequests();
|
||||
[[nodiscard]] Fn<void(TimeId)> updateHttpUnixtime();
|
||||
|
||||
not_null<Instance*> _instance;
|
||||
not_null<DcOptions*> _dcOptions;
|
||||
|
@ -186,10 +189,13 @@ private:
|
|||
|
||||
std::unique_ptr<internal::ConfigLoader> _configLoader;
|
||||
std::unique_ptr<DomainResolver> _domainResolver;
|
||||
std::unique_ptr<SpecialConfigRequest> _httpUnixtimeLoader;
|
||||
QString _userPhone;
|
||||
mtpRequestId _cdnConfigLoadRequestId = 0;
|
||||
crl::time _lastConfigLoadedTime = 0;
|
||||
crl::time _configExpiresAt = 0;
|
||||
std::atomic<bool> _httpUnixtimeValid = false;
|
||||
std::atomic<TimeId> _httpUnixtimeShift = 0;
|
||||
|
||||
std::map<DcId, AuthKeyPtr> _keysForWrite;
|
||||
mutable QReadWriteLock _keysForWriteLock;
|
||||
|
@ -407,7 +413,8 @@ void Instance::Private::requestConfig() {
|
|||
_instance,
|
||||
_userPhone,
|
||||
rpcDone([=](const MTPConfig &result) { configLoadDone(result); }),
|
||||
rpcFail([=](const RPCError &error) { return configLoadFail(error); }));
|
||||
rpcFail([=](const RPCError &error) { return configLoadFail(error); }),
|
||||
updateHttpUnixtime());
|
||||
_configLoader->load();
|
||||
}
|
||||
|
||||
|
@ -426,6 +433,35 @@ void Instance::Private::badConfigurationError() {
|
|||
}
|
||||
}
|
||||
|
||||
int32 Instance::Private::httpUnixtime() const {
|
||||
return unixtime() + _httpUnixtimeShift;
|
||||
}
|
||||
|
||||
void Instance::Private::syncHttpUnixtime() {
|
||||
if (_httpUnixtimeValid) {
|
||||
return;
|
||||
}
|
||||
InvokeQueued(_instance, [=] {
|
||||
if (_httpUnixtimeValid || _httpUnixtimeLoader) {
|
||||
return;
|
||||
}
|
||||
_httpUnixtimeLoader = std::make_unique<SpecialConfigRequest>(
|
||||
updateHttpUnixtime());
|
||||
});
|
||||
}
|
||||
|
||||
Fn<void(TimeId)> Instance::Private::updateHttpUnixtime() {
|
||||
return [=](TimeId httpUnixtime) {
|
||||
_httpUnixtimeValid = true;
|
||||
_httpUnixtimeShift = httpUnixtime - unixtime();
|
||||
InvokeQueued(_instance, [=] {
|
||||
if (_httpUnixtimeValid) {
|
||||
_httpUnixtimeLoader = nullptr;
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
void Instance::Private::requestConfigIfOld() {
|
||||
const auto timeout = Global::BlockedMode()
|
||||
? kConfigBecomesOldForBlockedIn
|
||||
|
@ -1579,6 +1615,14 @@ void Instance::badConfigurationError() {
|
|||
_private->badConfigurationError();
|
||||
}
|
||||
|
||||
int32 Instance::httpUnixtime() const {
|
||||
return _private->httpUnixtime();
|
||||
}
|
||||
|
||||
void Instance::syncHttpUnixtime() {
|
||||
_private->syncHttpUnixtime();
|
||||
}
|
||||
|
||||
void Instance::requestConfigIfOld() {
|
||||
_private->requestConfigIfOld();
|
||||
}
|
||||
|
|
|
@ -40,7 +40,6 @@ public:
|
|||
};
|
||||
enum class Mode {
|
||||
Normal,
|
||||
SpecialConfigRequester,
|
||||
KeysDestroyer,
|
||||
};
|
||||
Instance(not_null<DcOptions*> options, Mode mode, Config &&config);
|
||||
|
@ -52,20 +51,20 @@ public:
|
|||
void setGoodProxyDomain(const QString &host, const QString &ip);
|
||||
void suggestMainDcId(DcId mainDcId);
|
||||
void setMainDcId(DcId mainDcId);
|
||||
DcId mainDcId() const;
|
||||
QString systemLangCode() const;
|
||||
QString cloudLangCode() const;
|
||||
QString langPackName() const;
|
||||
[[nodiscard]] DcId mainDcId() const;
|
||||
[[nodiscard]] QString systemLangCode() const;
|
||||
[[nodiscard]] QString cloudLangCode() const;
|
||||
[[nodiscard]] QString langPackName() const;
|
||||
|
||||
// Thread safe.
|
||||
QString deviceModel() const;
|
||||
QString systemVersion() const;
|
||||
[[nodiscard]] QString deviceModel() const;
|
||||
[[nodiscard]] QString systemVersion() const;
|
||||
|
||||
void setKeyForWrite(DcId dcId, const AuthKeyPtr &key);
|
||||
AuthKeysList getKeysForWrite() const;
|
||||
[[nodiscard]] AuthKeysList getKeysForWrite() const;
|
||||
void addKeysForDestroy(AuthKeysList &&keys);
|
||||
|
||||
not_null<DcOptions*> dcOptions();
|
||||
[[nodiscard]] not_null<DcOptions*> dcOptions();
|
||||
|
||||
template <typename Request>
|
||||
mtpRequestId send(
|
||||
|
@ -181,6 +180,10 @@ public:
|
|||
void setUserPhone(const QString &phone);
|
||||
void badConfigurationError();
|
||||
|
||||
// Thread safe.
|
||||
[[nodiscard]] int32 httpUnixtime() const;
|
||||
void syncHttpUnixtime();
|
||||
|
||||
~Instance();
|
||||
|
||||
public slots:
|
||||
|
|
9
Telegram/SourceFiles/mtproto/mtp_pch.cpp
Normal file
9
Telegram/SourceFiles/mtproto/mtp_pch.cpp
Normal file
|
@ -0,0 +1,9 @@
|
|||
/*
|
||||
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/mtp_pch.h"
|
||||
|
19
Telegram/SourceFiles/mtproto/mtp_pch.h
Normal file
19
Telegram/SourceFiles/mtproto/mtp_pch.h
Normal file
|
@ -0,0 +1,19 @@
|
|||
/*
|
||||
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 <QtCore/QObject>
|
||||
#include <QtCore/QThread>
|
||||
#include <QtNetwork/QNetworkProxy>
|
||||
#include <QtNetwork/QTcpSocket>
|
||||
|
||||
#include <rpl/rpl.h>
|
||||
#include <crl/crl.h>
|
||||
|
||||
#include "base/bytes.h"
|
||||
|
||||
#include "logs.h"
|
||||
#include "scheme.h"
|
|
@ -7,6 +7,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
*/
|
||||
#include "mtproto/mtp_tcp_socket.h"
|
||||
|
||||
#include "base/invoke_queued.h"
|
||||
|
||||
namespace MTP {
|
||||
namespace internal {
|
||||
|
||||
|
@ -45,6 +47,9 @@ void TcpSocket::connectToHost(const QString &address, int port) {
|
|||
_socket.connectToHost(address, port);
|
||||
}
|
||||
|
||||
void TcpSocket::timedOut() {
|
||||
}
|
||||
|
||||
bool TcpSocket::isConnected() {
|
||||
return (_socket.state() == QAbstractSocket::ConnectedState);
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@ public:
|
|||
TcpSocket(not_null<QThread*> thread, const QNetworkProxy &proxy);
|
||||
|
||||
void connectToHost(const QString &address, int port) override;
|
||||
void timedOut() override;
|
||||
bool isConnected() override;
|
||||
bool hasBytesAvailable() override;
|
||||
int64 read(bytes::span buffer) override;
|
||||
|
|
|
@ -9,6 +9,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
|
||||
#include "mtproto/mtp_tcp_socket.h"
|
||||
#include "base/openssl_help.h"
|
||||
#include "base/bytes.h"
|
||||
#include "base/invoke_queued.h"
|
||||
|
||||
#include <QtCore/QtEndian>
|
||||
|
||||
namespace MTP {
|
||||
namespace internal {
|
||||
|
@ -132,7 +136,8 @@ public:
|
|||
ClientHelloGenerator(
|
||||
const MTPTlsClientHello &rules,
|
||||
bytes::const_span domain,
|
||||
bytes::const_span key);
|
||||
bytes::const_span key,
|
||||
Fn<int32()> unixtime);
|
||||
[[nodiscard]] ClientHello result();
|
||||
|
||||
private:
|
||||
|
@ -151,6 +156,7 @@ private:
|
|||
|
||||
bytes::const_span _domain;
|
||||
bytes::const_span _key;
|
||||
Fn<int32()> _unixtime;
|
||||
bytes::vector _greases;
|
||||
std::vector<int> _scopeStack;
|
||||
QByteArray _result;
|
||||
|
@ -163,9 +169,11 @@ private:
|
|||
ClientHelloGenerator::ClientHelloGenerator(
|
||||
const MTPTlsClientHello &rules,
|
||||
bytes::const_span domain,
|
||||
bytes::const_span key)
|
||||
bytes::const_span key,
|
||||
Fn<int32()> unixtime)
|
||||
: _domain(domain)
|
||||
, _key(key)
|
||||
, _unixtime(unixtime)
|
||||
, _greases(PrepareGreases()) {
|
||||
_result.reserve(kClientHelloLength);
|
||||
writeBlocks(rules.match([&](const MTPDtlsClientHello &data) {
|
||||
|
@ -296,7 +304,7 @@ void ClientHelloGenerator::writeTimestamp() {
|
|||
sizeof(int32));
|
||||
auto already = int32();
|
||||
bytes::copy(bytes::object_as_span(&already), storage);
|
||||
already ^= qToLittleEndian(int32(unixtime()));
|
||||
already ^= qToLittleEndian(_unixtime());
|
||||
bytes::copy(storage, bytes::object_as_span(&already));
|
||||
|
||||
_digest = QByteArray(kHelloDigestLength, Qt::Uninitialized);
|
||||
|
@ -310,8 +318,9 @@ void ClientHelloGenerator::writeTimestamp() {
|
|||
[[nodiscard]] ClientHello PrepareClientHello(
|
||||
const MTPTlsClientHello &rules,
|
||||
bytes::const_span domain,
|
||||
bytes::const_span key) {
|
||||
return ClientHelloGenerator(rules, domain, key).result();
|
||||
bytes::const_span key,
|
||||
Fn<int32()> unixtime) {
|
||||
return ClientHelloGenerator(rules, domain, key, unixtime).result();
|
||||
}
|
||||
|
||||
[[nodiscard]] bool CheckPart(bytes::const_span data, QLatin1String check) {
|
||||
|
@ -334,10 +343,13 @@ void ClientHelloGenerator::writeTimestamp() {
|
|||
TlsSocket::TlsSocket(
|
||||
not_null<QThread*> thread,
|
||||
const bytes::vector &secret,
|
||||
const QNetworkProxy &proxy)
|
||||
const QNetworkProxy &proxy,
|
||||
Fn<int32()> unixtime)
|
||||
: AbstractSocket(thread)
|
||||
, _secret(secret) {
|
||||
, _secret(secret)
|
||||
, _unixtime(unixtime) {
|
||||
Expects(_secret.size() >= 21 && _secret[0] == bytes::type(0xEE));
|
||||
Expects(_unixtime != nullptr);
|
||||
|
||||
_socket.moveToThread(thread);
|
||||
_socket.setProxy(proxy);
|
||||
|
@ -385,7 +397,8 @@ void TlsSocket::plainConnected() {
|
|||
const auto hello = PrepareClientHello(
|
||||
kClientHelloRules,
|
||||
domainFromSecret(),
|
||||
keyFromSecret());
|
||||
keyFromSecret(),
|
||||
_unixtime);
|
||||
if (hello.data.isEmpty()) {
|
||||
LOG(("TLS Error: Could not generate Client Hello!"));
|
||||
_state = State::Error;
|
||||
|
@ -570,6 +583,10 @@ void TlsSocket::connectToHost(const QString &address, int port) {
|
|||
_socket.connectToHost(address, port);
|
||||
}
|
||||
|
||||
void TlsSocket::timedOut() {
|
||||
_syncTimeRequests.fire({});
|
||||
}
|
||||
|
||||
bool TlsSocket::isConnected() {
|
||||
return (_state == State::Connected);
|
||||
}
|
||||
|
@ -648,6 +665,9 @@ int32 TlsSocket::debugState() {
|
|||
}
|
||||
|
||||
void TlsSocket::handleError(int errorCode) {
|
||||
if (_state != State::Connected) {
|
||||
_syncTimeRequests.fire({});
|
||||
}
|
||||
if (errorCode) {
|
||||
TcpSocket::LogError(errorCode, _socket.errorString());
|
||||
}
|
||||
|
|
|
@ -17,9 +17,11 @@ public:
|
|||
TlsSocket(
|
||||
not_null<QThread*> thread,
|
||||
const bytes::vector &secret,
|
||||
const QNetworkProxy &proxy);
|
||||
const QNetworkProxy &proxy,
|
||||
Fn<int32()> unixtime);
|
||||
|
||||
void connectToHost(const QString &address, int port) override;
|
||||
void timedOut() override;
|
||||
bool isConnected() override;
|
||||
bool hasBytesAvailable() override;
|
||||
int64 read(bytes::span buffer) override;
|
||||
|
@ -54,6 +56,7 @@ private:
|
|||
|
||||
const bytes::vector _secret;
|
||||
QTcpSocket _socket;
|
||||
Fn<int32()> _unixtime;
|
||||
State _state = State::NotConnected;
|
||||
QByteArray _incoming;
|
||||
int _incomingGoodDataOffset = 0;
|
||||
|
|
|
@ -170,6 +170,52 @@ QByteArray ConcatenateDnsTxtFields(const std::vector<DnsEntry> &response) {
|
|||
return QStringList(entries.values()).join(QString()).toLatin1();
|
||||
}
|
||||
|
||||
[[nodiscard]] QDateTime ParseHttpDate(const QString &date) {
|
||||
// Wed, 10 Jul 2019 14:33:38 GMT
|
||||
static const auto expression = QRegularExpression(
|
||||
R"(\w\w\w, (\d\d) (\w\w\w) (\d\d\d\d) (\d\d):(\d\d):(\d\d) GMT)");
|
||||
const auto match = expression.match(date);
|
||||
if (!match.hasMatch()) {
|
||||
return QDateTime();
|
||||
}
|
||||
|
||||
const auto number = [&](int index) {
|
||||
return match.capturedRef(index).toInt();
|
||||
};
|
||||
const auto day = number(1);
|
||||
const auto month = [&] {
|
||||
static const auto months = {
|
||||
"Jan",
|
||||
"Feb",
|
||||
"Mar",
|
||||
"Apr",
|
||||
"May",
|
||||
"Jun",
|
||||
"Jul",
|
||||
"Aug",
|
||||
"Sep",
|
||||
"Oct",
|
||||
"Nov",
|
||||
"Dec"
|
||||
};
|
||||
const auto captured = match.capturedRef(2);
|
||||
for (auto i = begin(months); i != end(months); ++i) {
|
||||
if (captured == (*i)) {
|
||||
return 1 + int(i - begin(months));
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}();
|
||||
const auto year = number(3);
|
||||
const auto hour = number(4);
|
||||
const auto minute = number(5);
|
||||
const auto second = number(6);
|
||||
return QDateTime(
|
||||
QDate(year, month, day),
|
||||
QTime(hour, minute, second),
|
||||
Qt::UTC);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
ServiceWebRequest::ServiceWebRequest(not_null<QNetworkReply*> reply)
|
||||
|
@ -212,8 +258,10 @@ SpecialConfigRequest::SpecialConfigRequest(
|
|||
const std::string &ip,
|
||||
int port,
|
||||
bytes::const_span secret)> callback,
|
||||
Fn<void(TimeId)> timeCallback,
|
||||
const QString &phone)
|
||||
: _callback(std::move(callback))
|
||||
, _timeCallback(std::move(timeCallback))
|
||||
, _phone(phone) {
|
||||
_manager.setProxy(QNetworkProxy::NoProxy);
|
||||
_attempts = {
|
||||
|
@ -227,6 +275,10 @@ SpecialConfigRequest::SpecialConfigRequest(
|
|||
sendNextRequest();
|
||||
}
|
||||
|
||||
SpecialConfigRequest::SpecialConfigRequest(Fn<void(TimeId)> timeCallback)
|
||||
: SpecialConfigRequest(nullptr, std::move(timeCallback), QString()) {
|
||||
}
|
||||
|
||||
void SpecialConfigRequest::sendNextRequest() {
|
||||
Expects(!_attempts.empty());
|
||||
|
||||
|
@ -272,10 +324,40 @@ void SpecialConfigRequest::performRequest(const Attempt &attempt) {
|
|||
});
|
||||
}
|
||||
|
||||
void SpecialConfigRequest::handleHeaderUnixtime(
|
||||
not_null<QNetworkReply*> reply) {
|
||||
if (!_timeCallback || reply->error() != QNetworkReply::NoError) {
|
||||
return;
|
||||
}
|
||||
const auto date = QString::fromLatin1([&] {
|
||||
for (const auto &pair : reply->rawHeaderPairs()) {
|
||||
if (pair.first == "Date") {
|
||||
return pair.second;
|
||||
}
|
||||
}
|
||||
return QByteArray();
|
||||
}());
|
||||
if (date.isEmpty()) {
|
||||
LOG(("Config Error: No 'Date' header received."));
|
||||
return;
|
||||
}
|
||||
const auto parsed = ParseHttpDate(date);
|
||||
if (!parsed.isValid()) {
|
||||
LOG(("Config Error: Bad 'Date' header received: %1").arg(date));
|
||||
return;
|
||||
}
|
||||
_timeCallback(parsed.toTime_t());
|
||||
}
|
||||
|
||||
void SpecialConfigRequest::requestFinished(
|
||||
Type type,
|
||||
not_null<QNetworkReply*> reply) {
|
||||
handleHeaderUnixtime(reply);
|
||||
const auto result = finalizeRequest(reply);
|
||||
if (!_callback) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
//case Type::App: handleResponse(result); break;
|
||||
case Type::Dns: {
|
||||
|
|
|
@ -12,14 +12,14 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
namespace MTP {
|
||||
|
||||
struct ServiceWebRequest {
|
||||
ServiceWebRequest(not_null<QNetworkReply*> reply);
|
||||
ServiceWebRequest(ServiceWebRequest &&other);
|
||||
ServiceWebRequest &operator=(ServiceWebRequest &&other);
|
||||
~ServiceWebRequest();
|
||||
ServiceWebRequest(not_null<QNetworkReply*> reply);
|
||||
ServiceWebRequest(ServiceWebRequest &&other);
|
||||
ServiceWebRequest &operator=(ServiceWebRequest &&other);
|
||||
~ServiceWebRequest();
|
||||
|
||||
void destroy();
|
||||
void destroy();
|
||||
|
||||
QPointer<QNetworkReply> reply;
|
||||
QPointer<QNetworkReply> reply;
|
||||
|
||||
};
|
||||
|
||||
|
@ -31,7 +31,9 @@ public:
|
|||
const std::string &ip,
|
||||
int port,
|
||||
bytes::const_span secret)> callback,
|
||||
Fn<void(TimeId)> timeCallback,
|
||||
const QString &phone);
|
||||
explicit SpecialConfigRequest(Fn<void(TimeId)> timeCallback);
|
||||
|
||||
private:
|
||||
enum class Type {
|
||||
|
@ -46,6 +48,7 @@ private:
|
|||
void sendNextRequest();
|
||||
void performRequest(const Attempt &attempt);
|
||||
void requestFinished(Type type, not_null<QNetworkReply*> reply);
|
||||
void handleHeaderUnixtime(not_null<QNetworkReply*> reply);
|
||||
QByteArray finalizeRequest(not_null<QNetworkReply*> reply);
|
||||
void handleResponse(const QByteArray &bytes);
|
||||
bool decryptSimpleConfig(const QByteArray &bytes);
|
||||
|
@ -55,6 +58,7 @@ private:
|
|||
const std::string &ip,
|
||||
int port,
|
||||
bytes::const_span secret)> _callback;
|
||||
Fn<void(TimeId)> _timeCallback;
|
||||
QString _phone;
|
||||
MTPhelp_ConfigSimple _simpleConfig;
|
||||
|
||||
|
|
|
@ -83,6 +83,7 @@
|
|||
'lib_storage.gyp:lib_storage',
|
||||
'lib_lottie.gyp:lib_lottie',
|
||||
'lib_ffmpeg.gyp:lib_ffmpeg',
|
||||
'lib_mtproto.gyp:lib_mtproto',
|
||||
],
|
||||
|
||||
'defines': [
|
||||
|
|
|
@ -57,6 +57,7 @@
|
|||
'<(src_loc)/base/flat_set.h',
|
||||
'<(src_loc)/base/functors.h',
|
||||
'<(src_loc)/base/index_based_iterator.h',
|
||||
'<(src_loc)/base/invoke_queued.h',
|
||||
'<(src_loc)/base/last_used_cache.h',
|
||||
'<(src_loc)/base/match_method.h',
|
||||
'<(src_loc)/base/observer.cpp',
|
||||
|
|
64
Telegram/gyp/lib_mtproto.gyp
Normal file
64
Telegram/gyp/lib_mtproto.gyp
Normal file
|
@ -0,0 +1,64 @@
|
|||
# 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
|
||||
|
||||
{
|
||||
'includes': [
|
||||
'common.gypi',
|
||||
],
|
||||
'targets': [{
|
||||
'target_name': 'lib_mtproto',
|
||||
'type': 'static_library',
|
||||
'includes': [
|
||||
'common.gypi',
|
||||
'qt.gypi',
|
||||
'telegram_linux.gypi',
|
||||
'pch.gypi',
|
||||
'openssl.gypi',
|
||||
],
|
||||
'variables': {
|
||||
'src_loc': '../SourceFiles',
|
||||
'res_loc': '../Resources',
|
||||
'libs_loc': '../../../Libraries',
|
||||
'official_build_target%': '',
|
||||
'submodules_loc': '../ThirdParty',
|
||||
'pch_source': '<(src_loc)/mtproto/mtp_pch.cpp',
|
||||
'pch_header': '<(src_loc)/mtproto/mtp_pch.h',
|
||||
},
|
||||
'defines': [
|
||||
],
|
||||
'dependencies': [
|
||||
'lib_scheme.gyp:lib_scheme',
|
||||
'crl.gyp:crl',
|
||||
],
|
||||
'export_dependent_settings': [
|
||||
'lib_scheme.gyp:lib_scheme',
|
||||
],
|
||||
'conditions': [[ 'build_macold', {
|
||||
'xcode_settings': {
|
||||
'OTHER_CPLUSPLUSFLAGS': [ '-nostdinc++' ],
|
||||
},
|
||||
'include_dirs': [
|
||||
'/usr/local/macold/include/c++/v1',
|
||||
],
|
||||
}]],
|
||||
'include_dirs': [
|
||||
'<(src_loc)',
|
||||
'<(SHARED_INTERMEDIATE_DIR)',
|
||||
'<(libs_loc)/range-v3/include',
|
||||
'<(submodules_loc)/GSL/include',
|
||||
'<(submodules_loc)/variant/include',
|
||||
'<(submodules_loc)/crl/src',
|
||||
],
|
||||
'sources': [
|
||||
'<(src_loc)/mtproto/mtp_abstract_socket.cpp',
|
||||
'<(src_loc)/mtproto/mtp_abstract_socket.h',
|
||||
'<(src_loc)/mtproto/mtp_tcp_socket.cpp',
|
||||
'<(src_loc)/mtproto/mtp_tcp_socket.h',
|
||||
'<(src_loc)/mtproto/mtp_tls_socket.cpp',
|
||||
'<(src_loc)/mtproto/mtp_tls_socket.h',
|
||||
],
|
||||
}],
|
||||
}
|
|
@ -531,12 +531,6 @@
|
|||
<(src_loc)/mtproto/dedicated_file_loader.h
|
||||
<(src_loc)/mtproto/facade.cpp
|
||||
<(src_loc)/mtproto/facade.h
|
||||
<(src_loc)/mtproto/mtp_abstract_socket.cpp
|
||||
<(src_loc)/mtproto/mtp_abstract_socket.h
|
||||
<(src_loc)/mtproto/mtp_tcp_socket.cpp
|
||||
<(src_loc)/mtproto/mtp_tcp_socket.h
|
||||
<(src_loc)/mtproto/mtp_tls_socket.cpp
|
||||
<(src_loc)/mtproto/mtp_tls_socket.h
|
||||
<(src_loc)/mtproto/mtp_instance.cpp
|
||||
<(src_loc)/mtproto/mtp_instance.h
|
||||
<(src_loc)/mtproto/rsa_public_key.cpp
|
||||
|
|
Loading…
Add table
Reference in a new issue