Open-Transactions  0.93.0-ge03d287
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
OTWallet.cpp
Go to the documentation of this file.
1 /************************************************************
2  *
3  * OTWallet.cpp
4  *
5  */
6 
7 /************************************************************
8  -----BEGIN PGP SIGNED MESSAGE-----
9  Hash: SHA1
10 
11  * OPEN TRANSACTIONS
12  *
13  * Financial Cryptography and Digital Cash
14  * Library, Protocol, API, Server, CLI, GUI
15  *
16  * -- Anonymous Numbered Accounts.
17  * -- Untraceable Digital Cash.
18  * -- Triple-Signed Receipts.
19  * -- Cheques, Vouchers, Transfers, Inboxes.
20  * -- Basket Currencies, Markets, Payment Plans.
21  * -- Signed, XML, Ricardian-style Contracts.
22  * -- Scripted smart contracts.
23  *
24  * Copyright (C) 2010-2013 by "Fellow Traveler" (A pseudonym)
25  *
26  * EMAIL:
28  *
29  * BITCOIN: 1NtTPVVjDsUfDWybS4BwvHpG2pdS9RnYyQ
30  *
31  * KEY FINGERPRINT (PGP Key in license file):
32  * 9DD5 90EB 9292 4B48 0484 7910 0308 00ED F951 BB8E
33  *
34  * OFFICIAL PROJECT WIKI(s):
35  * https://github.com/FellowTraveler/Moneychanger
36  * https://github.com/FellowTraveler/Open-Transactions/wiki
37  *
38  * WEBSITE:
39  * http://www.OpenTransactions.org/
40  *
41  * Components and licensing:
42  * -- Moneychanger..A Java client GUI.....LICENSE:.....GPLv3
43  * -- otlib.........A class library.......LICENSE:...LAGPLv3
44  * -- otapi.........A client API..........LICENSE:...LAGPLv3
45  * -- opentxs/ot....Command-line client...LICENSE:...LAGPLv3
46  * -- otserver......Server Application....LICENSE:....AGPLv3
47  * Github.com/FellowTraveler/Open-Transactions/wiki/Components
48  *
49  * All of the above OT components were designed and written by
50  * Fellow Traveler, with the exception of Moneychanger, which
51  * was contracted out to Vicky C ([email protected]).
52  * The open-source community has since actively contributed.
53  *
54  * -----------------------------------------------------
55  *
56  * LICENSE:
57  * This program is free software: you can redistribute it
58  * and/or modify it under the terms of the GNU Affero
59  * General Public License as published by the Free Software
60  * Foundation, either version 3 of the License, or (at your
61  * option) any later version.
62  *
63  * ADDITIONAL PERMISSION under the GNU Affero GPL version 3
64  * section 7: (This paragraph applies only to the LAGPLv3
65  * components listed above.) If you modify this Program, or
66  * any covered work, by linking or combining it with other
67  * code, such other code is not for that reason alone subject
68  * to any of the requirements of the GNU Affero GPL version 3.
69  * (==> This means if you are only using the OT API, then you
70  * don't have to open-source your code--only your changes to
71  * Open-Transactions itself must be open source. Similar to
72  * LGPLv3, except it applies to software-as-a-service, not
73  * just to distributing binaries.)
74  *
75  * Extra WAIVER for OpenSSL, Lucre, and all other libraries
76  * used by Open Transactions: This program is released under
77  * the AGPL with the additional exemption that compiling,
78  * linking, and/or using OpenSSL is allowed. The same is true
79  * for any other open source libraries included in this
80  * project: complete waiver from the AGPL is hereby granted to
81  * compile, link, and/or use them with Open-Transactions,
82  * according to their own terms, as long as the rest of the
83  * Open-Transactions terms remain respected, with regard to
84  * the Open-Transactions code itself.
85  *
86  * Lucre License:
87  * This code is also "dual-license", meaning that Ben Lau-
88  * rie's license must also be included and respected, since
89  * the code for Lucre is also included with Open Transactions.
90  * See Open-Transactions/src/otlib/lucre/LUCRE_LICENSE.txt
91  * The Laurie requirements are light, but if there is any
92  * problem with his license, simply remove the Lucre code.
93  * Although there are no other blind token algorithms in Open
94  * Transactions (yet. credlib is coming), the other functions
95  * will continue to operate.
96  * See Lucre on Github: https://github.com/benlaurie/lucre
97  * -----------------------------------------------------
98  * You should have received a copy of the GNU Affero General
99  * Public License along with this program. If not, see:
100  * http://www.gnu.org/licenses/
101  *
102  * If you would like to use this software outside of the free
103  * software license, please contact FellowTraveler.
104  * (Unfortunately many will run anonymously and untraceably,
105  * so who could really stop them?)
106  *
107  * DISCLAIMER:
108  * This program is distributed in the hope that it will be
109  * useful, but WITHOUT ANY WARRANTY; without even the implied
110  * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
111  * PURPOSE. See the GNU Affero General Public License for
112  * more details.
113 
114  -----BEGIN PGP SIGNATURE-----
115  Version: GnuPG v1.4.9 (Darwin)
116 
117  iQIcBAEBAgAGBQJRSsfJAAoJEAMIAO35UbuOQT8P/RJbka8etf7wbxdHQNAY+2cC
118  vDf8J3X8VI+pwMqv6wgTVy17venMZJa4I4ikXD/MRyWV1XbTG0mBXk/7AZk7Rexk
119  KTvL/U1kWiez6+8XXLye+k2JNM6v7eej8xMrqEcO0ZArh/DsLoIn1y8p8qjBI7+m
120  aE7lhstDiD0z8mwRRLKFLN2IH5rAFaZZUvj5ERJaoYUKdn4c+RcQVei2YOl4T0FU
121  LWND3YLoH8naqJXkaOKEN4UfJINCwxhe5Ke9wyfLWLUO7NamRkWD2T7CJ0xocnD1
122  sjAzlVGNgaFDRflfIF4QhBx1Ddl6wwhJfw+d08bjqblSq8aXDkmFA7HeunSFKkdn
123  oIEOEgyj+veuOMRJC5pnBJ9vV+7qRdDKQWaCKotynt4sWJDGQ9kWGWm74SsNaduN
124  TPMyr9kNmGsfR69Q2Zq/FLcLX/j8ESxU+HYUB4vaARw2xEOu2xwDDv6jt0j3Vqsg
125  x7rWv4S/Eh18FDNDkVRChiNoOIilLYLL6c38uMf1pnItBuxP3uhgY6COm59kVaRh
126  nyGTYCDYD2TK+fI9o89F1297uDCwEJ62U0Q7iTDp5QuXCoxkPfv8/kX6lS6T3y9G
127  M9mqIoLbIQ1EDntFv7/t6fUTS2+46uCrdZWbQ5RjYXdrzjij02nDmJAm2BngnZvd
128  kamH0Y/n11lCvo1oQxM+
129  =uSzz
130  -----END PGP SIGNATURE-----
131  **************************************************************/
132 
133 #include "../core/stdafx.hpp"
134 
135 #include "OTWallet.hpp"
136 
137 #include "../cash/Purse.hpp"
138 
139 #include "../core/OTAccount.hpp"
140 #include "../core/OTAssetContract.hpp"
141 #include "../core/crypto/OTCachedKey.hpp"
142 #include "../core/util/OTDataFolder.hpp"
143 #include "../core/util/OTFolders.hpp"
144 #include "../core/OTLog.hpp"
145 #include "../core/crypto/OTPassword.hpp"
146 #include "../core/crypto/OTPasswordData.hpp"
147 #include "../core/OTPseudonym.hpp"
148 #include "../core/OTServerContract.hpp"
149 #include "../core/OTStorage.hpp"
150 #include "../core/crypto/OTSymmetricKey.hpp"
151 
152 #include <irrxml/irrXML.hpp>
153 
154 namespace opentxs
155 {
156 
158  : m_strDataFolder(OTDataFolder::Get())
159 {
160  m_pWithdrawalPurse = nullptr;
161 }
162 
164 {
165  Release();
166 }
167 
168 void OTWallet::Release()
169 {
170  // 1) Go through the map of Nyms and delete them. (They were dynamically
171  // allocated.)
172  while (!m_mapNyms.empty()) {
173  OTPseudonym* pNym = m_mapNyms.begin()->second;
174 
175  OT_ASSERT(nullptr != pNym);
176 
177  delete pNym;
178  pNym = nullptr;
179 
180  m_mapNyms.erase(m_mapNyms.begin());
181  }
182 
183  // 2) Go through the map of Contracts and delete them. (They were
184  // dynamically allocated.)
185  while (!m_mapContracts.empty()) {
186  OTAssetContract* pContract = m_mapContracts.begin()->second;
187 
188  OT_ASSERT(nullptr != pContract);
189 
190  delete pContract;
191  pContract = nullptr;
192 
193  m_mapContracts.erase(m_mapContracts.begin());
194  }
195 
196  // 3) Go through the map of Servers and delete them. (They were dynamically
197  // allocated.)
198  while (!m_mapServers.empty()) {
199  OTServerContract* pContract = m_mapServers.begin()->second;
200 
201  OT_ASSERT(nullptr != pContract);
202 
203  delete pContract;
204  pContract = nullptr;
205 
206  m_mapServers.erase(m_mapServers.begin());
207  }
208 
209  // 4) Go through the map of Accounts and delete them. (They were dynamically
210  // allocated.)
211  while (!m_mapAccounts.empty()) {
212  OTAccount* pAccount = m_mapAccounts.begin()->second;
213 
214  OT_ASSERT(nullptr != pAccount);
215 
216  delete pAccount;
217  pAccount = nullptr;
218 
219  m_mapAccounts.erase(m_mapAccounts.begin());
220  }
221 
222  // Watch how much prettier this one is, since we used smart pointers!
223  //
224  m_mapExtraKeys.clear();
225 }
226 
227 // While waiting on server response to a withdrawal, we keep the private coin
228 // data here so we can unblind the response.
229 // This information is so important (as important as the digital cash token
230 // itself, until the unblinding is done) that we need to save the file right
231 // away.
233 {
234  // TODO maintain a list here (I don't know why, the server response is
235  // nearly
236  // instant and then it's done.)
237 
238  // TODO notice I don't check the pointer here to see if it's already set, I
239  // just start using it.. Fix that.
240  m_pWithdrawalPurse = (Purse*)&thePurse;
241 } // TODO WARNING: If this data is lost before the transaction is completed,
242  // the user will be unable to unblind his tokens and make them spendable.
243  // So this data MUST be SAVED until the successful withdrawal is verified!
244 
246 {
247  if (m_pWithdrawalPurse) delete m_pWithdrawalPurse;
248 
249  m_pWithdrawalPurse = nullptr;
250 }
251 
253 {
254  if (GetNymCount() > 0) {
255  OTIdentifier NYM_ID;
256  OTString NYM_NAME;
257 
258  if (GetNym(0, // index 0
259  NYM_ID, NYM_NAME)) {
260  OTPseudonym* pNym = GetNymByID(NYM_ID);
261 
262  if (nullptr != pNym) {
263  theContract.SignContract(*pNym);
264  return true;
265  }
266  }
267  }
268 
269  return false;
270 }
271 
272 // The wallet presumably has multiple Nyms listed within.
273 // I should be able to pass in a Nym ID and, if the Nym is there,
274 // the wallet returns a pointer to that nym.
276 {
277  for (auto& it : m_mapNyms) {
278  OTPseudonym* pNym = it.second;
279  OT_ASSERT_MSG((nullptr != pNym),
280  "nullptr pseudonym pointer in OTWallet::GetNymByID.");
281 
282  OTIdentifier id_CurrentNym;
283  pNym->GetIdentifier(id_CurrentNym);
284 
285  if (id_CurrentNym == NYM_ID) return pNym;
286  }
287 
288  return nullptr;
289 }
290 
291 OTPseudonym* OTWallet::GetNymByIDPartialMatch(std::string PARTIAL_ID) // works
292  // with
293  // name as
294  // well.
295 {
296  for (auto& it : m_mapNyms) {
297  OTPseudonym* pNym = it.second;
299  (nullptr != pNym),
300  "nullptr pseudonym pointer in OTWallet::GetNymByIDPartialMatch.");
301 
302  OTString strTemp;
303  pNym->GetIdentifier(strTemp);
304 
305  std::string strIdentifier = strTemp.Get();
306 
307  if (strIdentifier.compare(0, PARTIAL_ID.length(), PARTIAL_ID) == 0)
308  return pNym;
309  }
310 
311  // OK, let's try it by the name, then...
312  //
313  for (auto& it : m_mapNyms) {
314  OTPseudonym* pNym = it.second;
316  (nullptr != pNym),
317  "nullptr pseudonym pointer in OTWallet::GetNymByIDPartialMatch.");
318 
319  OTString strNymName;
320  strNymName.Set(pNym->GetNymName());
321  std::string str_NymName = strNymName.Get();
322 
323  if (str_NymName.compare(0, PARTIAL_ID.length(), PARTIAL_ID) == 0)
324  return pNym;
325  }
326 
327  return nullptr;
328 }
329 
330 // used by high-level wrapper.
332 {
333  return static_cast<int32_t>(m_mapNyms.size());
334 }
335 
337 {
338  return static_cast<int32_t>(m_mapServers.size());
339 }
340 
342 {
343  return static_cast<int32_t>(m_mapContracts.size());
344 }
345 
347 {
348  return static_cast<int32_t>(m_mapAccounts.size());
349 }
350 
351 // used by high-level wrapper.
352 bool OTWallet::GetNym(int32_t iIndex, OTIdentifier& NYM_ID, OTString& NYM_NAME)
353 {
354  // if iIndex is within proper bounds (0 through count minus 1)
355  if (iIndex < GetNymCount() && iIndex >= 0) {
356  int32_t iCurrentIndex = (-1);
357 
358  for (auto& it : m_mapNyms) {
359  OTPseudonym* pNym = it.second;
360  OT_ASSERT(nullptr != pNym);
361 
362  iCurrentIndex++; // On first iteration, this becomes 0 here. (For 0
363  // index.) Increments thereafter.
364 
365  if (iIndex == iCurrentIndex) {
366  pNym->GetIdentifier(NYM_ID);
367  NYM_NAME.Set(pNym->GetNymName());
368  return true;
369  }
370  }
371  }
372 
373  return false;
374 }
375 
376 // used by high-level wrapper.
377 bool OTWallet::GetServer(int32_t iIndex, OTIdentifier& THE_ID,
378  OTString& THE_NAME)
379 {
380  // if iIndex is within proper bounds (0 through count minus 1)
381  if (iIndex < GetServerCount() && iIndex >= 0) {
382  int32_t iCurrentIndex = (-1);
383 
384  for (auto& it : m_mapServers) {
385  OTServerContract* pServer = it.second;
386  OT_ASSERT(nullptr != pServer);
387 
388  iCurrentIndex++; // On first iteration, this becomes 0 here. (For 0
389  // index.) Increments thereafter.
390 
391  if (iIndex == iCurrentIndex) // if not null
392  {
393  pServer->GetIdentifier(THE_ID);
394  pServer->GetName(THE_NAME);
395  return true;
396  }
397  }
398  }
399 
400  return false;
401 }
402 
403 // used by high-level wrapper.
404 bool OTWallet::GetAssetType(int32_t iIndex, OTIdentifier& THE_ID,
405  OTString& THE_NAME)
406 {
407  // if iIndex is within proper bounds (0 through count minus 1)
408  if (iIndex < GetAssetTypeCount() && iIndex >= 0) {
409  int32_t iCurrentIndex = (-1);
410 
411  for (auto& it : m_mapContracts) {
412  OTAssetContract* pAssetType = it.second;
413  OT_ASSERT(nullptr != pAssetType);
414 
415  iCurrentIndex++; // On first iteration, this becomes 0 here. (For 0
416  // index.) Increments thereafter.
417 
418  if (iIndex == iCurrentIndex) // if not null
419  {
420  pAssetType->GetIdentifier(THE_ID);
421  pAssetType->GetName(THE_NAME);
422  return true;
423  }
424  }
425  }
426 
427  return false;
428 }
429 
430 // used by high-level wrapper.
431 bool OTWallet::GetAccount(int32_t iIndex, OTIdentifier& THE_ID,
432  OTString& THE_NAME)
433 {
434  // if iIndex is within proper bounds (0 through count minus 1)
435  if (iIndex < GetAccountCount() && iIndex >= 0) {
436  int32_t iCurrentIndex = (-1);
437 
438  for (auto& it : m_mapAccounts) {
439  OTAccount* pAccount = it.second;
440  OT_ASSERT(nullptr != pAccount);
441 
442  iCurrentIndex++; // On first iteration, this becomes 0 here. (For 0
443  // index.) Increments thereafter.
444 
445  if (iIndex == iCurrentIndex) // if not null
446  {
447  pAccount->GetIdentifier(THE_ID);
448  pAccount->GetName(THE_NAME);
449  return true;
450  }
451  }
452  }
453 
454  return false;
455 }
456 
458 {
459  strOutput.Concatenate(
460  "\n-------------------------------------------------\n");
461  strOutput.Concatenate("WALLET STATISTICS:\n");
462 
463  strOutput.Concatenate("\nPSEUDONYM(s):\n\n");
464 
465  for (auto& it : m_mapNyms) {
466  OTPseudonym* pNym = it.second;
467  OT_ASSERT_MSG((nullptr != pNym), "nullptr pseudonym pointer in "
468  "OTWallet::m_mapNyms, "
469  "OTWallet::DisplayStatistics.");
470 
471  pNym->DisplayStatistics(strOutput);
472  }
473 
474  strOutput.Concatenate(
475  "\n-------------------------------------------------\n");
476  strOutput.Concatenate("ASSET CONTRACTS:\n\n");
477 
478  for (auto& it : m_mapContracts) {
479  OTContract* pContract = it.second;
480  OT_ASSERT_MSG(nullptr != pContract, "nullptr contract pointer in "
481  "OTWallet::m_mapContracts, "
482  "OTWallet::DisplayStatistics");
483 
484  pContract->DisplayStatistics(strOutput);
485  }
486 
487  strOutput.Concatenate(
488  "-------------------------------------------------\n");
489  strOutput.Concatenate("SERVER CONTRACTS:\n\n");
490 
491  for (auto& it : m_mapServers) {
492  OTContract* pServer = it.second;
493  OT_ASSERT_MSG(nullptr != pServer, "nullptr server pointer in "
494  "OTWallet::m_mapServers, "
495  "OTWallet::DisplayStatistics");
496 
497  pServer->DisplayStatistics(strOutput);
498  }
499 
500  strOutput.Concatenate(
501  "-------------------------------------------------\n");
502  strOutput.Concatenate("ACCOUNTS:\n\n");
503 
504  for (auto& it : m_mapAccounts) {
505  OTAccount* pAccount = it.second;
506  OT_ASSERT_MSG(nullptr != pAccount, "nullptr account pointer in "
507  "OTWallet::m_mapAccounts, "
508  "OTWallet::DisplayStatistics");
509 
510  pAccount->DisplayStatistics(strOutput);
511 
512  strOutput.Concatenate(
513  "-------------------------------------------------\n\n");
514  }
515 }
516 
517 // Wallet takes ownership and will delete.
518 // theNym is passed as reference only to prove that it's real.
519 //
520 // This function assumes the Nym has already been loaded, verified, etc.
521 // AND that it's been dynamically allocated.
522 //
523 void OTWallet::AddNym(const OTPseudonym& theNym)
524 {
525  const OTIdentifier NYM_ID(theNym);
526  OTIdentifier aNymID;
527 
528  OTString strName;
529 
530  for (auto it(m_mapNyms.begin()); it != m_mapNyms.end(); ++it) {
531  OTPseudonym* pNym = it->second;
532  OT_ASSERT(nullptr != pNym);
533 
534  pNym->GetIdentifier(aNymID);
535 
536  if (aNymID == NYM_ID) {
537  OTString strTemp(pNym->GetNymName());
538  strName = strTemp; // todo optimize. currently am fixing "blank nym
539  // name" bug.
540 
541  m_mapNyms.erase(it);
542 
543  // Don't delete it if they are physically the same object.
544  // (Versus each being separate copies of the same object.)
545  //
546  if (&theNym != pNym) delete pNym;
547  pNym = nullptr;
548 
549  break;
550  }
551  }
552 
553  const OTString strNymID(NYM_ID);
554  m_mapNyms[strNymID.Get()] =
555  (OTPseudonym*)&theNym; // Insert to wallet's list of Nyms.
556 
557  if (strName.Exists())
558  (const_cast<OTPseudonym&>(theNym)).SetNymName(strName);
559 }
560 
561 void OTWallet::AddAccount(const OTAccount& theAcct)
562 {
563  const OTIdentifier ACCOUNT_ID(theAcct);
564 
565  // See if there is already an account object on this wallet with the same ID
566  // (Otherwise if we don't delete it, this would be a memory leak.)
567  // Should use a smart pointer.
568  OTIdentifier anAccountID;
569 
570  for (auto it(m_mapAccounts.begin()); it != m_mapAccounts.end(); ++it) {
571  OTAccount* pAccount = it->second;
572  OT_ASSERT(nullptr != pAccount);
573 
574  pAccount->GetIdentifier(anAccountID);
575 
576  if (anAccountID == ACCOUNT_ID) {
577  OTString strName;
578  pAccount->GetName(strName);
579 
580  if (strName.Exists()) ((OTAccount&)theAcct).SetName(strName);
581 
582  m_mapAccounts.erase(it);
583  delete pAccount;
584  pAccount = nullptr;
585 
586  break;
587  }
588  }
589 
590  const OTString strAcctID(ACCOUNT_ID);
591  m_mapAccounts[strAcctID.Get()] = (OTAccount*)&theAcct;
592 }
593 
594 // Look up an account by ID and see if it is in the wallet.
595 // If it is, return a pointer to it, otherwise return nullptr.
597 {
598  // loop through the accounts and find one with a specific ID.
599  //
600  for (auto& it : m_mapAccounts) {
601  OTAccount* pAccount = it.second;
602  OT_ASSERT(nullptr != pAccount);
603 
604  OTIdentifier anAccountID;
605  pAccount->GetIdentifier(anAccountID);
606 
607  if (anAccountID == theAccountID) return pAccount;
608  }
609 
610  return nullptr;
611 }
612 
613 OTAccount* OTWallet::GetAccountPartialMatch(std::string PARTIAL_ID) // works
614  // with the
615  // name,
616  // too.
617 {
618  // loop through the accounts and find one with a specific ID.
619  for (auto& it : m_mapAccounts) {
620  OTAccount* pAccount = it.second;
621  OT_ASSERT(nullptr != pAccount);
622 
623  OTIdentifier anAccountID;
624  pAccount->GetIdentifier(anAccountID);
625  OTString strTemp(anAccountID);
626  std::string strIdentifier = strTemp.Get();
627 
628  if (strIdentifier.compare(0, PARTIAL_ID.length(), PARTIAL_ID) == 0)
629  return pAccount;
630  }
631 
632  // Okay, let's try it by name, then...
633  //
634  for (auto& it : m_mapAccounts) {
635  OTAccount* pAccount = it.second;
636  OT_ASSERT(nullptr != pAccount);
637 
638  OTString strName;
639  pAccount->GetName(strName);
640  std::string str_Name = strName.Get();
641 
642  if (str_Name.compare(0, PARTIAL_ID.length(), PARTIAL_ID) == 0)
643  return pAccount;
644  }
645 
646  return nullptr;
647 }
648 
650 {
651  // loop through the accounts and find one with a specific asset type ID.
652  // (And with the issuer type set.)
653  //
654  for (auto& it : m_mapAccounts) {
655  OTAccount* pIssuerAccount = it.second;
656  OT_ASSERT(nullptr != pIssuerAccount);
657 
658  if ((pIssuerAccount->GetAssetTypeID() == theAssetTypeID) &&
659  (pIssuerAccount->IsIssuer()))
660  return pIssuerAccount;
661  }
662 
663  return nullptr;
664 }
665 
666 // Pass in the Server ID and get the pointer back.
668 {
669  for (auto& it : m_mapServers) {
670  OTContract* pServer = it.second;
671  OT_ASSERT_MSG((nullptr != pServer), "nullptr server pointer in "
672  "OTWallet::m_mapServers, "
673  "OTWallet::GetServerContract");
674 
675  OTIdentifier id_CurrentContract;
676  pServer->GetIdentifier(id_CurrentContract);
677 
678  if (id_CurrentContract == SERVER_ID)
679  return dynamic_cast<OTServerContract*>(pServer);
680  }
681 
682  return nullptr;
683 }
684 
686  std::string PARTIAL_ID)
687 {
688  for (auto& it : m_mapServers) {
689  OTContract* pServer = it.second;
690  OT_ASSERT_MSG((nullptr != pServer), "nullptr server pointer in "
691  "OTWallet::m_mapServers, "
692  "OTWallet::GetServerContract");
693 
694  OTIdentifier id_CurrentContract;
695  pServer->GetIdentifier(id_CurrentContract);
696 
697  OTString strTemp(id_CurrentContract);
698  std::string strIdentifier = strTemp.Get();
699 
700  if (strIdentifier.compare(0, PARTIAL_ID.length(), PARTIAL_ID) == 0)
701  return dynamic_cast<OTServerContract*>(pServer);
702  }
703 
704  // Okay, let's try it by the name, then.
705  //
706  for (auto& it : m_mapServers) {
707  OTContract* pServer = it.second;
708  OT_ASSERT_MSG((nullptr != pServer), "nullptr server pointer in "
709  "OTWallet::m_mapServers, "
710  "OTWallet::GetServerContract");
711 
712  OTString strName;
713  pServer->GetName(strName);
714  std::string str_Name = strName.Get();
715 
716  if (str_Name.compare(0, PARTIAL_ID.length(), PARTIAL_ID) == 0)
717  return dynamic_cast<OTServerContract*>(pServer);
718  }
719 
720  return nullptr;
721 }
722 
723 // The wallet "owns" theContract and will handle cleaning it up.
724 // So make SURE you allocate it on the heap.
726 {
727  OTIdentifier CONTRACT_ID(theContract);
728  OTString STR_CONTRACT_ID(CONTRACT_ID);
729 
730  OTServerContract* pContract = GetServerContract(CONTRACT_ID);
731 
732  if (pContract) {
733  otErr << "Error: Attempt to add Server Contract but it is already in "
734  "the wallet.\n";
735 
736  delete &theContract; // I have to do this, since the return value is
737  // void, the caller MUST assume I took ownership.
738  }
739  else {
740  m_mapServers[STR_CONTRACT_ID.Get()] =
741  &(const_cast<OTServerContract&>(theContract));
742 
743  otInfo << "Saving server contract to disk...\n";
744  (const_cast<OTServerContract&>(theContract)).SaveToContractFolder();
745 
746  SaveWallet();
747  }
748 }
749 
750 // The wallet "owns" theContract and will handle cleaning it up.
751 // So make SURE you allocate it on the heap.
753 {
754  OTIdentifier CONTRACT_ID(theContract);
755  OTString STR_CONTRACT_ID(CONTRACT_ID);
756 
757  OTAssetContract* pContract = GetAssetContract(CONTRACT_ID);
758 
759  if (pContract) {
760  otErr << "Error: Attempt to add Asset Contract but it is already in "
761  "the wallet.\n";
762 
763  delete &theContract; // I have to do this, since the return value is
764  // void, the caller MUST assume I took ownership.
765  }
766  else {
767  m_mapContracts[STR_CONTRACT_ID.Get()] =
768  &(const_cast<OTAssetContract&>(theContract));
769 
770  otInfo << "Saving asset contract to disk...\n";
771  (const_cast<OTAssetContract&>(theContract)).SaveToContractFolder();
772 
773  SaveWallet();
774  }
775 }
776 
778  const OTIdentifier& SERVER_ID,
779  const OTString& strAcctID,
780  const char* szFuncName)
781 {
782  const char* szFunc =
783  (nullptr != szFuncName) ? szFuncName : "OTWallet::VerifyAssetAccount";
784 
785  if (SERVER_ID != theAcct.GetRealServerID()) {
786  const OTString s1(SERVER_ID), s2(theAcct.GetRealServerID());
787  otOut << "OTWallet::VerifyAssetAccount " << szFunc
788  << ": Server ID passed in (" << s1 << ") didn't match the one "
789  "on the account (" << s2
790  << "). Acct ID: " << strAcctID << "\n";
791  return false;
792  }
793 
794  const OTIdentifier theNymID(theNym);
795  const OTString strNymID(theNymID);
796 
797  if (!theAcct.VerifyOwner(theNym)) // Verifies Ownership.
798  {
799  otOut << "OTWallet::VerifyAssetAccount " << szFunc
800  << ": Nym (ID: " << strNymID
801  << ") is not the owner of the account: " << strAcctID << "\n";
802  return false;
803  }
804 
805  if (false ==
806  theAcct.VerifyAccount(theNym)) // Verifies ContractID and Signature.
807  {
808  otOut << "OTWallet::VerifyAssetAccount " << szFunc
809  << ": Account signature or AccountID fails to verify. "
810  "NymID: " << strNymID << " AcctID: " << strAcctID << "\n";
811  return false;
812  }
813  // By this point, I know that everything checks out. Signature and Account
814  // ID,
815  // Nym is owner, etc.
816 
817  return true;
818 }
819 
820 // No need to cleanup the account returned, it's owned by the wallet.
821 //
823  const OTIdentifier& ACCT_ID,
824  const OTIdentifier& SERVER_ID,
825  const char* szFuncName)
826 {
827  const char* szFunc =
828  (nullptr != szFuncName) ? szFuncName : "OTWallet::GetOrLoadAccount";
829 
830  const OTString strAcctID(ACCT_ID);
831 
832  OTAccount* pAccount = GetAccount(ACCT_ID);
833 
834  if (nullptr ==
835  pAccount) // It wasn't there already, so we'll have to load it...
836  {
837  otOut << "OTWallet::GetOrLoadAccount " << szFunc
838  << ": There's no asset account in the wallet with that ID ("
839  << strAcctID << "). "
840  "Attempting to load it from storage...\n";
841  pAccount = LoadAccount(theNym, ACCT_ID, SERVER_ID, szFuncName);
842  } // pAccount == nullptr.
843 
844  // It either was already there, or it loaded successfully...
845  //
846  if (nullptr == pAccount) // pAccount EXISTS...
847  {
848  otErr << "OTWallet::GetOrLoadAccount " << szFunc
849  << ": Error loading Asset Account: " << strAcctID << "\n";
850  return nullptr;
851  }
852 
853  return pAccount;
854 }
855 
856 // No need to cleanup the account returned, it's owned by the wallet.
857 //
858 // We don't care if this asset account is already loaded in the wallet.
859 // Presumably, the user has just download the latest copy of the account
860 // from the server, and the one in the wallet is old, so now this function
861 // is being called to load the new one from storage and update the wallet.
862 //
864  const OTIdentifier& ACCT_ID,
865  const OTIdentifier& SERVER_ID,
866  const char* szFuncName)
867 {
868  const char* szFunc =
869  (nullptr != szFuncName) ? szFuncName : "OTWallet::LoadAccount";
870 
871  const OTString strAcctID(ACCT_ID);
872  OTAccount* pAccount = OTAccount::LoadExistingAccount(ACCT_ID, SERVER_ID);
873 
874  // It loaded successfully...
875  //
876  if (nullptr != pAccount) // pAccount EXISTS...
877  {
878  bool bVerified =
879  VerifyAssetAccount(theNym, *pAccount, SERVER_ID, strAcctID, szFunc);
880 
881  if (!bVerified) {
882  delete pAccount;
883  pAccount = nullptr;
884  return nullptr; // No need to log, since VerifyAssetAccount()
885  // already
886  // logs.
887  }
888 
889  // If I had to load it myself, that means I need to add it to the
890  // wallet.
891  // (Whereas if GetAccount() had worked, then it would ALREADY be in the
892  // wallet,
893  // and thus I shouldn't add it twice...)
894  //
895  AddAccount(*pAccount);
896 
897  }
898  else {
899  otErr << "OTWallet::LoadAccount " << szFunc
900  << ": Failed loading Asset Account: " << strAcctID << "\n";
901  return nullptr;
902  }
903 
904  return pAccount;
905 }
906 
907 // This function only tries to load as a public Nym.
908 // No need to cleanup, since it adds the Nym to the wallet.
909 //
911  const char* szFuncName)
912 {
913  const OTString strNymID(NYM_ID);
914  const char* szFunc = "OTWallet::GetOrLoadPublicNym";
915 
916  szFuncName = (szFuncName == nullptr) ? "" : szFuncName;
917 
918  OTPseudonym* pNym = GetNymByID(NYM_ID); // <===========
919 
920  if (nullptr == pNym) // Wasn't already in the wallet. Try loading it.
921  {
922  otWarn << szFunc << " " << szFuncName
923  << ": There's no Nym already loaded with that ID. "
924  "Attempting to load public key...\n";
925  pNym = OTPseudonym::LoadPublicNym(NYM_ID); // <===========
926  // It worked!
927  if (nullptr !=
928  pNym) // LoadPublicNym has plenty of error logging already.
929  {
930  if (pNym->HasPrivateKey()) // We don't auto-add public Nyms -- only
931  // private ones.
932  AddNym(*pNym); // <===========
933  }
934  else
935  otOut << szFunc << " " << szFuncName
936  << ": Unable to load public Nym for: " << strNymID << " \n";
937  }
938 
939  // If pNym exists, yet he doesn't have a public key (weird!)
940  // Though we log the error, we still return pNym, since it exists.
941  //
942  if ((nullptr != pNym) && (false == pNym->HasPublicKey()))
943  otErr << szFunc << " " << szFuncName << ": Found nym (" << strNymID
944  << "), but he has no public key. "
945  "(Still returning the Nym, since it exists.)\n";
946  return pNym;
947 }
948 
949 // This function only tries to load as a private Nym.
950 // No need to cleanup, since it adds the Nym to the wallet.
951 //
952 // It is smart enough to Get the Nym from the wallet, and if it
953 // sees that it's only a public nym (no private key) then it
954 // reloads it as a private nym at that time.
955 //
957  bool bChecking,
958  const char* szFuncName,
959  const OTPasswordData* pPWData,
960  const OTPassword* pImportPassword)
961 {
962  if (NYM_ID.IsEmpty()) {
963  otErr << __FUNCTION__ << ":" << szFuncName
964  << ": Error: NYM_ID passed in empty, returning null";
965  return nullptr;
966  }
967 
968  const OTString strNymID(NYM_ID);
969  OTPasswordData thePWData(OT_PW_DISPLAY);
970  if (nullptr == pPWData) pPWData = &thePWData;
971 
972  szFuncName = (szFuncName == nullptr) ? "" : szFuncName;
973 
974  // See if it's already there. (Could be the public version
975  // though :P Still might have to reload it.)
976  //
977  OTPseudonym* pNym = GetNymByID(NYM_ID); // <===========
978 
979  if (nullptr ==
980  pNym) // Wasn't already in the wallet. Let's try loading it...
981  {
982  otWarn << __FUNCTION__ << " " << szFuncName
983  << ": There's no Nym already loaded with that ID. "
984  "Attempting to load private key...\n";
985  pNym = OTPseudonym::LoadPrivateNym(NYM_ID, bChecking, nullptr,
986  szFuncName, // <===========
987  pPWData, pImportPassword);
988  // It worked!
989  if (nullptr !=
990  pNym) // LoadPublicNym has plenty of error logging already.
991  AddNym(*pNym); // <===========
992  else {
993  OTLogStream& otLog = bChecking ? otWarn : otOut;
994  otLog << __FUNCTION__ << ": " << szFuncName << ": ("
995  << "bChecking"
996  << ": is " << (bChecking ? "true" : "false")
997  << "). Unable to load Private Nym for: " << strNymID << "\n";
998  }
999  }
1000 
1001  // If pNym EXISTS, then let's make sure he has a public AND a
1002  // private key, as he should. (He might be already loaded on the
1003  // wallet, without his private key, necessitating a reload.)
1004  //
1005  if (nullptr != pNym) // pNym definitely NOT nullptr (it exists)...
1006  {
1007 
1008  // ...yet he doesn't have a public key (Weird!)
1009  if (!pNym->HasPublicKey())
1010  otErr << __FUNCTION__ << " " << szFuncName
1011  << ": Found nym, but he has no public key: " << strNymID
1012  << "\n";
1013 
1014  // ...hmm, he doesn't have a private key. Possible! If the wallet
1015  // already had
1016  // my public key loaded (without the private one) from some earlier
1017  // action.
1018  //
1019  if (!pNym->HasPrivateKey()) {
1020  otWarn
1021  << __FUNCTION__ << " " << szFuncName
1022  << ": Found nym in wallet (" << strNymID
1023  << "), "
1024  "but he currently has no private key loaded. Reloading...\n";
1025 
1026  // ASSUMPTION: The Nym is always saved right after some important
1027  // change,
1028  // to avoid the risk of losing it. Therefore I don't have to save
1029  // the
1030  // current Nym here--I can just remove it from the wallet now, and
1031  // then
1032  // reload it (as a private key this time, of course.)
1033  //
1034 
1035  // Let's save the Name, in case that is already set, so we don't
1036  // blank it out...
1037  //
1038  OTString strName =
1039  pNym->GetNymName().Get(); // Get returns "" if string is empty.
1040 
1041  if (RemoveNym(NYM_ID)) {
1042  pNym = OTPseudonym::LoadPrivateNym(NYM_ID, false, &strName,
1043  szFuncName, // <===========
1044  pPWData, pImportPassword);
1045  // It worked!
1046  if (nullptr !=
1047  pNym) // LoadPrivateNym has plenty of error logging already.
1048  AddNym(*pNym); // <===========
1049  else
1050  otOut << __FUNCTION__ << " " << szFuncName
1051  << ": Unable to load private Nym for: " << strNymID
1052  << " \n";
1053  }
1054  else
1055  otErr << __FUNCTION__ << " " << szFuncName << ": Found nym ("
1056  << strNymID << "), but he had no private key. Then tried "
1057  "to remove him from wallet (in order "
1058  "to reload him with private key) and then "
1059  "the removal failed. Sorry.\n";
1060  }
1061  }
1062  return pNym;
1063 }
1064 
1065 // This function tries to load as public Nym first, then if it fails,
1066 // it tries the private one next. (So as to avoid unnecessarily asking
1067 // users for their passphrase.) Be sure to use GetOrLoadPublicNym() or
1068 // GetOrLoadPrivateNym() if you want to force it one way or the other.
1069 //
1070 // No need to cleanup, since either function called will add the loaded
1071 // Nym to the wallet, which will take ownership.
1072 //
1073 OTPseudonym* OTWallet::GetOrLoadNym(const OTIdentifier& NYM_ID, bool bChecking,
1074  const char* szFuncName,
1075  const OTPasswordData* pPWData)
1076 {
1077  OTPseudonym* pNym = GetOrLoadPublicNym(NYM_ID, szFuncName);
1078 
1079  // It tries to load as public Nym first, so as not to force the user to
1080  // enter his passphrase unnecessarily.
1081  // However, if this fails, then it tries the private one, just to see
1082  // if it can be found.
1083  //
1084  OTPasswordData thePWData(OT_PW_DISPLAY);
1085 
1086  if (nullptr == pNym)
1087  pNym = GetOrLoadPrivateNym(NYM_ID, bChecking, szFuncName,
1088  nullptr == pPWData ? &thePWData : pPWData);
1089 
1090  return pNym;
1091 }
1092 
1093 // These functions are low-level. They don't check for dependent data before
1094 // deleting,
1095 // and they don't save the wallet after they do.
1096 //
1097 // You have to handle that at a higher level.
1098 
1099 // higher level version of this will require a server message, in addition to
1100 // removing from wallet.
1101 bool OTWallet::RemoveNym(const OTIdentifier& theTargetID)
1102 {
1103  for (auto it(m_mapNyms.begin()); it != m_mapNyms.end(); ++it) {
1104  OTPseudonym* pNym = it->second;
1105  OT_ASSERT_MSG((nullptr != pNym),
1106  "nullptr pseudonym pointer in OTWallet::RemoveNym.");
1107 
1108  if (pNym->CompareID(theTargetID)) {
1109 
1110  // We have a set of NymIDs for Nyms in the wallet who are using the
1111  // Master key.
1112  // So if we're removing the Nym from the wallet, we also remove its
1113  // ID from that set.
1114  //
1115  for (const auto& it_master : m_setNymsOnCachedKey) {
1116  const OTIdentifier& theNymID = it_master;
1117  if (theTargetID == theNymID) {
1118  m_setNymsOnCachedKey.erase(it_master);
1119  break;
1120  }
1121  }
1122 
1123  m_mapNyms.erase(it);
1124  delete pNym;
1125  return true;
1126  }
1127  }
1128  return false;
1129 }
1130 
1132 {
1133  // loop through the items that make up this transaction and print them out
1134  // here, base64-encoded, of course.
1135  OTIdentifier aContractID;
1136 
1137  for (auto it(m_mapContracts.begin()); it != m_mapContracts.end(); ++it) {
1138  OTAssetContract* pContract = it->second;
1139  OT_ASSERT(nullptr != pContract);
1140 
1141  pContract->GetIdentifier(aContractID);
1142 
1143  if (aContractID == theTargetID) {
1144  m_mapContracts.erase(it);
1145 
1146  delete pContract;
1147 
1148  return true;
1149  }
1150  }
1151 
1152  return false;
1153 }
1154 
1156 {
1157  for (auto it(m_mapServers.begin()); it != m_mapServers.end(); ++it) {
1158  OTContract* pServer = it->second;
1159  OT_ASSERT_MSG((nullptr != pServer), "nullptr server pointer in "
1160  "OTWallet::m_mapServers, "
1161  "OTWallet::RemoveServerContract");
1162 
1163  OTIdentifier id_CurrentContract;
1164  pServer->GetIdentifier(id_CurrentContract);
1165 
1166  if (id_CurrentContract == theTargetID) {
1167  m_mapServers.erase(it);
1168 
1169  OTServerContract* pServerContract =
1170  static_cast<OTServerContract*>(pServer);
1171  delete pServerContract;
1172 
1173  return true;
1174  }
1175  }
1176 
1177  return false;
1178 }
1179 
1180 // higher level version of this will require a server message, in addition to
1181 // removing from wallet.
1182 bool OTWallet::RemoveAccount(const OTIdentifier& theTargetID)
1183 {
1184  // loop through the accounts and find one with a specific ID.
1185  OTIdentifier anAccountID;
1186 
1187  for (auto it(m_mapAccounts.begin()); it != m_mapAccounts.end(); ++it) {
1188  OTAccount* pAccount = it->second;
1189  OT_ASSERT(nullptr != pAccount);
1190 
1191  pAccount->GetIdentifier(anAccountID);
1192 
1193  if (anAccountID == theTargetID) {
1194  m_mapAccounts.erase(it);
1195  delete pAccount;
1196  return true;
1197  }
1198  }
1199 
1200  return false;
1201 }
1202 
1204 {
1205  for (auto& it : m_mapContracts) {
1206  OTAssetContract* pContract = it.second;
1207  OT_ASSERT(nullptr != pContract);
1208 
1209  OTIdentifier aContractID;
1210  pContract->GetIdentifier(aContractID);
1211 
1212  if (aContractID == theContractID) return pContract;
1213  }
1214 
1215  return nullptr;
1216 }
1217 
1219  std::string PARTIAL_ID) // works with name, too.
1220 {
1221  for (auto& it : m_mapContracts) {
1222  OTAssetContract* pContract = it.second;
1223  OT_ASSERT(nullptr != pContract);
1224 
1225  OTIdentifier aContractID;
1226  pContract->GetIdentifier(aContractID);
1227 
1228  OTString strTemp(aContractID);
1229  std::string strIdentifier = strTemp.Get();
1230 
1231  if (strIdentifier.compare(0, PARTIAL_ID.length(), PARTIAL_ID) == 0)
1232  return pContract;
1233  }
1234 
1235  // Okay, let's try it by the name, then...
1236  //
1237  for (auto& it : m_mapContracts) {
1238  OTAssetContract* pContract = it.second;
1239  OT_ASSERT(nullptr != pContract);
1240 
1241  OTString strName;
1242  pContract->GetName(strName);
1243  std::string str_Name = strName.Get();
1244 
1245  if (str_Name.compare(0, PARTIAL_ID.length(), PARTIAL_ID) == 0)
1246  return pContract;
1247  }
1248 
1249  return nullptr;
1250 }
1251 
1253 {
1254  OTASCIIArmor ascName;
1255 
1256  if (m_strName.Exists()) // name is in the clear in memory, and base64 in
1257  // storage.
1258  {
1259  ascName.SetString(m_strName, false); // linebreaks == false
1260  }
1261 
1262  strContract.Concatenate(
1263  "<?xml version=\"1.0\"?>\n<wallet name=\"%s\" version=\"%s\">\n\n",
1264  ascName.Get(),
1265  OTCachedKey::It()->IsGenerated() ? "2.0" : m_strVersion.Get());
1266 
1267  if (OTCachedKey::It()->IsGenerated()) // If it exists, then serialize it.
1268  {
1269  OTASCIIArmor ascMasterContents;
1270 
1271  if (OTCachedKey::It()->SerializeTo(ascMasterContents)) {
1272  strContract.Concatenate("<cachedKey>\n%s</cachedKey>\n\n",
1273  ascMasterContents.Get());
1274  }
1275  else
1276  otErr << "OTWallet::SaveContract: Failed trying to write master "
1277  "key to wallet.\n";
1278  }
1279 
1280  // Save the extra symmetric keys. (The ones the client app might use to
1281  // encrypt his local sql-lite DB's record of his Bitmessage connect string,
1282  // or any other local data.)
1283  //
1284  for (auto& it : m_mapExtraKeys) {
1285  const std::string str_id = it.first;
1286  std::shared_ptr<OTSymmetricKey> pKey = it.second;
1287 
1288  OTString strKeyID(str_id.c_str());
1289  OTASCIIArmor ascKeyID;
1290 
1291  ascKeyID.SetString(strKeyID,
1292  false); // linebreaks=false (true by default.)
1293 
1294  OTASCIIArmor ascKeyContents;
1295 
1296  if (pKey && pKey->SerializeTo(ascKeyContents)) {
1297  strContract.Concatenate(
1298  "<symmetricKey id=\"%s\">\n%s</symmetricKey>\n\n",
1299  ascKeyID.Get(), ascKeyContents.Get());
1300  }
1301  else
1302  otErr << "OTWallet::SaveContract: Failed trying to serialize "
1303  "symmetric keys to wallet.\n";
1304  }
1305 
1306  //
1307  // We want to save the NymIDs for the Nyms on the master key. I save those
1308  // before the Nyms themselves, so that they are all loaded up and available
1309  // in LoadWallet before the Nyms themselves are loaded.
1310  //
1311  for (const auto& it : m_setNymsOnCachedKey) {
1312  const OTIdentifier& theNymID = it;
1313  OTString strNymID(theNymID);
1314 
1315  strContract.Concatenate("<nymUsingCachedKey id=\"%s\" />\n\n",
1316  strNymID.Get());
1317  }
1318 
1319  for (auto& it : m_mapNyms) {
1320  OTPseudonym* pNym = it.second;
1321  OT_ASSERT_MSG(nullptr != pNym, "nullptr pseudonym pointer in "
1322  "OTWallet::m_mapNyms, "
1323  "OTWallet::SaveContract");
1324 
1325  pNym->SavePseudonymWallet(strContract);
1326  }
1327 
1328  for (auto& it : m_mapContracts) {
1329  OTContract* pContract = it.second;
1330  OT_ASSERT_MSG(nullptr != pContract, "nullptr contract pointer in "
1331  "OTWallet::m_mapContracts, "
1332  "OTWallet::SaveContract");
1333 
1334  pContract->SaveContractWallet(strContract);
1335  }
1336 
1337  for (auto& it : m_mapServers) {
1338  OTContract* pServer = it.second;
1339  OT_ASSERT_MSG(nullptr != pServer, "nullptr server pointer in "
1340  "OTWallet::m_mapServers, "
1341  "OTWallet::SaveContract");
1342 
1343  pServer->SaveContractWallet(strContract);
1344  }
1345 
1346  for (auto& it : m_mapAccounts) {
1347  OTContract* pAccount = it.second;
1348  OT_ASSERT_MSG(nullptr != pAccount, "nullptr account pointer in "
1349  "OTWallet::m_mapAccounts, "
1350  "OTWallet::SaveContract");
1351 
1352  pAccount->SaveContractWallet(strContract);
1353  }
1354 
1355  strContract.Concatenate("%s", "</wallet>\n");
1356 
1357  return true;
1358 }
1359 
1360 // Let's say you have client-app data that you want to keep in encrypted form.
1361 // Well, use this function to create/retrieve a symmetric key based on an ID.
1362 // For example, "mc_sql_lite" might be the name of the symmetric key that I use
1363 // to encrypt sensitive contents in the sql*lite DB.
1364 // This function will find or create the key and return it to you. The key is
1365 // encrypted to the master key in the wallet, so you never actually have to type
1366 // a password to use it, except when the master key itself has expired.
1367 //
1368 std::shared_ptr<OTSymmetricKey> OTWallet::getOrCreateExtraKey(
1369  const std::string& str_KeyID, const std::string* pReason)
1370 {
1371  // const std::string str_KeyID("mc_sql_lite");
1372 
1373  // Get the appropriate symmetric key from the wallet.
1374  // (Which we will decrypt using pMaster.)
1375  // Once it's decrypted, we'll use this key for encrypting/decrypting
1376  // the sql*lite DB data on the client side.
1377  //
1378  std::shared_ptr<OTSymmetricKey> pExtraKey = getExtraKey(str_KeyID);
1379 
1380  // (If it doesn't exist, let's just create it here.)
1381  //
1382  if (!pExtraKey) {
1383  // The extra keys, like the Nyms, are all encrypted to the master key
1384  // for the wallet.
1385  // Thus, to create a new extra symmetrical key, we need to get the
1386  // master key from OTCachedKey...
1387  //
1388  std::shared_ptr<OTCachedKey> pMasterKey(OTCachedKey::It());
1389 
1390  if (pMasterKey) {
1391  OTPassword master_password;
1392  const bool bGotMasterPW = pMasterKey->GetMasterPassword(
1393  pMasterKey, master_password,
1394  (nullptr == pReason) ? "" : pReason->c_str());
1395  OTString strNewKeyOutput;
1396 
1397  if (bGotMasterPW &&
1398  OTSymmetricKey::CreateNewKey(strNewKeyOutput, nullptr,
1399  &master_password)) {
1400  std::shared_ptr<OTSymmetricKey> pNewExtraKey(
1401  new OTSymmetricKey);
1402 
1403  if (pNewExtraKey &&
1404  pNewExtraKey->SerializeFrom(strNewKeyOutput) &&
1405  addExtraKey(str_KeyID, pNewExtraKey)) {
1406 
1407  pExtraKey = pNewExtraKey;
1408 
1409  SaveWallet();
1410  }
1411  } // if (bGotMasterPW)
1412  } // if (pMasterKey)
1413  }
1414 
1415  // Then:
1416  //
1417  if (pExtraKey) return pExtraKey; // <======== SUCCESS.
1418 
1419  return std::shared_ptr<OTSymmetricKey>();
1420 }
1421 
1422 // The "extra" symmetric keys in the wallet are all, like the Nyms, encrypted
1423 // to the wallet's master key. So whenever the wallet's master key is changed,
1424 // this method needs to be called as well, to update those extra symmetric keys
1425 // to the new master key. (Otherwise they'll stop working.)
1426 //
1428  const OTPassword& newPassphrase)
1429 {
1430  // First we copy all the keys over to a new map, since we aren't going
1431  // to copy the changed ones back to the actual map unless EVERYTHING
1432  // succeeds.
1433  //
1434  mapOfSymmetricKeys mapChanged;
1435 
1436  for (auto& it : m_mapExtraKeys) {
1437  const std::string str_id = it.first;
1438  std::shared_ptr<OTSymmetricKey> pOldKey = it.second;
1439 
1440  OTPayload thePayload;
1441 
1442  if (pOldKey && pOldKey->SerializeTo(thePayload)) {
1443  std::shared_ptr<OTSymmetricKey> pNewKey(new OTSymmetricKey);
1444 
1445  if (pNewKey && pNewKey->SerializeFrom(thePayload))
1446  mapChanged.insert(
1447  std::pair<std::string, std::shared_ptr<OTSymmetricKey>>(
1448  str_id, pNewKey));
1449  else
1450  return false;
1451  }
1452  else
1453  return false;
1454  }
1455 
1456  // We're still here? Must have been a success so far.
1457  // Next we'll loop through mapChanged, and change the passphrase
1458  // on each key in there. If they all succeed, we'll clear the old
1459  // map and copy mapChanged into it.
1460  //
1461  for (auto& it : mapChanged) {
1462  std::shared_ptr<OTSymmetricKey> pNewKey = it.second;
1463 
1464  if (pNewKey) {
1465  if (!pNewKey->ChangePassphrase(oldPassphrase, newPassphrase))
1466  return false;
1467  }
1468  else
1469  return false;
1470  }
1471 
1472  // Still here? Must have been successful changing the passphrases
1473  // on all the various extra symmetric keys. So let's clear the main
1474  // map and copy the changed map into it.
1475  //
1476  m_mapExtraKeys.clear();
1477  m_mapExtraKeys = mapChanged;
1478 
1479  return true;
1480 }
1481 
1482 bool OTWallet::Encrypt_ByKeyID(const std::string& key_id,
1483  const OTString& strPlaintext,
1484  OTString& strOutput, const OTString* pstrDisplay,
1485  bool bBookends)
1486 {
1487  if (key_id.empty() || !strPlaintext.Exists()) return false;
1488 
1489  std::string str_Reason((nullptr != pstrDisplay) ? pstrDisplay->Get() : "");
1490 
1491  std::shared_ptr<OTSymmetricKey> pKey =
1492  OTWallet::getOrCreateExtraKey(key_id, &str_Reason);
1493 
1494  if (pKey) {
1495  std::shared_ptr<OTCachedKey> pMasterKey(OTCachedKey::It());
1496 
1497  if (pMasterKey) {
1498  OTPassword master_password;
1499 
1500  if (pMasterKey->GetMasterPassword(pMasterKey, master_password))
1501  return OTSymmetricKey::Encrypt(*pKey, strPlaintext, strOutput,
1502  pstrDisplay, bBookends,
1503  &master_password);
1504  }
1505  }
1506  return false;
1507 }
1508 bool OTWallet::Decrypt_ByKeyID(const std::string& key_id,
1509  const OTString& strCiphertext,
1510  OTString& strOutput, const OTString* pstrDisplay)
1511 {
1512  if (key_id.empty() || !strCiphertext.Exists()) return false;
1513 
1514  std::shared_ptr<OTSymmetricKey> pKey = OTWallet::getExtraKey(key_id);
1515 
1516  if (pKey) {
1517  std::shared_ptr<OTCachedKey> pMasterKey(OTCachedKey::It());
1518 
1519  if (pMasterKey) {
1520  OTPassword master_password;
1521 
1522  if (pMasterKey->GetMasterPassword(pMasterKey, master_password))
1523  return OTSymmetricKey::Decrypt(*pKey, strCiphertext, strOutput,
1524  pstrDisplay, &master_password);
1525  }
1526  }
1527  return false;
1528 }
1529 
1530 std::shared_ptr<OTSymmetricKey> OTWallet::getExtraKey(const std::string& str_id)
1531 {
1532  if (str_id.empty()) return std::shared_ptr<OTSymmetricKey>();
1533 
1534  auto it = m_mapExtraKeys.find(str_id);
1535 
1536  if (it != m_mapExtraKeys.end()) // It's already there (can't add it.)
1537  {
1538  std::shared_ptr<OTSymmetricKey> pKey = it->second;
1539 
1540  return pKey;
1541  }
1542 
1543  return std::shared_ptr<OTSymmetricKey>();
1544 }
1545 
1546 bool OTWallet::addExtraKey(const std::string& str_id,
1547  std::shared_ptr<OTSymmetricKey> pKey)
1548 {
1549  if (str_id.empty() || !pKey) return false;
1550 
1551  auto it = m_mapExtraKeys.find(str_id);
1552 
1553  if (it != m_mapExtraKeys.end()) // It's already there (can't add it.)
1554  return false;
1555 
1556  m_mapExtraKeys.insert(
1557  std::pair<std::string, std::shared_ptr<OTSymmetricKey>>(str_id, pKey));
1558 
1559  return true;
1560 }
1561 
1562 // Pass in the name only, NOT the full path.
1563 // If you pass nullptr, it remembers full path from last time.
1564 // (Better to do that.)
1565 //
1566 bool OTWallet::SaveWallet(const char* szFilename)
1567 {
1568  if (nullptr != szFilename) m_strFilename.Set(szFilename);
1569 
1570  if (!m_strFilename.Exists()) {
1571  otErr << __FUNCTION__ << ": Filename Dosn't Exist!\n";
1572  OT_FAIL;
1573  }
1574 
1575  bool bSuccess = false;
1576  OTString strContract;
1577 
1578  if (SaveContract(strContract)) {
1579 
1580  // Try to save the wallet to local storage.
1581  //
1582  OTString strFinal;
1583  OTASCIIArmor ascTemp(strContract);
1584 
1585  if (false ==
1586  ascTemp.WriteArmoredString(strFinal, "WALLET")) // todo hardcoding.
1587  {
1588  otErr << "OTWallet::SaveWallet: Error saving wallet (failed "
1589  "writing armored string):\n" << m_strDataFolder
1590  << OTLog::PathSeparator() << m_strFilename << "\n";
1591  return false;
1592  }
1593 
1594  // Wallet file is the only one in data_folder (".") and not a subfolder
1595  // of that.
1596  bSuccess = OTDB::StorePlainString(
1597  strFinal.Get(), ".",
1598  m_strFilename.Get()); // <==== Store Plain String
1599  }
1600 
1601  return bSuccess;
1602 }
1603 
1604 /*
1605 
1606 <?xml version="1.0"?>
1607 <wallet name="" version="2.0">
1608 
1609 <cachedKey>
1610 CkwAAQCAAAD//wAAAAhVRpwTzc+1NAAAABCKe14aROG8v/ite3un3bBCAAAAINyw
1611 HXTM/x449Al2z8zBHBTRF77jhHkYLj8MIgqrJ2Ep
1612 </cachedKey>
1613 
1614 </wallet>
1615 
1616  */
1617 bool OTWallet::LoadWallet(const char* szFilename)
1618 {
1619  OT_ASSERT_MSG(m_strFilename.Exists() || (nullptr != szFilename),
1620  "OTWallet::LoadWallet: nullptr filename.\n");
1621 
1622  Release();
1623 
1624  // The directory is "." because unlike every other OT file, the wallet file
1625  // doesn't go into a subdirectory, but it goes into the main data_folder
1626  // itself.
1627  // Every other file, however, needs to specify its folder AND filename (and
1628  // both
1629  // of those will be appended to the local path to form the complete file
1630  // path.)
1631  //
1632  if (!m_strFilename.Exists()) // If it's not already set, then set it.
1634  szFilename); // (We know nullptr wasn't passed in, in this case.)
1635 
1636  if (nullptr ==
1637  szFilename) // If nullptr was passed in, then set the pointer to
1638  // existing string.
1639  szFilename = m_strFilename.Get(); // (We know existing string is there,
1640  // in this case.)
1641 
1642  if (!OTDB::Exists(".", szFilename)) {
1643  otErr << __FUNCTION__ << ": Wallet file does not exist: " << szFilename
1644  << ". Creating...\n";
1645 
1646  const char* szContents = "<?xml version=\"1.0\"?>\n"
1647  "<wallet name=\"\" version=\"1.0\">\n"
1648  "\n"
1649  "</wallet>\n";
1650 
1651  if (!OTDB::StorePlainString(szContents, ".", szFilename)) {
1652  otErr << __FUNCTION__
1653  << ": Error: Unable to create blank wallet file.\n";
1654  OT_FAIL;
1655  }
1656  }
1657 
1658  OTString strFileContents(OTDB::QueryPlainString(
1659  ".", szFilename)); // <=== LOADING FROM DATA STORE.
1660 
1661  if (!strFileContents.Exists()) {
1662  otErr << __FUNCTION__ << ": Error reading wallet file: " << szFilename
1663  << "\n";
1664  return false;
1665  }
1666 
1667  bool bNeedToSaveAgain = false;
1668 
1669  {
1670  OTStringXML xmlFileContents(strFileContents);
1671 
1672  if (!xmlFileContents.DecodeIfArmored()) {
1673  otErr << __FUNCTION__
1674  << ": Input string apparently was encoded and then failed "
1675  "decoding. Filename: " << szFilename << " \n"
1676  "Contents: \n"
1677  << strFileContents << "\n";
1678  return false;
1679  }
1680 
1681  irr::io::IrrXMLReader* xml =
1682  irr::io::createIrrXMLReader(xmlFileContents);
1683 
1684  // parse the file until end reached
1685  while (xml && xml->read()) {
1686  // strings for storing the data that we want to read out of the file
1687  OTString NymName;
1688  OTString NymID;
1689 
1690  OTString AssetName;
1691  OTString AssetContract;
1692  OTString AssetID;
1693 
1694  OTString ServerName;
1695  OTString ServerContract;
1696  OTString ServerID;
1697 
1698  OTString AcctName;
1699  OTString AcctFile;
1700  OTString AcctID;
1701 
1702  const OTString strNodeName(xml->getNodeName());
1703 
1704  switch (xml->getNodeType()) {
1705  case irr::io::EXN_NONE:
1706  case irr::io::EXN_TEXT:
1707  case irr::io::EXN_COMMENT:
1708  case irr::io::EXN_ELEMENT_END:
1709  case irr::io::EXN_CDATA:
1710  // in this xml file, the only text which occurs is the
1711  // messageText
1712  // messageText = xml->getNodeData();
1713  break;
1714  case irr::io::EXN_ELEMENT: {
1715  if (strNodeName.Compare("wallet")) {
1716  OTASCIIArmor ascWalletName = xml->getAttributeValue("name");
1717 
1718  if (ascWalletName.Exists())
1719  ascWalletName.GetString(m_strName,
1720  false); // linebreaks == false
1721 
1722  // m_strName =
1723  // xml->getAttributeValue("name");
1724  // OTLog::OTPath =
1725  // xml->getAttributeValue("path");
1726  m_strVersion = xml->getAttributeValue("version");
1727 
1728  otWarn << "\nLoading wallet: " << m_strName
1729  << ", version: " << m_strVersion << "\n";
1730  }
1731 
1732  // todo: Remove the masterKey after a while. It's here for now
1733  // so people's data files can get
1734  // converted over. After a while, just remove it.
1735  else if (strNodeName.Compare("masterKey") ||
1736  strNodeName.Compare("cachedKey")) {
1737  OTASCIIArmor ascCachedKey;
1738 
1739  if (OTContract::LoadEncodedTextField(xml, ascCachedKey)) {
1740  // We successfully loaded the cachedKey from file, so
1741  // let's SET it
1742  // as the cached key globally...
1743  //
1744  OTCachedKey::It()->SetCachedKey(ascCachedKey);
1745 
1746  if (!OTCachedKey::It()->HasHashCheck()) {
1747  OTPassword tempPassword;
1748  tempPassword.zeroMemory();
1749 
1750  std::shared_ptr<OTCachedKey> sharedPtr(
1751  OTCachedKey::It());
1752 
1753  bNeedToSaveAgain = sharedPtr->GetMasterPassword(
1754  sharedPtr, tempPassword,
1755  "We do not have a check hash yet for this "
1756  "password, please enter your password",
1757  true);
1758  }
1759  }
1760 
1761  otWarn << "Loading cachedKey:\n" << ascCachedKey << "\n";
1762  }
1763 
1764  // todo: Remove the nymUsingMasterKey after a while. It's here
1765  // for now so people's data files can get
1766  // converted over. After a while, just remove it.
1767  else if (strNodeName.Compare("nymUsingMasterKey") ||
1768  strNodeName.Compare("nymUsingCachedKey")) {
1769  NymID = xml->getAttributeValue("id"); // message digest from
1770  // hash of x.509 cert
1771  // or public key.
1772 
1773  otWarn << "NymID using Cached Key: " << NymID << "\n";
1774  if (!NymID.Exists()) {
1775  otErr << __FUNCTION__ << ": NymID using Cached Key was "
1776  "empty when loading wallet!\n";
1777  OT_FAIL;
1778  }
1779 
1780  const OTIdentifier theNymID(NymID);
1781 
1782  m_setNymsOnCachedKey.insert(theNymID);
1783  }
1784  else if (strNodeName.Compare("symmetricKey")) {
1785  OTString strKeyID;
1786  OTASCIIArmor ascKeyID = xml->getAttributeValue("id");
1787  OTASCIIArmor ascSymmetricKey;
1788 
1789  if (!ascKeyID.Exists() ||
1790  !ascKeyID.GetString(strKeyID, false)) // linebreaks ==
1791  // false (true by
1792  // default.)
1793  otErr << __FUNCTION__ << ": Failed loading "
1794  "symmetricKey ID (it was "
1795  "blank.)\n";
1796 
1798  xml, ascSymmetricKey)) {
1799  std::shared_ptr<OTSymmetricKey> pKey(
1800  new OTSymmetricKey);
1801 
1802  if (!pKey || !pKey->SerializeFrom(ascSymmetricKey))
1803  otErr << __FUNCTION__
1804  << ": Failed serializing symmetricKey from "
1805  "string (id: " << strKeyID << ")\n";
1806  else {
1807  const std::string str_id(strKeyID.Get());
1808 
1809  if (!addExtraKey(str_id, pKey))
1810  otErr << __FUNCTION__
1811  << ": Failed adding serialized "
1812  "symmetricKey to wallet (id: "
1813  << strKeyID << ")\n";
1814  }
1815  }
1816  }
1817  else if (strNodeName.Compare("pseudonym")) {
1818  OTASCIIArmor ascNymName = xml->getAttributeValue("name");
1819  if (ascNymName.Exists())
1820  ascNymName.GetString(NymName,
1821  false); // linebreaks == false
1822 
1823  NymID = xml->getAttributeValue("nymID"); // message digest
1824  // from hash of
1825  // x.509 cert or
1826  // public key.
1827 
1828  otInfo << "\n\n** Pseudonym ** (wallet listing): "
1829  << NymName << "\nID: " << NymID << "\n";
1830  if (!NymID.Exists()) {
1831  otErr << __FUNCTION__ << ": NymID dosn't Exist!\n";
1832  OT_FAIL;
1833  }
1834 
1835  const OTIdentifier theNymID(NymID);
1836 
1837  // What's going on here? We need to see if the MASTER KEY
1838  // exists at this point. If it's GENERATED.
1839  // If not, that means the Nyms are all still encrypted to
1840  // their own passphrases, not to the master key.
1841  // In which case we need to generate one and re-encrypt each
1842  // private key to that new master key.
1843  //
1844  // bool OTWallet::IsNymOnCachedKey(const
1845  // OTIdentifier& needle) const // needle and haystack.
1846 
1847  const bool bIsOldStyleNym =
1848  (false == IsNymOnCachedKey(theNymID));
1849 
1850  if (bIsOldStyleNym && !(OTCachedKey::It()->isPaused()))
1851  // if (m_strVersion.Compare("1.0")) //
1852  // This means this Nym has not been converted yet to
1853  // master password.
1854  {
1855  OTCachedKey::It()->Pause();
1856  }
1857 
1858  OTPseudonym* pNym =
1859  OTPseudonym::LoadPrivateNym(theNymID, false, &NymName);
1860  // If it fails loading as a private Nym, then maybe it's a
1861  // public one...
1862  if (nullptr == pNym)
1863  pNym = OTPseudonym::LoadPublicNym(theNymID, &NymName);
1864 
1865  if (nullptr == pNym) // STILL null ??
1866  otOut << __FUNCTION__ << ": Failed loading Nym ("
1867  << NymName << ") with ID: " << NymID << "\n";
1868  else
1869  AddNym(*pNym); // Nym loaded. Insert to wallet's
1870  // list of Nyms.
1871 
1872  if (bIsOldStyleNym && OTCachedKey::It()->isPaused()) {
1873  OTCachedKey::It()->Unpause();
1874  }
1875  // (Here we set it back again, so any new-style Nyms will
1876  // still load properly, when they come around.)
1877  }
1878 
1879  // NOTE: It's only by THIS point (assetType) that we KNOW we
1880  // loaded all the Nyms.
1881  // If we are version 1.0, NOW we should convert them all to the
1882  // new master key!!
1883  else if (strNodeName.Compare("assetType")) {
1884 
1885  OTASCIIArmor ascAssetName = xml->getAttributeValue("name");
1886 
1887  if (ascAssetName.Exists())
1888  ascAssetName.GetString(AssetName,
1889  false); // linebreaks == false
1890 
1891  // AssetName =
1892  // xml->getAttributeValue("name");
1893  AssetID = xml->getAttributeValue(
1894  "assetTypeID"); // hash of contract itself
1895 
1896  otInfo << "\n\n****Asset Contract**** (wallet listing)\n "
1897  "Asset Name: " << AssetName
1898  << "\n Contract ID: " << AssetID << "\n";
1899 
1900  OTString strContractPath;
1901  strContractPath.Format(OTFolders::Contract().Get());
1902  OTAssetContract* pContract = new OTAssetContract(
1903  AssetName, strContractPath, AssetID, AssetID);
1904 
1905  OT_ASSERT_MSG(nullptr != pContract,
1906  "Error allocating memory "
1907  "for Asset Contract in "
1908  "OTWallet::LoadWallet\n");
1909 
1910  if (pContract->LoadContract()) {
1911  if (pContract->VerifyContract()) {
1912  otWarn << "** Asset Contract Verified "
1913  "**\n------------------------------------"
1914  "----------------------------------------"
1915  "-\n\n";
1916 
1917  pContract->SetName(AssetName);
1918 
1919  m_mapContracts[AssetID.Get()] = pContract;
1920  }
1921  else {
1922  delete pContract;
1923  pContract = nullptr;
1924  otOut << "Contract FAILED to verify.\n";
1925  }
1926  }
1927  else {
1928  delete pContract;
1929  pContract = nullptr;
1930  otErr << __FUNCTION__
1931  << ": Error reading file for Asset Contract.\n";
1932  }
1933 
1934  }
1935  else if (strNodeName.Compare("notaryProvider")) {
1936  OTASCIIArmor ascServerName = xml->getAttributeValue("name");
1937 
1938  if (ascServerName.Exists())
1939  ascServerName.GetString(ServerName,
1940  false); // linebreaks == false
1941 
1942  // ServerName =
1943  // xml->getAttributeValue("name");
1944  ServerID =
1945  xml->getAttributeValue("serverID"); // hash of contract
1946 
1947  otInfo << "\n\n\n****Server Contract**** (wallet "
1948  "listing):\n Server Name: " << ServerName
1949  << "\n Server ID: " << ServerID << "\n";
1950 
1951  OTString strContractPath(OTFolders::Contract().Get());
1952 
1953  OTServerContract* pContract = new OTServerContract(
1954  ServerName, strContractPath, ServerID, ServerID);
1955 
1956  OT_ASSERT_MSG(nullptr != pContract,
1957  "Error allocating memory "
1958  "for Server Contract in "
1959  "OTWallet::LoadWallet\n");
1960 
1961  if (pContract->LoadContract()) {
1962  if (pContract->VerifyContract()) {
1963  pContract->SetName(ServerName); // This isn't
1964  // needed, but it's
1965  // proper.
1966 
1967  otWarn << "** Server Contract Verified "
1968  "**\n------------------------------------"
1969  "----------------------------------------"
1970  "-\n\n";
1971  // Uncomment : Move these lines back above the 'if'
1972  // block to regenerate some newly-signed contracts.
1973  // (for testing only.) Otherwise leave here where it
1974  // belongs.
1975  m_mapServers[ServerID.Get()] = pContract;
1976  }
1977  else {
1978  delete pContract;
1979  pContract = nullptr;
1980  otOut << __FUNCTION__
1981  << ": Server contract failed to verify.\n";
1982  }
1983  }
1984  else {
1985  delete pContract;
1986  pContract = nullptr;
1987  otErr
1988  << __FUNCTION__
1989  << ": Error reading file for Transaction Server.\n";
1990  }
1991  }
1992  else if (strNodeName.Compare("assetAccount")) {
1993  OTASCIIArmor ascAcctName = xml->getAttributeValue("name");
1994 
1995  if (ascAcctName.Exists())
1996  ascAcctName.GetString(AcctName,
1997  false); // linebreaks == false
1998 
1999  AcctID = xml->getAttributeValue("accountID");
2000  ServerID = xml->getAttributeValue("serverID");
2001 
2002  otInfo << "\n----------------------------------------------"
2003  "----------------------------\n"
2004  "****Account**** (wallet listing)\n"
2005  " Account Name: " << AcctName
2006  << "\n Account ID: " << AcctID
2007  << "\n Server ID: " << ServerID << "\n";
2008 
2009  const OTIdentifier ACCOUNT_ID(AcctID), SERVER_ID(ServerID);
2010 
2011  OTAccount* pAccount =
2012  OTAccount::LoadExistingAccount(ACCOUNT_ID, SERVER_ID);
2013 
2014  if (pAccount) {
2015  pAccount->SetName(AcctName);
2016  AddAccount(*pAccount);
2017  }
2018  else {
2019  otErr << __FUNCTION__
2020  << ": Error loading existing Asset Account.\n";
2021  }
2022  }
2023  else {
2024  // unknown element type
2025  otErr << __FUNCTION__
2026  << ": unknown element type: " << xml->getNodeName()
2027  << "\n";
2028  }
2029  } break;
2030  default:
2031  otLog5 << __FUNCTION__
2032  << ": Unknown XML type: " << xml->getNodeName() << "\n";
2033  break;
2034  }
2035  } // while xml->read()
2036 
2037  // After we've loaded all the old-format Nyms that don't use the master
2038  // key,
2039  // NOW we can go through and convert them all, now that they're all
2040  // loaded.
2041 
2042  for (auto& it : m_mapNyms) {
2043  OTPseudonym* pNym = it.second;
2044  OT_ASSERT_MSG(
2045  (nullptr != pNym),
2046  "ASSERT: OTWallet::LoadWallet: nullptr pseudonym pointer.");
2047 
2048  if (pNym->HasPrivateKey() &&
2049  ConvertNymToCachedKey(*pNym)) // Internally this is smart
2050  // enough to only convert
2051  // the unconverted.
2052  bNeedToSaveAgain = true;
2053  }
2054 
2055  //
2056  // delete the xml parser after usage
2057  if (xml) delete xml;
2058  }
2059 
2060  // In case we converted any of the Nyms to the new "master key" encryption.
2061  if (bNeedToSaveAgain) SaveWallet(szFilename);
2062 
2063  return true;
2064 }
2065 
2067 {
2068  // If he's not ALREADY on the master key...
2069  //
2070  if (!IsNymOnCachedKey(theNym.GetConstID())) {
2071  bool bConverted = false;
2072  // The Nym has credentials.
2073  //
2074  if (theNym.GetMasterCredentialCount() > 0) {
2075  OTString strNymID, strCredList, strOutput;
2076  OTString::Map mapCredFiles;
2077 
2078  theNym.GetIdentifier(strNymID);
2079  theNym.GetPrivateCredentials(strCredList, &mapCredFiles);
2080 
2081  OTString strFilename;
2082  strFilename.Format("%s.cred", strNymID.Get());
2083 
2084  OTASCIIArmor ascArmor(strCredList);
2085  if (ascArmor.Exists() &&
2086  ascArmor.WriteArmoredString(
2087  strOutput,
2088  "CREDENTIAL LIST") && // bEscaped=false by default.
2089  strOutput.Exists()) {
2090  if (!OTDB::StorePlainString(strOutput.Get(),
2092  strFilename.Get())) {
2093  otErr << __FUNCTION__ << ": Failure trying to store "
2094  << (theNym.HasPrivateKey() ? "private" : "public")
2095  << " credential list for Nym: " << strNymID << "\n";
2096  return false;
2097  }
2098  }
2099 
2100  // Here we do the actual credentials.
2101  for (auto& it : mapCredFiles) {
2102  std::string str_cred_id = it.first;
2103  OTString strCredential(it.second);
2104 
2105  strOutput.Release();
2106  OTASCIIArmor ascLoopArmor(strCredential);
2107  if (ascLoopArmor.Exists() &&
2108  ascLoopArmor.WriteArmoredString(
2109  strOutput,
2110  "CREDENTIAL") && // bEscaped=false by default.
2111  strOutput.Exists()) {
2112  if (false ==
2113  OTDB::StorePlainString(strOutput.Get(),
2115  strNymID.Get(), str_cred_id)) {
2116  otErr << __FUNCTION__ << ": Failure trying to store "
2117  << (theNym.HasPrivateKey() ? "private" : "public")
2118  << " credential for Nym: " << strNymID << "\n";
2119  return false;
2120  }
2121  }
2122  }
2123  bConverted = true;
2124  }
2125  else // Kicking it old-school. (No credentials.)
2126  {
2127  OTString strReason("Converting Nym to cached master key.");
2128  bConverted = theNym.Savex509CertAndPrivateKey(true, &strReason);
2129  }
2130 
2131  if (bConverted) {
2132  m_setNymsOnCachedKey.insert(theNym.GetConstID());
2133  }
2134 
2135  return bConverted;
2136  } // This block only occurs if Nym is not ALREADY on the wallet's list of
2137  // Nym using the wallet's cached master key.
2138 
2139  return false;
2140 }
2141 
2142 // setOfIdentifiers m_setNymsOnCachedKey; // All the Nyms that use the
2143 // Master key are listed here (makes it easy to see which ones are converted
2144 // already.)
2145 // Todo: serialize?
2146 //
2147 bool OTWallet::IsNymOnCachedKey(const OTIdentifier& needle) const // needle and
2148  // haystack.
2149 {
2150  for (const auto& it : m_setNymsOnCachedKey) {
2151  if (needle == it) return true;
2152  }
2153  return false;
2154 }
2155 
2156 } // namespace opentxs
EXPORT bool GetNym(int32_t iIndex, OTIdentifier &NYM_ID, OTString &NYM_NAME)
Definition: OTWallet.cpp:352
EXPORT bool StorePlainString(std::string strContents, std::string strFolder, std::string oneStr="", std::string twoStr="", std::string threeStr="")
Definition: OTStorage.cpp:698
EXPORT OTPseudonym * GetOrLoadPrivateNym(const OTIdentifier &NYM_ID, bool bChecking=false, const char *szFuncName=nullptr, const OTPasswordData *pPWData=nullptr, const OTPassword *pImportPassword=nullptr)
Definition: OTWallet.cpp:956
std::map< std::string, std::string > Map
Definition: OTString.hpp:162
static EXPORT OTPseudonym * LoadPublicNym(const OTIdentifier &NYM_ID, const OTString *pstrName=nullptr, const char *szFuncName=nullptr)
EXPORT OTAccount * GetOrLoadAccount(const OTPseudonym &theNym, const OTIdentifier &ACCT_ID, const OTIdentifier &SERVER_ID, const char *szFuncName=nullptr)
Definition: OTWallet.cpp:822
EXPORT int32_t GetAccountCount()
Definition: OTWallet.cpp:346
EXPORT bool IsNymOnCachedKey(const OTIdentifier &needle) const
Definition: OTWallet.cpp:2147
EXPORT bool Encrypt_ByKeyID(const std::string &key_id, const OTString &strPlaintext, OTString &strOutput, const OTString *pstrDisplay=nullptr, bool bBookends=true)
Definition: OTWallet.cpp:1482
EXPORT bool ChangePassphrasesOnExtraKeys(const OTPassword &oldPassphrase, const OTPassword &newPassphrase)
Definition: OTWallet.cpp:1427
EXPORT std::shared_ptr< OTSymmetricKey > getOrCreateExtraKey(const std::string &str_KeyID, const std::string *pReason=nullptr)
Definition: OTWallet.cpp:1368
virtual EXPORT bool DisplayStatistics(OTString &contents) const
Definition: OTAccount.cpp:728
EXPORT void GetIdentifier(OTIdentifier &theIdentifier) const
EXPORT OTAccount * GetAccountPartialMatch(std::string PARTIAL_ID)
Definition: OTWallet.cpp:613
std::map< std::string, std::shared_ptr< OTSymmetricKey > > mapOfSymmetricKeys
Definition: OTWallet.hpp:164
EXPORT const OTIdentifier & GetAssetTypeID() const
Definition: OTAccount.cpp:449
EXPORT OTAssetContract * GetAssetContract(const OTIdentifier &theContractID)
Definition: OTWallet.cpp:1203
virtual EXPORT bool DisplayStatistics(OTString &strContents) const
Definition: OTContract.cpp:999
OTString m_strDataFolder
Definition: OTWallet.hpp:361
static EXPORT const char * PathSeparator()
Definition: OTLog.cpp:408
EXPORT void AddServerContract(const OTServerContract &theContract)
Definition: OTWallet.cpp:725
EXPORT void GetName(OTString &strName) const
Definition: OTContract.hpp:360
EXPORT void AddPendingWithdrawal(const Purse &thePurse)
Definition: OTWallet.cpp:232
EXPORT void zeroMemory()
Definition: OTPassword.cpp:281
EXPORT bool SavePseudonymWallet(OTString &strOutput) const
bool VerifyAssetAccount(const OTPseudonym &theNym, OTAccount &theAcct, const OTIdentifier &SERVER_ID, const OTString &strAcctID, const char *szFuncName=nullptr)
Definition: OTWallet.cpp:777
EXPORT void GetPrivateCredentials(OTString &strCredList, OTString::Map *pmapCredFiles=nullptr)
EXPORT OTPseudonym * GetNymByIDPartialMatch(std::string PARTIAL_ID)
Definition: OTWallet.cpp:291
OTLOG_IMPORT OTLogStream otOut
EXPORT void AddAssetContract(const OTAssetContract &theContract)
Definition: OTWallet.cpp:752
EXPORT OTPseudonym * GetOrLoadNym(const OTIdentifier &NYM_ID, bool bChecking=false, const char *szFuncName=nullptr, const OTPasswordData *pPWData=nullptr)
Definition: OTWallet.cpp:1073
EXPORT void DisplayStatistics(OTString &strOutput)
Definition: OTWallet.cpp:457
EXPORT bool GetAccount(int32_t iIndex, OTIdentifier &THE_ID, OTString &THE_NAME)
Definition: OTWallet.cpp:431
OTString & GetNymName()
EXPORT OTAccount * GetIssuerAccount(const OTIdentifier &theAssetTypeID)
Definition: OTWallet.cpp:649
EXPORT int32_t GetAssetTypeCount()
Definition: OTWallet.cpp:341
EXPORT void Concatenate(const char *arg,...)
Definition: OTString.cpp:1334
EXPORT bool IsIssuer() const
Definition: OTAccount.cpp:1036
EXPORT bool WriteArmoredString(OTString &strOutput, const std::string str_type, bool bEscaped=false) const
static EXPORT const OTString & Contract()
Definition: OTFolders.cpp:303
EXPORT bool SignContractWithFirstNymOnList(OTContract &theContract)
Definition: OTWallet.cpp:252
EXPORT bool DecodeIfArmored(bool escapedIsAllowed=true)
Definition: OTString.cpp:1212
EXPORT bool Exists() const
Definition: OTString.cpp:1035
EXPORT bool SetString(const OTString &theData, bool bLineBreaks=true)
static EXPORT std::shared_ptr< OTCachedKey > It(OTIdentifier *pIdentifier=nullptr)
EXPORT bool RemoveAssetContract(const OTIdentifier &theTargetID)
Definition: OTWallet.cpp:1131
EXPORT bool RemoveNym(const OTIdentifier &theTargetID)
Definition: OTWallet.cpp:1101
EXPORT std::shared_ptr< OTSymmetricKey > getExtraKey(const std::string &str_id)
Definition: OTWallet.cpp:1530
EXPORT void Format(const char *fmt,...)
Definition: OTString.cpp:1319
void RemovePendingWithdrawal()
Definition: OTWallet.cpp:245
EXPORT bool addExtraKey(const std::string &str_id, std::shared_ptr< OTSymmetricKey > pKey)
Definition: OTWallet.cpp:1546
static EXPORT bool Decrypt(const OTString &strKey, OTString &strCiphertext, OTString &strOutput, const OTString *pstrDisplay=nullptr, const OTPassword *pAlreadyHavePW=nullptr)
static EXPORT const OTString & Credential()
Definition: OTFolders.cpp:307
EXPORT bool VerifyOwner(const OTPseudonym &candidate) const
Definition: OTAccount.cpp:463
EXPORT bool ConvertNymToCachedKey(OTPseudonym &theNym)
Definition: OTWallet.cpp:2066
EXPORT void Set(const char *data, uint32_t enforcedMaxLength=0)
Definition: OTString.cpp:1055
EXPORT int32_t GetServerCount()
Definition: OTWallet.cpp:336
EXPORT std::string QueryPlainString(std::string strFolder, std::string oneStr="", std::string twoStr="", std::string threeStr="")
Definition: OTStorage.cpp:728
EXPORT OTPseudonym * GetNymByID(const OTIdentifier &NYM_ID)
Definition: OTWallet.cpp:275
static EXPORT bool Encrypt(const OTString &strKey, const OTString &strPlaintext, OTString &strOutput, const OTString *pstrDisplay=nullptr, bool bBookends=true, const OTPassword *pAlreadyHavePW=nullptr)
static EXPORT bool LoadEncodedTextField(irr::io::IrrXMLReader *&xml, OTASCIIArmor &ascOutput)
EXPORT bool LoadWallet(const char *szFilename=nullptr)
Definition: OTWallet.cpp:1617
EXPORT bool RemoveAccount(const OTIdentifier &theTargetID)
Definition: OTWallet.cpp:1182
EXPORT bool Decrypt_ByKeyID(const std::string &key_id, const OTString &strCiphertext, OTString &strOutput, const OTString *pstrDisplay=nullptr)
Definition: OTWallet.cpp:1508
#define OT_PW_DISPLAY
Definition: OTCallback.hpp:164
#define OT_ASSERT(x)
Definition: Assert.hpp:150
EXPORT OTAssetContract * GetAssetContractPartialMatch(std::string PARTIAL_ID)
Definition: OTWallet.cpp:1218
EXPORT bool HasPublicKey()
#define OT_ASSERT_MSG(x, s)
Definition: Assert.hpp:155
OTLOG_IMPORT OTLogStream otInfo
virtual EXPORT bool LoadContract()
EXPORT OTAccount * LoadAccount(const OTPseudonym &theNym, const OTIdentifier &ACCT_ID, const OTIdentifier &SERVER_ID, const char *szFuncName=nullptr)
Definition: OTWallet.cpp:863
EXPORT bool CompareID(const OTIdentifier &theIdentifier) const
static EXPORT OTPseudonym * LoadPrivateNym(const OTIdentifier &NYM_ID, bool bChecking=false, const OTString *pstrName=nullptr, const char *szFuncName=nullptr, const OTPasswordData *pPWData=nullptr, const OTPassword *pImportPassword=nullptr)
EXPORT bool SaveWallet(const char *szFilename=nullptr)
Definition: OTWallet.cpp:1566
virtual EXPORT void GetIdentifier(OTIdentifier &theIdentifier) const
Definition: OTContract.cpp:317
#define OT_FAIL
Definition: Assert.hpp:139
EXPORT bool HasPrivateKey()
OTLOG_IMPORT OTLogStream otWarn
OTString m_strFilename
Definition: OTWallet.hpp:360
EXPORT const char * Get() const
Definition: OTString.cpp:1045
EXPORT OTWallet()
Definition: OTWallet.cpp:157
virtual EXPORT bool SignContract(const OTPseudonym &theNym, const OTPasswordData *pPWData=nullptr)
Definition: OTContract.cpp:484
OTLOG_IMPORT OTLogStream otErr
virtual bool VerifyAccount(const OTPseudonym &theNym)
EXPORT void DisplayStatistics(OTString &strOutput)
EXPORT const OTIdentifier & GetConstID() const
virtual EXPORT bool VerifyContract()
Definition: OTContract.cpp:330
EXPORT bool GetServer(int32_t iIndex, OTIdentifier &THE_ID, OTString &THE_NAME)
Definition: OTWallet.cpp:377
EXPORT bool Exists(std::string strFolder, std::string oneStr="", std::string twoStr="", std::string threeStr="")
Definition: OTStorage.cpp:584
EXPORT bool IsEmpty() const
Definition: OTData.cpp:291
EXPORT OTServerContract * GetServerContractPartialMatch(std::string PARTIAL_ID)
Definition: OTWallet.cpp:685
EXPORT bool GetString(OTString &theData, bool bLineBreaks=true) const
EXPORT bool Savex509CertAndPrivateKey(bool bCreateFile=true, const OTString *pstrReason=nullptr)
EXPORT OTServerContract * GetServerContract(const OTIdentifier &SERVER_ID)
Definition: OTWallet.cpp:667
EXPORT size_t GetMasterCredentialCount() const
EXPORT int32_t GetNymCount()
Definition: OTWallet.cpp:331
static EXPORT OTAccount * LoadExistingAccount(const OTIdentifier &accountId, const OTIdentifier &serverId)
Definition: OTAccount.cpp:480
static EXPORT bool CreateNewKey(OTString &strOutput, const OTString *pstrDisplay=nullptr, const OTPassword *pAlreadyHavePW=nullptr)
EXPORT void AddNym(const OTPseudonym &theNym)
Definition: OTWallet.cpp:523
virtual EXPORT void Release()
Definition: OTString.cpp:765
bool SaveContract(OTString &strContract)
Definition: OTWallet.cpp:1252
const OTIdentifier & GetRealServerID() const
EXPORT void AddAccount(const OTAccount &theAcct)
Definition: OTWallet.cpp:561
EXPORT OTPseudonym * GetOrLoadPublicNym(const OTIdentifier &NYM_ID, const char *szFuncName=nullptr)
Definition: OTWallet.cpp:910
EXPORT bool RemoveServerContract(const OTIdentifier &theTargetID)
Definition: OTWallet.cpp:1155
virtual bool SaveContractWallet(std::ofstream &ofs) const =0
OTLOG_IMPORT OTLogStream otLog5
EXPORT void SetName(const OTString &strName)
Definition: OTContract.hpp:364
EXPORT bool GetAssetType(int32_t iIndex, OTIdentifier &THE_ID, OTString &THE_NAME)
Definition: OTWallet.cpp:404