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