Skip to content

Commit

Permalink
add support for reauthentication
Browse files Browse the repository at this point in the history
  • Loading branch information
d99kris committed Apr 20, 2024
1 parent 8f7b24e commit 1621aff
Show file tree
Hide file tree
Showing 14 changed files with 339 additions and 61 deletions.
21 changes: 20 additions & 1 deletion lib/common/src/protocol.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// protocol.h
//
// Copyright (c) 2020-2023 Kristofer Berggren
// Copyright (c) 2020-2024 Kristofer Berggren
// All rights reserved.
//
// nchat is distributed under the MIT license, see LICENSE for details.
Expand Down Expand Up @@ -94,6 +94,8 @@ enum MessageType
NewMessageFileNotifyType,
DeleteChatNotifyType,
UpdateMuteNotifyType,
ProtocolUiControlNotifyType,
RequestAppExitNotifyType,
};

struct ContactInfo
Expand Down Expand Up @@ -509,3 +511,20 @@ class UpdateMuteNotify : public ServiceMessage
std::string chatId;
bool isMuted;
};

class ProtocolUiControlNotify : public ServiceMessage
{
public:
explicit ProtocolUiControlNotify(const std::string& p_ProfileId) :
ServiceMessage(p_ProfileId) { }
virtual MessageType GetMessageType() const { return ProtocolUiControlNotifyType; }
bool isTakeControl;
};

class RequestAppExitNotify : public ServiceMessage
{
public:
explicit RequestAppExitNotify(const std::string& p_ProfileId) :
ServiceMessage(p_ProfileId) { }
virtual MessageType GetMessageType() const { return RequestAppExitNotifyType; }
};
2 changes: 1 addition & 1 deletion lib/common/src/version.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,4 @@

#pragma once

#define NCHAT_VERSION "4.53"
#define NCHAT_VERSION "4.54"
3 changes: 2 additions & 1 deletion lib/ncutil/src/status.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// status.cpp
//
// Copyright (c) 2020-2023 Kristofer Berggren
// Copyright (c) 2020-2024 Kristofer Berggren
// All rights reserved.
//
// nchat is distributed under the MIT license, see LICENSE for details.
Expand Down Expand Up @@ -38,6 +38,7 @@ std::string Status::ToString(uint32_t p_Mask)
if (maskedFlags & FlagUpdating) return "Updating";
if (maskedFlags & FlagAway) return "Away";
if (maskedFlags & FlagOnline) return "Online";
if (maskedFlags & FlagConnecting) return "Connecting";

return "Offline";
}
16 changes: 9 additions & 7 deletions lib/ncutil/src/status.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// status.h
//
// Copyright (c) 2020-2023 Kristofer Berggren
// Copyright (c) 2020-2024 Kristofer Berggren
// All rights reserved.
//
// nchat is distributed under the MIT license, see LICENSE for details.
Expand All @@ -14,16 +14,18 @@
class Status
{
public:
// keep in sync with constants in gowm.go
enum Flag
{
FlagNone = 0,
FlagOffline = (1 << 0),
FlagOnline = (1 << 1),
FlagFetching = (1 << 2),
FlagSending = (1 << 3),
FlagUpdating = (1 << 4),
FlagSyncing = (1 << 5),
FlagAway = (1 << 6),
FlagConnecting = (1 << 1),
FlagOnline = (1 << 2),
FlagFetching = (1 << 3),
FlagSending = (1 << 4),
FlagUpdating = (1 << 5),
FlagSyncing = (1 << 6),
FlagAway = (1 << 7),
};

static uint32_t Get();
Expand Down
155 changes: 125 additions & 30 deletions lib/tgchat/src/tgchat.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,8 @@ class TgChat::Impl
td::td_api::object_ptr<td::td_api::formattedText> GetFormattedText(const std::string& p_Text);
td::td_api::object_ptr<td::td_api::inputMessageText> GetMessageText(const std::string& p_Text);
std::string ConvertMarkdownV2ToV1(const std::string& p_Str);
void SetProtocolUiControl(bool p_IsTakeControl);
std::string GetProfilePhoneNumber();

private:
std::thread m_ServiceThread;
Expand All @@ -173,6 +175,7 @@ class TgChat::Impl
std::map<std::uint64_t, std::function<void(Object)>> m_Handlers;
td::td_api::object_ptr<td::td_api::AuthorizationState> m_AuthorizationState;
bool m_IsSetup = false;
bool m_IsReinit = false;
bool m_Authorized = false;
bool m_WasAuthorized = false;
std::int64_t m_SelfUserId = 0;
Expand Down Expand Up @@ -354,8 +357,6 @@ bool TgChat::Impl::CloseProfile()

bool TgChat::Impl::Login()
{
Status::Set(Status::FlagOnline);

if (!m_Running)
{
m_Running = true;
Expand All @@ -371,6 +372,7 @@ bool TgChat::Impl::Login()
bool TgChat::Impl::Logout()
{
Status::Clear(Status::FlagOnline);
Status::Clear(Status::FlagConnecting);

if (m_Running)
{
Expand Down Expand Up @@ -1458,21 +1460,32 @@ void TgChat::Impl::ProcessUpdate(td::td_api::object_ptr<td::td_api::Object> upda
},
[this](td::td_api::updateConnectionState& connection_state)
{
LOG_TRACE("update connection state");

if (!connection_state.state_) return;

if (connection_state.state_->get_id() == td::td_api::connectionStateReady::ID)
if (connection_state.state_->get_id() == td::td_api::connectionStateWaitingForNetwork::ID)
{
m_WasOnline = true;
Status::Set(Status::FlagOnline);
Status::Clear(Status::FlagOffline);
LOG_TRACE("update connectionStateWaitingForNetwork");
}
else
else if (connection_state.state_->get_id() == td::td_api::connectionStateConnectingToProxy::ID)
{
Status::Set(Status::FlagOffline);
LOG_TRACE("update connectionStateConnectingToProxy");
}
else if (connection_state.state_->get_id() == td::td_api::connectionStateConnecting::ID)
{
LOG_TRACE("update connectionStateConnecting");
Status::Clear(Status::FlagOnline);
}
else if (connection_state.state_->get_id() == td::td_api::connectionStateUpdating::ID)
{
LOG_TRACE("update connectionStateUpdating");
}
else if (connection_state.state_->get_id() == td::td_api::connectionStateReady::ID)
{
LOG_TRACE("update connectionStateReady");
m_WasOnline = true; // set flag indicating we have been online at some point
Status::Set(Status::FlagOnline);
Status::Clear(Status::FlagConnecting);
}
},
[this](td::td_api::updateMessageContent& update_message_content)
{
Expand Down Expand Up @@ -1696,6 +1709,11 @@ void TgChat::Impl::OnAuthStateUpdate()
}
else
{
if (m_IsReinit)
{
SetProtocolUiControl(false);
}

SendQuery(td::td_api::make_object<td::td_api::getMe>(),
[this](Object object)
{
Expand Down Expand Up @@ -1740,26 +1758,50 @@ void TgChat::Impl::OnAuthStateUpdate()
m_Authorized = false;
m_Running = false;
LOG_DEBUG("closed");

if (m_WasAuthorized)
{
LOG_WARNING("session closed by other device");
SetProtocolUiControl(true);
std::cout << "\n";
std::cout << "WARNING: Session terminated by other device.\n";
std::cout << "Please restart nchat to reauthenticate. Press ENTER to continue.\n";
std::string str;
std::getline(std::cin, str);
SetProtocolUiControl(false);

LOG_TRACE("request app exit");
std::shared_ptr<RequestAppExitNotify> requestAppExitNotify =
std::make_shared<RequestAppExitNotify>(m_ProfileId);
CallMessageHandler(requestAppExitNotify);
}
},
[this](td::td_api::authorizationStateWaitCode&)
{
if (m_IsSetup)
{
std::cout << "Enter authentication code: ";
std::string code;
std::getline(std::cin, code);
SendQuery(td::td_api::make_object<td::td_api::checkAuthenticationCode>(code),
CreateAuthQueryHandler());
LOG_DEBUG("fresh code");
}
else
{
LOG_DEBUG("unexpected state");
m_Running = false;
LOG_DEBUG("reinit code");
if (!m_IsReinit)
{
m_IsReinit = true;
SetProtocolUiControl(true);
std::cout << "Telegram reauthentication for " << GetProfilePhoneNumber() << " required\n\n";
}
}

std::cout << "Enter authentication code: ";
std::string code;
std::getline(std::cin, code);
SendQuery(td::td_api::make_object<td::td_api::checkAuthenticationCode>(code),
CreateAuthQueryHandler());
},
[this](td::td_api::authorizationStateWaitRegistration&)
{
if (m_IsSetup)
if (m_IsSetup || m_IsReinit)
{
std::string first_name;
std::string last_name;
Expand All @@ -1779,7 +1821,7 @@ void TgChat::Impl::OnAuthStateUpdate()
},
[this](td::td_api::authorizationStateWaitPassword&)
{
if (m_IsSetup)
if (m_IsSetup || m_IsReinit)
{
std::cout << "Enter authentication password: ";
std::string password = StrUtil::GetPass();
Expand All @@ -1788,24 +1830,33 @@ void TgChat::Impl::OnAuthStateUpdate()
}
else
{
LOG_DEBUG("Unexpected state");
LOG_DEBUG("unexpected state");
m_Running = false;
}
},
[this](td::td_api::authorizationStateWaitPhoneNumber&)
{
std::string phone_number;
if (m_IsSetup)
{
std::string phone_number = m_SetupPhoneNumber;
SendQuery(td::td_api::make_object<td::td_api::setAuthenticationPhoneNumber>(phone_number,
nullptr),
CreateAuthQueryHandler());
LOG_DEBUG("fresh number");
phone_number = m_SetupPhoneNumber;
}
else
{
LOG_DEBUG("unexpected state");
m_Running = false;
LOG_DEBUG("reinit number");
phone_number = GetProfilePhoneNumber();
if (!m_IsReinit)
{
m_IsReinit = true;
SetProtocolUiControl(true);
std::cout << "Telegram reauthentication for " << phone_number << " required\n\n";
}
}

SendQuery(td::td_api::make_object<td::td_api::setAuthenticationPhoneNumber>(phone_number,
nullptr),
CreateAuthQueryHandler());
},
[this](td::td_api::authorizationStateWaitTdlibParameters&)
{
Expand Down Expand Up @@ -1881,14 +1932,27 @@ void TgChat::Impl::CheckAuthError(Object object)
{
auto error = td::move_tl_object_as<td::td_api::error>(object);
LOG_WARNING("auth error \"%s\"", to_string(error).c_str());
if (m_IsSetup)
if (m_IsSetup || m_IsReinit)
{
std::cout << "Authentication error: " << error->message_ << "\n";
if (m_IsReinit)
{
SetProtocolUiControl(false);
}

m_IsSetup = false;
}
m_IsReinit = false;
m_Running = false;

m_Running = false;
OnAuthStateUpdate();
LOG_TRACE("request app exit");
std::shared_ptr<RequestAppExitNotify> requestAppExitNotify =
std::make_shared<RequestAppExitNotify>(m_ProfileId);
CallMessageHandler(requestAppExitNotify);
}
else
{
OnAuthStateUpdate();
}
}
}

Expand Down Expand Up @@ -2725,3 +2789,34 @@ std::string TgChat::Impl::ConvertMarkdownV2ToV1(const std::string& p_Str)
rv += ReplaceV2Markup(str); // text non-match
return rv;
}

void TgChat::Impl::SetProtocolUiControl(bool p_IsTakeControl)
{
LOG_TRACE("set protocol ui control %d", p_IsTakeControl);
std::shared_ptr<ProtocolUiControlNotify> protocolUiControlNotify =
std::make_shared<ProtocolUiControlNotify>(m_ProfileId);
protocolUiControlNotify->isTakeControl = p_IsTakeControl;
CallMessageHandler(protocolUiControlNotify);

// if attempting to take control, but failed to do so, keep retrying
while (p_IsTakeControl && !protocolUiControlNotify->isTakeControl)
{
TimeUtil::Sleep(0.500);
LOG_TRACE("set protocol ui control retry");
protocolUiControlNotify->isTakeControl = p_IsTakeControl;
CallMessageHandler(protocolUiControlNotify);
}

TimeUtil::Sleep(0.100); // wait more than GetKey timeout
}

std::string TgChat::Impl::GetProfilePhoneNumber()
{
std::vector<std::string> profileInfo = StrUtil::Split(m_ProfileId, '_');
if (profileInfo.size() == 2)
{
return profileInfo.at(1);
}

return "";
}
5 changes: 5 additions & 0 deletions lib/wmchat/go/cgowm.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ package main
// extern void WmDeleteChatNotify(int p_ConnId, char* p_ChatId);
// extern void WmUpdateMuteNotify(int p_ConnId, char* p_ChatId, int p_IsMuted);
// extern void WmReinit(int p_ConnId);
// extern void WmSetProtocolUiControl(int p_ConnId, int p_IsTakeControl);
// extern void WmSetStatus(int p_Flags);
// extern void WmClearStatus(int p_Flags);
// extern void WmLogTrace(char* p_Filename, int p_LineNo, char* p_Message);
Expand Down Expand Up @@ -138,6 +139,10 @@ func CWmReinit(connId int) {
C.WmReinit(C.int(connId))
}

func CWmSetProtocolUiControl(connId int, isTakeControl int) {
C.WmSetProtocolUiControl(C.int(connId), C.int(isTakeControl))
}

func CWmSetStatus(flags int) {
C.WmSetStatus(C.int(flags))
}
Expand Down
Loading

0 comments on commit 1621aff

Please sign in to comment.