mirror of
https://github.com/meganz/MEGAcmd
synced 2025-08-22 01:47:24 +00:00
Merge branch 'task/CMD-620_folder_link_implicit_resume' into 'develop'
CMD-620. Allow explicit --resume for folder links logins Closes CMD-620 See merge request apps/MEGAcmd!873
This commit is contained in:
commit
e85a3e42db
@ -20,6 +20,10 @@
|
||||
#include "configurationmanager.h"
|
||||
#include "megacmdutils.h"
|
||||
|
||||
#ifdef MEGACMD_TESTING_CODE
|
||||
#include "../tests/common/Instruments.h"
|
||||
#endif
|
||||
|
||||
#include <utility>
|
||||
|
||||
using namespace mega;
|
||||
@ -642,6 +646,9 @@ void MegaCmdListener::onRequestUpdate(MegaApi* api, MegaRequest *request)
|
||||
{
|
||||
case MegaRequest::TYPE_FETCH_NODES:
|
||||
{
|
||||
#ifdef MEGACMD_TESTING_CODE
|
||||
TestInstruments::Instance().fireEvent(TestInstruments::Event::FETCH_NODES_REQ_UPDATE);
|
||||
#endif
|
||||
unsigned int cols = getNumberOfCols(80);
|
||||
string outputString;
|
||||
outputString.resize(cols+1);
|
||||
|
@ -777,6 +777,7 @@ void insertValidParamsPerCommand(set<string> *validParams, string thecommand, se
|
||||
validOptValues->insert("auth-code");
|
||||
validOptValues->insert("auth-key");
|
||||
validOptValues->insert("password");
|
||||
validOptValues->insert("resume");
|
||||
}
|
||||
else if ("psa" == thecommand)
|
||||
{
|
||||
@ -1541,13 +1542,13 @@ const char * getUsageStr(const char *command, const HelpFlags& flags)
|
||||
if (isCurrentThreadInteractive())
|
||||
{
|
||||
return "login [--auth-code=XXXX] [email [password]] | exportedfolderurl#key"
|
||||
" [--auth-key=XXXX] | passwordprotectedlink [--password=PASSWORD]"
|
||||
" [--auth-key=XXXX] [--resume] | passwordprotectedlink [--password=PASSWORD]"
|
||||
" | session";
|
||||
}
|
||||
else
|
||||
{
|
||||
return "login [--auth-code=XXXX] email password | exportedfolderurl#key"
|
||||
" [--auth-key=XXXX] | passwordprotectedlink [--password=PASSWORD]"
|
||||
" [--auth-key=XXXX] [--resume] | passwordprotectedlink [--password=PASSWORD]"
|
||||
" | session";
|
||||
}
|
||||
}
|
||||
@ -2072,7 +2073,7 @@ string getHelpStr(const char *command, const HelpFlags& flags = {})
|
||||
os << "Usage: " << getUsageStr(command, flags) << endl;
|
||||
if (!strcmp(command, "login"))
|
||||
{
|
||||
os << "Logs into a MEGA account or folder link. You can only log into one entity at a time." << endl;
|
||||
os << "Logs into a MEGA account, folder link or a previous session. You can only log into one entity at a time." << endl;
|
||||
os << "Logging into a MEGA account:" << endl;
|
||||
os << "\tYou can log into a MEGA account by providing either a session ID or a username and password. A session "
|
||||
"ID simply identifies a session that you have previously logged in with using a username and password; "
|
||||
@ -2091,6 +2092,10 @@ string getHelpStr(const char *command, const HelpFlags& flags = {})
|
||||
"the password for that link." << endl;
|
||||
os << "\t--auth-key=AUTHKEY: If the link is a writable folder link, then this option allows you to log in with "
|
||||
"write privileges. Without this option, you will log into the link with read access only." << endl;
|
||||
os << "\t--resume: A convenience option to try to resume from cache. When login into a folder, contrary to what occurs with login into a user account,"
|
||||
" MEGAcmd will not try to load anything from cache: loading everything from scratch. This option changes that. Note, "
|
||||
"login using a session string, will of course, try to load from cache. This option may be convinient, for instance, if you previously "
|
||||
"logged out using --keep-session." << endl;
|
||||
os << endl;
|
||||
os << "For more information about MEGA folder links, see \"" << getCommandPrefixBasedOnMode() << "export --help\"." << endl;
|
||||
}
|
||||
@ -2330,7 +2335,8 @@ string getHelpStr(const char *command, const HelpFlags& flags = {})
|
||||
os << "Logs out" << endl;
|
||||
os << endl;
|
||||
os << "Options:" << endl;
|
||||
os << " --keep-session" << "\t" << "Keeps the current session." << endl;
|
||||
os << " --keep-session" << "\t" << "Keeps the current session. This will also prevent the deletion of cached data associated "
|
||||
"with current session." << endl;
|
||||
}
|
||||
else if (!strcmp(command, "import"))
|
||||
{
|
||||
|
@ -8012,99 +8012,104 @@ void MegaCmdExecuter::executecommand(vector<string> words, map<string, int> *clf
|
||||
LoginGuard loginGuard;
|
||||
int clientID = getintOption(cloptions, "clientID", -1);
|
||||
|
||||
if (!api->isLoggedIn())
|
||||
{
|
||||
if (words.size() > 1)
|
||||
{
|
||||
if (strchr(words[1].c_str(), '@'))
|
||||
{
|
||||
// full account login
|
||||
if (words.size() > 2)
|
||||
{
|
||||
MegaCmdListener *megaCmdListener = new MegaCmdListener(NULL,NULL,clientID);
|
||||
sandboxCMD->resetSandBox();
|
||||
api->login(words[1].c_str(), words[2].c_str(), megaCmdListener);
|
||||
if (actUponLogin(megaCmdListener) == MegaError::API_EMFAREQUIRED )
|
||||
{
|
||||
MegaCmdListener *megaCmdListener2 = new MegaCmdListener(NULL,NULL,clientID);
|
||||
string pin2fa = getOption(cloptions, "auth-code", "");
|
||||
if (!pin2fa.size())
|
||||
{
|
||||
pin2fa = askforUserResponse("Enter the code generated by your authentication app: ");
|
||||
}
|
||||
LOG_verbose << " Using confirmation pin: " << pin2fa;
|
||||
api->multiFactorAuthLogin(words[1].c_str(), words[2].c_str(), pin2fa.c_str(), megaCmdListener2);
|
||||
actUponLogin(megaCmdListener2);
|
||||
delete megaCmdListener2;
|
||||
return;
|
||||
|
||||
}
|
||||
delete megaCmdListener;
|
||||
}
|
||||
else
|
||||
{
|
||||
login = words[1];
|
||||
if (isCurrentThreadInteractive())
|
||||
{
|
||||
setprompt(LOGINPASSWORD);
|
||||
}
|
||||
else
|
||||
{
|
||||
setCurrentThreadOutCode(MCMD_EARGS);
|
||||
LOG_err << "Extra args required in non-interactive mode. Usage: " << getUsageStr("login");
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
const char* ptr;
|
||||
if (( ptr = strchr(words[1].c_str(), '#'))) // folder link indicator
|
||||
{
|
||||
string publicLink = words[1];
|
||||
if (!decryptLinkIfEncrypted(api, publicLink, cloptions))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
MegaCmdListener *megaCmdListener = new MegaCmdListener(NULL);
|
||||
sandboxCMD->resetSandBox();
|
||||
|
||||
string authKey = getOption(cloptions, "auth-key", "");
|
||||
if (authKey.empty())
|
||||
{
|
||||
api->loginToFolder(publicLink.c_str(), megaCmdListener);
|
||||
}
|
||||
else
|
||||
{
|
||||
api->loginToFolder(publicLink.c_str(), authKey.c_str(), megaCmdListener);
|
||||
}
|
||||
|
||||
actUponLogin(megaCmdListener);
|
||||
delete megaCmdListener;
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_info << "Resuming session...";
|
||||
MegaCmdListener *megaCmdListener = new MegaCmdListener(NULL);
|
||||
sandboxCMD->resetSandBox();
|
||||
api->fastLogin(words[1].c_str(), megaCmdListener);
|
||||
actUponLogin(megaCmdListener);
|
||||
delete megaCmdListener;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
setCurrentThreadOutCode(MCMD_EARGS);
|
||||
LOG_err << " " << getUsageStr("login");
|
||||
}
|
||||
}
|
||||
else
|
||||
if (api->isLoggedIn())
|
||||
{
|
||||
setCurrentThreadOutCode(MCMD_INVALIDSTATE);
|
||||
LOG_err << "Already logged in. Please log out first.";
|
||||
return;
|
||||
}
|
||||
|
||||
if (words.size() < 2)
|
||||
{
|
||||
setCurrentThreadOutCode(MCMD_EARGS);
|
||||
LOG_err << " " << getUsageStr("login");
|
||||
return;
|
||||
}
|
||||
|
||||
bool accountLogin = words[1].find('@') != std::string::npos;
|
||||
bool folderLinkLogin = !accountLogin && words[1].find('#') != std::string::npos;
|
||||
bool resumeFolderLink = getFlag(clflags, "resume");
|
||||
string authKey = getOption(cloptions, "auth-key", "");
|
||||
|
||||
if (!folderLinkLogin)
|
||||
{
|
||||
if (resumeFolderLink)
|
||||
{
|
||||
setCurrentThreadOutCode(MCMD_EARGS);
|
||||
LOG_err << "Explicit resumption only required for folder links logins.";
|
||||
return;
|
||||
}
|
||||
if (!authKey.empty())
|
||||
{
|
||||
setCurrentThreadOutCode(MCMD_EARGS);
|
||||
LOG_err << "Auth key only required for login in writable folder links.";
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (accountLogin)
|
||||
{
|
||||
if (words.size() > 2)
|
||||
{
|
||||
MegaCmdListener *megaCmdListener = new MegaCmdListener(NULL,NULL,clientID);
|
||||
sandboxCMD->resetSandBox();
|
||||
api->login(words[1].c_str(), words[2].c_str(), megaCmdListener);
|
||||
if (actUponLogin(megaCmdListener) == MegaError::API_EMFAREQUIRED )
|
||||
{
|
||||
MegaCmdListener *megaCmdListener2 = new MegaCmdListener(NULL,NULL,clientID);
|
||||
string pin2fa = getOption(cloptions, "auth-code", "");
|
||||
if (!pin2fa.size())
|
||||
{
|
||||
pin2fa = askforUserResponse("Enter the code generated by your authentication app: ");
|
||||
}
|
||||
LOG_verbose << " Using confirmation pin: " << pin2fa;
|
||||
api->multiFactorAuthLogin(words[1].c_str(), words[2].c_str(), pin2fa.c_str(), megaCmdListener2);
|
||||
actUponLogin(megaCmdListener2);
|
||||
delete megaCmdListener2;
|
||||
return;
|
||||
|
||||
}
|
||||
delete megaCmdListener;
|
||||
}
|
||||
else
|
||||
{
|
||||
login = words[1];
|
||||
if (isCurrentThreadInteractive())
|
||||
{
|
||||
setprompt(LOGINPASSWORD);
|
||||
}
|
||||
else
|
||||
{
|
||||
setCurrentThreadOutCode(MCMD_EARGS);
|
||||
LOG_err << "Extra args required in non-interactive mode. Usage: " << getUsageStr("login");
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (folderLinkLogin) // folder link indicator
|
||||
{
|
||||
string publicLink = words[1];
|
||||
if (!decryptLinkIfEncrypted(api, publicLink, cloptions))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
std::unique_ptr<MegaCmdListener>megaCmdListener = std::make_unique<MegaCmdListener>(nullptr);
|
||||
sandboxCMD->resetSandBox();
|
||||
api->loginToFolder(publicLink.c_str(), authKey.empty() ? nullptr : authKey.c_str(),
|
||||
resumeFolderLink, megaCmdListener.get());
|
||||
|
||||
actUponLogin(megaCmdListener.get());
|
||||
return;
|
||||
}
|
||||
else // session resumption
|
||||
{
|
||||
LOG_info << "Resuming session...";
|
||||
MegaCmdListener *megaCmdListener = new MegaCmdListener(NULL);
|
||||
sandboxCMD->resetSandBox();
|
||||
api->fastLogin(words[1].c_str(), megaCmdListener);
|
||||
actUponLogin(megaCmdListener);
|
||||
delete megaCmdListener;
|
||||
return;
|
||||
}
|
||||
|
||||
return;
|
||||
|
@ -66,6 +66,7 @@ public:
|
||||
{
|
||||
SERVER_ABOUT_TO_START_WAITING_FOR_PETITIONS,
|
||||
SYNC_ISSUES_LIST_UPDATED,
|
||||
FETCH_NODES_REQ_UPDATE,
|
||||
};
|
||||
|
||||
typedef std::function<void()> EventCallback;
|
||||
|
@ -32,6 +32,28 @@ TEST_F(NOINTERACTIVEBasicTest, Help)
|
||||
executeInClient({"help"});
|
||||
}
|
||||
|
||||
TEST_F(NOINTERACTIVENotLoggedTest, Folderlogin)
|
||||
{
|
||||
{
|
||||
auto rLoging = executeInClient({"login", LINK_TESTEXPORTFOLDER});
|
||||
ASSERT_TRUE(rLoging.ok());
|
||||
}
|
||||
|
||||
{
|
||||
auto rLogout = executeInClient({"logout", "--keep-session"});
|
||||
ASSERT_TRUE(rLogout.ok());
|
||||
}
|
||||
|
||||
{
|
||||
EventTracker evTracker({TestInstruments::Event::FETCH_NODES_REQ_UPDATE});
|
||||
auto rLoging = executeInClient({"login", "--resume", LINK_TESTEXPORTFOLDER});
|
||||
ASSERT_TRUE(rLoging.ok());
|
||||
ASSERT_STREQ(rLoging.out().c_str(), "");
|
||||
ASSERT_STREQ(rLoging.err().c_str(), "");
|
||||
ASSERT_FALSE(evTracker.eventHappened(TestInstruments::Event::FETCH_NODES_REQ_UPDATE));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(NOINTERACTIVEReadTest, Find)
|
||||
{
|
||||
auto r = executeInClient({"find"});
|
||||
|
@ -88,6 +88,25 @@ class BasicGenericTest : public ::testing::Test
|
||||
{
|
||||
};
|
||||
|
||||
class NotLoggedTest : public BasicGenericTest
|
||||
{
|
||||
protected:
|
||||
|
||||
void SetUp() override
|
||||
{
|
||||
BasicGenericTest::SetUp();
|
||||
auto result = executeInClient({"logout"}).ok();
|
||||
ASSERT_TRUE(result);
|
||||
}
|
||||
|
||||
void TearDown() override
|
||||
{
|
||||
BasicGenericTest::SetUp();
|
||||
auto result = executeInClient({"logout"}).ok();
|
||||
ASSERT_TRUE(result);
|
||||
}
|
||||
};
|
||||
|
||||
class LoggedInTest : public BasicGenericTest
|
||||
{
|
||||
protected:
|
||||
@ -133,4 +152,5 @@ protected:
|
||||
|
||||
class NOINTERACTIVEBasicTest : public BasicGenericTest{};
|
||||
class NOINTERACTIVELoggedInTest : public LoggedInTest{};
|
||||
class NOINTERACTIVENotLoggedTest : public NotLoggedTest{};
|
||||
class NOINTERACTIVEReadTest : public ReadTest{};
|
||||
|
Loading…
x
Reference in New Issue
Block a user