1 /**
2  * @file user.cpp
3  * @brief Class for manipulating user / contact data
4  *
5  * (c) 2013-2014 by Mega Limited, Auckland, New Zealand
6  *
7  * This file is part of the MEGA SDK - Client Access Engine.
8  *
9  * Applications using the MEGA API must present a valid application key
10  * and comply with the the rules set forth in the Terms of Service.
11  *
12  * The MEGA SDK is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
15  *
16  * @copyright Simplified (2-clause) BSD License.
17  *
18  * You should have received a copy of the license along with this
19  * program.
20  */
21 
22 #include "mega/user.h"
23 #include "mega/megaclient.h"
24 #include "mega/logging.h"
25 #include "mega/base64.h"
26 
27 namespace mega {
User(const char * cemail)28 User::User(const char* cemail)
29 {
30     userhandle = UNDEF;
31     show = VISIBILITY_UNKNOWN;
32     ctime = 0;
33     pubkrequested = false;
34     isTemporary = false;
35     resetTag();
36 
37     if (cemail)
38     {
39         email = cemail;
40     }
41 
42     memset(&changed, 0, sizeof(changed));
43 }
44 
mergeUserAttribute(attr_t type,const string_map & newValuesMap,TLVstore & tlv)45 bool User::mergeUserAttribute(attr_t type, const string_map &newValuesMap, TLVstore &tlv)
46 {
47     bool modified = false;
48 
49     for (const auto &it : newValuesMap)
50     {
51         const char *key = it.first.c_str();
52         string newValue = it.second;
53         string currentValue;
54         if (tlv.find(key))  // the key may not exist in the current user attribute
55         {
56             Base64::btoa(tlv.get(key), currentValue);
57         }
58         if (newValue != currentValue)
59         {
60             if (type == ATTR_ALIAS && newValue[0] == '\0')
61             {
62                 // alias being removed
63                 tlv.reset(key);
64             }
65             else
66             {
67                 tlv.set(key, Base64::atob(newValue));
68             }
69             modified = true;
70         }
71     }
72 
73     return modified;
74 }
75 
serialize(string * d)76 bool User::serialize(string* d)
77 {
78     unsigned char l;
79     unsigned short ll;
80     time_t ts;
81     AttrMap attrmap;
82     char attrVersion = '1';
83 
84     d->reserve(d->size() + 100 + attrmap.storagesize(10));
85 
86     d->append((char*)&userhandle, sizeof userhandle);
87 
88     // FIXME: use m_time_t & Serialize64 instead
89     ts = ctime;
90     d->append((char*)&ts, sizeof ts);
91     d->append((char*)&show, sizeof show);
92 
93     l = (unsigned char)email.size();
94     d->append((char*)&l, sizeof l);
95     d->append(email.c_str(), l);
96 
97     d->append((char*)&attrVersion, 1);
98 
99     char bizMode = 0;
100     if (mBizMode != BIZ_MODE_UNKNOWN) // convert number to ascii
101     {
102         bizMode = static_cast<char>('0' + mBizMode);
103     }
104 
105     d->append((char*)&bizMode, 1);
106     d->append("\0\0\0\0\0", 6);
107 
108     // serialization of attributes
109     l = (unsigned char)attrs.size();
110     d->append((char*)&l, sizeof l);
111     for (userattr_map::iterator it = attrs.begin(); it != attrs.end(); it++)
112     {
113         d->append((char*)&it->first, sizeof it->first);
114 
115         ll = (unsigned short)it->second.size();
116         d->append((char*)&ll, sizeof ll);
117         d->append(it->second.data(), ll);
118 
119         if (attrsv.find(it->first) != attrsv.end())
120         {
121             ll = (unsigned short)attrsv[it->first].size();
122             d->append((char*)&ll, sizeof ll);
123             d->append(attrsv[it->first].data(), ll);
124         }
125         else
126         {
127             ll = 0;
128             d->append((char*)&ll, sizeof ll);
129         }
130     }
131 
132     if (pubk.isvalid())
133     {
134         pubk.serializekey(d, AsymmCipher::PUBKEY);
135     }
136 
137     return true;
138 }
139 
unserialize(MegaClient * client,string * d)140 User* User::unserialize(MegaClient* client, string* d)
141 {
142     handle uh;
143     time_t ts;
144     visibility_t v;
145     unsigned char l;
146     unsigned short ll;
147     string m;
148     User* u;
149     const char* ptr = d->data();
150     const char* end = ptr + d->size();
151     int i;
152     char attrVersion;
153 
154     if (ptr + sizeof(handle) + sizeof(time_t) + sizeof(visibility_t) + 2 > end)
155     {
156         return NULL;
157     }
158 
159     uh = MemAccess::get<handle>(ptr);
160     ptr += sizeof uh;
161 
162     // FIXME: use m_time_t & Serialize64
163     ts = MemAccess::get<time_t>(ptr);
164     ptr += sizeof ts;
165 
166     v = MemAccess::get<visibility_t>(ptr);
167     ptr += sizeof v;
168 
169     l = *ptr++;
170     if (l)
171     {
172         if (ptr + l > end)
173         {
174             return NULL;
175         }
176         m.assign(ptr, l);
177     }
178     ptr += l;
179 
180     if (ptr + sizeof(char) + sizeof(char) > end)
181     {
182         return NULL;
183     }
184 
185     attrVersion = MemAccess::get<char>(ptr);
186     ptr += sizeof(attrVersion);
187 
188     char bizModeValue = MemAccess::get<char>(ptr);
189     ptr += sizeof(bizModeValue);
190     BizMode bizMode;
191     switch (bizModeValue)
192     {
193         case '0':
194             bizMode = BIZ_MODE_SUBUSER;
195             break;
196         case '1':
197             bizMode = BIZ_MODE_MASTER;
198             break;
199         default:
200             bizMode = BIZ_MODE_UNKNOWN;
201             break;
202     }
203 
204     for (i = 6; i--;)
205     {
206         if (ptr + MemAccess::get<unsigned char>(ptr) < end)
207         {
208             ptr += MemAccess::get<unsigned char>(ptr) + 1;
209         }
210     }
211 
212     if ((i >= 0) || !(u = client->finduser(uh, 1)))
213     {
214         return NULL;
215     }
216 
217     client->mapuser(uh, m.c_str());
218     u->set(v, ts);
219     u->resetTag();
220     u->mBizMode = bizMode;
221 
222     if (attrVersion == '\0')
223     {
224         AttrMap attrmap;
225         if ((ptr < end) && !(ptr = attrmap.unserialize(ptr, end)))
226         {
227             client->discarduser(uh);
228             return NULL;
229         }
230     }
231     else if (attrVersion == '1')
232     {
233         attr_t key;
234 
235         if (ptr + sizeof(char) > end)
236         {
237             client->discarduser(uh);
238             return NULL;
239         }
240 
241         l = *ptr++;
242         for (int i = 0; i < l; i++)
243         {
244             if (ptr + sizeof key + sizeof(ll) > end)
245             {
246                 client->discarduser(uh);
247                 return NULL;
248             }
249 
250             key = MemAccess::get<attr_t>(ptr);
251             ptr += sizeof key;
252 
253             ll = MemAccess::get<short>(ptr);
254             ptr += sizeof ll;
255 
256             if (ptr + ll + sizeof(ll) > end)
257             {
258                 client->discarduser(uh);
259                 return NULL;
260             }
261 
262             if (!u->isattrvalid(key))
263             {
264                 u->attrs[key].assign(ptr, ll);
265             }
266 
267             ptr += ll;
268 
269             ll = MemAccess::get<short>(ptr);
270             ptr += sizeof ll;
271 
272             if (ll)
273             {
274                 if (ptr + ll > end)
275                 {
276                     client->discarduser(uh);
277                     return NULL;
278                 }
279 
280                 if (!u->isattrvalid(key))
281                 {
282                     u->attrsv[key].assign(ptr,ll);
283                 }
284 
285                 ptr += ll;
286             }
287         }
288     }
289 
290     const string *av = (u->isattrvalid(ATTR_KEYRING)) ? u->getattr(ATTR_KEYRING) : NULL;
291     if (av)
292     {
293         TLVstore *tlvRecords = TLVstore::containerToTLVrecords(av, &client->key);
294         if (tlvRecords)
295         {
296             if (tlvRecords->find(EdDSA::TLV_KEY))
297             {
298                 client->signkey = new EdDSA(client->rng, (unsigned char *) tlvRecords->get(EdDSA::TLV_KEY).data());
299                 if (!client->signkey->initializationOK)
300                 {
301                     delete client->signkey;
302                     client->signkey = NULL;
303                     LOG_warn << "Failed to load chat key from local cache.";
304                 }
305                 else
306                 {
307                     LOG_info << "Signing key loaded from local cache.";
308                 }
309             }
310 
311             if (tlvRecords->find(ECDH::TLV_KEY))
312             {
313                 client->chatkey = new ECDH((unsigned char *) tlvRecords->get(ECDH::TLV_KEY).data());
314                 if (!client->chatkey->initializationOK)
315                 {
316                     delete client->chatkey;
317                     client->chatkey = NULL;
318                     LOG_warn << "Failed to load chat key from local cache.";
319                 }
320                 else
321                 {
322                     LOG_info << "Chat key successfully loaded from local cache.";
323                 }
324             }
325 
326             delete tlvRecords;
327         }
328         else
329         {
330             LOG_warn << "Failed to decrypt keyring from cache";
331         }
332     }
333 
334     if ((ptr < end) && !u->pubk.setkey(AsymmCipher::PUBKEY, (byte*)ptr, int(end - ptr)))
335     {
336         client->discarduser(uh);
337         return NULL;
338     }
339 
340     return u;
341 }
342 
setattr(attr_t at,string * av,string * v)343 void User::setattr(attr_t at, string *av, string *v)
344 {
345     setChanged(at);
346 
347     if (at != ATTR_AVATAR)  // avatar is saved to disc
348     {
349         attrs[at] = *av;
350     }
351 
352     attrsv[at] = v ? *v : "N";
353 }
354 
invalidateattr(attr_t at)355 void User::invalidateattr(attr_t at)
356 {
357     setChanged(at);
358     attrsv.erase(at);
359 }
360 
removeattr(attr_t at,const string * version)361 void User::removeattr(attr_t at, const string *version)
362 {
363     if (isattrvalid(at))
364     {
365         setChanged(at);
366     }
367 
368     attrs.erase(at);
369     if (version)
370     {
371         attrsv[at] = *version;
372     }
373     else
374     {
375         attrsv.erase(at);
376     }
377 }
378 
379 // updates the user attribute value+version only if different
updateattr(attr_t at,std::string * av,std::string * v)380 int User::updateattr(attr_t at, std::string *av, std::string *v)
381 {
382     if (attrsv[at] == *v)
383     {
384         return 0;
385     }
386 
387     setattr(at, av, v);
388     return 1;
389 }
390 
391 // returns the value if there is value (even if it's invalid by now)
getattr(attr_t at)392 const string * User::getattr(attr_t at)
393 {
394     userattr_map::const_iterator it = attrs.find(at);
395     if (it != attrs.end())
396     {
397         return &(it->second);
398     }
399 
400     return NULL;
401 }
402 
isattrvalid(attr_t at)403 bool User::isattrvalid(attr_t at)
404 {
405     return attrs.count(at) && attrsv.count(at);
406 }
407 
attr2string(attr_t type)408 string User::attr2string(attr_t type)
409 {
410     string attrname;
411 
412     // Special first character (required, except for the oldest attributes):
413     // `+` is public and unencrypted
414     // `#` is 'protected' and unencrypted, the API will allow contacts to fetch it but not give it out to non-contacts
415     // `^` is private but unencrypted, i.e.the API won't give it out to anybody except you, but the API can read the value as well
416     // `*` is private and encrypted, API only gives it to you and the API doesn't have a way to know the true value
417     // `%` business usage
418 
419     // Special second character (optional)
420     // ! only store a single copy and do not keep a history of changes
421     // ~ only store one time (ignore subsequent updates, and no history of course)
422 
423     switch(type)
424     {
425         case ATTR_AVATAR:
426             attrname = "+a";
427             break;
428 
429         case ATTR_FIRSTNAME:
430             attrname = "firstname";
431             break;
432 
433         case ATTR_LASTNAME:
434             attrname = "lastname";
435             break;
436 
437         case ATTR_AUTHRING:
438             attrname = "*!authring";
439             break;
440 
441         case ATTR_AUTHRSA:
442             attrname = "*!authRSA";
443             break;
444 
445         case ATTR_AUTHCU255:
446             attrname = "*!authCu255";
447             break;
448 
449         case ATTR_LAST_INT:
450             attrname = "*!lstint";
451             break;
452 
453         case ATTR_ED25519_PUBK:
454             attrname = "+puEd255";
455             break;
456 
457         case ATTR_CU25519_PUBK:
458             attrname = "+puCu255";
459             break;
460 
461         case ATTR_SIG_RSA_PUBK:
462             attrname = "+sigPubk";
463             break;
464 
465         case ATTR_SIG_CU255_PUBK:
466             attrname = "+sigCu255";
467             break;
468 
469         case ATTR_KEYRING:
470             attrname = "*keyring";
471             break;
472 
473         case ATTR_COUNTRY:
474             attrname = "country";
475             break;
476 
477         case ATTR_BIRTHDAY:
478             attrname = "birthday";
479             break;
480 
481         case ATTR_BIRTHMONTH:
482             attrname = "birthmonth";
483             break;
484 
485         case ATTR_BIRTHYEAR:
486             attrname = "birthyear";
487             break;
488 
489         case ATTR_LANGUAGE:
490             attrname = "^!lang";
491             break;
492 
493         case ATTR_PWD_REMINDER:
494             attrname = "^!prd";
495             break;
496 
497         case ATTR_DISABLE_VERSIONS:
498             attrname = "^!dv";
499             break;
500 
501         case ATTR_CONTACT_LINK_VERIFICATION:
502             attrname = "^clv";
503             break;
504 
505         case ATTR_RICH_PREVIEWS:
506             attrname = "*!rp";
507             break;
508 
509         case ATTR_LAST_PSA:
510             attrname = "^!lastPsa";
511             break;
512 
513         case ATTR_RUBBISH_TIME:
514             attrname = "^!rubbishtime";
515             break;
516 
517         case ATTR_STORAGE_STATE:
518             attrname = "^!usl";
519             break;
520 
521         case ATTR_GEOLOCATION:
522             attrname = "*!geo";
523             break;
524 
525         case ATTR_CAMERA_UPLOADS_FOLDER:
526             attrname = "*!cam";
527             break;
528 
529         case ATTR_MY_CHAT_FILES_FOLDER:
530             attrname = "*!cf";
531             break;
532 
533         case ATTR_PUSH_SETTINGS:
534             attrname = "^!ps";
535             break;
536 
537         case ATTR_UNSHAREABLE_KEY:
538             attrname = "*~usk";  // unshareable key (for encrypting attributes that should not be shared)
539             break;
540 
541         case ATTR_ALIAS:
542             attrname =  "*!>alias";
543             break;
544 
545         case ATTR_DEVICE_NAMES:
546             attrname =  "*!dn";
547             break;
548 
549         case ATTR_UNKNOWN:  // empty string
550             break;
551     }
552 
553     return attrname;
554 }
555 
attr2longname(attr_t type)556 string User::attr2longname(attr_t type)
557 {
558     string longname;
559 
560     switch(type)
561     {
562     case ATTR_AVATAR:
563         longname = "AVATAR";
564         break;
565 
566     case ATTR_FIRSTNAME:
567         longname = "FIRSTNAME";
568         break;
569 
570     case ATTR_LASTNAME:
571         longname = "LASTNAME";
572         break;
573 
574     case ATTR_AUTHRING:
575         longname = "AUTHRING";
576         break;
577 
578     case ATTR_AUTHRSA:
579         longname = "AUTHRSA";
580         break;
581 
582     case ATTR_AUTHCU255:
583         longname = "AUTHCU255";
584         break;
585 
586     case ATTR_LAST_INT:
587         longname = "LAST_INT";
588         break;
589 
590     case ATTR_ED25519_PUBK:
591         longname = "ED25519_PUBK";
592         break;
593 
594     case ATTR_CU25519_PUBK:
595         longname = "CU25519_PUBK";
596         break;
597 
598     case ATTR_SIG_RSA_PUBK:
599         longname = "SIG_RSA_PUBK";
600         break;
601 
602     case ATTR_SIG_CU255_PUBK:
603         longname = "SIG_CU255_PUBK";
604         break;
605 
606     case ATTR_KEYRING:
607         longname = "KEYRING";
608         break;
609 
610     case ATTR_COUNTRY:
611         longname = "COUNTRY";
612         break;
613 
614     case ATTR_BIRTHDAY:
615         longname = "BIRTHDAY";
616         break;
617 
618     case ATTR_BIRTHMONTH:
619         longname = "BIRTHMONTH";
620         break;
621 
622     case ATTR_BIRTHYEAR:
623         longname = "BIRTHYEAR";
624         break;
625 
626     case ATTR_LANGUAGE:
627         longname = "LANGUAGE";
628         break;
629 
630     case ATTR_PWD_REMINDER:
631         longname = "PWD_REMINDER";
632         break;
633 
634     case ATTR_DISABLE_VERSIONS:
635         longname = "DISABLE_VERSIONS";
636         break;
637 
638     case ATTR_CONTACT_LINK_VERIFICATION:
639         longname = "CONTACT_LINK_VERIFICATION";
640         break;
641 
642     case ATTR_RICH_PREVIEWS:
643         longname = "RICH_PREVIEWS";
644         break;
645 
646     case ATTR_LAST_PSA:
647         longname = "LAST_PSA";
648         break;
649 
650     case ATTR_RUBBISH_TIME:
651         longname = "RUBBISH_TIME";
652         break;
653 
654     case ATTR_STORAGE_STATE:
655         longname = "STORAGE_STATE";
656         break;
657 
658     case ATTR_GEOLOCATION:
659         longname = "GEOLOCATION";
660         break;
661 
662     case ATTR_UNSHAREABLE_KEY:
663         longname = "UNSHAREABLE_KEY";
664         break;
665 
666     case ATTR_CAMERA_UPLOADS_FOLDER:
667         longname = "CAMERA_UPLOADS_FOLDER";
668         break;
669 
670     case ATTR_MY_CHAT_FILES_FOLDER:
671         longname = "MY_CHAT_FILES_FOLDER";
672         break;
673 
674     case ATTR_UNKNOWN:
675         longname = "";  // empty string
676         break;
677 
678     case ATTR_PUSH_SETTINGS:
679         longname = "PUSH_SETTINGS";
680         break;
681 
682     case ATTR_ALIAS:
683         longname = "ALIAS";
684         break;
685 
686     case ATTR_DEVICE_NAMES:
687         longname = "DEVICE_NAMES";
688         break;
689     }
690 
691     return longname;
692 }
693 
694 
string2attr(const char * name)695 attr_t User::string2attr(const char* name)
696 {
697     if (!strcmp(name, "*keyring"))
698     {
699         return ATTR_KEYRING;
700     }
701     else if (!strcmp(name, "*!authring"))
702     {
703         return ATTR_AUTHRING;
704     }
705     else if (!strcmp(name, "*!authRSA"))
706     {
707         return ATTR_AUTHRSA;
708     }
709     else if (!strcmp(name, "*!authCu255"))
710     {
711         return ATTR_AUTHCU255;
712     }
713     else if (!strcmp(name, "*!lstint"))
714     {
715         return ATTR_LAST_INT;
716     }
717     else if (!strcmp(name, "+puCu255"))
718     {
719         return ATTR_CU25519_PUBK;
720     }
721     else if (!strcmp(name, "+puEd255"))
722     {
723         return ATTR_ED25519_PUBK;
724     }
725     else if (!strcmp(name, "+sigPubk"))
726     {
727         return ATTR_SIG_RSA_PUBK;
728     }
729     else if (!strcmp(name, "+sigCu255"))
730     {
731         return ATTR_SIG_CU255_PUBK;
732     }
733     else if (!strcmp(name, "+a"))
734     {
735         return ATTR_AVATAR;
736     }
737     else if (!strcmp(name, "firstname"))
738     {
739         return ATTR_FIRSTNAME;
740     }
741     else if (!strcmp(name, "lastname"))
742     {
743         return ATTR_LASTNAME;
744     }
745     else if (!strcmp(name, "country"))
746     {
747         return ATTR_COUNTRY;
748     }
749     else if (!strcmp(name, "birthday"))
750     {
751         return ATTR_BIRTHDAY;
752     }
753     else if(!strcmp(name, "birthmonth"))
754     {
755         return ATTR_BIRTHMONTH;
756     }
757     else if(!strcmp(name, "birthyear"))
758     {
759         return ATTR_BIRTHYEAR;
760     }
761     else if(!strcmp(name, "^!lang"))
762     {
763         return ATTR_LANGUAGE;
764     }
765     else if(!strcmp(name, "^!prd"))
766     {
767         return ATTR_PWD_REMINDER;
768     }
769     else if(!strcmp(name, "^!dv"))
770     {
771         return ATTR_DISABLE_VERSIONS;
772     }
773     else if(!strcmp(name, "^clv"))
774     {
775         return ATTR_CONTACT_LINK_VERIFICATION;
776     }
777     else if(!strcmp(name, "*!rp"))
778     {
779         return ATTR_RICH_PREVIEWS;
780     }
781     else if(!strcmp(name, "^!lastPsa"))
782     {
783         return ATTR_LAST_PSA;
784     }
785     else if(!strcmp(name, "^!rubbishtime"))
786     {
787         return ATTR_RUBBISH_TIME;
788     }
789     else if(!strcmp(name, "^!usl"))
790     {
791         return ATTR_STORAGE_STATE;
792     }
793     else if(!strcmp(name, "*!geo"))
794     {
795         return ATTR_GEOLOCATION;
796     }
797     else if (!strcmp(name, "*!cam"))
798     {
799         return ATTR_CAMERA_UPLOADS_FOLDER;
800     }
801     else if(!strcmp(name, "*!cf"))
802     {
803         return ATTR_MY_CHAT_FILES_FOLDER;
804     }
805     else if(!strcmp(name, "^!ps"))
806     {
807         return ATTR_PUSH_SETTINGS;
808     }
809     else if (!strcmp(name, "*~usk"))
810     {
811         return ATTR_UNSHAREABLE_KEY;
812     }
813     else if (!strcmp(name, "*!>alias"))
814     {
815         return ATTR_ALIAS;
816     }
817     else if (!strcmp(name, "*!dn"))
818     {
819         return ATTR_DEVICE_NAMES;
820     }
821     else
822     {
823         return ATTR_UNKNOWN;   // attribute not recognized
824     }
825 }
826 
needversioning(attr_t at)827 int User::needversioning(attr_t at)
828 {
829     switch(at)
830     {
831         case ATTR_AVATAR:
832         case ATTR_FIRSTNAME:
833         case ATTR_LASTNAME:
834         case ATTR_COUNTRY:
835         case ATTR_BIRTHDAY:
836         case ATTR_BIRTHMONTH:
837         case ATTR_BIRTHYEAR:
838         case ATTR_LANGUAGE:
839         case ATTR_PWD_REMINDER:
840         case ATTR_DISABLE_VERSIONS:
841         case ATTR_RICH_PREVIEWS:
842         case ATTR_LAST_PSA:
843         case ATTR_RUBBISH_TIME:
844         case ATTR_GEOLOCATION:
845         case ATTR_MY_CHAT_FILES_FOLDER:
846         case ATTR_PUSH_SETTINGS:
847             return 0;
848 
849         case ATTR_LAST_INT:
850         case ATTR_ED25519_PUBK:
851         case ATTR_CU25519_PUBK:
852         case ATTR_SIG_RSA_PUBK:
853         case ATTR_SIG_CU255_PUBK:
854         case ATTR_KEYRING:
855         case ATTR_AUTHRING:
856         case ATTR_AUTHRSA:
857         case ATTR_AUTHCU255:
858         case ATTR_CONTACT_LINK_VERIFICATION:
859         case ATTR_ALIAS:
860         case ATTR_CAMERA_UPLOADS_FOLDER:
861         case ATTR_UNSHAREABLE_KEY:
862         case ATTR_DEVICE_NAMES:
863             return 1;
864 
865         case ATTR_STORAGE_STATE: //putua is forbidden for this attribute
866         default:
867             return -1;
868     }
869 }
870 
scope(attr_t at)871 char User::scope(attr_t at)
872 {
873     switch(at)
874     {
875         case ATTR_KEYRING:
876         case ATTR_AUTHRING:
877         case ATTR_AUTHRSA:
878         case ATTR_AUTHCU255:
879         case ATTR_LAST_INT:
880         case ATTR_RICH_PREVIEWS:
881         case ATTR_GEOLOCATION:
882         case ATTR_CAMERA_UPLOADS_FOLDER:
883         case ATTR_MY_CHAT_FILES_FOLDER:
884         case ATTR_UNSHAREABLE_KEY:
885         case ATTR_ALIAS:
886         case ATTR_DEVICE_NAMES:
887             return '*';
888 
889         case ATTR_AVATAR:
890         case ATTR_ED25519_PUBK:
891         case ATTR_CU25519_PUBK:
892         case ATTR_SIG_RSA_PUBK:
893         case ATTR_SIG_CU255_PUBK:
894             return '+';
895 
896         case ATTR_LANGUAGE:
897         case ATTR_PWD_REMINDER:
898         case ATTR_DISABLE_VERSIONS:
899         case ATTR_CONTACT_LINK_VERIFICATION:
900         case ATTR_LAST_PSA:
901         case ATTR_RUBBISH_TIME:
902         case ATTR_STORAGE_STATE:
903         case ATTR_PUSH_SETTINGS:
904             return '^';
905 
906         default:
907             return '0';
908     }
909 }
910 
isAuthring(attr_t at)911 bool User::isAuthring(attr_t at)
912 {
913     return (at == ATTR_AUTHRING || at == ATTR_AUTHCU255 || at == ATTR_AUTHRSA);
914 }
915 
mergePwdReminderData(int numDetails,const char * data,unsigned int size,string * newValue)916 bool User::mergePwdReminderData(int numDetails, const char *data, unsigned int size, string *newValue)
917 {
918     if (numDetails == 0)
919     {
920         return false;
921     }
922 
923     // format: <lastSuccess>:<lastSkipped>:<mkExported>:<dontShowAgain>:<lastLogin>
924     string oldValue;
925     if (data && size)
926     {
927         oldValue.assign(data, size);
928 
929         // ensure the old value has a valid format
930         if (std::count(oldValue.begin(), oldValue.end(), ':') != 4
931                 || oldValue.length() < 9)
932         {
933             oldValue = "0:0:0:0:0";
934         }
935     }
936     else    // no existing value, set with default values and update it consequently
937     {
938         oldValue = "0:0:0:0:0";
939     }
940 
941     bool lastSuccess = (numDetails & PWD_LAST_SUCCESS) != 0;
942     bool lastSkipped = (numDetails & PWD_LAST_SKIPPED) != 0;
943     bool mkExported = (numDetails & PWD_MK_EXPORTED) != 0;
944     bool dontShowAgain = (numDetails & PWD_DONT_SHOW) != 0;
945     bool lastLogin = (numDetails & PWD_LAST_LOGIN) != 0;
946 
947     bool changed = false;
948 
949     // Timestamp for last successful validation of password in PRD
950     m_time_t tsLastSuccess;
951     size_t len = oldValue.find(":");
952     string buf = oldValue.substr(0, len) + "#"; // add character control '#' for conversion
953     oldValue = oldValue.substr(len + 1);    // skip ':'
954     if (lastSuccess)
955     {
956         changed = true;
957         tsLastSuccess = m_time();
958     }
959     else
960     {
961         char *pEnd = NULL;
962         tsLastSuccess = strtoll(buf.data(), &pEnd, 10);
963         if (*pEnd != '#' || tsLastSuccess == LLONG_MAX || tsLastSuccess == LLONG_MIN)
964         {
965             tsLastSuccess = 0;
966             changed = true;
967         }
968     }
969 
970     // Timestamp for last time the PRD was skipped
971     m_time_t tsLastSkipped;
972     len = oldValue.find(":");
973     buf = oldValue.substr(0, len) + "#";
974     oldValue = oldValue.substr(len + 1);
975     if (lastSkipped)
976     {
977         tsLastSkipped = m_time();
978         changed = true;
979     }
980     else
981     {
982         char *pEnd = NULL;
983         tsLastSkipped = strtoll(buf.data(), &pEnd, 10);
984         if (*pEnd != '#' || tsLastSkipped == LLONG_MAX || tsLastSkipped == LLONG_MIN)
985         {
986             tsLastSkipped = 0;
987             changed = true;
988         }
989     }
990 
991     // Flag for Recovery Key exported
992     bool flagMkExported;
993     len = oldValue.find(":");
994     if (len != 1)
995     {
996         return false;
997     }
998     buf = oldValue.substr(0, len) + "#";
999     oldValue = oldValue.substr(len + 1);
1000     if (mkExported && !(buf.at(0) == '1'))
1001     {
1002         flagMkExported = true;
1003         changed = true;
1004     }
1005     else
1006     {
1007         char *pEnd = NULL;
1008         long tmp = strtol(buf.data(), &pEnd, 10);
1009         if (*pEnd != '#' || (tmp != 0 && tmp != 1))
1010         {
1011             flagMkExported = false;
1012             changed = true;
1013         }
1014         else
1015         {
1016             flagMkExported = tmp;
1017         }
1018     }
1019 
1020     // Flag for "Don't show again" the PRD
1021     bool flagDontShowAgain;
1022     len = oldValue.find(":");
1023     if (len != 1 || len + 1 == oldValue.length())
1024     {
1025         return false;
1026     }
1027     buf = oldValue.substr(0, len) + "#";
1028     oldValue = oldValue.substr(len + 1);
1029     if (dontShowAgain && !(buf.at(0) == '1'))
1030     {
1031         flagDontShowAgain = true;
1032         changed = true;
1033     }
1034     else
1035     {
1036         char *pEnd = NULL;
1037         long tmp = strtol(buf.data(), &pEnd, 10);
1038         if (*pEnd != '#' || (tmp != 0 && tmp != 1))
1039         {
1040             flagDontShowAgain = false;
1041             changed = true;
1042         }
1043         else
1044         {
1045             flagDontShowAgain = tmp;
1046         }
1047     }
1048 
1049     // Timestamp for last time user logged in
1050     m_time_t tsLastLogin = 0;
1051     len = oldValue.length();
1052     if (lastLogin)
1053     {
1054         tsLastLogin = m_time();
1055         changed = true;
1056     }
1057     else
1058     {
1059         buf = oldValue.substr(0, len) + "#";
1060 
1061         char *pEnd = NULL;
1062         tsLastLogin = strtoll(buf.data(), &pEnd, 10);
1063         if (*pEnd != '#' || tsLastLogin == LLONG_MAX || tsLastLogin == LLONG_MIN)
1064         {
1065             tsLastLogin = 0;
1066             changed = true;
1067         }
1068     }
1069 
1070     std::stringstream value;
1071     value << tsLastSuccess << ":" << tsLastSkipped << ":" << flagMkExported
1072         << ":" << flagDontShowAgain << ":" << tsLastLogin;
1073 
1074     *newValue = value.str();
1075 
1076     return changed;
1077 }
1078 
getPwdReminderData(int numDetail,const char * data,unsigned int size)1079 m_time_t User::getPwdReminderData(int numDetail, const char *data, unsigned int size)
1080 {
1081     if (!numDetail || !data || !size)
1082     {
1083         return 0;
1084     }
1085 
1086     // format: <lastSuccess>:<lastSkipped>:<mkExported>:<dontShowAgain>:<lastLogin>
1087     string value;
1088     value.assign(data, size);
1089 
1090     // ensure the value has a valid format
1091     if (std::count(value.begin(), value.end(), ':') != 4
1092             || value.length() < 9)
1093     {
1094         return 0;
1095     }
1096 
1097     bool lastSuccess = (numDetail & PWD_LAST_SUCCESS) != 0;
1098     bool lastSkipped = (numDetail & PWD_LAST_SKIPPED) != 0;
1099     bool mkExported = (numDetail & PWD_MK_EXPORTED) != 0;
1100     bool dontShowAgain = (numDetail & PWD_DONT_SHOW) != 0;
1101     bool lastLogin = (numDetail & PWD_LAST_LOGIN) != 0;
1102 
1103     // Timestamp for last successful validation of password in PRD
1104     m_time_t tsLastSuccess;
1105     size_t len = value.find(":");
1106     string buf = value.substr(0, len) + "#"; // add character control '#' for conversion
1107     value = value.substr(len + 1);    // skip ':'
1108     if (lastSuccess)
1109     {
1110         char *pEnd = NULL;
1111         tsLastSuccess = strtoll(buf.data(), &pEnd, 10);
1112         if (*pEnd != '#' || tsLastSuccess == LLONG_MAX || tsLastSuccess == LLONG_MIN)
1113         {
1114             tsLastSuccess = 0;
1115         }
1116         return tsLastSuccess;
1117     }
1118 
1119     // Timestamp for last time the PRD was skipped
1120     m_time_t tsLastSkipped;
1121     len = value.find(":");
1122     buf = value.substr(0, len) + "#";
1123     value = value.substr(len + 1);
1124     if (lastSkipped)
1125     {
1126         char *pEnd = NULL;
1127         tsLastSkipped = strtoll(buf.data(), &pEnd, 10);
1128         if (*pEnd != '#' || tsLastSkipped == LLONG_MAX || tsLastSkipped == LLONG_MIN)
1129         {
1130             tsLastSkipped = 0;
1131         }
1132         return tsLastSkipped;
1133     }
1134 
1135     // Flag for Recovery Key exported
1136     len = value.find(":");
1137     buf = value.substr(0, len) + "#";
1138     value = value.substr(len + 1);
1139     if (mkExported)
1140     {
1141         char *pEnd = NULL;
1142         m_time_t flagMkExported = strtoll(buf.data(), &pEnd, 10);
1143         if (*pEnd != '#' || (flagMkExported != 0 && flagMkExported != 1))
1144         {
1145             flagMkExported = 0;
1146         }
1147         return flagMkExported;
1148     }
1149 
1150     // Flag for "Don't show again" the PRD
1151     len = value.find(":");
1152     buf = value.substr(0, len) + "#";
1153     value = value.substr(len + 1);
1154     if (dontShowAgain)
1155     {
1156         char *pEnd = NULL;
1157         m_time_t flagDontShowAgain = strtoll(buf.data(), &pEnd, 10);
1158         if (*pEnd != '#' || (flagDontShowAgain != 0 && flagDontShowAgain != 1))
1159         {
1160             flagDontShowAgain = 0;
1161         }
1162         return flagDontShowAgain;
1163     }
1164 
1165     // Timestamp for last time user logged in
1166     m_time_t tsLastLogin = 0;
1167     len = value.length();
1168     if (lastLogin)
1169     {
1170         buf = value.substr(0, len) + "#";
1171 
1172         char *pEnd = NULL;
1173         tsLastLogin = strtoll(buf.data(), &pEnd, 10);
1174         if (*pEnd != '#' || tsLastLogin == LLONG_MAX || tsLastLogin == LLONG_MIN)
1175         {
1176             tsLastLogin = 0;
1177         }
1178         return tsLastLogin;
1179     }
1180 
1181     return 0;
1182 }
1183 
getattrversion(attr_t at)1184 const string *User::getattrversion(attr_t at)
1185 {
1186     userattr_map::iterator it = attrsv.find(at);
1187     if (it != attrsv.end())
1188     {
1189         return &(it->second);
1190     }
1191 
1192     return NULL;
1193 }
1194 
setChanged(attr_t at)1195 bool User::setChanged(attr_t at)
1196 {
1197     switch(at)
1198     {
1199         case ATTR_AVATAR:
1200             changed.avatar = true;
1201             break;
1202 
1203         case ATTR_FIRSTNAME:
1204             changed.firstname = true;
1205             break;
1206 
1207         case ATTR_LASTNAME:
1208             changed.lastname = true;
1209             break;
1210 
1211         case ATTR_AUTHRING:
1212             changed.authring = true;
1213             break;
1214 
1215         case ATTR_AUTHRSA:
1216             changed.authrsa = true;
1217             break;
1218 
1219         case ATTR_AUTHCU255:
1220             changed.authcu255 = true;
1221             break;
1222 
1223         case ATTR_LAST_INT:
1224             changed.lstint = true;
1225             break;
1226 
1227         case ATTR_ED25519_PUBK:
1228             changed.puEd255 = true;
1229             break;
1230 
1231         case ATTR_CU25519_PUBK:
1232             changed.puCu255 = true;
1233             break;
1234 
1235         case ATTR_SIG_RSA_PUBK:
1236             changed.sigPubk = true;
1237             break;
1238 
1239         case ATTR_SIG_CU255_PUBK:
1240             changed.sigCu255 = true;
1241             break;
1242 
1243         case ATTR_KEYRING:
1244             changed.keyring = true;
1245             break;
1246 
1247         case ATTR_COUNTRY:
1248             changed.country = true;
1249             break;
1250 
1251         case ATTR_BIRTHDAY:
1252         case ATTR_BIRTHMONTH:
1253         case ATTR_BIRTHYEAR:
1254             changed.birthday = true;
1255             break;
1256 
1257         case ATTR_LANGUAGE:
1258             changed.language = true;
1259             break;
1260 
1261         case ATTR_PWD_REMINDER:
1262             changed.pwdReminder = true;
1263             break;
1264 
1265         case ATTR_DISABLE_VERSIONS:
1266             changed.disableVersions = true;
1267             break;
1268 
1269         case ATTR_CONTACT_LINK_VERIFICATION:
1270             changed.contactLinkVerification = true;
1271             break;
1272 
1273         case ATTR_RICH_PREVIEWS:
1274             changed.richPreviews = true;
1275             break;
1276 
1277         case ATTR_LAST_PSA:
1278             changed.lastPsa = true;
1279             break;
1280 
1281         case ATTR_RUBBISH_TIME:
1282             changed.rubbishTime = true;
1283             break;
1284 
1285         case ATTR_STORAGE_STATE:
1286             changed.storageState = true;
1287             break;
1288 
1289         case ATTR_GEOLOCATION:
1290             changed.geolocation = true;
1291             break;
1292 
1293         case ATTR_CAMERA_UPLOADS_FOLDER:
1294             changed.cameraUploadsFolder = true;
1295             break;
1296 
1297         case ATTR_MY_CHAT_FILES_FOLDER:
1298             changed.myChatFilesFolder = true;
1299             break;
1300 
1301         case ATTR_PUSH_SETTINGS:
1302             changed.pushSettings = true;
1303             break;
1304 
1305         case ATTR_ALIAS:
1306             changed.alias = true;
1307             break;
1308 
1309         case ATTR_UNSHAREABLE_KEY:
1310             changed.unshareablekey = true;
1311             break;
1312 
1313         case ATTR_DEVICE_NAMES:
1314             changed.devicenames = true;
1315             break;
1316 
1317         default:
1318             return false;
1319     }
1320 
1321     return true;
1322 }
1323 
setTag(int tag)1324 void User::setTag(int tag)
1325 {
1326     if (this->tag != 0)    // external changes prevail
1327     {
1328         this->tag = tag;
1329     }
1330 }
1331 
getTag()1332 int User::getTag()
1333 {
1334     return tag;
1335 }
1336 
resetTag()1337 void User::resetTag()
1338 {
1339     tag = -1;
1340 }
1341 
1342 // update user attributes
set(visibility_t v,m_time_t ct)1343 void User::set(visibility_t v, m_time_t ct)
1344 {
1345     show = v;
1346     ctime = ct;
1347 }
1348 
AuthRing(attr_t type,const TLVstore & authring)1349 AuthRing::AuthRing(attr_t type, const TLVstore &authring)
1350     : mType(type)
1351 {
1352     string authType = "";
1353     string authValue;
1354     if (authring.find(authType))  // key is an empty string, but may not be there if authring was reset
1355     {
1356         authValue = authring.get(authType);
1357 
1358         handle userhandle;
1359         byte authFingerprint[20];
1360         signed char authMethod = AUTH_METHOD_UNKNOWN;
1361 
1362         const char *ptr = authValue.data();
1363         const char *end = ptr + authValue.size();
1364         unsigned recordSize = 29;   // <handle.8> <fingerprint.20> <authLevel.1>
1365         while (ptr + recordSize <= end)
1366         {
1367             memcpy(&userhandle, ptr, sizeof(userhandle));
1368             ptr += sizeof(userhandle);
1369 
1370             memcpy(authFingerprint, ptr, sizeof(authFingerprint));
1371             ptr += sizeof(authFingerprint);
1372 
1373             memcpy(&authMethod, ptr, sizeof(authMethod));
1374             ptr += sizeof(authMethod);
1375 
1376             mFingerprint[userhandle] = string((const char*) authFingerprint, sizeof(authFingerprint));
1377             mAuthMethod[userhandle] = static_cast<AuthMethod>(authMethod);
1378         }
1379     }
1380 }
1381 
serialize(PrnGen & rng,SymmCipher & key) const1382 std::string* AuthRing::serialize(PrnGen &rng, SymmCipher &key) const
1383 {
1384     string buf;
1385 
1386     map<handle, string>::const_iterator itFingerprint;
1387     map<handle, AuthMethod>::const_iterator itAuthMethod;
1388     for (itFingerprint = mFingerprint.begin(), itAuthMethod = mAuthMethod.begin();
1389          itFingerprint != mFingerprint.end() && itAuthMethod != mAuthMethod.end();
1390          itFingerprint++, itAuthMethod++)
1391     {
1392         buf.append((const char *)&itFingerprint->first, sizeof(handle));
1393         buf.append(itFingerprint->second);
1394         buf.append((const char *)&itAuthMethod->second, 1);
1395     }
1396 
1397     TLVstore tlv;
1398     tlv.set("", buf);
1399 
1400     return tlv.tlvRecordsToContainer(rng, &key);
1401 }
1402 
isTracked(handle uh) const1403 bool AuthRing::isTracked(handle uh) const
1404 {
1405     return mAuthMethod.find(uh) != mAuthMethod.end();
1406 }
1407 
getAuthMethod(handle uh) const1408 AuthMethod AuthRing::getAuthMethod(handle uh) const
1409 {
1410     AuthMethod authMethod = AUTH_METHOD_UNKNOWN;
1411     auto it = mAuthMethod.find(uh);
1412     if (it != mAuthMethod.end())
1413     {
1414         authMethod = it->second;
1415     }
1416     return authMethod;
1417 }
1418 
getFingerprint(handle uh) const1419 std::string AuthRing::getFingerprint(handle uh) const
1420 {
1421     string fingerprint;
1422     auto it = mFingerprint.find(uh);
1423     if (it != mFingerprint.end())
1424     {
1425         fingerprint = it->second;
1426     }
1427     return fingerprint;
1428 }
1429 
getTrackedUsers() const1430 vector<handle> AuthRing::getTrackedUsers() const
1431 {
1432     vector<handle> users;
1433     for (auto &it : mFingerprint)
1434     {
1435         users.push_back(it.first);
1436     }
1437     return users;
1438 }
1439 
add(handle uh,const std::string & fingerprint,AuthMethod authMethod)1440 void AuthRing::add(handle uh, const std::string &fingerprint, AuthMethod authMethod)
1441 {
1442     assert(mFingerprint.find(uh) == mFingerprint.end());
1443     assert(mAuthMethod.find(uh) == mAuthMethod.end());
1444     mFingerprint[uh] = fingerprint;
1445     mAuthMethod[uh] = authMethod;
1446 }
1447 
update(handle uh,AuthMethod authMethod)1448 void AuthRing::update(handle uh, AuthMethod authMethod)
1449 {
1450     mAuthMethod.at(uh) = authMethod;
1451 }
1452 
remove(handle uh)1453 bool AuthRing::remove(handle uh)
1454 {
1455     return mFingerprint.erase(uh) + mAuthMethod.erase(uh);
1456 }
1457 
keyTypeToAuthringType(attr_t at)1458 attr_t AuthRing::keyTypeToAuthringType(attr_t at)
1459 {
1460     if (at == ATTR_ED25519_PUBK)
1461     {
1462         return ATTR_AUTHRING;
1463     }
1464     else if (at == ATTR_CU25519_PUBK)
1465     {
1466         return ATTR_AUTHCU255;
1467     }
1468     else if (at == ATTR_UNKNOWN)   // ATTR_UNKNOWN -> pubk is not a user attribute
1469     {
1470         return ATTR_AUTHRSA;
1471     }
1472 
1473     assert(false);
1474     return ATTR_UNKNOWN;
1475 }
1476 
signatureTypeToAuthringType(attr_t at)1477 attr_t AuthRing::signatureTypeToAuthringType(attr_t at)
1478 {
1479     if (at == ATTR_SIG_CU255_PUBK)
1480     {
1481         return ATTR_AUTHCU255;
1482     }
1483     else if (at == ATTR_SIG_RSA_PUBK)
1484     {
1485         return ATTR_AUTHRSA;
1486     }
1487 
1488     assert(false);
1489     return ATTR_UNKNOWN;
1490 }
1491 
authringTypeToSignatureType(attr_t at)1492 attr_t AuthRing::authringTypeToSignatureType(attr_t at)
1493 {
1494     if (at == ATTR_AUTHCU255)
1495     {
1496         return ATTR_SIG_CU255_PUBK;
1497     }
1498     else if (at == ATTR_AUTHRSA)
1499     {
1500         return ATTR_SIG_RSA_PUBK;
1501     }
1502 
1503     assert(false);
1504     return ATTR_UNKNOWN;
1505 }
1506 
authMethodToStr(AuthMethod authMethod)1507 std::string AuthRing::authMethodToStr(AuthMethod authMethod)
1508 {
1509     if (authMethod == AUTH_METHOD_SEEN)
1510     {
1511         return "seen";
1512     }
1513     else if (authMethod == AUTH_METHOD_FINGERPRINT)
1514     {
1515         return "fingerprint comparison";
1516     }
1517     else if (authMethod == AUTH_METHOD_SIGNATURE)
1518     {
1519         return "signature verified";
1520     }
1521 
1522     return "unknown";
1523 }
1524 
fingerprint(const std::string & pubKey,bool hexadecimal)1525 std::string AuthRing::fingerprint(const std::string &pubKey, bool hexadecimal)
1526 {
1527     HashSHA256 hash;
1528     hash.add((const byte *)pubKey.data(), static_cast<unsigned>(pubKey.size()));
1529 
1530     string result;
1531     hash.get(&result);
1532     result.erase(20);   // keep only the most significant 160 bits
1533 
1534     if (hexadecimal)
1535     {
1536         return Utils::stringToHex(result);
1537     }
1538 
1539     return result;
1540 }
1541 
isSignedKey() const1542 bool AuthRing::isSignedKey() const
1543 {
1544     return mType != ATTR_AUTHRING;
1545 }
1546 
areCredentialsVerified(handle uh) const1547 bool AuthRing::areCredentialsVerified(handle uh) const
1548 {
1549     if (isSignedKey())
1550     {
1551         return getAuthMethod(uh) == AUTH_METHOD_SIGNATURE;
1552     }
1553     else
1554     {
1555         return getAuthMethod(uh) == AUTH_METHOD_FINGERPRINT;
1556     }
1557 }
1558 
1559 } // namespace
1560