Open-Transactions  0.93.0-ge03d287
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
Purse.cpp
Go to the documentation of this file.
1 /************************************************************
2  *
3  * Purse.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 "Purse.hpp"
136 #include "Token.hpp"
137 
138 #include "../core/crypto/OTSymmetricKey.hpp"
139 #include "../core/crypto/OTCachedKey.hpp"
140 #include "../core/crypto/OTEnvelope.hpp"
141 #include "../core/crypto/OTNymOrSymmetricKey.hpp"
142 #include "../core/crypto/OTPassword.hpp"
143 #include "../core/util/OTFolders.hpp"
144 #include "../core/OTLog.hpp"
145 #include "../core/OTStorage.hpp"
146 
147 #include <irrxml/irrXML.hpp>
148 
149 namespace opentxs
150 {
151 
152 typedef std::map<std::string, Token*> mapOfTokenPointers;
153 
154 bool Purse::GetNymID(OTIdentifier& theOutput) const
155 {
156  bool bSuccess = false;
157  theOutput.Release();
158 
159  if (IsPasswordProtected()) {
160  bSuccess = false; // optimizer will remove automatically anyway, I
161  // assume. Might as well have it here for clarity.
162  }
163  else if (IsNymIDIncluded() && !m_UserID.IsEmpty()) {
164  bSuccess = true;
165  theOutput = m_UserID;
166  }
167  else if (!m_UserID.IsEmpty()) {
168  bSuccess = true;
169  theOutput = m_UserID;
170  }
171 
172  return bSuccess;
173 }
174 
175 // Retrieves the passphrase for this purse (which is cached by its master key.)
176 // Prompts the user to enter his actual passphrase, if necessary to unlock it.
177 // (May not need unlocking yet -- there is a timeout.)
178 //
179 bool Purse::GetPassphrase(OTPassword& theOutput, const char* szDisplay)
180 {
181  const char* szFunc = "Purse::GetPassphrase";
182 
183  if (!IsPasswordProtected()) {
184  otOut << szFunc
185  << ": Failed: this purse isn't even password-protected.\n";
186  return false;
187  }
188 
189  std::shared_ptr<OTCachedKey> pCachedKey(GetInternalMaster());
190  if (!pCachedKey) OT_FAIL;
191 
192  const OTString strReason((nullptr == szDisplay) ? szFunc : szDisplay);
193 
194  const bool bGotMasterPassword = pCachedKey->GetMasterPassword(
195  pCachedKey, theOutput, strReason.Get()); // bVerifyTwice=false
196  return bGotMasterPassword;
197 }
198 
199 // Don't ever deal with m_pCachedKey directly (except before it's been created /
200 // loaded.)
201 // When you actually USE m_pCachedKey, you want to use this function instead.
202 // (It will save the user from having the type the password, for example, 50
203 // times in 1 minute,
204 // by using the cached one.)
205 
206 // stores the passphrase for the symmetric key.
207 std::shared_ptr<OTCachedKey> Purse::GetInternalMaster()
208 {
209 
210  if (!IsPasswordProtected() ||
211  (!m_pCachedKey)) // this second half of the logic should never happen.
212  {
213  otOut << __FUNCTION__
214  << ": Failed: no internal master key exists, in this purse.\n";
215  return std::shared_ptr<OTCachedKey>();
216  }
217 
218  if (!m_pCachedKey->IsGenerated()) // should never happen, since the purse IS
219  // password-protected... then where's the
220  // master key?
221  {
222  otOut << __FUNCTION__
223  << ": Error: internal master key has not yet been generated.\n";
224  return std::shared_ptr<OTCachedKey>();
225  }
226 
227  // By this point we know the purse is password protected, the internal
228  // master key
229  // exists (not nullptr) and it's been properly generated, so we won't be
230  // inadvertantly sticking
231  // a copy of it on the CachedKey map indexed to some nonexistent ID for an
232  // ungenerated key.
233  // The caller will be forced to make sure the master key is real and
234  // generated, before passing
235  // it in here where it could get copied.
236  //
237  // Why is that important? BECAUSE THE COPY is all the caller will ever
238  // actually use! So if it's
239  // not ENTIRELY loaded up properly BEFORE it's copied, the caller will never
240  // see the properly
241  // loaded version of that master key.
242  //
243  return OTCachedKey::It(*m_pCachedKey); // here we return a cached copy of
244  // the master key (so it's available
245  // between instances of this purse.)
246 }
247 
248 // INTERNAL KEY: For adding a PASSPHRASE to a PURSE.
249 //
250 // What if you DON'T want to encrypt the purse to your Nym??
251 // What if you just want to use a passphrase instead?
252 // That's what these functions are for. OT just generates
253 // a symmetric key and stores it INSIDE THE PURSE. You set the
254 // passphrase for the symmetric key, and thereafter your
255 // experience is one of a password-protected purse.
256 //
258 {
259  if (IsPasswordProtected() ||
260  (nullptr != m_pSymmetricKey) || // GetInternalKey())
261  (m_pCachedKey)) {
262  otOut << __FUNCTION__
263  << ": Failed: internal Key or master key already exists. "
264  "Or IsPasswordProtected was true.\n";
265  return false;
266  }
267 
268  if (!IsEmpty()) {
269  otOut << __FUNCTION__
270  << ": Failed: The purse must be EMPTY before you create a "
271  "new symmetric key, internal to that purse. (For the purposes "
272  "of "
273  "adding a passphrase to the purse, normally.) Otherwise I "
274  "would have "
275  "to loop through all the tokens and re-assign ownership of "
276  "each one. "
277  "Instead, I'm just going to return false. That's easier.\n";
278  return false;
279  }
280 
281  // OTSymmetricKey * m_pSymmetricKey; // If this purse contains its own
282  // symmetric key (instead of using an owner Nym)...
283  // OTCachedKey * m_pCachedKey; // ...then it will have a master
284  // key as well, for unlocking that symmetric key, and managing timeouts.
285 
286  // m_pSymmetricKey and m_pCachedKey are both explicitly checked for nullptr
287  // (above.)
288  // Therefore we have to instantiate them both now.
289  //
290  // We'll do the Master key first, since we need the passphrase from that, in
291  // order to
292  // create the symmetric key.
293  //
294  OTPassword thePassphrase;
295  const OTString strDisplay(
296  "Enter the new passphrase for this new password-protected "
297  "purse."); // todo internationalization / hardcoding.
298 
299  // thePassphrase and m_pCachedKey are BOTH output from the below function.
300  //
302  thePassphrase,
303  strDisplay.Get()); // int32_t nTimeoutSeconds=OT_MASTER_KEY_TIMEOUT)
304 
305  if ((!m_pCachedKey) || !m_pCachedKey->IsGenerated()) // This one is
306  // unnecessary because
307  // CreateMasterPassword
308  // already checks it.
309  // todo optimize.
310  {
311  otOut << __FUNCTION__
312  << ": Failed: While calling OTCachedKey::CreateMasterPassword.\n";
313  return false;
314  }
315 
317  new OTSymmetricKey(thePassphrase); // Creates the symmetric key here
318  // based on the passphrase from
319  // purse's master key.
320  OT_ASSERT(nullptr != m_pSymmetricKey);
321 
322  if (!m_pSymmetricKey->IsGenerated()) {
323  otOut << __FUNCTION__ << ": Failed: generating m_pSymmetricKey.\n";
324  delete m_pSymmetricKey;
325  m_pSymmetricKey = nullptr;
326  m_pCachedKey.reset();
327  return false;
328  }
329 
330  m_UserID.Release();
331  m_bIsNymIDIncluded = false;
332 
333  otWarn << __FUNCTION__
334  << ": Successfully created a purse's internal key.\n";
335 
336  m_bPasswordProtected = true;
337 
338  std::shared_ptr<OTCachedKey> pCachedMaster(Purse::GetInternalMaster());
339  if (!pCachedMaster)
340  otErr << __FUNCTION__
341  << ": Failed trying to cache the master key for this purse.\n";
342 
343  return true;
344 }
345 
346 // Take all the tokens from a purse and add them to this purse.
347 // Don't allow duplicates.
348 //
349 bool Purse::Merge(const OTPseudonym& theSigner,
350  OTNym_or_SymmetricKey theOldNym, // must be private, if a nym.
351  OTNym_or_SymmetricKey theNewNym, // must be private, if a nym.
352  Purse& theNewPurse)
353 {
354  const char* szFunc = "Purse::Merge";
355 
356  mapOfTokenPointers theMap;
357 
358  while (Count() > 0) {
359  Token* pToken = Pop(theOldNym); // must be private, if a Nym.
360  OT_ASSERT_MSG(nullptr != pToken,
361  "Purse::Merge: Assert: nullptr != Pop(theOldNym) \n");
362 
363  const OTASCIIArmor& ascTokenID = pToken->GetSpendable();
364 
365  std::list<mapOfTokenPointers::iterator> listOfTokenMapIterators;
366 
367  // I just popped a Token off of *this. Let's see if it's in my temporary
368  // map...
369  // If it's already there, then just delete it (duplicate).
370  //
371  for (auto it(theMap.begin()); it != theMap.end(); ++it) {
372  Token* pTempToken = it->second;
373  OT_ASSERT(nullptr != pTempToken);
374 
375  const OTASCIIArmor& ascTempTokenID = pTempToken->GetSpendable();
376 
377  // It's already there. Delete the one that's already there.
378  // (That way we can add it after, whether it was there originally or
379  // not.)
380  if (ascTempTokenID == ascTokenID) {
381  listOfTokenMapIterators.push_back(it);
382  // theMap.erase(it);
383  // delete pTempToken;
384  // pTempToken = nullptr;
385  // break; // In case there are multiple duplicates, not just
386  // one.
387  }
388  }
389  while (!listOfTokenMapIterators.empty()) {
390  Token* pTempToken = (listOfTokenMapIterators.back())->second;
391  theMap.erase(listOfTokenMapIterators.back());
392  delete pTempToken;
393  pTempToken = nullptr;
394  listOfTokenMapIterators.pop_back();
395  }
396 
397  // Now we know there aren't any duplicates on the temporary map, let's
398  // add the token to it.
399  std::string theKey = ascTokenID.Get();
400  theMap.insert(std::pair<std::string, Token*>(theKey, pToken));
401  }
402  // At this point, all of the tokens on *this have been popped, and added
403  // to the temporary map as token pointers, with any duplicates removed.
404 
405  // Basically now I just want to do the exact same thing with the other
406  // purse...
407  //
408  while (theNewPurse.Count() > 0) {
409  Token* pToken = theNewPurse.Pop(theNewNym);
411  nullptr != pToken,
412  "Purse::Merge: Assert: nullptr != theNewPurse.Pop(theNewNym) \n");
413 
414  const OTASCIIArmor& ascTokenID = pToken->GetSpendable();
415 
416  std::list<mapOfTokenPointers::iterator> listOfTokenMapIterators;
417 
418  // I just popped a Token off of theNewPurse. Let's see if it's in my
419  // temporary map...
420  // If it's already there, then just delete it (it's a duplicate.)
421  for (auto it(theMap.begin()); it != theMap.end(); ++it) {
422  Token* pTempToken = it->second;
423  OT_ASSERT(nullptr != pTempToken);
424 
425  const OTASCIIArmor& ascTempTokenID = pTempToken->GetSpendable();
426 
427  // It's already there. Delete the one that's already there.
428  // (That way we can add it after, whether it was there originally or
429  // not.)
430  if (ascTempTokenID == ascTokenID) {
431  listOfTokenMapIterators.push_back(it);
432  // theMap.erase(it);
433  // delete pTempToken;
434  // pTempToken = nullptr;
435  // break; // In case there are multiple duplicates, not just
436  // one.
437  }
438  }
439  while (!listOfTokenMapIterators.empty()) {
440  Token* pTempToken = (listOfTokenMapIterators.back())->second;
441  theMap.erase(listOfTokenMapIterators.back());
442  delete pTempToken;
443  pTempToken = nullptr;
444  listOfTokenMapIterators.pop_back();
445  }
446  // Now we KNOW there aren't any duplicates on the temporary map, so
447  // let's
448  // add the token to it...
449  //
450  std::string theKey = ascTokenID.Get();
451  theMap.insert(std::pair<std::string, Token*>(theKey, pToken));
452 
453  //
454  // SINCE THE new purse is being MERGED into the old purse, we don't have
455  // to re-assign ownership
456  // of any of the old tokens. But we DO need to re-assign ownership of
457  // the NEW tokens that are being
458  // merged in. We reassign them from New ==> TO OLD. (And we only bother
459  // if they aren't the same Nym.)
460  //
461  // if (!theNewNym.CompareID(theOldNym)) // Not the same
462  // Nym!!
463  //
464  // UPDATE: the above line was moved INSIDE OTToken::ReassignOwnership,
465  // FYI.
466  //
467  if (false ==
468  pToken->ReassignOwnership(theNewNym, // must be private, if a Nym.
469  theOldNym)) // can be public, if a Nym.
470  {
471  otErr << szFunc << ": Error: Failed while attempting to re-assign "
472  "ownership of token during purse merge.\n";
473  }
474  else {
475  otWarn << szFunc << ": FYI: Success re-assigning ownership of "
476  "token during purse merge.\n";
477 
478  pToken->ReleaseSignatures();
479  pToken->SignContract(theSigner);
480  pToken->SaveContract();
481  }
482  }
483 
484  // At this point, all of the tokens on *this (old purse) AND theNewPurse
485  // have been popped, and added
486  // to the temporary map as token pointers, with any duplicates removed.
487  // Also, the tokens on the New Purse have been reassigned (from theNewNym as
488  // owner, to theOldNym as
489  // owner) and each has been signed and saved properly, using the old Nym.
490 
491  // Next, we loop through theMap, and Push ALL of those tokens back onto
492  // *this. (The old purse.)
493 
494  bool bSuccess = true;
495 
496  for (auto& it : theMap) {
497  Token* pToken = it.second;
498  OT_ASSERT(nullptr != pToken);
499 
500  bool bPush = Push(theOldNym, // can be public, if a Nym.
501  *pToken); // The purse makes it's own copy of
502  // the token, into string form.
503 
504  if (!bPush) {
505  otErr << szFunc << ": Error: Failure pushing token into purse.\n";
506  bSuccess = false;
507  }
508  // Notice we don't break here if 1 token fails -- we loop through them
509  // all.
510  // Maybe shouldn't? Seems right somehow.
511  }
512 
513  // Next I clean up all the tokens out of the temporary map, since they will
514  // leak otherwise.
515  //
516  while (!theMap.empty()) {
517  Token* pToken = theMap.begin()->second;
518  OT_ASSERT(nullptr != pToken);
519 
520  delete pToken;
521  pToken = nullptr;
522 
523  theMap.erase(theMap.begin());
524  }
525 
526  // Note: Caller needs to re-sign and re-save this purse, since we aren't
527  // doing it
528  // internally here.
529 
530  return bSuccess;
531 }
532 
533 // static -- class factory.
534 //
536  const OTIdentifier& SERVER_ID,
537  const OTIdentifier& ASSET_ID)
538 {
539  Purse* pPurse = nullptr;
540  if (strFirstLine.Contains("-----BEGIN SIGNED PURSE-----")) // this string is
541  // 28 chars long.
542  // todo
543  // hardcoding.
544  {
545  pPurse = new Purse(SERVER_ID, ASSET_ID);
546  OT_ASSERT(nullptr != pPurse);
547  }
548  return pPurse;
549 }
550 
552  const OTIdentifier& SERVER_ID)
553 {
554  Purse* pPurse = nullptr;
555  if (strFirstLine.Contains("-----BEGIN SIGNED PURSE-----")) // this string is
556  // 28 chars long.
557  // todo
558  // hardcoding.
559  {
560  pPurse = new Purse(SERVER_ID);
561  OT_ASSERT(nullptr != pPurse);
562  }
563  return pPurse;
564 }
565 
567 {
568  Purse* pPurse = nullptr;
569  if (strFirstLine.Contains("-----BEGIN SIGNED PURSE-----")) // this string is
570  // 28 chars long.
571  // todo
572  // hardcoding.
573  {
574  pPurse = new Purse();
575  OT_ASSERT(nullptr != pPurse);
576  }
577  return pPurse;
578 }
579 
580 // static -- class factory.
581 //
582 // Checks the serverID / AssetID, so you don't have to.
583 //
584 Purse* Purse::PurseFactory(OTString strInput, const OTIdentifier& SERVER_ID,
585  const OTIdentifier& ASSET_ID)
586 {
587  OTString strContract, strFirstLine; // output for the below function.
588  const bool bProcessed =
589  OTContract::DearmorAndTrim(strInput, strContract, strFirstLine);
590 
591  if (bProcessed) {
592  Purse* pPurse =
593  Purse::LowLevelInstantiate(strFirstLine, SERVER_ID, ASSET_ID);
594 
595  // The string didn't match any of the options in the factory.
596  if (nullptr == pPurse) return nullptr;
597 
598  // Does the contract successfully load from the string passed in?
599  if (pPurse->LoadContractFromString(strContract)) {
600  const char* szFunc = "Purse::PurseFactory";
601  if (SERVER_ID != pPurse->GetServerID()) {
602  const OTString strServerID(SERVER_ID),
603  strPurseServerID(pPurse->GetServerID());
604  otErr << szFunc << ": Failure: ServerID on purse ("
605  << strPurseServerID << ") doesn't match expected "
606  "server ID (" << strServerID
607  << ").\n";
608  delete pPurse;
609  pPurse = nullptr;
610  }
611  else if (ASSET_ID != pPurse->GetAssetID()) {
612  const OTString strAssetID(ASSET_ID),
613  strPurseAssetID(pPurse->GetAssetID());
614  otErr << szFunc << ": Failure: AssetID on purse ("
615  << strPurseAssetID << ") doesn't match expected "
616  "asset ID (" << strAssetID
617  << ").\n";
618  delete pPurse;
619  pPurse = nullptr;
620  }
621  else
622  return pPurse;
623  }
624  else {
625  delete pPurse;
626  pPurse = nullptr;
627  }
628  }
629 
630  return nullptr;
631 }
632 
633 // Checks the serverID, so you don't have to.
634 //
635 Purse* Purse::PurseFactory(OTString strInput, const OTIdentifier& SERVER_ID)
636 {
637  OTString strContract, strFirstLine; // output for the below function.
638  const bool bProcessed =
639  OTContract::DearmorAndTrim(strInput, strContract, strFirstLine);
640 
641  if (bProcessed) {
642  Purse* pPurse = Purse::LowLevelInstantiate(strFirstLine, SERVER_ID);
643 
644  // The string didn't match any of the options in the factory.
645  if (nullptr == pPurse) return nullptr;
646 
647  // Does the contract successfully load from the string passed in?
648  if (pPurse->LoadContractFromString(strContract)) {
649  if (SERVER_ID != pPurse->GetServerID()) {
650  const OTString strServerID(SERVER_ID),
651  strPurseServerID(pPurse->GetServerID());
652  otErr << "Purse::PurseFactory"
653  << ": Failure: ServerID on purse (" << strPurseServerID
654  << ") doesn't match expected server ID (" << strServerID
655  << ").\n";
656  delete pPurse;
657  pPurse = nullptr;
658  }
659  else
660  return pPurse;
661  }
662  else {
663  delete pPurse;
664  pPurse = nullptr;
665  }
666  }
667 
668  return nullptr;
669 }
670 
672 {
673  // const char * szFunc = "Purse::PurseFactory";
674 
675  OTString strContract, strFirstLine; // output for the below function.
676  const bool bProcessed =
677  OTContract::DearmorAndTrim(strInput, strContract, strFirstLine);
678 
679  if (bProcessed) {
680  Purse* pPurse = Purse::LowLevelInstantiate(strFirstLine);
681 
682  // The string didn't match any of the options in the factory.
683  if (nullptr == pPurse) return nullptr;
684 
685  // Does the contract successfully load from the string passed in?
686  if (pPurse->LoadContractFromString(strContract))
687  return pPurse;
688  else
689  delete pPurse;
690  }
691 
692  return nullptr;
693 }
694 
695 // private, used by factory.
697  : ot_super()
698  ,
699  // m_ServerID(),
700  // m_AssetID(),
701  m_lTotalValue(0)
702  , m_bPasswordProtected(false)
703  , m_bIsNymIDIncluded(false)
704  , m_pSymmetricKey(nullptr)
705  , m_tLatestValidFrom(OT_TIME_ZERO)
706  , m_tEarliestValidTo(OT_TIME_ZERO)
707 {
708  InitPurse();
709 }
710 
711 Purse::Purse(const Purse& thePurse)
712  : ot_super()
713  , m_UserID()
714  , m_ServerID(thePurse.GetServerID())
715  , m_AssetID(thePurse.GetAssetID())
716  , m_lTotalValue(0)
717  , m_bPasswordProtected(false)
718  , m_bIsNymIDIncluded(false)
719  , m_pSymmetricKey(nullptr)
720  , m_tLatestValidFrom(OT_TIME_ZERO)
721  , m_tEarliestValidTo(OT_TIME_ZERO)
722 {
723  InitPurse();
724 }
725 
726 // Don't use this unless you really don't have the asset type handy.
727 // Perhaps you know you're about to read this purse from a string and you
728 // know the asset type is in there anyway. So you use this constructor.
729 Purse::Purse(const OTIdentifier& SERVER_ID)
730  : ot_super()
731  , m_ServerID(SERVER_ID)
732  , m_lTotalValue(0)
733  , m_bPasswordProtected(false)
734  , m_bIsNymIDIncluded(false)
735  , m_pSymmetricKey(nullptr)
736  , m_tLatestValidFrom(OT_TIME_ZERO)
737  , m_tEarliestValidTo(OT_TIME_ZERO)
738 {
739  InitPurse();
740 }
741 
742 Purse::Purse(const OTIdentifier& SERVER_ID, const OTIdentifier& ASSET_ID)
743  : ot_super()
744  , m_ServerID(SERVER_ID)
745  , m_AssetID(ASSET_ID)
746  , m_lTotalValue(0)
747  , m_bPasswordProtected(false)
748  , m_bIsNymIDIncluded(false)
749  , m_pSymmetricKey(nullptr)
750  , m_tLatestValidFrom(OT_TIME_ZERO)
751  , m_tEarliestValidTo(OT_TIME_ZERO)
752 {
753  InitPurse();
754 }
755 
756 Purse::Purse(const OTIdentifier& SERVER_ID, const OTIdentifier& ASSET_ID,
757  const OTIdentifier& USER_ID)
758  : ot_super()
759  , m_UserID(USER_ID)
760  , m_ServerID(SERVER_ID)
761  , m_AssetID(ASSET_ID)
762  , m_lTotalValue(0)
763  , m_bPasswordProtected(false)
764  , m_bIsNymIDIncluded(false)
765  , m_pSymmetricKey(nullptr)
766  , m_tLatestValidFrom(OT_TIME_ZERO)
767  , m_tEarliestValidTo(OT_TIME_ZERO)
768 {
769  InitPurse();
770 }
771 
773 {
774  m_strContractType.Set("PURSE");
775 
776  m_lTotalValue = 0;
777 
778  m_bPasswordProtected = false;
779  m_bIsNymIDIncluded = false;
780 }
781 
783 {
784  Release_Purse();
785 }
786 
788 {
789  // This sets m_lTotalValue to 0 already.
790  ReleaseTokens();
791  // m_lTotalValue = 0;
792 
793  m_bPasswordProtected = false;
794  m_bIsNymIDIncluded = false;
795 
796  // the Temp Nym is when a purse contains its own Nym, created just
797  // for that purse, so that it can be password protected instead of using
798  // one of the real Nyms in your wallet.
799  //
800  if (nullptr != m_pSymmetricKey) {
801  delete m_pSymmetricKey;
802  m_pSymmetricKey = nullptr;
803  }
804 
805  // if (m_pCachedKey)
806  // {
807  // delete m_pCachedKey;
808  // m_pCachedKey = nullptr;
809  // }
810 }
811 
813 {
814  Release_Purse();
815 
817 
818  InitPurse();
819 }
820 
821 /*
822  OTIdentifier m_UserID; // Optional
823  OTIdentifier m_ServerID; // Mandatory
824  OTIdentifier m_AssetID; // Mandatory
825  */
826 
828 {
829  return LoadPurse();
830 }
831 
832 bool Purse::LoadPurse(const char* szServerID, const char* szUserID,
833  const char* szAssetTypeID)
834 {
836 
837  if (!m_strFoldername.Exists())
839 
840  OTString strServerID(m_ServerID), strUserID(m_UserID),
841  strAssetTypeID(m_AssetID);
842 
843  if (nullptr != szServerID) strServerID = szServerID;
844  if (nullptr != szUserID) strUserID = szUserID;
845  if (nullptr != szAssetTypeID) strAssetTypeID = szAssetTypeID;
846 
847  if (!m_strFilename.Exists()) {
848  m_strFilename.Format("%s%s%s%s%s", strServerID.Get(),
849  OTLog::PathSeparator(), strUserID.Get(),
850  OTLog::PathSeparator(), strAssetTypeID.Get());
851  }
852 
853  const char* szFolder1name = OTFolders::Purse().Get(); // purse
854  const char* szFolder2name = strServerID.Get(); // purse/SERVER_ID
855  const char* szFolder3name = strUserID.Get(); // purse/SERVER_ID/USER_ID
856  const char* szFilename =
857  strAssetTypeID.Get(); // purse/SERVER_ID/USER_ID/ASSET_TYPE_ID
858 
859  if (false ==
860  OTDB::Exists(szFolder1name, szFolder2name, szFolder3name, szFilename)) {
861  otInfo << "Purse::LoadPurse: File does not exist: " << szFolder1name
862  << OTLog::PathSeparator() << szFolder2name
863  << OTLog::PathSeparator() << szFolder3name
864  << OTLog::PathSeparator() << szFilename << "\n";
865  return false;
866  }
867 
868  std::string strFileContents(
869  OTDB::QueryPlainString(szFolder1name, szFolder2name, szFolder3name,
870  szFilename)); // <=== LOADING FROM DATA STORE.
871 
872  if (strFileContents.length() < 2) {
873  otErr << "Purse::LoadPurse: Error reading file: " << szFolder1name
874  << OTLog::PathSeparator() << szFolder2name
875  << OTLog::PathSeparator() << szFolder3name
876  << OTLog::PathSeparator() << szFilename << "\n";
877  return false;
878  }
879 
880  // NOTE: No need here to deal with OT ARMORED file format, since
881  // LoadContractFromString
882  // already handles it internally.
883 
884  OTString strRawFile(strFileContents.c_str());
885 
886  return LoadContractFromString(strRawFile);
887 }
888 
889 bool Purse::SavePurse(const char* szServerID, const char* szUserID,
890  const char* szAssetTypeID)
891 {
893 
894  if (!m_strFoldername.Exists())
896 
897  OTString strServerID(m_ServerID), strUserID(m_UserID),
898  strAssetTypeID(m_AssetID);
899 
900  if (nullptr != szServerID) strServerID = szServerID;
901  if (nullptr != szUserID) strUserID = szUserID;
902  if (nullptr != szAssetTypeID) strAssetTypeID = szAssetTypeID;
903 
904  if (!m_strFilename.Exists()) {
905  m_strFilename.Format("%s%s%s%s%s", strServerID.Get(),
906  OTLog::PathSeparator(), strUserID.Get(),
907  OTLog::PathSeparator(), strAssetTypeID.Get());
908  }
909 
910  const char* szFolder1name = OTFolders::Purse().Get(); // purse
911  const char* szFolder2name = strServerID.Get(); // purse/SERVER_ID
912  const char* szFolder3name = strUserID.Get(); // purse/SERVER_ID/USER_ID
913  const char* szFilename =
914  strAssetTypeID.Get(); // purse/SERVER_ID/USER_ID/ASSET_TYPE_ID
915 
916  OTString strRawFile;
917 
918  if (!SaveContractRaw(strRawFile)) {
919  otErr << "Purse::SavePurse: Error saving Pursefile (to string):\n"
920  << szFolder1name << OTLog::PathSeparator() << szFolder2name
921  << OTLog::PathSeparator() << szFolder3name
922  << OTLog::PathSeparator() << szFilename << "\n";
923  return false;
924  }
925 
926  OTString strFinal;
927  OTASCIIArmor ascTemp(strRawFile);
928 
929  if (false ==
930  ascTemp.WriteArmoredString(strFinal, m_strContractType.Get())) {
931  otErr << "Purse::SavePurse: Error saving Pursefile (failed writing "
932  "armored string):\n" << szFolder1name << OTLog::PathSeparator()
933  << szFolder2name << OTLog::PathSeparator() << szFolder3name
934  << OTLog::PathSeparator() << szFilename << "\n";
935  return false;
936  }
937 
938  bool bSaved = OTDB::StorePlainString(
939  strFinal.Get(), szFolder1name, szFolder2name, szFolder3name,
940  szFilename); // <=== SAVING TO DATA STORE.
941  if (!bSaved) {
942  otErr << "Purse::SavePurse: Error writing to file: " << szFolder1name
943  << OTLog::PathSeparator() << szFolder2name
944  << OTLog::PathSeparator() << szFolder3name
945  << OTLog::PathSeparator() << szFilename << "\n";
946  return false;
947  }
948 
949  return true;
950 }
951 
952 void Purse::UpdateContents() // Before transmission or serialization, this is
953  // where the Purse saves its contents
954 {
955  const OTString SERVER_ID(m_ServerID), USER_ID(m_UserID),
956  ASSET_TYPE_ID(m_AssetID);
957 
958  int64_t lValidFrom = OTTimeGetSecondsFromTime(m_tLatestValidFrom);
959  int64_t lValidTo = OTTimeGetSecondsFromTime(m_tEarliestValidTo);
960 
961  // I release this because I'm about to repopulate it.
963  m_xmlUnsigned.Concatenate("<?xml version=\"%s\"?>\n\n", "1.0");
965  "<purse version=\"%s\"\n"
966  " totalValue=\"%" PRId64 "\"\n" // Total value of all the tokens within.
967  " validFrom=\"%" PRId64
968  "\"\n" // Latest "valid from" date of all tokens contained.
969  " validTo=\"%" PRId64
970  "\"\n" // Earliest "valid to" date of all tokens contained.
971  " isPasswordProtected=\"%s\"\n"
972  " isNymIDIncluded=\"%s\"\n"
973  " userID=\"%s\"\n" // UserID is optional.
974  " assetTypeID=\"%s\"\n" // assetTypeID required.
975  " serverID=\"%s\">\n\n", // serverID is required.
976  m_strVersion.Get(),
977  m_lTotalValue, lValidFrom, lValidTo,
978  m_bPasswordProtected ? "true" : "false",
979  m_bIsNymIDIncluded ? "true" : "false",
980 
981  // USER_ID / NYM_ID of purse owner.
982  // IF a real NymID (from the user's wallet) is listed in the purse
983  // (which is
984  // optional--user's choice) we attach that NymID here...
985  //
987  !m_UserID.IsEmpty()) // (Provided that the ID even exists, of course.)
988  ? // =====>
989  USER_ID.Get()
990  : "", // Then print the ID (otherwise print an empty string.)
991  (!m_AssetID.IsEmpty()) ? ASSET_TYPE_ID.Get()
992  : "", // (Should never actually be empty.) todo:
993  // Change this to just the Get()
994  (!m_ServerID.IsEmpty()) ? SERVER_ID.Get()
995  : "" // (Should never actually be empty.) todo:
996  // Change this to just the Get()
997  );
998 
999  // Save the Internal Symmetric Key here (if there IS one.)
1000  // (Some Purses own their own internal Symmetric Key, in order to "password
1001  // protect" the purse.)
1002  //
1003  if (m_bPasswordProtected) {
1004  if (!m_pCachedKey)
1005  otErr
1006  << __FUNCTION__
1007  << ": Error: m_pCachedKey is unexpectedly nullptr, even though "
1008  "m_bPasswordProtected is true!\n";
1009  else if (nullptr == m_pSymmetricKey)
1010  otErr << __FUNCTION__ << ": Error: m_pSymmetricKey is unexpectedly "
1011  "nullptr, even though "
1012  "m_bPasswordProtected is true!\n";
1013  else // m_pCachedKey and m_pSymmetricKey are good pointers. (Or at
1014  // least, not-null.)
1015  {
1016  if (!m_pCachedKey->IsGenerated())
1017  otErr << __FUNCTION__ << ": Error: m_pCachedKey wasn't a "
1018  "generated key! Even though "
1019  "m_bPasswordProtected is true.\n";
1020  else if (!m_pSymmetricKey->IsGenerated())
1021  otErr << __FUNCTION__ << ": Error: m_pSymmetricKey wasn't a "
1022  "generated key! Even though "
1023  "m_bPasswordProtected is true.\n";
1024  else {
1025  OTASCIIArmor ascCachedKey, ascSymmetricKey;
1026 
1027  if (!m_pCachedKey->SerializeTo(ascCachedKey) ||
1028  !ascCachedKey.Exists() ||
1029  !m_pSymmetricKey->SerializeTo(ascSymmetricKey) ||
1030  !ascSymmetricKey.Exists())
1031  otErr << __FUNCTION__
1032  << ": Error: m_pCachedKey or m_pSymmetricKey failed "
1033  "trying to serialize to OTASCIIArmor.\n";
1034  else {
1035  // ascInternalKey is good by this point.
1036  // Therefore, let's serialize it...
1037 
1038  // By this point, ascInternalKey contains the Key itself.
1039  //
1041  "<cachedKey>\n%s</cachedKey>\n\n",
1042  ascCachedKey.Get()); // The "password" for the internal
1043  // symmetric key.
1044 
1046  "<internalKey>\n%s</internalKey>\n\n",
1047  ascSymmetricKey.Get()); // The internal symmetric key,
1048  // owned by the purse.
1049  // ascii-armored.
1050  }
1051  }
1052  }
1053  }
1054 
1055  for (int32_t i = 0; i < Count(); i++) {
1056  m_xmlUnsigned.Concatenate("<token>\n%s</token>\n\n",
1057  m_dequeTokens[i]->Get());
1058  }
1059 
1060  m_xmlUnsigned.Concatenate("</purse>\n");
1061 }
1062 
1064 {
1065  const char* szFunc = "Purse::ProcessXMLNode";
1066 
1067  const OTString strNodeName(xml->getNodeName());
1068 
1069  if (strNodeName.Compare("purse")) {
1070  m_strVersion = xml->getAttributeValue("version");
1071 
1072  const OTString strTotalValue = xml->getAttributeValue("totalValue");
1073 
1074  if (strTotalValue.Exists() && (atol(strTotalValue.Get()) > 0))
1075  m_lTotalValue = atol(strTotalValue.Get());
1076  else
1077  m_lTotalValue = 0;
1078 
1079  const OTString str_valid_from = xml->getAttributeValue("validFrom");
1080  const OTString str_valid_to = xml->getAttributeValue("validTo");
1081 
1082  if (str_valid_from.Exists()) {
1083  int64_t lValidFrom = str_valid_from.ToLong();
1084 
1086  }
1087  if (str_valid_to.Exists()) {
1088  int64_t lValidTo = str_valid_to.ToLong();
1089 
1091  }
1092 
1093  const OTString strPasswdProtected =
1094  xml->getAttributeValue("isPasswordProtected");
1095  m_bPasswordProtected = strPasswdProtected.Compare("true");
1096 
1097  const OTString strNymIDIncluded =
1098  xml->getAttributeValue("isNymIDIncluded");
1099  m_bIsNymIDIncluded = strNymIDIncluded.Compare("true");
1100 
1101  // TODO security: Might want to verify the server ID here, if it's
1102  // already set.
1103  // Just to make sure it's the one we were expecting.
1104  const OTString strServerID = xml->getAttributeValue("serverID");
1105  if (strServerID.Exists())
1106  m_ServerID.SetString(strServerID);
1107  else {
1108  m_ServerID.Release();
1109  otErr << szFunc
1110  << ": Failed loading serverID, when one was expected.\n";
1111  return (-1);
1112  }
1113 
1114  // TODO security: Might want to verify the asset ID here, if it's
1115  // already set.
1116  // Just to make sure it's the one we were expecting.
1117  const OTString strAssetTypeID = xml->getAttributeValue("assetTypeID");
1118  if (strAssetTypeID.Exists())
1119  m_AssetID.SetString(strAssetTypeID);
1120  else {
1121  m_AssetID.Release();
1122  otErr << szFunc
1123  << ": Failed loading assetTypeID, when one was expected.\n";
1124  return (-1);
1125  }
1126 
1127  const OTString strUserID =
1128  xml->getAttributeValue("userID"); // (May not exist.)
1129  if (m_bIsNymIDIncluded) // Nym ID **is** included. (It's optional. Even
1130  // if you use one, you don't have to list it.)
1131  {
1132  if (strUserID.Exists())
1133  m_UserID.SetString(strUserID);
1134  else {
1135  otErr << szFunc
1136  << ": Failed loading userID, when one was expected. "
1137  "(isNymIDIncluded was true.)\n";
1138  m_UserID.Release();
1139  return (-1);
1140  }
1141  }
1142  else // UserID SUPPOSED to be blank here. (Thus the Release.) Maybe
1143  // later,
1144  // we might consider trying to read it, in order to validate this.
1145  //
1146  m_UserID.Release(); // For now, just assume it's not there to be
1147  // read, and Release my own value to match it.
1148 
1149  otLog4 << szFunc << ": Loaded purse... ("
1150  << (m_bPasswordProtected ? "Password-protected"
1151  : "NOT password-protected")
1152  << ")\n ServerID: " << strServerID
1153  << "\n UserID: " << (m_bIsNymIDIncluded ? strUserID.Get() : "")
1154  << "\n Asset ID: " << strAssetTypeID << "\n----------\n";
1155 
1156  return 1;
1157  }
1158 
1159  // Sometimes you want the purse to have a passphrase on it, without being
1160  // attached to
1161  // one of your actual Nyms in your wallet. To accommodate this, OT creates a
1162  // symmetric key
1163  // and stashes it INSIDE the purse. This symmetric key can have whatever
1164  // passphrase you want.
1165  // There is also a master key attached, which allows for passphrase timeouts
1166  // on the symmetric key.
1167  // Therefore internalKey and cachedKey will both be attached to the purse
1168  // (or neither will be.)
1169  //
1170  else if (strNodeName.Compare("internalKey")) {
1171  if (!m_bPasswordProtected) // If we're NOT using the internal key, then
1172  // why am I in the middle of loading one
1173  // here?
1174  {
1175  otErr << szFunc << ": Error: Unexpected 'internalKey' data, "
1176  "since m_bPasswordProtected is set to false!\n";
1177  return (-1); // error condition
1178  }
1179 
1180  if (!m_UserID.IsEmpty()) // If the UserID isn't empty, then why am I in
1181  // the middle of loading an internal Key?
1182  {
1183  otErr << szFunc << ": Error: Unexpected 'internalKey' data, since "
1184  "m_UserID is not blank! "
1185  "(The UserID should have loaded before THIS "
1186  "node ever popped up...)\n";
1187  return (-1); // error condition
1188  }
1189 
1190  OTASCIIArmor ascValue;
1191 
1192  if (!OTContract::LoadEncodedTextField(xml, ascValue) ||
1193  !ascValue.Exists()) {
1194  otErr << szFunc << ": Error: Expected "
1195  << "internalKey"
1196  << " element to have text field.\n";
1197  return (-1); // error condition
1198  }
1199 
1200  // Let's see if the internal key is already loaded somehow... (Shouldn't
1201  // be...)
1202  //
1203  if (nullptr != m_pSymmetricKey) {
1204  otErr << szFunc
1205  << ": WARNING: While loading internal Key for a purse, "
1206  "noticed the pointer was ALREADY set! (I'm deleting old "
1207  "one to make room, "
1208  "and then allowing this one to load instead...)\n";
1209  // return (-1); // error condition
1210 
1211  delete m_pSymmetricKey;
1212  m_pSymmetricKey = nullptr;
1213  }
1214 
1215  // By this point, I've loaded up the string containing the encrypted
1216  // symmetric key.
1217  // I also know that m_bPasswordProtected is set to true, and I know that
1218  // m_pSymmetricKey is nullptr.
1219  //
1220  // (It's only now that I bother instantiating.)
1221  //
1222  OTSymmetricKey* pSymmetricKey = new OTSymmetricKey();
1223  OT_ASSERT_MSG(nullptr != pSymmetricKey, "Purse::ProcessXMLNode: "
1224  "Assert: nullptr != new "
1225  "OTSymmetricKey \n");
1226 
1227  // NOTE: In the event of any error, need to delete pSymmetricKey before
1228  // returning.
1229  // (Or it will leak.)
1230  //
1231  if (!pSymmetricKey->SerializeFrom(ascValue)) {
1232  otErr
1233  << szFunc
1234  << ": Error: While loading internal Key for a purse, failed "
1235  "serializing from stored string! (Failed loading purse.)\n";
1236  delete pSymmetricKey;
1237  pSymmetricKey = nullptr;
1238  return (-1);
1239  }
1240 
1241  // By this point, the symmetric key has loaded successfully from
1242  // storage.
1243 
1244  otWarn << szFunc << ": Successfully loaded a purse's internal key.\n";
1245 
1246  // No more worry about pSymmetricKey cleanup, now that this pointer is
1247  // set.
1248 
1249  m_pSymmetricKey = pSymmetricKey;
1250 
1251  return 1;
1252  }
1253  else if (strNodeName.Compare("cachedKey")) {
1254  if (!m_bPasswordProtected) // If we're NOT using the internal and master
1255  // keys, then why am I in the middle of
1256  // loading one here?
1257  {
1258  otErr << szFunc << ": Error: Unexpected 'cachedKey' data, "
1259  "since m_bPasswordProtected is set to false!\n";
1260  return (-1); // error condition
1261  }
1262 
1263  if (!m_UserID.IsEmpty()) // If the UserID isn't empty, then why am I in
1264  // the middle of loading an internal Key?
1265  {
1266  otErr << szFunc << ": Error: Unexpected 'cachedKey' data, since "
1267  "m_UserID is not blank!\n";
1268  return (-1); // error condition
1269  }
1270 
1271  OTASCIIArmor ascValue;
1272 
1273  if (!OTContract::LoadEncodedTextField(xml, ascValue) ||
1274  !ascValue.Exists()) {
1275  otErr << szFunc << ": Error: Expected "
1276  << "cachedKey"
1277  << " element to have text field.\n";
1278  return (-1); // error condition
1279  }
1280 
1281  // Let's see if the master key is already loaded somehow... (Shouldn't
1282  // be...)
1283  //
1284  if (m_pCachedKey) {
1285  otErr << szFunc
1286  << ": WARNING: While loading master Key for a purse, "
1287  "noticed the pointer was ALREADY set! (I'm deleting old "
1288  "one to make room, "
1289  "and then allowing this one to load instead...)\n";
1290  // return (-1); // error condition
1291 
1292  m_pCachedKey.reset();
1293  }
1294 
1295  // By this point, I've loaded up the string containing the encrypted
1296  // symmetric key.
1297  // I also know that m_bPasswordProtected is set to true, and I know that
1298  // m_pSymmetricKey is nullptr.
1299  //
1300  // (It's only now that I bother instantiating.)
1301  //
1302  std::shared_ptr<OTCachedKey> pCachedKey(new OTCachedKey(ascValue));
1303  // OT_ASSERT_MSG(nullptr != pCachedKey, "Purse::ProcessXMLNode:
1304  // Assert: nullptr != new OTCachedKey \n");
1305 
1306  // NOTE: In the event of any error, need to delete pCachedKey before
1307  // returning.
1308  // (Or it will leak.)
1309  //
1310  if (!pCachedKey->SerializeFrom(ascValue)) {
1311  otErr
1312  << szFunc
1313  << ": Error: While loading master Key for a purse, failed "
1314  "serializing from stored string! (Failed loading purse.)\n";
1315  // delete pCachedKey; pCachedKey = nullptr;
1316  return (-1);
1317  }
1318 
1319  // By this point, the symmetric key has loaded successfully from
1320  // storage.
1321 
1322  otWarn << szFunc << ": Successfully loaded a purse's master key.\n";
1323 
1324  // No more worry about pSymmetricKey cleanup, now that this pointer is
1325  // set.
1326 
1327  m_pCachedKey = pCachedKey;
1328 
1329  // NOTE: Hereafter, do NOT use m_pCachedKey directly.
1330  // Instead, use OTCachedKey::It(*m_pCachedKey) (So you deal with the
1331  // cached
1332  // version, and avoid forcing the user to re-type his passphrase more
1333  // than
1334  // necessary according to timeouts designed in OTCachedKey class.)
1335  //
1336  // In fact, don't even use that. Instead, I'll add an
1337  // Purse::GetPassphrase
1338  // method, which handles that for you.
1339 
1340  return 1;
1341  }
1342  else if (strNodeName.Compare("token")) {
1343  OTASCIIArmor* pArmor = new OTASCIIArmor;
1344  OT_ASSERT(nullptr != pArmor);
1345 
1346  if (!OTContract::LoadEncodedTextField(xml, *pArmor) ||
1347  !pArmor->Exists()) {
1348  otErr << szFunc << ": Error: token field without value.\n";
1349 
1350  delete pArmor;
1351  pArmor = nullptr;
1352 
1353  return (-1); // error condition
1354  }
1355  else {
1356  m_dequeTokens.push_front(pArmor);
1357  }
1358 
1359  return 1;
1360  }
1361 
1362  return 0;
1363 }
1364 
1365 bool Purse::SaveContractWallet(std::ofstream&) const
1366 {
1367  return true;
1368 }
1369 
1371 {
1372  return m_tLatestValidFrom;
1373 }
1374 
1376 {
1377  return m_tEarliestValidTo;
1378 }
1379 
1380 // Verify whether the CURRENT date is AFTER the the VALID TO date.
1381 // Notice, this will return false, if the instrument is NOT YET VALID.
1382 // You have to use VerifyCurrentDate() to make sure you're within the
1383 // valid date range to use this instrument. But sometimes you only want
1384 // to know if it's expired, regardless of whether it's valid yet. So this
1385 // function answers that for you.
1386 //
1388 {
1389  const time64_t CURRENT_TIME = OTTimeGetCurrentTime();
1390 
1391  // If the current time is AFTER the valid-TO date,
1392  // AND the valid_to is a nonzero number (0 means "doesn't expire")
1393  // THEN return true (it's expired.)
1394  //
1395  if ((CURRENT_TIME >= m_tEarliestValidTo) &&
1397  return true;
1398  else
1399  return false;
1400 }
1401 
1402 // Verify whether the CURRENT date is WITHIN the VALID FROM / TO dates.
1403 //
1405 {
1406  const time64_t CURRENT_TIME = OTTimeGetCurrentTime();
1407 
1408  if ((CURRENT_TIME >= m_tLatestValidFrom) &&
1409  ((CURRENT_TIME <= m_tEarliestValidTo) ||
1411  return true;
1412  else
1413  return false;
1414 }
1415 
1416 // Caller IS responsible to delete. (Peek returns an instance of the
1417 // actual token, which is stored in encrypted form inside the purse.)
1418 //
1420 {
1421  if (m_dequeTokens.empty()) return nullptr;
1422 
1423  // Grab a pointer to the first armored token on the deque.
1424  //
1425  const OTASCIIArmor* pArmor = m_dequeTokens.front();
1426  // ---------------
1427  // Copy the token contents into an Envelope.
1428  OTEnvelope theEnvelope(*pArmor);
1429 
1430  // Open the envelope into a string.
1431  //
1432  OTString strToken;
1433  const OTString strDisplay(__FUNCTION__); // this is the passphrase string
1434  // that will display if theOwner
1435  // doesn't have one already.
1436 
1437  const bool bSuccess =
1438  theOwner.Open_or_Decrypt(theEnvelope, strToken, &strDisplay);
1439 
1440  if (bSuccess) {
1441  // Create a new token with the same server and asset IDs as this purse.
1442  Token* pToken = Token::TokenFactory(strToken, *this);
1443  OT_ASSERT(nullptr != pToken);
1444 
1445  if (pToken->GetAssetID() != m_AssetID ||
1446  pToken->GetServerID() != m_ServerID) {
1447  delete pToken;
1448  pToken = nullptr;
1449 
1450  otErr << __FUNCTION__
1451  << ": ERROR: Cash token with wrong server or asset type.\n";
1452  }
1453  else {
1454  // CALLER is responsible to delete this token.
1455  return pToken;
1456  }
1457  }
1458  else
1459  otErr << __FUNCTION__ << ": Failure: theOwner.Open_or_Decrypt.\n";
1460 
1461  return nullptr;
1462 }
1463 
1464 // Hypocritically (compared to Push) in the case of Pop(), we DO
1465 // allocate a OTToken and return the pointer. The caller IS
1466 // responsible to delete it when he's done with it.
1467 //
1468 // The apparent discrepancy is due to the fact that internally,
1469 // we aren't storing the token object but an encrypted string of it.
1470 // But this is hidden from the user of the purse, who perceives only
1471 // that he is passing tokens in and getting them back out again.
1472 //
1474 {
1475  if (m_dequeTokens.empty()) return nullptr;
1476 
1477  Token* pToken = Peek(theOwner);
1478 
1479  if (nullptr == pToken) {
1480  otErr << __FUNCTION__ << ": Failure: Peek(theOwner) "
1481  "(And m_dequeTokens isn't empty, either.)\n";
1482  return nullptr;
1483  }
1484 
1485  // Grab a pointer to the ascii-armored token, and remove it from the deque.
1486  // (And delete it.)
1487  //
1488  OTASCIIArmor* pArmor = m_dequeTokens.front();
1489  m_dequeTokens.pop_front();
1490  delete pArmor;
1491  pArmor = nullptr;
1492 
1493  // We keep track of the purse's total value.
1494  m_lTotalValue -= pToken->GetDenomination();
1495 
1496  // We keep track of the purse's expiration dates, based on the tokens
1497  // within.
1498  //
1499  // OT_ASSERT(pToken->GetValidFrom() <= m_tLatestValidFrom); // If the
1500  // token's was larger, then the purse's should match it already.
1501  // OT_ASSERT(pToken->GetValidTo() >= m_tEarliestValidTo); // If the
1502  // token's was smaller, then the purse's should match it already.
1503 
1504  // NOTE: the above asserts were commented out because the below call to
1505  // RecalculateExpirationDates
1506  // was commented out (because without recalculating those dates when tokens
1507  // are removed, these asserts
1508  // would get triggered.)
1509 
1510  if ((pToken->GetValidFrom() == m_tLatestValidFrom) ||
1511  (pToken->GetValidTo() == m_tEarliestValidTo)) {
1512  // RecalculateExpirationDates(theOwner);
1513  }
1514 
1515  // CALLER is responsible to delete this token.
1516  return pToken;
1517 }
1518 
1520 {
1523 
1524  for (auto& it : m_dequeTokens) {
1525  OTASCIIArmor* pArmor = it;
1526  OT_ASSERT(nullptr != pArmor);
1527 
1528  OTEnvelope theEnvelope(*pArmor);
1529 
1530  // Open the envelope into a string.
1531  //
1532  OTString strToken;
1533  const OTString strDisplay(__FUNCTION__); // this is the passphrase
1534  // string that will display if
1535  // theOwner doesn't have one
1536  // already.
1537 
1538  const bool bSuccess =
1539  theOwner.Open_or_Decrypt(theEnvelope, strToken, &strDisplay);
1540 
1541  if (bSuccess) {
1542  // Create a new token with the same server and asset IDs as this
1543  // purse.
1544  Token* pToken = Token::TokenFactory(strToken, *this);
1545  OT_ASSERT(nullptr != pToken);
1546 
1547  if (m_tLatestValidFrom < pToken->GetValidFrom()) {
1548  m_tLatestValidFrom = pToken->GetValidFrom();
1549  }
1550 
1551  if ((OT_TIME_ZERO == m_tEarliestValidTo) ||
1552  (m_tEarliestValidTo > pToken->GetValidTo())) {
1553  m_tEarliestValidTo = pToken->GetValidTo();
1554  }
1555 
1557  otErr << __FUNCTION__
1558  << ": WARNING: This purse has a 'valid from' date LATER "
1559  "than the 'valid to' date. "
1560  "(due to different tokens with different date "
1561  "ranges...)\n";
1562 
1563  }
1564  else
1565  otErr << __FUNCTION__
1566  << ": Failure while trying to decrypt a token.\n";
1567  }
1568 }
1569 
1570 // Use a local variable for theToken, do NOT allocate it on the heap
1571 // unless you are going to delete it yourself.
1572 // Repeat: Purse is NOT responsible to delete it. We create our OWN internal
1573 // variable here, new that, and add it to the stack. We do not add the one
1574 // passed in.
1575 bool Purse::Push(OTNym_or_SymmetricKey theOwner, const Token& theToken)
1576 {
1577  if (theToken.GetAssetID() == m_AssetID) {
1578  const OTString strDisplay(__FUNCTION__); // this is the passphrase
1579  // string that will display if
1580  // theOwner doesn't have one
1581  // already.
1582 
1583  OTString strToken(theToken);
1584  OTEnvelope theEnvelope;
1585  const bool bSuccess =
1586  theOwner.Seal_or_Encrypt(theEnvelope, strToken, &strDisplay);
1587 
1588  if (bSuccess) {
1589  OTASCIIArmor* pArmor = new OTASCIIArmor(theEnvelope);
1590 
1591  m_dequeTokens.push_front(pArmor);
1592 
1593  // We keep track of the purse's total value.
1594  m_lTotalValue += theToken.GetDenomination();
1595 
1596  // We keep track of the expiration dates for the purse, based on the
1597  // tokens within.
1598  //
1599  if (m_tLatestValidFrom < theToken.GetValidFrom()) {
1600  m_tLatestValidFrom = theToken.GetValidFrom();
1601  }
1602 
1603  if ((OT_TIME_ZERO == m_tEarliestValidTo) ||
1604  (m_tEarliestValidTo > theToken.GetValidTo())) {
1605  m_tEarliestValidTo = theToken.GetValidTo();
1606  }
1607 
1609  otErr << __FUNCTION__
1610  << ": WARNING: This purse has a 'valid from' date LATER "
1611  "than the 'valid to' date. "
1612  "(due to different tokens with different date "
1613  "ranges...)\n";
1614 
1615  return true;
1616  }
1617  else {
1618  OTString strPurseAssetType(m_AssetID),
1619  strTokenAssetType(theToken.GetAssetID());
1620  otErr << __FUNCTION__ << ": Failed while calling: "
1621  "theOwner.Seal_or_Encrypt(theEnvelope, "
1622  "strToken)\nPurse Asset Type:\n"
1623  << strPurseAssetType << "\n"
1624  "Token Asset Type:\n"
1625  << strTokenAssetType << "\n";
1626  }
1627  }
1628  else {
1629  OTString strPurseAssetType(m_AssetID),
1630  strTokenAssetType(theToken.GetAssetID());
1631  otErr << __FUNCTION__ << ": ERROR: Tried to push token with wrong "
1632  "asset type.\nPurse Asset Type:\n"
1633  << strPurseAssetType << "\n"
1634  "Token Asset Type:\n" << strTokenAssetType
1635  << "\n";
1636  }
1637 
1638  return false;
1639 }
1640 
1641 int32_t Purse::Count() const
1642 {
1643  return static_cast<int32_t>(m_dequeTokens.size());
1644 }
1645 
1646 bool Purse::IsEmpty() const
1647 {
1648  return m_dequeTokens.empty();
1649 }
1650 
1652 {
1653  while (!m_dequeTokens.empty()) {
1654  OTASCIIArmor* pArmor = m_dequeTokens.front();
1655  m_dequeTokens.pop_front();
1656  delete pArmor;
1657  }
1658 
1659  m_lTotalValue = 0;
1660 }
1661 
1662 } // namespace opentxs
int64_t m_lTotalValue
Definition: Purse.hpp:190
EXPORT bool StorePlainString(std::string strContents, std::string strFolder, std::string oneStr="", std::string twoStr="", std::string threeStr="")
Definition: OTStorage.cpp:698
OTLOG_IMPORT OTLogStream otLog4
EXPORT bool GetPassphrase(OTPassword &theOutput, const char *szDisplay=nullptr)
Definition: Purse.cpp:179
EXPORT bool IsExpired()
Definition: Purse.cpp:1387
EXPORT bool IsNymIDIncluded() const
Definition: Purse.hpp:268
EXPORT int32_t Count() const
Definition: Purse.cpp:1641
static EXPORT bool DearmorAndTrim(const OTString &strInput, OTString &strOutput, OTString &strFirstLine)
Definition: OTContract.cpp:158
EXPORT bool IsPasswordProtected() const
Definition: Purse.hpp:272
std::map< std::string, Token * > mapOfTokenPointers
Definition: Purse.cpp:152
time64_t GetValidTo() const
static EXPORT std::shared_ptr< OTCachedKey > CreateMasterPassword(OTPassword &theOutput, const char *szDisplay=nullptr, int32_t nTimeoutSeconds=OT_MASTER_KEY_TIMEOUT)
virtual bool SaveContractWallet(std::ofstream &ofs) const
Definition: Purse.cpp:1365
EXPORT bool Push(OTNym_or_SymmetricKey theOwner, const Token &theToken)
Definition: Purse.cpp:1575
bool m_bIsNymIDIncluded
Definition: Purse.hpp:208
EXPORT bool SaveContract()
EXPORT int64_t ToLong() const
Definition: OTString.cpp:702
static EXPORT const char * PathSeparator()
Definition: OTLog.cpp:408
EXPORT bool SerializeFrom(OTPayload &theInput)
const OTIdentifier & GetAssetID() const
virtual void Release()
Definition: Purse.cpp:812
time64_t m_tLatestValidFrom
Definition: Purse.hpp:219
OTLOG_IMPORT OTLogStream otOut
virtual int32_t ProcessXMLNode(irr::io::IrrXMLReader *&xml)
Definition: Purse.cpp:1063
time64_t m_tEarliestValidTo
Definition: Purse.hpp:221
EXPORT bool VerifyCurrentDate()
Definition: Purse.cpp:1404
const OTIdentifier & GetAssetID() const
Definition: Purse.hpp:335
OTIdentifier m_ServerID
Definition: Purse.hpp:188
static EXPORT Purse * PurseFactory(OTString strInput)
Definition: Purse.cpp:671
EXPORT bool SaveContractRaw(OTString &strOutput) const
OTSymmetricKey * m_pSymmetricKey
Definition: Purse.hpp:213
time64_t OTTimeGetTimeFromSeconds(int64_t seconds)
Definition: Common.hpp:215
EXPORT void Concatenate(const char *arg,...)
Definition: OTString.cpp:1334
int64_t time64_t
Definition: Common.hpp:209
EXPORT bool WriteArmoredString(OTString &strOutput, const std::string str_type, bool bEscaped=false) const
const OTASCIIArmor & GetSpendable() const
Definition: Token.hpp:329
EXPORT void ReleaseSignatures()
Definition: OTContract.cpp:989
EXPORT bool Exists() const
Definition: OTString.cpp:1035
static EXPORT std::shared_ptr< OTCachedKey > It(OTIdentifier *pIdentifier=nullptr)
EXPORT void SetString(const char *szString)
const OTIdentifier & GetServerID() const
EXPORT void Format(const char *fmt,...)
Definition: OTString.cpp:1319
time64_t GetValidFrom() const
EXPORT bool Compare(const char *compare) const
Definition: OTString.cpp:1102
virtual bool LoadContract()
Definition: Purse.cpp:827
EXPORT bool Seal_or_Encrypt(OTEnvelope &outputEnvelope, const OTString &strInput, const OTString *pstrDisplay=nullptr)
EXPORT void Set(const char *data, uint32_t enforcedMaxLength=0)
Definition: OTString.cpp:1055
EXPORT std::shared_ptr< OTCachedKey > GetInternalMaster()
Definition: Purse.cpp:207
time64_t OTTimeGetCurrentTime()
Definition: Common.hpp:211
OTIdentifier m_AssetID
Definition: Purse.hpp:189
EXPORT Token * Peek(OTNym_or_SymmetricKey theOwner) const
Definition: Purse.cpp:1419
EXPORT std::string QueryPlainString(std::string strFolder, std::string oneStr="", std::string twoStr="", std::string threeStr="")
Definition: OTStorage.cpp:728
static EXPORT bool LoadEncodedTextField(irr::io::IrrXMLReader *&xml, OTASCIIArmor &ascOutput)
int64_t GetDenomination() const
Definition: Token.hpp:409
EXPORT void Release_Purse()
Definition: Purse.cpp:787
#define OT_ASSERT(x)
Definition: Assert.hpp:150
OTString m_strContractType
Definition: OTContract.hpp:178
EXPORT bool SerializeTo(OTPayload &theOutput) const
#define OT_ASSERT_MSG(x, s)
Definition: Assert.hpp:155
OTLOG_IMPORT OTLogStream otInfo
std::shared_ptr< OTCachedKey > m_pCachedKey
Definition: Purse.hpp:218
bool m_bPasswordProtected
Definition: Purse.hpp:192
EXPORT time64_t GetLatestValidFrom() const
Definition: Purse.cpp:1370
#define OT_FAIL
Definition: Assert.hpp:139
EXPORT void ReleaseTokens()
Definition: Purse.cpp:1651
OTStringXML m_xmlUnsigned
Definition: OTContract.hpp:174
EXPORT bool Merge(const OTPseudonym &theSigner, OTNym_or_SymmetricKey theOldNym, OTNym_or_SymmetricKey theNewNym, Purse &theNewPurse)
Definition: Purse.cpp:349
static EXPORT const OTString & Purse()
Definition: OTFolders.cpp:351
void RecalculateExpirationDates(OTNym_or_SymmetricKey &theOwner)
Definition: Purse.cpp:1519
OTLOG_IMPORT OTLogStream otWarn
EXPORT const char * Get() const
Definition: OTString.cpp:1045
EXPORT bool ReassignOwnership(OTNym_or_SymmetricKey &oldOwner, OTNym_or_SymmetricKey &newOwner)
Definition: Token.cpp:716
virtual EXPORT bool SignContract(const OTPseudonym &theNym, const OTPasswordData *pPWData=nullptr)
Definition: OTContract.cpp:484
OTLOG_IMPORT OTLogStream otErr
EXPORT void InitPurse()
Definition: Purse.cpp:772
EXPORT time64_t GetEarliestValidTo() const
Definition: Purse.cpp:1375
EXPORT bool SavePurse(const char *szServerID=nullptr, const char *szUserID=nullptr, const char *szAssetTypeID=nullptr)
Definition: Purse.cpp:889
virtual EXPORT ~Purse()
Definition: Purse.cpp:782
virtual EXPORT void Release()
Definition: OTContract.cpp:277
EXPORT bool Exists(std::string strFolder, std::string oneStr="", std::string twoStr="", std::string threeStr="")
Definition: OTStorage.cpp:584
EXPORT bool LoadPurse(const char *szServerID=nullptr, const char *szUserID=nullptr, const char *szAssetTypeID=nullptr)
Definition: Purse.cpp:832
static EXPORT Purse * LowLevelInstantiate(const OTString &strFirstLine)
Definition: Purse.cpp:566
EXPORT bool Contains(const char *compare) const
Definition: OTString.cpp:1137
static EXPORT Token * TokenFactory(OTString strInput)
Definition: Token.cpp:518
OTIdentifier m_UserID
Definition: Purse.hpp:187
EXPORT bool IsEmpty() const
Definition: OTData.cpp:291
int64_t OTTimeGetSecondsFromTime(time64_t time)
Definition: Common.hpp:230
EXPORT bool LoadContractFromString(const OTString &theStr)
#define OT_TIME_ZERO
Definition: Common.hpp:180
virtual EXPORT void Release()
Definition: OTData.cpp:257
EXPORT bool GetNymID(OTIdentifier &theOutput) const
Definition: Purse.cpp:154
EXPORT bool GenerateInternalKey()
Definition: Purse.cpp:257
dequeOfTokens m_dequeTokens
Definition: Purse.hpp:181
virtual EXPORT void Release()
Definition: OTString.cpp:765
EXPORT bool Open_or_Decrypt(const OTEnvelope &inputEnvelope, OTString &strOutput, const OTString *pstrDisplay=nullptr)
EXPORT bool IsEmpty() const
Definition: Purse.cpp:1646
OTString m_strFoldername
Definition: OTContract.hpp:169
virtual void UpdateContents()
Definition: Purse.cpp:952
const OTIdentifier & GetServerID() const
Definition: Purse.hpp:331
EXPORT Token * Pop(OTNym_or_SymmetricKey theOwner)
Definition: Purse.cpp:1473