Support base64 encoding of the secret.

This commit is contained in:
John Preston 2019-07-08 18:02:45 +02:00
parent 2f0331b2e0
commit 8135f4b427
13 changed files with 269 additions and 117 deletions

View File

@ -145,6 +145,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_sure_ban_admin" = "This user is an admin. Are you sure you want to go ahead and restrict them?"; "lng_sure_ban_admin" = "This user is an admin. Are you sure you want to go ahead and restrict them?";
"lng_sure_enable_socks" = "Are you sure you want to enable this proxy?\n\nServer: {server}\nPort: {port}\n\nYou can change your proxy server later in the Settings (Connection Type)."; "lng_sure_enable_socks" = "Are you sure you want to enable this proxy?\n\nServer: {server}\nPort: {port}\n\nYou can change your proxy server later in the Settings (Connection Type).";
"lng_sure_enable" = "Enable"; "lng_sure_enable" = "Enable";
"lng_proxy_invalid" = "The proxy link is invalid.";
"lng_proxy_unsupported" = "Your Telegram Desktop version doesn't support this proxy type or the proxy link is invalid. Please update Telegram Desktop to the latest version.";
"lng_edit_deleted" = "This message was deleted"; "lng_edit_deleted" = "This message was deleted";
"lng_edit_too_long" = "Your message text is too long"; "lng_edit_too_long" = "Your message text is too long";

View File

@ -31,6 +31,57 @@ namespace {
constexpr auto kSaveSettingsDelayedTimeout = crl::time(1000); constexpr auto kSaveSettingsDelayedTimeout = crl::time(1000);
class Base64UrlInput : public Ui::MaskedInputField {
public:
Base64UrlInput(
QWidget *parent,
const style::InputField &st,
rpl::producer<QString> placeholder,
const QString &val);
protected:
void correctValue(
const QString &was,
int wasCursor,
QString &now,
int &nowCursor) override;
};
Base64UrlInput::Base64UrlInput(
QWidget *parent,
const style::InputField &st,
rpl::producer<QString> placeholder,
const QString &val)
: MaskedInputField(parent, st, std::move(placeholder), val) {
if (!QRegularExpression("^[a-zA-Z0-9_\\-]+$").match(val).hasMatch()) {
setText(QString());
}
}
void Base64UrlInput::correctValue(
const QString &was,
int wasCursor,
QString &now,
int &nowCursor) {
QString newText;
newText.reserve(now.size());
auto newPos = nowCursor;
for (auto i = 0, l = now.size(); i < l; ++i) {
const auto ch = now[i];
if ((ch >= '0' && ch <= '9')
|| (ch >= 'a' && ch <= 'z')
|| (ch >= 'A' && ch <= 'Z')
|| (ch == '-')
|| (ch == '_')) {
newText.append(ch);
} else if (i < nowCursor) {
--newPos;
}
}
setCorrectedText(now, nowCursor, newText, newPos);
}
class ProxyRow : public Ui::RippleButton { class ProxyRow : public Ui::RippleButton {
public: public:
using View = ProxiesBoxController::ItemView; using View = ProxiesBoxController::ItemView;
@ -150,7 +201,7 @@ private:
QPointer<Ui::PortInput> _port; QPointer<Ui::PortInput> _port;
QPointer<Ui::InputField> _user; QPointer<Ui::InputField> _user;
QPointer<Ui::PasswordInput> _password; QPointer<Ui::PasswordInput> _password;
QPointer<Ui::HexInput> _secret; QPointer<Base64UrlInput> _secret;
QPointer<Ui::SlideWrap<Ui::VerticalLayout>> _credentials; QPointer<Ui::SlideWrap<Ui::VerticalLayout>> _credentials;
QPointer<Ui::SlideWrap<Ui::VerticalLayout>> _mtprotoCredentials; QPointer<Ui::SlideWrap<Ui::VerticalLayout>> _mtprotoCredentials;
@ -852,12 +903,11 @@ void ProxyBox::setupMtprotoCredentials(const ProxyData &data) {
addLabel(mtproto, tr::lng_proxy_credentials(tr::now)); addLabel(mtproto, tr::lng_proxy_credentials(tr::now));
auto secretWrap = object_ptr<Ui::RpWidget>(mtproto); auto secretWrap = object_ptr<Ui::RpWidget>(mtproto);
_secret = Ui::CreateChild<Ui::HexInput>( _secret = Ui::CreateChild<Base64UrlInput>(
secretWrap.data(), secretWrap.data(),
st::connectionUserInputField, st::connectionUserInputField,
tr::lng_connection_proxy_secret_ph(), tr::lng_connection_proxy_secret_ph(),
(data.type == Type::Mtproto) ? data.password : QString()); (data.type == Type::Mtproto) ? data.password : QString());
_secret->setMaxLength(ProxyData::MaxMtprotoPasswordLength());
_secret->move(0, 0); _secret->move(0, 0);
_secret->heightValue( _secret->heightValue(
) | rpl::start_with_next([=, wrap = secretWrap.data()](int height) { ) | rpl::start_with_next([=, wrap = secretWrap.data()](int height) {
@ -975,6 +1025,11 @@ void ProxiesBoxController::ShowApplyConfirmation(
strong->closeBox(); strong->closeBox();
} }
}), LayerOption::KeepOther); }), LayerOption::KeepOther);
} else {
Ui::show(Box<InformBox>(
(proxy.status() == ProxyData::Status::Unsupported
? tr::lng_proxy_unsupported(tr::now)
: tr::lng_proxy_invalid(tr::now))));
} }
} }

View File

@ -84,8 +84,105 @@ std::atomic<int> GlobalAtomicRequestId = 0;
memset_rand(&msgIdRand, sizeof(uint32)); memset_rand(&msgIdRand, sizeof(uint32));
_msgIdStart = (((uint64)((uint32)unixtime()) << 32) | (uint64)msgIdRand); _msgIdStart = (((uint64)((uint32)unixtime()) << 32) | (uint64)msgIdRand);
} }
[[nodiscard]] bool IsHexMtprotoPassword(const QString &password) {
const auto bad = [](QChar ch) {
const auto code = ch.unicode();
return (code < 'a' || code > 'f')
&& (code < 'A' || code > 'F')
&& (code < '0' || code > '9');
};
return (password.size() % 2 == 0)
&& (std::find_if(password.begin(), password.end(), bad)
== password.end());
} }
[[nodiscard]] ProxyData::Status HexMtprotoPasswordStatus(
const QString &password) {
const auto size = password.size() / 2;
const auto valid = (size == 16)
|| (size == 17 && (password[0] == 'd') && (password[1] == 'd'))
|| (size >= 21 && (password[0] == 'e') && (password[1] == 'e'));
if (valid) {
return ProxyData::Status::Valid;
} else if (size < 16) {
return ProxyData::Status::Invalid;
}
return ProxyData::Status::Unsupported;
}
[[nodiscard]] bytes::vector SecretFromHexMtprotoPassword(
const QString &password) {
Expects(password.size() % 2 == 0);
const auto size = password.size() / 2;
const auto fromHex = [](QChar ch) -> int {
const auto code = int(ch.unicode());
if (code >= '0' && code <= '9') {
return (code - '0');
} else if (code >= 'A' && code <= 'F') {
return 10 + (code - 'A');
} else if (ch >= 'a' && ch <= 'f') {
return 10 + (code - 'a');
}
Unexpected("Code in ProxyData fromHex.");
};
auto result = bytes::vector(size);
for (auto i = 0; i != size; ++i) {
const auto high = fromHex(password[2 * i]);
const auto low = fromHex(password[2 * i + 1]);
if (high < 0 || low < 0) {
return {};
}
result[i] = static_cast<bytes::type>(high * 16 + low);
}
return result;
}
[[nodiscard]] bool IsBase64UrlMtprotoPassword(const QString &password) {
const auto bad = [](QChar ch) {
const auto code = ch.unicode();
return (code < 'a' || code > 'z')
&& (code < 'A' || code > 'Z')
&& (code < '0' || code > '9')
&& (code != '_')
&& (code != '-');
};
return (password.size() % 4 != 1)
&& (std::find_if(password.begin(), password.end(), bad)
== password.end());
}
[[nodiscard]] ProxyData::Status Base64UrlMtprotoPasswordStatus(
const QString &password) {
const auto size = (password.size() * 3) / 4;
const auto valid = (size == 16)
|| (size == 17
&& (password[0] == '3')
&& ((password[1] >= 'Q') && (password[1] <= 'Z')
|| (password[1] >= 'a') && (password[1] <= 'f')))
|| (size >= 21
&& (password[0] == '7')
&& (password[1] >= 'g')
&& (password[1] <= 'v'));
if (size < 16) {
return ProxyData::Status::Invalid;
} else if (valid) {
return ProxyData::Status::Valid;
}
return ProxyData::Status::Unsupported;
}
[[nodiscard]] bytes::vector SecretFromBase64UrlMtprotoPassword(
const QString &password) {
const auto result = QByteArray::fromBase64(
password.toLatin1(),
QByteArray::Base64UrlEncoding);
return bytes::make_vector(bytes::make_span(result));
}
} // namespace
TimeId LocalUnixtime() { TimeId LocalUnixtime() {
return (TimeId)time(nullptr); return (TimeId)time(nullptr);
} }
@ -233,16 +330,16 @@ namespace {
} }
bool ProxyData::valid() const { bool ProxyData::valid() const {
if (type == Type::None || host.isEmpty() || !port) { return status() == Status::Valid;
return false;
} else if (type == Type::Mtproto && !ValidMtprotoPassword(password)) {
return false;
}
return true;
} }
int ProxyData::MaxMtprotoPasswordLength() { ProxyData::Status ProxyData::status() const {
return 34; if (type == Type::None || host.isEmpty() || !port) {
return Status::Invalid;
} else if (type == Type::Mtproto) {
return MtprotoPasswordStatus(password);
}
return Status::Valid;
} }
bool ProxyData::supportsCalls() const { bool ProxyData::supportsCalls() const {
@ -259,31 +356,14 @@ bool ProxyData::tryCustomResolve() const {
bytes::vector ProxyData::secretFromMtprotoPassword() const { bytes::vector ProxyData::secretFromMtprotoPassword() const {
Expects(type == Type::Mtproto); Expects(type == Type::Mtproto);
Expects(password.size() % 2 == 0);
const auto length = password.size() / 2; if (IsHexMtprotoPassword(password)) {
const auto fromHex = [](QChar ch) -> int { return SecretFromHexMtprotoPassword(password);
const auto code = int(ch.unicode()); } else if (IsBase64UrlMtprotoPassword(password)) {
if (code >= '0' && code <= '9') { return SecretFromBase64UrlMtprotoPassword(password);
return (code - '0');
} else if (code >= 'A' && code <= 'F') {
return 10 + (code - 'A');
} else if (ch >= 'a' && ch <= 'f') {
return 10 + (code - 'a');
} }
return -1;
};
auto result = bytes::vector(length);
for (auto i = 0; i != length; ++i) {
const auto high = fromHex(password[2 * i]);
const auto low = fromHex(password[2 * i + 1]);
if (high < 0 || low < 0) {
return {}; return {};
} }
result[i] = static_cast<gsl::byte>(high * 16 + low);
}
return result;
}
ProxyData::operator bool() const { ProxyData::operator bool() const {
return valid(); return valid();
@ -304,16 +384,17 @@ bool ProxyData::operator!=(const ProxyData &other) const {
return !(*this == other); return !(*this == other);
} }
bool ProxyData::ValidMtprotoPassword(const QString &secret) { bool ProxyData::ValidMtprotoPassword(const QString &password) {
using Expression = QRegularExpression; return MtprotoPasswordStatus(password) == Status::Valid;
if (secret.size() == 32) {
static const auto check = Expression("^[a-fA-F0-9]{32}$");
return check.match(secret).hasMatch();
} else if (secret.size() == 34) {
static const auto check = Expression("^(dd|ee)[a-fA-F0-9]{32}$");
return check.match(secret).hasMatch();
} }
return false;
ProxyData::Status ProxyData::MtprotoPasswordStatus(const QString &password) {
if (IsHexMtprotoPassword(password)) {
return HexMtprotoPasswordStatus(password);
} else if (IsBase64UrlMtprotoPassword(password)) {
return Base64UrlMtprotoPasswordStatus(password);
}
return Status::Invalid;
} }
ProxyData ToDirectIpProxy(const ProxyData &proxy, int ipIndex) { ProxyData ToDirectIpProxy(const ProxyData &proxy, int ipIndex) {

View File

@ -270,6 +270,11 @@ struct ProxyData {
Http, Http,
Mtproto, Mtproto,
}; };
enum class Status {
Valid,
Unsupported,
Invalid,
};
Type type = Type::None; Type type = Type::None;
QString host; QString host;
@ -279,16 +284,18 @@ struct ProxyData {
std::vector<QString> resolvedIPs; std::vector<QString> resolvedIPs;
crl::time resolvedExpireAt = 0; crl::time resolvedExpireAt = 0;
bool valid() const; [[nodiscard]] bool valid() const;
bool supportsCalls() const; [[nodiscard]] Status status() const;
bool tryCustomResolve() const; [[nodiscard]] bool supportsCalls() const;
bytes::vector secretFromMtprotoPassword() const; [[nodiscard]] bool tryCustomResolve() const;
explicit operator bool() const; [[nodiscard]] bytes::vector secretFromMtprotoPassword() const;
bool operator==(const ProxyData &other) const; [[nodiscard]] explicit operator bool() const;
bool operator!=(const ProxyData &other) const; [[nodiscard]] bool operator==(const ProxyData &other) const;
[[nodiscard]] bool operator!=(const ProxyData &other) const;
static bool ValidMtprotoPassword(const QString &secret); [[nodiscard]] static bool ValidMtprotoPassword(const QString &password);
static int MaxMtprotoPasswordLength(); [[nodiscard]] static Status MtprotoPasswordStatus(
const QString &password);
}; };

View File

@ -30,7 +30,7 @@ constexpr auto kConnectionStartPrefixSize = 64;
class TcpConnection::Protocol { class TcpConnection::Protocol {
public: public:
static std::unique_ptr<Protocol> Create(bytes::vector &&secret); static std::unique_ptr<Protocol> Create(bytes::const_span secret);
virtual uint32 id() const = 0; virtual uint32 id() const = 0;
virtual bool supportsArbitraryLength() const = 0; virtual bool supportsArbitraryLength() const = 0;
@ -223,15 +223,14 @@ bytes::const_span TcpConnection::Protocol::VersionD::readPacket(
return bytes.subspan(sizeLength, size - sizeLength); return bytes.subspan(sizeLength, size - sizeLength);
} }
auto TcpConnection::Protocol::Create(bytes::vector &&secret) auto TcpConnection::Protocol::Create(bytes::const_span secret)
-> std::unique_ptr<Protocol> { -> std::unique_ptr<Protocol> {
if (secret.size() == 17 if ((secret.size() >= 21 && secret[0] == bytes::type(0xEE))
&& (static_cast<uchar>(secret[0]) == 0xDD || (secret.size() == 17 && secret[0] == bytes::type(0xDD))) {
|| static_cast<uchar>(secret[0]) == 0xEE)) {
return std::make_unique<VersionD>( return std::make_unique<VersionD>(
bytes::make_vector(bytes::make_span(secret).subspan(1))); bytes::make_vector(secret.subspan(1, 16)));
} else if (secret.size() == 16) { } else if (secret.size() == 16) {
return std::make_unique<Version1>(std::move(secret)); return std::make_unique<Version1>(bytes::make_vector(secret));
} else if (secret.empty()) { } else if (secret.empty()) {
return std::make_unique<Version0>(); return std::make_unique<Version0>();
} }
@ -522,10 +521,13 @@ void TcpConnection::connectToServer(
Expects(_protocol == nullptr); Expects(_protocol == nullptr);
Expects(_protocolDcId == 0); Expects(_protocolDcId == 0);
const auto secret = (_proxy.type == ProxyData::Type::Mtproto)
? _proxy.secretFromMtprotoPassword()
: protocolSecret;
if (_proxy.type == ProxyData::Type::Mtproto) { if (_proxy.type == ProxyData::Type::Mtproto) {
_address = _proxy.host; _address = _proxy.host;
_port = _proxy.port; _port = _proxy.port;
_protocol = Protocol::Create(_proxy.secretFromMtprotoPassword()); _protocol = Protocol::Create(secret);
DEBUG_LOG(("TCP Info: " DEBUG_LOG(("TCP Info: "
"dc:%1 - Connecting to proxy '%2'" "dc:%1 - Connecting to proxy '%2'"
@ -534,14 +536,17 @@ void TcpConnection::connectToServer(
} else { } else {
_address = address; _address = address;
_port = port; _port = port;
_protocol = Protocol::Create(base::duplicate(protocolSecret)); _protocol = Protocol::Create(secret);
DEBUG_LOG(("TCP Info: " DEBUG_LOG(("TCP Info: "
"dc:%1 - Connecting to '%2'" "dc:%1 - Connecting to '%2'"
).arg(protocolDcId ).arg(protocolDcId
).arg(_address + ':' + QString::number(_port))); ).arg(_address + ':' + QString::number(_port)));
} }
_socket = AbstractSocket::Create(thread(), protocolSecret, _proxy); _socket = AbstractSocket::Create(
thread(),
secret,
ToNetworkProxy(_proxy));
_protocolDcId = protocolDcId; _protocolDcId = protocolDcId;
_socket->connected( _socket->connected(

View File

@ -257,7 +257,7 @@ bool DcOptions::ApplyOneOption(
return false; return false;
} }
} }
i->second.push_back(Endpoint(dcId, flags, ip, port, secret)); i->second.emplace_back(dcId, flags, ip, port, secret);
} else { } else {
data.emplace(dcId, std::vector<Endpoint>( data.emplace(dcId, std::vector<Endpoint>(
1, 1,

View File

@ -16,12 +16,8 @@ namespace internal {
std::unique_ptr<AbstractSocket> AbstractSocket::Create( std::unique_ptr<AbstractSocket> AbstractSocket::Create(
not_null<QThread*> thread, not_null<QThread*> thread,
const bytes::vector &secret, const bytes::vector &secret,
const ProxyData &proxy) { const QNetworkProxy &proxy) {
const auto proxySecret = (proxy.type == ProxyData::Type::Mtproto) if (secret.size() >= 21 && secret[0] == bytes::type(0xEE)) {
? proxy.secretFromMtprotoPassword()
: bytes::vector();
const auto &usingSecret = proxySecret.empty() ? secret : proxySecret;
if (!usingSecret.empty() && usingSecret[0] == bytes::type(0xEE)) {
return std::make_unique<TlsSocket>(thread, secret, proxy); return std::make_unique<TlsSocket>(thread, secret, proxy);
} else { } else {
return std::make_unique<TcpSocket>(thread, proxy); return std::make_unique<TcpSocket>(thread, proxy);

View File

@ -17,7 +17,7 @@ public:
static std::unique_ptr<AbstractSocket> Create( static std::unique_ptr<AbstractSocket> Create(
not_null<QThread*> thread, not_null<QThread*> thread,
const bytes::vector &secret, const bytes::vector &secret,
const ProxyData &proxy); const QNetworkProxy &proxy);
explicit AbstractSocket(not_null<QThread*> thread) { explicit AbstractSocket(not_null<QThread*> thread) {
moveToThread(thread); moveToThread(thread);

View File

@ -10,10 +10,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
namespace MTP { namespace MTP {
namespace internal { namespace internal {
TcpSocket::TcpSocket(not_null<QThread*> thread, const ProxyData &proxy) TcpSocket::TcpSocket(not_null<QThread*> thread, const QNetworkProxy &proxy)
: AbstractSocket(thread) { : AbstractSocket(thread) {
_socket.moveToThread(thread); _socket.moveToThread(thread);
_socket.setProxy(ToNetworkProxy(proxy)); _socket.setProxy(proxy);
const auto wrap = [&](auto handler) { const auto wrap = [&](auto handler) {
return [=](auto &&...args) { return [=](auto &&...args) {
InvokeQueued(this, [=] { handler(args...); }); InvokeQueued(this, [=] { handler(args...); });

View File

@ -14,7 +14,7 @@ namespace internal {
class TcpSocket final : public AbstractSocket { class TcpSocket final : public AbstractSocket {
public: public:
TcpSocket(not_null<QThread*> thread, const ProxyData &proxy); TcpSocket(not_null<QThread*> thread, const QNetworkProxy &proxy);
void connectToHost(const QString &address, int port) override; void connectToHost(const QString &address, int port) override;
bool isConnected() override; bool isConnected() override;

View File

@ -131,8 +131,8 @@ class ClientHelloGenerator {
public: public:
ClientHelloGenerator( ClientHelloGenerator(
const MTPTlsClientHello &rules, const MTPTlsClientHello &rules,
const QByteArray &domain, bytes::const_span domain,
const bytes::vector &key); bytes::const_span key);
[[nodiscard]] ClientHello result(); [[nodiscard]] ClientHello result();
private: private:
@ -149,8 +149,8 @@ private:
void writeDigest(); void writeDigest();
void writeTimestamp(); void writeTimestamp();
const QByteArray &_domain; bytes::const_span _domain;
const bytes::vector &_key; bytes::const_span _key;
bytes::vector _greases; bytes::vector _greases;
std::vector<int> _scopeStack; std::vector<int> _scopeStack;
QByteArray _result; QByteArray _result;
@ -162,8 +162,8 @@ private:
ClientHelloGenerator::ClientHelloGenerator( ClientHelloGenerator::ClientHelloGenerator(
const MTPTlsClientHello &rules, const MTPTlsClientHello &rules,
const QByteArray &domain, bytes::const_span domain,
const bytes::vector &key) bytes::const_span key)
: _domain(domain) : _domain(domain)
, _key(key) , _key(key)
, _greases(PrepareGreases()) { , _greases(PrepareGreases()) {
@ -256,7 +256,7 @@ void ClientHelloGenerator::writeBlock(const MTPDtlsBlockDomain &data) {
if (storage.empty()) { if (storage.empty()) {
return; return;
} }
bytes::copy(storage, bytes::make_span(_domain)); bytes::copy(storage, _domain);
} }
void ClientHelloGenerator::writeBlock(const MTPDtlsBlockScope &data) { void ClientHelloGenerator::writeBlock(const MTPDtlsBlockScope &data) {
@ -309,22 +309,11 @@ void ClientHelloGenerator::writeTimestamp() {
[[nodiscard]] ClientHello PrepareClientHello( [[nodiscard]] ClientHello PrepareClientHello(
const MTPTlsClientHello &rules, const MTPTlsClientHello &rules,
const QByteArray &domain, bytes::const_span domain,
const bytes::vector &key) { bytes::const_span key) {
return ClientHelloGenerator(rules, domain, key).result(); return ClientHelloGenerator(rules, domain, key).result();
} }
[[nodiscard]] bytes::vector ExtractKey(
const bytes::vector &secret,
const ProxyData &proxy) {
const auto proxySecret = proxy.secretFromMtprotoPassword();
const auto &useSecret = proxySecret.empty() ? secret : proxySecret;
if (useSecret.size() != 17 || useSecret[0] != bytes::type(0xEE)) {
return {};
}
return bytes::make_vector(bytes::make_span(useSecret).subspan(1));
}
[[nodiscard]] bool CheckPart(bytes::const_span data, QLatin1String check) { [[nodiscard]] bool CheckPart(bytes::const_span data, QLatin1String check) {
if (data.size() < check.size()) { if (data.size() < check.size()) {
return false; return false;
@ -345,11 +334,13 @@ void ClientHelloGenerator::writeTimestamp() {
TlsSocket::TlsSocket( TlsSocket::TlsSocket(
not_null<QThread*> thread, not_null<QThread*> thread,
const bytes::vector &secret, const bytes::vector &secret,
const ProxyData &proxy) const QNetworkProxy &proxy)
: AbstractSocket(thread) : AbstractSocket(thread)
, _key(ExtractKey(secret, proxy)) { , _secret(secret) {
Expects(_secret.size() >= 21 && _secret[0] == bytes::type(0xEE));
_socket.moveToThread(thread); _socket.moveToThread(thread);
_socket.setProxy(ToNetworkProxy(proxy)); _socket.setProxy(proxy);
const auto wrap = [&](auto handler) { const auto wrap = [&](auto handler) {
return [=](auto &&...args) { return [=](auto &&...args) {
InvokeQueued(this, [=] { handler(args...); }); InvokeQueued(this, [=] { handler(args...); });
@ -377,6 +368,14 @@ TlsSocket::TlsSocket(
wrap([=](Error e) { handleError(e); })); wrap([=](Error e) { handleError(e); }));
} }
bytes::const_span TlsSocket::domainFromSecret() const {
return bytes::make_span(_secret).subspan(17);
}
bytes::const_span TlsSocket::keyFromSecret() const {
return bytes::make_span(_secret).subspan(1, 16);
}
void TlsSocket::plainConnected() { void TlsSocket::plainConnected() {
if (_state != State::Connecting) { if (_state != State::Connecting) {
return; return;
@ -385,8 +384,8 @@ void TlsSocket::plainConnected() {
static const auto kClientHelloRules = PrepareClientHelloRules(); static const auto kClientHelloRules = PrepareClientHelloRules();
const auto hello = PrepareClientHello( const auto hello = PrepareClientHello(
kClientHelloRules, kClientHelloRules,
"www.google.com", domainFromSecret(),
_key); keyFromSecret());
if (hello.data.isEmpty()) { if (hello.data.isEmpty()) {
LOG(("TLS Error: Could not generate Client Hello!")); LOG(("TLS Error: Could not generate Client Hello!"));
_state = State::Error; _state = State::Error;
@ -492,7 +491,7 @@ void TlsSocket::checkHelloDigest() {
kHelloDigestLength); kHelloDigestLength);
const auto digestCopy = bytes::make_vector(digest); const auto digestCopy = bytes::make_vector(digest);
bytes::set_with_const(digest, bytes::type(0)); bytes::set_with_const(digest, bytes::type(0));
const auto check = openssl::HmacSha256(_key, fulldata); const auto check = openssl::HmacSha256(keyFromSecret(), fulldata);
if (bytes::compare(digestCopy, check) != 0) { if (bytes::compare(digestCopy, check) != 0) {
LOG(("TLS Error: Bad Server Hello digest.")); LOG(("TLS Error: Bad Server Hello digest."));
handleError(); handleError();

View File

@ -17,7 +17,7 @@ public:
TlsSocket( TlsSocket(
not_null<QThread*> thread, not_null<QThread*> thread,
const bytes::vector &secret, const bytes::vector &secret,
const ProxyData &proxy); const QNetworkProxy &proxy);
void connectToHost(const QString &address, int port) override; void connectToHost(const QString &address, int port) override;
bool isConnected() override; bool isConnected() override;
@ -36,6 +36,9 @@ private:
Error, Error,
}; };
[[nodiscard]] bytes::const_span domainFromSecret() const;
[[nodiscard]] bytes::const_span keyFromSecret() const;
void plainConnected(); void plainConnected();
void plainDisconnected(); void plainDisconnected();
void plainReadyRead(); void plainReadyRead();
@ -49,8 +52,8 @@ private:
[[nodiscard]] bool checkNextPacket(); [[nodiscard]] bool checkNextPacket();
void shiftIncomingBy(int amount); void shiftIncomingBy(int amount);
const bytes::vector _secret;
QTcpSocket _socket; QTcpSocket _socket;
bytes::vector _key;
State _state = State::NotConnected; State _state = State::NotConnected;
QByteArray _incoming; QByteArray _incoming;
int _incomingGoodDataOffset = 0; int _incomingGoodDataOffset = 0;

View File

@ -1332,9 +1332,13 @@ bool _readSetting(quint32 blockId, QDataStream &stream, int version, ReadSetting
const auto unchecked = static_cast<ProxyData::Settings>(settings); const auto unchecked = static_cast<ProxyData::Settings>(settings);
switch (unchecked) { switch (unchecked) {
case ProxyData::Settings::Enabled:
Global::SetProxySettings(Global::SelectedProxy()
? ProxyData::Settings::Enabled
: ProxyData::Settings::System);
break;
case ProxyData::Settings::Disabled: case ProxyData::Settings::Disabled:
case ProxyData::Settings::System: case ProxyData::Settings::System:
case ProxyData::Settings::Enabled:
Global::SetProxySettings(unchecked); Global::SetProxySettings(unchecked);
break; break;
default: default: