Skip to content

Commit 43a995a

Browse files
author
Glib Dzevo
committed
NO_REF: Experimental TFA support.
1 parent 1850db4 commit 43a995a

File tree

11 files changed

+139
-70
lines changed

11 files changed

+139
-70
lines changed

README.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,13 +37,14 @@ On Ubuntu you can run the following command:
3737
## Usage
3838
Terminal command is pcloudcc and -h option prints short options description.
3939
> ./pcloudcc -h
40-
> pCloud console client v.2.0.1
40+
> pCloud console client v.2.1.0
4141
>Allowed options:
4242
> -h [ --help ] produce help message
4343
> -u [ --username ] arg pCloud account name
4444
> -p [ --password ] pCloud account password
4545
> -c [ --crypto ] arg Crypto password
46-
> -y [ --passascrypto ] arg Use user password as crypto password also.
46+
> -y [ --passascrypto ] arg Use user password as crypto password also.
47+
> -t [ --trust ] Trust this device.
4748
> -d [ --daemonize ] Daemonize the process.
4849
> -o [ --commands ] Parent stays alive and processes commands.
4950
> -m [ --mountpoint ] arg Mount point where drive to be mounted.

pCloudCC/lib/pclsync/pdiff.c

Lines changed: 87 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -111,22 +111,62 @@ static void delete_cached_crypto_keys(){
111111
psync_sql_statement("DELETE FROM cryptofilekey");
112112
}
113113

114-
static binresult *get_userinfo_user_digest(psync_socket *sock, const char *username, size_t userlen, const char *pwddig, const char *digest, uint32_t diglen,
115-
const char *device){
114+
static binresult *login_with_digest(psync_socket *sock, const char *username, size_t userlen, const char *pwddig,
115+
const char *digest, uint32_t diglen,
116+
const char *device) {
116117
binparam params[]={P_STR("timeformat", "timestamp"),
117118
P_LSTR("username", username, userlen),
118119
P_LSTR("digest", digest, diglen),
119120
P_LSTR("passworddigest", pwddig, PSYNC_SHA1_DIGEST_HEXLEN),
120121
P_STR("device", device),
122+
P_STR("deviceid", device),
121123
P_BOOL("getauth", 1),
122124
P_BOOL("getapiserver", 1),
123125
P_BOOL("cryptokeyssign", 1),
124126
P_NUM("os", P_OS_ID)};
125127
return send_command(sock, "login", params);
126128
}
127129

128-
static binresult *get_userinfo_user_pass(psync_socket *sock, const char *username, const char *password, const char *device){
129-
binparam empty_params[]={P_STR("MS", "sucks")};
130+
static binresult *get_userinfo_user_pass(psync_socket *sock, const char *username, const char *password,
131+
const char *device) {
132+
binparam params[] = {P_STR("timeformat", "timestamp"),
133+
P_STR("username", username),
134+
P_STR("password", password),
135+
P_STR("device", device),
136+
P_STR("deviceid", device),
137+
P_BOOL("getauth", 1),
138+
P_BOOL("cryptokeyssign", 1),
139+
P_BOOL("getapiserver", 1),
140+
P_NUM("os", P_OS_ID)};
141+
return send_command(sock, "login", params);
142+
}
143+
144+
static binresult *get_userinfo_auth(psync_socket *sock, const char *auth, const char *device) {
145+
binparam params[]={P_STR("timeformat", "timestamp"),
146+
P_STR("auth", auth),
147+
P_STR("device", device),
148+
P_STR("deviceid", device),
149+
P_BOOL("getauth", 1),
150+
P_BOOL("cryptokeyssign", 1),
151+
P_BOOL("getapiserver", 1),
152+
P_NUM("os", P_OS_ID)};
153+
return send_command(sock, "userinfo", params);
154+
}
155+
156+
static binresult *get_tfa_auth(psync_socket *sock, const char *token, const char *code, const char *device) {
157+
binparam params[]={P_STR("timeformat", "timestamp"),
158+
P_STR("token", token),
159+
P_STR("device", device),
160+
P_STR("deviceid", device),
161+
P_NUM("code", atol(code)),
162+
P_BOOL("trustdevice", psync_setting_get_bool(_PS(trusted))),
163+
P_NUM("os", P_OS_ID)};
164+
return send_command(sock, "tfa_login", params);
165+
}
166+
167+
static binresult *get_userinfo_user_pass_digest(psync_socket *sock, const char *username, const char *password,
168+
const char *device){
169+
binparam empty_params[]={P_STR("NO_PARAM", "empty")};
130170
psync_sha1_ctx ctx;
131171
binresult *res, *ret;
132172
const binresult *dig;
@@ -156,23 +196,23 @@ static binresult *get_userinfo_user_pass(psync_socket *sock, const char *usernam
156196
psync_sha1_update(&ctx, dig->str, dig->length);
157197
psync_sha1_final(sha1bin, &ctx);
158198
psync_binhex(sha1hex, sha1bin, PSYNC_SHA1_DIGEST_LEN);
159-
ret=get_userinfo_user_digest(sock, username, ul, sha1hex, dig->str, dig->length, device);
199+
ret=login_with_digest(sock, username, ul, sha1hex, dig->str, dig->length, device);
160200
psync_free(res);
161201
return ret;
162202
}
163203

164204
static psync_socket *get_connected_socket(){
165-
char *auth, *user, *pass;
205+
char *auth, *user, *pass, *tfa_pin, *tfa_token, *device;
166206
psync_socket *sock;
167207
binresult *res;
168208
const binresult *cres;
169209
psync_sql_res *q;
170-
char *device;
171210
uint64_t result, userid, luserid;
172211
int saveauth, isbusiness, cryptosetup;
173-
auth=user=pass=NULL;
212+
auth=user=pass=tfa_pin=tfa_token=NULL;
174213
psync_is_business = 0;
175214
int digest = 1;
215+
int auth_reset = 0;
176216
while (1){
177217
psync_free(auth);
178218
psync_free(user);
@@ -202,30 +242,16 @@ static psync_socket *get_connected_socket(){
202242
}
203243
device=psync_deviceid();
204244

205-
if (user && pass && pass[0])
206-
if (digest)
245+
if (tfa_token && tfa_pin) {
246+
res=get_tfa_auth(sock, tfa_token, tfa_pin, device);
247+
} else if ((!auth || auth_reset) && user && pass && pass[0]) {
248+
if (digest) {
249+
res=get_userinfo_user_pass_digest(sock, user, pass, device);
250+
} else {
207251
res=get_userinfo_user_pass(sock, user, pass, device);
208-
else
209-
{
210-
binparam params[]={P_STR("timeformat", "timestamp"),
211-
P_STR("username", user),
212-
P_STR("password", pass),
213-
P_STR("device", device),
214-
P_BOOL("getauth", 1),
215-
P_BOOL("cryptokeyssign", 1),
216-
P_BOOL("getapiserver", 1),
217-
P_NUM("os", P_OS_ID)};
218-
res=send_command(sock, "login", params);
219252
}
220-
else {
221-
binparam params[]={P_STR("timeformat", "timestamp"),
222-
P_STR("auth", auth),
223-
P_STR("device", device),
224-
P_BOOL("getauth", 1),
225-
P_BOOL("cryptokeyssign", 1),
226-
P_BOOL("getapiserver", 1),
227-
P_NUM("os", P_OS_ID)};
228-
res=send_command(sock, "userinfo", params);
253+
} else {
254+
res=get_userinfo_auth(sock, auth, device);
229255
}
230256
psync_free(device);
231257
if (unlikely_log(!res)){
@@ -240,33 +266,48 @@ static psync_socket *get_connected_socket(){
240266
if (unlikely(result)){
241267
debug(D_NOTICE, "userinfo returned error %lu %s", (unsigned long)result, psync_find_result(res, "error", PARAM_STR)->str);
242268
psync_socket_close(sock);
243-
psync_free(res);
244-
if (result==2000){
245-
if (user && pass)
269+
if (result == 2000) {
270+
if (user && pass) {
246271
psync_set_status(PSTATUS_TYPE_AUTH, PSTATUS_AUTH_BADLOGIN);
247-
else
272+
} else {
248273
psync_set_status(PSTATUS_TYPE_AUTH, PSTATUS_AUTH_BADTOKEN);
274+
}
249275
psync_wait_status(PSTATUS_TYPE_AUTH, PSTATUS_AUTH_PROVIDED);
250-
}
251-
else if (result==4000)
252-
psync_milisleep(5*60*1000);
253-
else if (result == 2297 ){
276+
} else if (result == 4000) {
277+
psync_milisleep(5 * 60 * 1000);
278+
} else if (result == 2297) {
279+
tfa_token=psync_strdup(psync_find_result(res, "token", PARAM_STR)->str);
254280
psync_set_status(PSTATUS_TYPE_AUTH, PSTATUS_AUTH_TFAERR);
255281
psync_wait_status(PSTATUS_TYPE_AUTH, PSTATUS_AUTH_PROVIDED);
256-
}
257-
else if (result==2205 || result==2229){
282+
tfa_pin=psync_strdup(psync_my_tfa_pin);
283+
debug(D_NOTICE, "provided token from console: %s", tfa_pin);
284+
} else if (result == 2064) { //Expired 'token'.
285+
debug(D_NOTICE, "expired tfa token");
286+
psync_free(tfa_token);
287+
psync_free(tfa_pin);
288+
} else if (result == 2012) { //"Invalid 'code' provided."
289+
debug(D_NOTICE, "invalid tfa pin");
290+
psync_free(tfa_pin);
291+
psync_set_status(PSTATUS_TYPE_AUTH, PSTATUS_AUTH_TFAERR);
292+
psync_wait_status(PSTATUS_TYPE_AUTH, PSTATUS_AUTH_PROVIDED);
293+
tfa_pin=psync_strdup(psync_my_tfa_pin);
294+
debug(D_NOTICE, "provided token from console: %s", tfa_pin);
295+
} else if (result == 2205 || result == 2229) {
296+
auth_reset=1;
258297
psync_set_status(PSTATUS_TYPE_AUTH, PSTATUS_AUTH_EXPIRED);
259298
psync_wait_status(PSTATUS_TYPE_AUTH, PSTATUS_AUTH_PROVIDED);
260-
} else if (result == 2237)
261-
{
262-
digest = 0;
299+
} else if (result == 2237) {
300+
digest=0;
263301
continue;
264-
}
265-
266-
else
302+
} else {
267303
psync_milisleep(PSYNC_SLEEP_BEFORE_RECONNECT);
304+
}
305+
psync_free(res);
268306
continue;
269307
}
308+
psync_free(tfa_pin);
309+
psync_free(tfa_token);
310+
auth_reset=0;
270311
psync_my_userid=userid=psync_find_result(res, "userid", PARAM_NUM)->num;
271312
current_quota=psync_find_result(res, "quota", PARAM_NUM)->num;
272313
luserid=psync_sql_cellint("SELECT value FROM setting WHERE id='userid'", 0);

pCloudCC/lib/pclsync/plibs.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ static char normalize_table[256];
108108

109109
const static char *psync_typenames[]={"[invalid type]", "[number]", "[string]", "[float]", "[null]", "[bool]"};
110110

111-
char psync_my_auth[64]="", *psync_my_user=NULL, *psync_my_pass=NULL;
111+
char psync_my_auth[64]="", *psync_my_user=NULL, *psync_my_pass=NULL, psync_my_tfa_pin[6]="";
112112
uint64_t psync_my_userid=0;
113113
pthread_mutex_t psync_my_auth_mutex=PTHREAD_MUTEX_INITIALIZER;
114114

pCloudCC/lib/pclsync/plibs.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,7 @@ typedef void (*psync_transaction_callback_t)(void *);
188188
extern int psync_do_run;
189189
extern int psync_recache_contacts;
190190
extern pstatus_t psync_status;
191-
extern char psync_my_auth[64], *psync_my_user, *psync_my_pass;
191+
extern char psync_my_auth[64], psync_my_tfa_pin[6], *psync_my_user, *psync_my_pass;
192192
extern uint64_t psync_my_userid;
193193
extern pthread_mutex_t psync_my_auth_mutex;
194194
extern PSYNC_THREAD uint32_t psync_error;

pCloudCC/lib/pclsync/psettings.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,8 @@ static psync_setting_t settings[]={
6868
{"autostartfs", NULL, NULL, {PSYNC_AUTOSTARTFS_DEFAULT}, PSYNC_TBOOL},
6969
{"fscachesize", psync_pagecache_resize_cache, NULL, {PSYNC_FS_DEFAULT_CACHE_SIZE}, PSYNC_TNUMBER},
7070
{"fscachepath", NULL, NULL, {0}, PSYNC_TSTRING},
71-
{"sleepstopcrypto", NULL, NULL, {PSYNC_CRYPTO_DEFAULT_STOP_ON_SLEEP}, PSYNC_TBOOL}
71+
{"sleepstopcrypto", NULL, NULL, {PSYNC_CRYPTO_DEFAULT_STOP_ON_SLEEP}, PSYNC_TBOOL},
72+
{"trusted", NULL, NULL, {0}, PSYNC_TBOOL}
7273
};
7374

7475
void psync_settings_reset(){

pCloudCC/lib/pclsync/psettings.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -280,6 +280,7 @@ pagefile.sys;\
280280
#define PSYNC_SETTING_fscachesize 9
281281
#define PSYNC_SETTING_fscachepath 10
282282
#define PSYNC_SETTING_sleepstopcrypto 11
283+
#define PSYNC_SETTING_trusted 12
283284

284285
typedef int psync_settingid_t;
285286

pCloudCC/lib/pclsync/psynclib.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -334,10 +334,14 @@ void psync_set_auth(const char *auth, int save){
334334
if (save)
335335
psync_set_string_value("auth", auth);
336336
else
337-
psync_strlcpy(psync_my_auth, auth, sizeof(psync_my_auth));
337+
psync_strlcpy(psync_my_auth, auth, sizeof(psync_my_auth)+1);
338338
psync_set_status(PSTATUS_TYPE_AUTH, PSTATUS_AUTH_PROVIDED);
339339
}
340340

341+
void psync_set_tfa_pin(const char *tfa_pin){
342+
psync_strlcpy(psync_my_tfa_pin, tfa_pin, sizeof(psync_my_tfa_pin)+1);
343+
psync_set_status(PSTATUS_TYPE_AUTH, PSTATUS_AUTH_PROVIDED);
344+
}
341345

342346
int psync_mark_notificaitons_read(uint32_t notificationid){
343347
binparam params[]={P_STR("auth", psync_my_auth), P_NUM("notificationid", notificationid)};

pCloudCC/lib/pclsync/psynclib.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -637,6 +637,7 @@ void psync_get_status(pstatus_t *status);
637637

638638
char *psync_get_username();
639639
void psync_set_user_pass(const char *username, const char *password, int save);
640+
void psync_set_tfa_pin(const char *tfa_pin);
640641
void psync_set_pass(const char *password, int save);
641642
void psync_set_auth(const char *auth, int save);
642643
void psync_logout();

pCloudCC/main.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ namespace po = boost::program_options;
66
#include "control_tools.h"
77
namespace ct = control_tools;
88

9-
static std::string version = "2.0.1";
9+
static std::string version = "2.1.0";
1010

1111
int main(int argc, char **argv) {
1212
std::cout << "pCloud console client v."<< version << std::endl;
@@ -19,7 +19,8 @@ int main(int argc, char **argv) {
1919
bool passwordsw = false;
2020
bool save_pass = false;
2121
bool crypto = false;
22-
22+
bool trusted_device = false;
23+
2324
try {
2425
po::options_description desc("Allowed options");
2526
desc.add_options()
@@ -28,6 +29,7 @@ int main(int argc, char **argv) {
2829
("password,p", po::bool_switch(&passwordsw), "Ask pCloud account password")
2930
("crypto,c", po::bool_switch(&crypto), "Ask crypto password")
3031
("passascrypto,y", po::value<std::string>(), "Use user password as crypto password also.")
32+
("trusted_device,t", po::bool_switch(&trusted_device), "Trust this device.")
3133
("daemonize,d", po::bool_switch(&daemon), "Daemonize the process.")
3234
("commands ,o", po::bool_switch(&commands), "Parent stays alive and processes commands. ")
3335
("mountpoint,m", po::value<std::string>(), "Mount point where drive to be mounted.")
@@ -85,6 +87,7 @@ int main(int argc, char **argv) {
8587
console_client::clibrary::pclsync_lib::get_lib().newuser_ = newuser;
8688
console_client::clibrary::pclsync_lib::get_lib().set_savepass(save_pass);
8789
console_client::clibrary::pclsync_lib::get_lib().set_daemon(daemon);
90+
console_client::clibrary::pclsync_lib::get_lib().set_trusted_device(trusted_device);
8891
}
8992
catch(std::exception& e) {
9093
std::cerr << "error: " << e.what() << "\n";

pCloudCC/pclsync_lib.cpp

Lines changed: 28 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,11 @@ void clib::pclsync_lib::get_cryptopass_from_console()
7474
do_get_pass_from_console(crypto_pass_);
7575
}
7676

77+
void clib::pclsync_lib::get_tfa_pin_from_console()
78+
{
79+
do_get_pass_from_console(tfa_pin_);
80+
}
81+
7782
void clib::pclsync_lib::do_get_pass_from_console(std::string& password)
7883
{
7984
if (daemon_) {
@@ -164,7 +169,8 @@ static char const * status2string (uint32_t status){
164169
case PSTATUS_SCANNING: return "SCANNING";
165170
case PSTATUS_USER_MISMATCH: return "USER_MISMATCH";
166171
case PSTATUS_ACCOUT_EXPIRED: return "ACCOUT_EXPIRED";
167-
default :return "Unrecognized status";
172+
case PSTATUS_ACCOUT_TFAERR: return "TFA_ERROR";
173+
default :return "UNRECOGNIZED_STATUS";
168174
}
169175
}
170176

@@ -186,17 +192,24 @@ static void status_change(pstatus_t* status) {
186192
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_);
187193
}
188194
else {
189-
std::cout << "registering" << std::endl;
190-
if (psync_register(clib::pclsync_lib::get_lib().get_username().c_str(), clib::pclsync_lib::get_lib().get_password().c_str(),1, NULL)){
191-
std::cout << "both login and registration failed" << std::endl;
192-
exit(1);
193-
}
194-
else{
195-
std::cout << "registered, logging in" << std::endl;
196-
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_);
197-
}
198-
195+
std::cout << "registering" << std::endl;
196+
if (psync_register(clib::pclsync_lib::get_lib().get_username().c_str(), clib::pclsync_lib::get_lib().get_password().c_str(),1, NULL)){
197+
std::cout << "both login and registration failed" << std::endl;
198+
exit(1);
199+
}
200+
else{
201+
std::cout << "registered, logging in" << std::endl;
202+
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_);
203+
}
199204
}
205+
} else if (status->status==PSTATUS_BAD_LOGIN_TOKEN){
206+
clib::pclsync_lib::get_lib().get_pass_from_console();
207+
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_);
208+
} else if (status->status==PSTATUS_ACCOUT_TFAERR){
209+
std::cout << "two factor authentication - ";
210+
clib::pclsync_lib::get_lib().get_tfa_pin_from_console();
211+
psync_set_bool_setting("trusted", clib::pclsync_lib::get_lib().trusted_device_);
212+
psync_set_tfa_pin(clib::pclsync_lib::get_lib().get_tfa_pin().c_str());
200213
}
201214
if (status->status==PSTATUS_READY || status->status==PSTATUS_UPLOADING || status->status==PSTATUS_DOWNLOADING || status->status==PSTATUS_DOWNLOADINGANDUPLOADING){
202215
if (!cryptocheck){
@@ -230,15 +243,14 @@ int clib::pclsync_lib::list_sync_folders (const char* path, void * rep) {
230243
memcpy(rep, folders, sizeof(folders));
231244

232245
}
233-
static const std::string client_name = " Console Client v.2.0.1";
246+
static const std::string client_name = "Console Client v.2.1.0";
234247
int clib::pclsync_lib::init()//std::string& username, std::string& password, std::string* crypto_pass, int setup_crypto, int usesrypto_userpass)
235248
{
236-
std::string software_string = exec("lsb_release -ds");
237-
psync_set_software_string(software_string.append(client_name).c_str());
249+
std::string software_string = exec("hostname -f");
250+
psync_set_software_string(software_string.append("(").append(client_name).append(")").c_str());
238251
if (setup_crypto_ && crypto_pass_.empty() )
239252
return 3;
240-
241-
253+
242254
if (psync_init()){
243255
std::cout <<"init failed\n";
244256
return 1;

0 commit comments

Comments
 (0)