diff --git a/README.md b/README.md index 7cae5772..a8e31c0a 100644 --- a/README.md +++ b/README.md @@ -37,13 +37,14 @@ On Ubuntu you can run the following command: ## Usage Terminal command is pcloudcc and -h option prints short options description. > ./pcloudcc -h -> pCloud console client v.2.0.1 +> pCloud console client v.2.1.0 >Allowed options: > -h [ --help ] produce help message > -u [ --username ] arg pCloud account name > -p [ --password ] pCloud account password > -c [ --crypto ] arg Crypto password -> -y [ --passascrypto ] arg Use user password as crypto password also. +> -y [ --passascrypto ] arg Use user password as crypto password also. +> -t [ --trust ] Trust this device. > -d [ --daemonize ] Daemonize the process. > -o [ --commands ] Parent stays alive and processes commands. > -m [ --mountpoint ] arg Mount point where drive to be mounted. diff --git a/pCloudCC/control_tools.cpp b/pCloudCC/control_tools.cpp index 4477e90b..97445c03 100644 --- a/pCloudCC/control_tools.cpp +++ b/pCloudCC/control_tools.cpp @@ -30,16 +30,16 @@ enum command_ids_ { }; -int start_crypto(const char * pass) { +void start_crypto(const char * pass) { int ret; char* errm; if (SendCall(STARTCRYPTO, pass, &ret, &errm)) std::cout << "Start Crypto failed. return is " << ret<< " and message is "<str, dig->length); psync_sha1_final(sha1bin, &ctx); psync_binhex(sha1hex, sha1bin, PSYNC_SHA1_DIGEST_LEN); - ret=get_userinfo_user_digest(sock, username, ul, sha1hex, dig->str, dig->length, device); + ret=login_with_digest(sock, username, ul, sha1hex, dig->str, dig->length, device); psync_free(res); return ret; } static psync_socket *get_connected_socket(){ - char *auth, *user, *pass; + char *auth, *user, *pass, *tfa_pin, *tfa_token, *device; psync_socket *sock; binresult *res; const binresult *cres; psync_sql_res *q; - char *device; uint64_t result, userid, luserid; int saveauth, isbusiness, cryptosetup; - auth=user=pass=NULL; + auth=user=pass=tfa_pin=tfa_token=NULL; psync_is_business = 0; int digest = 1; + int auth_reset = 0; while (1){ psync_free(auth); psync_free(user); @@ -202,30 +242,16 @@ static psync_socket *get_connected_socket(){ } device=psync_deviceid(); - if (user && pass && pass[0]) - if (digest) + if (tfa_token && tfa_pin) { + res=get_tfa_auth(sock, tfa_token, tfa_pin, device); + } else if ((!auth || auth_reset) && user && pass && pass[0]) { + if (digest) { + res=get_userinfo_user_pass_digest(sock, user, pass, device); + } else { res=get_userinfo_user_pass(sock, user, pass, device); - else - { - binparam params[]={P_STR("timeformat", "timestamp"), - P_STR("username", user), - P_STR("password", pass), - P_STR("device", device), - P_BOOL("getauth", 1), - P_BOOL("cryptokeyssign", 1), - P_BOOL("getapiserver", 1), - P_NUM("os", P_OS_ID)}; - res=send_command(sock, "login", params); } - else { - binparam params[]={P_STR("timeformat", "timestamp"), - P_STR("auth", auth), - P_STR("device", device), - P_BOOL("getauth", 1), - P_BOOL("cryptokeyssign", 1), - P_BOOL("getapiserver", 1), - P_NUM("os", P_OS_ID)}; - res=send_command(sock, "userinfo", params); + } else { + res=get_userinfo_auth(sock, auth, device); } psync_free(device); if (unlikely_log(!res)){ @@ -240,33 +266,48 @@ static psync_socket *get_connected_socket(){ if (unlikely(result)){ debug(D_NOTICE, "userinfo returned error %lu %s", (unsigned long)result, psync_find_result(res, "error", PARAM_STR)->str); psync_socket_close(sock); - psync_free(res); - if (result==2000){ - if (user && pass) + if (result == 2000) { + if (user && pass) { psync_set_status(PSTATUS_TYPE_AUTH, PSTATUS_AUTH_BADLOGIN); - else + } else { psync_set_status(PSTATUS_TYPE_AUTH, PSTATUS_AUTH_BADTOKEN); + } psync_wait_status(PSTATUS_TYPE_AUTH, PSTATUS_AUTH_PROVIDED); - } - else if (result==4000) - psync_milisleep(5*60*1000); - else if (result == 2297 ){ + } else if (result == 4000) { + psync_milisleep(5 * 60 * 1000); + } else if (result == 2297) { + tfa_token=psync_strdup(psync_find_result(res, "token", PARAM_STR)->str); psync_set_status(PSTATUS_TYPE_AUTH, PSTATUS_AUTH_TFAERR); psync_wait_status(PSTATUS_TYPE_AUTH, PSTATUS_AUTH_PROVIDED); - } - else if (result==2205 || result==2229){ + tfa_pin=psync_strdup(psync_my_tfa_pin); + debug(D_NOTICE, "provided token from console: %s", tfa_pin); + } else if (result == 2064) { //Expired 'token'. + debug(D_NOTICE, "expired tfa token"); + psync_free(tfa_token); + psync_free(tfa_pin); + } else if (result == 2012) { //"Invalid 'code' provided." + debug(D_NOTICE, "invalid tfa pin"); + psync_free(tfa_pin); + psync_set_status(PSTATUS_TYPE_AUTH, PSTATUS_AUTH_TFAERR); + psync_wait_status(PSTATUS_TYPE_AUTH, PSTATUS_AUTH_PROVIDED); + tfa_pin=psync_strdup(psync_my_tfa_pin); + debug(D_NOTICE, "provided token from console: %s", tfa_pin); + } else if (result == 2205 || result == 2229) { + auth_reset=1; psync_set_status(PSTATUS_TYPE_AUTH, PSTATUS_AUTH_EXPIRED); psync_wait_status(PSTATUS_TYPE_AUTH, PSTATUS_AUTH_PROVIDED); - } else if (result == 2237) - { - digest = 0; + } else if (result == 2237) { + digest=0; continue; - } - - else + } else { psync_milisleep(PSYNC_SLEEP_BEFORE_RECONNECT); + } + psync_free(res); continue; } + psync_free(tfa_pin); + psync_free(tfa_token); + auth_reset=0; psync_my_userid=userid=psync_find_result(res, "userid", PARAM_NUM)->num; current_quota=psync_find_result(res, "quota", PARAM_NUM)->num; luserid=psync_sql_cellint("SELECT value FROM setting WHERE id='userid'", 0); diff --git a/pCloudCC/lib/pclsync/plibs.c b/pCloudCC/lib/pclsync/plibs.c index 4d31e554..fbceddb8 100644 --- a/pCloudCC/lib/pclsync/plibs.c +++ b/pCloudCC/lib/pclsync/plibs.c @@ -108,7 +108,7 @@ static char normalize_table[256]; const static char *psync_typenames[]={"[invalid type]", "[number]", "[string]", "[float]", "[null]", "[bool]"}; -char psync_my_auth[64]="", *psync_my_user=NULL, *psync_my_pass=NULL; +char psync_my_auth[64]="", *psync_my_user=NULL, *psync_my_pass=NULL, psync_my_tfa_pin[8]=""; uint64_t psync_my_userid=0; pthread_mutex_t psync_my_auth_mutex=PTHREAD_MUTEX_INITIALIZER; diff --git a/pCloudCC/lib/pclsync/plibs.h b/pCloudCC/lib/pclsync/plibs.h index 09e9acbe..b11bc042 100644 --- a/pCloudCC/lib/pclsync/plibs.h +++ b/pCloudCC/lib/pclsync/plibs.h @@ -188,7 +188,7 @@ typedef void (*psync_transaction_callback_t)(void *); extern int psync_do_run; extern int psync_recache_contacts; extern pstatus_t psync_status; -extern char psync_my_auth[64], *psync_my_user, *psync_my_pass; +extern char psync_my_auth[64], psync_my_tfa_pin[8], *psync_my_user, *psync_my_pass; extern uint64_t psync_my_userid; extern pthread_mutex_t psync_my_auth_mutex; extern PSYNC_THREAD uint32_t psync_error; diff --git a/pCloudCC/lib/pclsync/psettings.c b/pCloudCC/lib/pclsync/psettings.c index f130716d..da462559 100644 --- a/pCloudCC/lib/pclsync/psettings.c +++ b/pCloudCC/lib/pclsync/psettings.c @@ -68,7 +68,8 @@ static psync_setting_t settings[]={ {"autostartfs", NULL, NULL, {PSYNC_AUTOSTARTFS_DEFAULT}, PSYNC_TBOOL}, {"fscachesize", psync_pagecache_resize_cache, NULL, {PSYNC_FS_DEFAULT_CACHE_SIZE}, PSYNC_TNUMBER}, {"fscachepath", NULL, NULL, {0}, PSYNC_TSTRING}, - {"sleepstopcrypto", NULL, NULL, {PSYNC_CRYPTO_DEFAULT_STOP_ON_SLEEP}, PSYNC_TBOOL} + {"sleepstopcrypto", NULL, NULL, {PSYNC_CRYPTO_DEFAULT_STOP_ON_SLEEP}, PSYNC_TBOOL}, + {"trusted", NULL, NULL, {0}, PSYNC_TBOOL} }; void psync_settings_reset(){ diff --git a/pCloudCC/lib/pclsync/psettings.h b/pCloudCC/lib/pclsync/psettings.h index 71fb8f24..a6d5f7d8 100644 --- a/pCloudCC/lib/pclsync/psettings.h +++ b/pCloudCC/lib/pclsync/psettings.h @@ -280,6 +280,7 @@ pagefile.sys;\ #define PSYNC_SETTING_fscachesize 9 #define PSYNC_SETTING_fscachepath 10 #define PSYNC_SETTING_sleepstopcrypto 11 +#define PSYNC_SETTING_trusted 12 typedef int psync_settingid_t; diff --git a/pCloudCC/lib/pclsync/psynclib.c b/pCloudCC/lib/pclsync/psynclib.c index 197905a7..1129ebdc 100644 --- a/pCloudCC/lib/pclsync/psynclib.c +++ b/pCloudCC/lib/pclsync/psynclib.c @@ -338,6 +338,10 @@ void psync_set_auth(const char *auth, int save){ psync_set_status(PSTATUS_TYPE_AUTH, PSTATUS_AUTH_PROVIDED); } +void psync_set_tfa_pin(const char *tfa_pin){ + psync_strlcpy(psync_my_tfa_pin, tfa_pin, sizeof(psync_my_tfa_pin)); + psync_set_status(PSTATUS_TYPE_AUTH, PSTATUS_AUTH_PROVIDED); +} int psync_mark_notificaitons_read(uint32_t notificationid){ binparam params[]={P_STR("auth", psync_my_auth), P_NUM("notificationid", notificationid)}; diff --git a/pCloudCC/lib/pclsync/psynclib.h b/pCloudCC/lib/pclsync/psynclib.h index 0f0531d6..ee80de71 100644 --- a/pCloudCC/lib/pclsync/psynclib.h +++ b/pCloudCC/lib/pclsync/psynclib.h @@ -637,6 +637,7 @@ void psync_get_status(pstatus_t *status); char *psync_get_username(); void psync_set_user_pass(const char *username, const char *password, int save); +void psync_set_tfa_pin(const char *tfa_pin); void psync_set_pass(const char *password, int save); void psync_set_auth(const char *auth, int save); void psync_logout(); diff --git a/pCloudCC/main.cpp b/pCloudCC/main.cpp index d2f6a8ff..37287b14 100644 --- a/pCloudCC/main.cpp +++ b/pCloudCC/main.cpp @@ -6,7 +6,7 @@ namespace po = boost::program_options; #include "control_tools.h" namespace ct = control_tools; -static std::string version = "2.0.1"; +static std::string version = "2.1.0"; int main(int argc, char **argv) { std::cout << "pCloud console client v."<< version << std::endl; @@ -19,7 +19,8 @@ int main(int argc, char **argv) { bool passwordsw = false; bool save_pass = false; bool crypto = false; - + bool trusted_device = false; + try { po::options_description desc("Allowed options"); desc.add_options() @@ -28,6 +29,7 @@ int main(int argc, char **argv) { ("password,p", po::bool_switch(&passwordsw), "Ask pCloud account password") ("crypto,c", po::bool_switch(&crypto), "Ask crypto password") ("passascrypto,y", po::value(), "Use user password as crypto password also.") + ("trusted_device,t", po::bool_switch(&trusted_device), "Trust this device.") ("daemonize,d", po::bool_switch(&daemon), "Daemonize the process.") ("commands ,o", po::bool_switch(&commands), "Parent stays alive and processes commands. ") ("mountpoint,m", po::value(), "Mount point where drive to be mounted.") @@ -85,6 +87,7 @@ int main(int argc, char **argv) { console_client::clibrary::pclsync_lib::get_lib().newuser_ = newuser; console_client::clibrary::pclsync_lib::get_lib().set_savepass(save_pass); console_client::clibrary::pclsync_lib::get_lib().set_daemon(daemon); + console_client::clibrary::pclsync_lib::get_lib().set_trusted_device(trusted_device); } catch(std::exception& e) { std::cerr << "error: " << e.what() << "\n"; diff --git a/pCloudCC/pclsync_lib.cpp b/pCloudCC/pclsync_lib.cpp index 2fd8a13a..0497ba8b 100644 --- a/pCloudCC/pclsync_lib.cpp +++ b/pCloudCC/pclsync_lib.cpp @@ -74,6 +74,11 @@ void clib::pclsync_lib::get_cryptopass_from_console() do_get_pass_from_console(crypto_pass_); } +void clib::pclsync_lib::get_tfa_pin_from_console() +{ + do_get_pass_from_console(tfa_pin_); +} + void clib::pclsync_lib::do_get_pass_from_console(std::string& password) { if (daemon_) { @@ -164,7 +169,8 @@ static char const * status2string (uint32_t status){ case PSTATUS_SCANNING: return "SCANNING"; case PSTATUS_USER_MISMATCH: return "USER_MISMATCH"; case PSTATUS_ACCOUT_EXPIRED: return "ACCOUT_EXPIRED"; - default :return "Unrecognized status"; + case PSTATUS_ACCOUT_TFAERR: return "TFA_ERROR"; + default :return "UNRECOGNIZED_STATUS"; } } @@ -186,17 +192,24 @@ static void status_change(pstatus_t* status) { psync_set_user_pass(clib::pclsync_lib::get_lib().get_username().c_str(), clib::pclsync_lib::get_lib().get_password().c_str(), (int) clib::pclsync_lib::get_lib().save_pass_); } else { - std::cout << "registering" << std::endl; - if (psync_register(clib::pclsync_lib::get_lib().get_username().c_str(), clib::pclsync_lib::get_lib().get_password().c_str(),1, NULL)){ - std::cout << "both login and registration failed" << std::endl; - exit(1); - } - else{ - std::cout << "registered, logging in" << std::endl; - psync_set_user_pass(clib::pclsync_lib::get_lib().get_username().c_str(), clib::pclsync_lib::get_lib().get_password().c_str(), (int) clib::pclsync_lib::get_lib().save_pass_); - } - + std::cout << "registering" << std::endl; + if (psync_register(clib::pclsync_lib::get_lib().get_username().c_str(), clib::pclsync_lib::get_lib().get_password().c_str(),1, NULL)){ + std::cout << "both login and registration failed" << std::endl; + exit(1); + } + else{ + std::cout << "registered, logging in" << std::endl; + psync_set_user_pass(clib::pclsync_lib::get_lib().get_username().c_str(), clib::pclsync_lib::get_lib().get_password().c_str(), (int) clib::pclsync_lib::get_lib().save_pass_); + } } + } else if (status->status==PSTATUS_BAD_LOGIN_TOKEN){ + clib::pclsync_lib::get_lib().get_pass_from_console(); + psync_set_user_pass(clib::pclsync_lib::get_lib().get_username().c_str(), clib::pclsync_lib::get_lib().get_password().c_str(), (int) clib::pclsync_lib::get_lib().save_pass_); + } else if (status->status==PSTATUS_ACCOUT_TFAERR){ + std::cout << "two factor authentication - "; + clib::pclsync_lib::get_lib().get_tfa_pin_from_console(); + psync_set_bool_setting("trusted", clib::pclsync_lib::get_lib().trusted_device_); + psync_set_tfa_pin(clib::pclsync_lib::get_lib().get_tfa_pin().c_str()); } if (status->status==PSTATUS_READY || status->status==PSTATUS_UPLOADING || status->status==PSTATUS_DOWNLOADING || status->status==PSTATUS_DOWNLOADINGANDUPLOADING){ if (!cryptocheck){ @@ -219,6 +232,7 @@ int clib::pclsync_lib::statrt_crypto (const char* pass, void * rep) { int clib::pclsync_lib::stop_crypto (const char* path, void * rep) { psync_crypto_stop(); get_lib().crypto_on_ = false; + return 0; } int clib::pclsync_lib::finalize (const char* path, void * rep) { psync_destroy(); @@ -228,17 +242,16 @@ int clib::pclsync_lib::list_sync_folders (const char* path, void * rep) { psync_folder_list_t * folders = psync_get_sync_list(); rep =psync_malloc(sizeof(folders)); memcpy(rep, folders, sizeof(folders)); - + return 0; } -static const std::string client_name = " Console Client v.2.0.1"; +static const std::string client_name = "Console Client v.2.1.0"; int clib::pclsync_lib::init()//std::string& username, std::string& password, std::string* crypto_pass, int setup_crypto, int usesrypto_userpass) { - std::string software_string = exec("lsb_release -ds"); - psync_set_software_string(software_string.append(client_name).c_str()); + std::string software_string = exec("hostname -f"); + psync_set_software_string(software_string.append("(").append(client_name).append(")").c_str()); if (setup_crypto_ && crypto_pass_.empty() ) return 3; - - + if (psync_init()){ std::cout <<"init failed\n"; return 1; diff --git a/pCloudCC/pclsync_lib.h b/pCloudCC/pclsync_lib.h index 17d8b417..c3b6c5cb 100644 --- a/pCloudCC/pclsync_lib.h +++ b/pCloudCC/pclsync_lib.h @@ -46,6 +46,7 @@ namespace console_client { //Getters const std::string& get_username() {return username_;} const std::string& get_password() {return password_;} + const std::string& get_tfa_pin() {return tfa_pin_;} const std::string& get_crypto_pass() {return crypto_pass_;}; const std::string& get_mount() {return mount_;} //Setters @@ -57,10 +58,12 @@ namespace console_client { void setupsetup_crypto(bool p) {setup_crypto_ = p;} void set_newuser(bool p) {newuser_ = p;} void set_daemon(bool p) {daemon_ = p;} + void set_trusted_device(bool p) {trusted_device_ = p;} void set_status_callback(status_callback_t p) {status_callback_ = p;} //Console void get_pass_from_console(); void get_cryptopass_from_console(); + void get_tfa_pin_from_console(); //API calls int init();//std::string& username, std::string& password, std::string* crypto_pass, int setup_crypto = 1, int usesrypto_userpass = 0); static int statrt_crypto (const char* pass, void * rep); @@ -76,6 +79,7 @@ namespace console_client { bool crypto_on_; bool save_pass_; + bool trusted_device_; bool setup_crypto_; pstatus_struct_* status_; bool newuser_; @@ -85,6 +89,7 @@ namespace console_client { private: std::string username_; std::string password_; + std::string tfa_pin_; std::string crypto_pass_; std::string mount_; diff --git a/pCloudCC/pclsync_lib_c.cpp b/pCloudCC/pclsync_lib_c.cpp index ea2bd096..52197566 100644 --- a/pCloudCC/pclsync_lib_c.cpp +++ b/pCloudCC/pclsync_lib_c.cpp @@ -14,13 +14,13 @@ int init() { else return 0; } - int statrt_crypto (const char* pass) { +void statrt_crypto (const char* pass) { cc::pclsync_lib::statrt_crypto (pass, NULL); } - int stop_crypto () { +void stop_crypto () { cc::pclsync_lib::stop_crypto (NULL, NULL); } - int finalize () { +void finalize () { cc::pclsync_lib::finalize(NULL, NULL); } void set_status_callback(status_callback_t c) { @@ -47,4 +47,4 @@ int unlinklib() { #ifdef __cplusplus } -#endif \ No newline at end of file +#endif diff --git a/pCloudCC/pclsync_lib_c.h b/pCloudCC/pclsync_lib_c.h index 79ff48d7..bbd9a3c7 100644 --- a/pCloudCC/pclsync_lib_c.h +++ b/pCloudCC/pclsync_lib_c.h @@ -10,9 +10,9 @@ extern "C" { typedef void (*status_callback_t)(int status, const char * stat_string); int init(); - int statrt_crypto (const char* pass); - int stop_crypto (); - int finalize (); + void statrt_crypto (const char* pass); + void stop_crypto (); + void finalize (); char * get_token(); void set_status_callback(status_callback_t); int logout(); @@ -21,4 +21,4 @@ extern "C" { #ifdef __cplusplus }; -#endif \ No newline at end of file +#endif