Open-Transactions  0.93.0-ge03d287
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
OTContract.cpp
Go to the documentation of this file.
1 /************************************************************
2  *
3  * OTContract.cpp
4  *
5  * Base class for many of the OT classes.
6  */
7 
8 /************************************************************
9  -----BEGIN PGP SIGNED MESSAGE-----
10  Hash: SHA1
11 
12  * OPEN TRANSACTIONS
13  *
14  * Financial Cryptography and Digital Cash
15  * Library, Protocol, API, Server, CLI, GUI
16  *
17  * -- Anonymous Numbered Accounts.
18  * -- Untraceable Digital Cash.
19  * -- Triple-Signed Receipts.
20  * -- Cheques, Vouchers, Transfers, Inboxes.
21  * -- Basket Currencies, Markets, Payment Plans.
22  * -- Signed, XML, Ricardian-style Contracts.
23  * -- Scripted smart contracts.
24  *
25  * Copyright (C) 2010-2013 by "Fellow Traveler" (A pseudonym)
26  *
27  * EMAIL:
29  *
30  * BITCOIN: 1NtTPVVjDsUfDWybS4BwvHpG2pdS9RnYyQ
31  *
32  * KEY FINGERPRINT (PGP Key in license file):
33  * 9DD5 90EB 9292 4B48 0484 7910 0308 00ED F951 BB8E
34  *
35  * OFFICIAL PROJECT WIKI(s):
36  * https://github.com/FellowTraveler/Moneychanger
37  * https://github.com/FellowTraveler/Open-Transactions/wiki
38  *
39  * WEBSITE:
40  * http://www.OpenTransactions.org/
41  *
42  * Components and licensing:
43  * -- Moneychanger..A Java client GUI.....LICENSE:.....GPLv3
44  * -- otlib.........A class library.......LICENSE:...LAGPLv3
45  * -- otapi.........A client API..........LICENSE:...LAGPLv3
46  * -- opentxs/ot....Command-line client...LICENSE:...LAGPLv3
47  * -- otserver......Server Application....LICENSE:....AGPLv3
48  * Github.com/FellowTraveler/Open-Transactions/wiki/Components
49  *
50  * All of the above OT components were designed and written by
51  * Fellow Traveler, with the exception of Moneychanger, which
52  * was contracted out to Vicky C ([email protected]).
53  * The open-source community has since actively contributed.
54  *
55  * -----------------------------------------------------
56  *
57  * LICENSE:
58  * This program is free software: you can redistribute it
59  * and/or modify it under the terms of the GNU Affero
60  * General Public License as published by the Free Software
61  * Foundation, either version 3 of the License, or (at your
62  * option) any later version.
63  *
64  * ADDITIONAL PERMISSION under the GNU Affero GPL version 3
65  * section 7: (This paragraph applies only to the LAGPLv3
66  * components listed above.) If you modify this Program, or
67  * any covered work, by linking or combining it with other
68  * code, such other code is not for that reason alone subject
69  * to any of the requirements of the GNU Affero GPL version 3.
70  * (==> This means if you are only using the OT API, then you
71  * don't have to open-source your code--only your changes to
72  * Open-Transactions itself must be open source. Similar to
73  * LGPLv3, except it applies to software-as-a-service, not
74  * just to distributing binaries.)
75  *
76  * Extra WAIVER for OpenSSL, Lucre, and all other libraries
77  * used by Open Transactions: This program is released under
78  * the AGPL with the additional exemption that compiling,
79  * linking, and/or using OpenSSL is allowed. The same is true
80  * for any other open source libraries included in this
81  * project: complete waiver from the AGPL is hereby granted to
82  * compile, link, and/or use them with Open-Transactions,
83  * according to their own terms, as long as the rest of the
84  * Open-Transactions terms remain respected, with regard to
85  * the Open-Transactions code itself.
86  *
87  * Lucre License:
88  * This code is also "dual-license", meaning that Ben Lau-
89  * rie's license must also be included and respected, since
90  * the code for Lucre is also included with Open Transactions.
91  * See Open-Transactions/src/otlib/lucre/LUCRE_LICENSE.txt
92  * The Laurie requirements are light, but if there is any
93  * problem with his license, simply remove the Lucre code.
94  * Although there are no other blind token algorithms in Open
95  * Transactions (yet. credlib is coming), the other functions
96  * will continue to operate.
97  * See Lucre on Github: https://github.com/benlaurie/lucre
98  * -----------------------------------------------------
99  * You should have received a copy of the GNU Affero General
100  * Public License along with this program. If not, see:
101  * http://www.gnu.org/licenses/
102  *
103  * If you would like to use this software outside of the free
104  * software license, please contact FellowTraveler.
105  * (Unfortunately many will run anonymously and untraceably,
106  * so who could really stop them?)
107  *
108  * DISCLAIMER:
109  * This program is distributed in the hope that it will be
110  * useful, but WITHOUT ANY WARRANTY; without even the implied
111  * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
112  * PURPOSE. See the GNU Affero General Public License for
113  * more details.
114 
115  -----BEGIN PGP SIGNATURE-----
116  Version: GnuPG v1.4.9 (Darwin)
117 
118  iQIcBAEBAgAGBQJRSsfJAAoJEAMIAO35UbuOQT8P/RJbka8etf7wbxdHQNAY+2cC
119  vDf8J3X8VI+pwMqv6wgTVy17venMZJa4I4ikXD/MRyWV1XbTG0mBXk/7AZk7Rexk
120  KTvL/U1kWiez6+8XXLye+k2JNM6v7eej8xMrqEcO0ZArh/DsLoIn1y8p8qjBI7+m
121  aE7lhstDiD0z8mwRRLKFLN2IH5rAFaZZUvj5ERJaoYUKdn4c+RcQVei2YOl4T0FU
122  LWND3YLoH8naqJXkaOKEN4UfJINCwxhe5Ke9wyfLWLUO7NamRkWD2T7CJ0xocnD1
123  sjAzlVGNgaFDRflfIF4QhBx1Ddl6wwhJfw+d08bjqblSq8aXDkmFA7HeunSFKkdn
124  oIEOEgyj+veuOMRJC5pnBJ9vV+7qRdDKQWaCKotynt4sWJDGQ9kWGWm74SsNaduN
125  TPMyr9kNmGsfR69Q2Zq/FLcLX/j8ESxU+HYUB4vaARw2xEOu2xwDDv6jt0j3Vqsg
126  x7rWv4S/Eh18FDNDkVRChiNoOIilLYLL6c38uMf1pnItBuxP3uhgY6COm59kVaRh
127  nyGTYCDYD2TK+fI9o89F1297uDCwEJ62U0Q7iTDp5QuXCoxkPfv8/kX6lS6T3y9G
128  M9mqIoLbIQ1EDntFv7/t6fUTS2+46uCrdZWbQ5RjYXdrzjij02nDmJAm2BngnZvd
129  kamH0Y/n11lCvo1oQxM+
130  =uSzz
131  -----END PGP SIGNATURE-----
132  **************************************************************/
133 
134 #include "stdafx.hpp"
135 
136 #include "OTContract.hpp"
138 #include "crypto/OTCrypto.hpp"
139 #include "util/OTFolders.hpp"
140 #include "OTLog.hpp"
141 #include "crypto/OTPasswordData.hpp"
142 #include "OTPseudonym.hpp"
143 #include "crypto/OTSignature.hpp"
144 #include "OTStorage.hpp"
145 
146 #include <irrxml/irrXML.hpp>
147 
148 #include <fstream>
149 #include <memory>
150 
151 using namespace irr;
152 using namespace io;
153 
154 namespace opentxs
155 {
156 
157 // static
158 bool OTContract::DearmorAndTrim(const OTString& strInput, OTString& strOutput,
159  OTString& strFirstLine)
160 {
161 
162  if (!strInput.Exists()) {
163  otErr << __FUNCTION__ << ": Input string is empty.\n";
164  return false;
165  }
166 
167  strOutput.Set(strInput);
168 
169  if (false ==
170  strOutput.DecodeIfArmored(false)) // bEscapedIsAllowed=true by default.
171  {
172  otErr << __FUNCTION__ << ": Input string apparently was encoded and "
173  "then failed decoding. Contents: \n"
174  << strInput << "\n";
175  return false;
176  }
177 
178  strOutput.reset(); // for sgets
179 
180  // At this point, strOutput contains the actual contents, whether they
181  // were originally ascii-armored OR NOT. (And they are also now trimmed,
182  // either way.)
183 
184  static char buf[75] = "";
185  buf[0] = 0; // probably unnecessary.
186  bool bGotLine = strOutput.sgets(buf, 70);
187 
188  if (!bGotLine) return false;
189 
190  strFirstLine.Set(buf);
191  strOutput.reset(); // set the "file" pointer within this string back to
192  // index 0.
193 
194  // Now I feel pretty safe -- the string I'm examining is within
195  // the first 70 characters of the beginning of the contract, and
196  // it will NOT contain the escape "- " sequence. From there, if
197  // it contains the proper sequence, I will instantiate that type.
198  if (!strFirstLine.Exists() || strFirstLine.Contains("- -")) return false;
199 
200  return true;
201 }
202 
203 OTContract::OTContract()
204 {
205  Initialize();
206 }
207 
208 OTContract::OTContract(const OTString& name, const OTString& foldername,
209  const OTString& filename, const OTString& strID)
210 {
211  Initialize();
212 
213  m_strName = name;
214  m_strFoldername = foldername;
215  m_strFilename = filename;
216 
217  m_ID.SetString(strID);
218 }
219 
220 OTContract::OTContract(const OTString& strID)
221 {
222  Initialize();
223 
224  m_ID.SetString(strID);
225 }
226 
227 OTContract::OTContract(const OTIdentifier& theID)
228 {
229  Initialize();
230 
231  m_ID = theID;
232 }
233 
234 void OTContract::Initialize()
235 {
236  m_strContractType =
237  "CONTRACT"; // CONTRACT, MESSAGE, TRANSACTION, LEDGER, TRANSACTION ITEM
238  // make sure subclasses set this in their own initialization routine.
239 
240  m_strSigHashType = OTIdentifier::DefaultHashAlgorithm;
241  m_strVersion = "2.0"; // since new credentials system.
242 }
243 
244 // The name, filename, version, and ID loaded by the wallet
245 // are NOT released here, since they are used immediately after
246 // the Release() call in LoadContract(). Really I just want to
247 // "Release" the stuff that is about to be loaded, not the stuff
248 // that I need to load it!
249 void OTContract::Release_Contract()
250 {
251  // !! Notice I don't release the m_strFilename here!!
252  // Because in LoadContract, we want to release all the members, and then
253  // load up from the file.
254  // So if I release the filename, now I can't load up from the file cause I
255  // just blanked it. DUh.
256  //
257  // m_strFilename.Release();
258 
259  m_strSigHashType = OTIdentifier::DefaultHashAlgorithm;
260  m_xmlUnsigned.Release();
261  m_strRawFile.Release();
262 
263  ReleaseSignatures();
264 
265  m_mapConditions.clear();
266 
267  // Go through the existing list of nyms at this point, and delete them all.
268  while (!m_mapNyms.empty()) {
269  OTPseudonym* pNym = m_mapNyms.begin()->second;
270  OT_ASSERT(nullptr != pNym);
271  delete pNym;
272  pNym = nullptr;
273  m_mapNyms.erase(m_mapNyms.begin());
274  }
275 }
276 
277 void OTContract::Release()
278 {
279  Release_Contract();
280 
281  // No call to ot_super::Release() here, since OTContract
282  // is the base class.
283 }
284 
285 OTContract::~OTContract()
286 {
287 
288  Release_Contract();
289 }
290 
291 bool OTContract::SaveToContractFolder()
292 {
293  OTString strFoldername(OTFolders::Contract().Get()), strFilename;
294 
295  GetIdentifier(strFilename);
296 
297  // These are already set in SaveContract(), called below.
298  // m_strFoldername = strFoldername;
299  // m_strFilename = strFilename;
300 
301  otInfo << "OTContract::SaveToContractFolder: Saving asset contract to "
302  "disk...\n";
303 
304  return SaveContract(strFoldername.Get(), strFilename.Get());
305 }
306 
307 void OTContract::GetFilename(OTString& strFilename) const
308 {
309  strFilename = m_strFilename;
310 }
311 
312 void OTContract::GetFoldername(OTString& strFoldername) const
313 {
314  strFoldername = m_strFoldername;
315 }
316 
317 void OTContract::GetIdentifier(OTIdentifier& theIdentifier) const
318 {
319  theIdentifier = m_ID;
320 }
321 
322 void OTContract::GetIdentifier(OTString& theIdentifier) const
323 {
324  m_ID.GetString(theIdentifier);
325 }
326 
327 // Make sure this contract checks out. Very high level.
328 // Verifies ID, existence of public key, and signature.
329 //
330 bool OTContract::VerifyContract()
331 {
332  // Make sure that the supposed Contract ID that was set is actually
333  // a hash of the contract file, signatures and all.
334  if (!VerifyContractID()) {
335  otWarn << __FUNCTION__ << ": Failed verifying contract ID.\n";
336  return false;
337  }
338 
339  // Make sure we are able to read the official "contract" public key out of
340  // this contract.
341  const OTPseudonym* pNym = GetContractPublicNym();
342 
343  if (nullptr == pNym) {
344  otOut << __FUNCTION__
345  << ": Failed retrieving public nym from contract.\n";
346  return false;
347  }
348 
349  if (!VerifySignature(*pNym)) {
350  const OTIdentifier theNymID(*pNym);
351  const OTString strNymID(theNymID);
352  otOut << __FUNCTION__ << ": Failed verifying the contract's signature "
353  "against the public key that was retrieved "
354  "from the contract, with key ID: " << strNymID
355  << "\n";
356  return false;
357  }
358 
359  otWarn << "\nVerified -- The Contract ID from the wallet matches the "
360  "newly-calculated hash of the contract file.\n"
361  "Verified -- A standard \"contract\" Public Key or x509 Cert WAS "
362  "found inside the contract.\n"
363  "Verified -- And the **SIGNATURE VERIFIED** with THAT key.\n\n";
364  return true;
365 }
366 
367 void OTContract::CalculateContractID(OTIdentifier& newID) const
368 {
369  // may be redundant...
370  std::string str_Trim(m_strRawFile.Get());
371  std::string str_Trim2 = OTString::trim(str_Trim);
372 
373  OTString strTemp(str_Trim2.c_str());
374 
375  if (!newID.CalculateDigest(strTemp))
376  otErr << __FUNCTION__ << ": Error calculating Contract digest.\n";
377 }
378 
379 bool OTContract::VerifyContractID() const
380 {
381  OTIdentifier newID;
382  CalculateContractID(newID);
383 
384  // newID now contains the Hash aka Message Digest aka Fingerprint
385  // aka thumbprint aka "IDENTIFIER" of the Contract.
386  //
387  // Now let's compare that identifier to the one already loaded by the wallet
388  // for this contract and make sure they MATCH.
389 
390  // I use the == operator here because there is no != operator at this time.
391  // That's why you see the ! outside the parenthesis.
392  //
393  if (!(m_ID == newID)) {
394  OTString str1(m_ID), str2(newID);
395 
396  otOut << "\nHashes do NOT match in OTContract::VerifyContractID.\n "
397  "Expected: " << str1 << "\n Actual: " << str2
398  << "\n"
399  // "\nRAW FILE:\n--->" << m_strRawFile << "<---"
400  "\n";
401  return false;
402  }
403  else {
404  OTString str1;
405  newID.GetString(str1);
406  otWarn << "\nContract ID *SUCCESSFUL* match to "
407  << OTIdentifier::DefaultHashAlgorithm
408  << " hash of contract file: " << str1 << "\n\n";
409  return true;
410  }
411 }
412 
413 const OTPseudonym* OTContract::GetContractPublicNym() const
414 {
415  for (auto& it : m_mapNyms) {
416  OTPseudonym* pNym = it.second;
418  nullptr != pNym,
419  "nullptr pseudonym pointer in OTContract::GetContractPublicNym.\n");
420 
421  // We favor the new "credential" system over the old "public key"
422  // system.
423  // No one will ever actually put BOTH in a single contract. But if they
424  // do,
425  // we favor the new version over the old.
426  if (it.first == "signer") {
427  return pNym;
428  }
429  // TODO have a place for hardcoded values like this.
430  else if (it.first == "contract") {
431  // We're saying here that every contract has to have a key tag
432  // called "contract"
433  // where the official public key can be found for it and for any
434  // contract.
435  return pNym;
436  }
437  }
438 
439  return nullptr;
440 }
441 
442 // If there is a public key I can find for this contract, then
443 // I will return it here -- or nullptr.
444 const OTAsymmetricKey* OTContract::GetContractPublicKey() const
445 {
446  for (auto& it : m_mapNyms) {
447  OTPseudonym* pNym = it.second;
449  nullptr != pNym,
450  "nullptr pseudonym pointer in OTContract::GetContractPublicKey.\n");
451 
452  // We favor the new "credential" system over the old "public key"
453  // system.
454  // No one will ever actually put BOTH in a single contract. But if they
455  // do,
456  // we favor the new version over the old.
457  if (it.first ==
458  "signer") // TODO have a place for hardcoded values like this.
459  { // We're saying here that every contract has a key tag called
460  // "contract"
461  // where the official public key can be found for it and for any
462  // contract.
463  OTAsymmetricKey* pKey =
464  (OTAsymmetricKey*)&(pNym->GetPublicSignKey()); // todo fix this
465  // cast.
466  return const_cast<OTAsymmetricKey*>(pKey);
467  }
468  else if (it.first == "contract") {
469  OTAsymmetricKey* pKey =
470  (OTAsymmetricKey*)&(pNym->GetPublicSignKey()); // todo fix this
471  // cast.
472  return const_cast<OTAsymmetricKey*>(pKey);
473  }
474  }
475 
476  return nullptr;
477 }
478 
479 // This is the one that you will most likely want to call.
480 // It actually attaches the resulting signature to this contract.
481 // If you want the signature to remain on the contract and be handled
482 // internally, then this is what you should call.
483 //
484 bool OTContract::SignContract(const OTPseudonym& theNym,
485  const OTPasswordData* pPWData)
486 {
487  OTSignature* pSig = new OTSignature();
489  nullptr != pSig,
490  "OTContract::SignContract: Error allocating memory for Signature.\n");
491 
492  bool bSigned = SignContract(theNym, *pSig, pPWData);
493 
494  if (bSigned)
495  m_listSignatures.push_back(pSig);
496  else {
497  otErr << __FUNCTION__ << ": Failure while calling "
498  "SignContract(theNym, *pSig, pPWData)\n";
499  delete pSig;
500  pSig = nullptr;
501  }
502 
503  return bSigned;
504 }
505 
506 // Signs using authentication key instead of signing key.
507 //
508 bool OTContract::SignContractAuthent(const OTPseudonym& theNym,
509  const OTPasswordData* pPWData)
510 {
511  OTSignature* pSig = new OTSignature();
512  OT_ASSERT_MSG(nullptr != pSig, "OTContract::SignContractAuthent: Error "
513  "allocating memory for Signature.\n");
514 
515  bool bSigned = SignContractAuthent(theNym, *pSig, pPWData);
516 
517  if (bSigned)
518  m_listSignatures.push_back(pSig);
519  else {
520  otErr << __FUNCTION__ << ": Failure while calling "
521  "SignContractAuthent(theNym, *pSig, "
522  "pPWData)\n";
523  delete pSig;
524  pSig = nullptr;
525  }
526 
527  return bSigned;
528 }
529 
530 // The output signature will be in theSignature.
531 // It is NOT attached to the contract. This is just a utility function.
532 bool OTContract::SignContract(const OTPseudonym& theNym,
533  OTSignature& theSignature,
534  const OTPasswordData* pPWData)
535 {
536  return SignContract(theNym.GetPrivateSignKey(), theSignature,
537  m_strSigHashType, pPWData);
538 }
539 
540 // Uses authentication key instead of signing key.
541 bool OTContract::SignContractAuthent(const OTPseudonym& theNym,
542  OTSignature& theSignature,
543  const OTPasswordData* pPWData)
544 {
545  return SignContract(theNym.GetPrivateAuthKey(), theSignature,
546  m_strSigHashType, pPWData);
547 }
548 
549 // Normally you'd use OTContract::SignContract(const OTPseudonym& theNym)...
550 // Normally you WOULDN'T use this function SignWithKey.
551 // But this is here anyway for those peculiar places where you need it. For
552 // example,
553 // when first creating a Nym, you generate the master credential as part of
554 // creating
555 // the Nym, and the master credential has to sign itself, and it therefore needs
556 // to be
557 // able to "sign a contract" at a high level using purely the key, without
558 // having the Nym
559 // ready yet to signing anything with.
560 //
561 bool OTContract::SignWithKey(const OTAsymmetricKey& theKey,
562  const OTPasswordData* pPWData)
563 {
564  OTSignature* pSig = new OTSignature();
566  nullptr != pSig,
567  "OTContract::SignWithKey: Error allocating memory for Signature.\n");
568 
569  bool bSigned = SignContract(theKey, *pSig, m_strSigHashType, pPWData);
570 
571  if (bSigned)
572  m_listSignatures.push_back(pSig);
573  else {
574  otErr << __FUNCTION__
575  << ": Failure while calling SignContract(theNym, *pSig).\n";
576  delete pSig;
577  pSig = nullptr;
578  }
579 
580  return bSigned;
581 }
582 
583 // Done: When signing a contract, need to record the metadata into the signature
584 // object here.
585 
586 // We will know if the key is signing, authentication, or encryption key
587 // because?
588 // Because we used the Nym to choose it! In which case we should have a default
589 // option,
590 // and also some other function with a new name that calls SignContract and
591 // CHANGES that default
592 // option.
593 // For example, SignContract(bool bUseAuthenticationKey=false)
594 // Then: SignContractAuthentication() { return SignContract(true); }
595 //
596 // In most cases we actually WILL want the signing key, since we are actually
597 // signing contracts
598 // such as cash withdrawals, etc. But when the Nym stores something for himself
599 // locally, or when
600 // sending messages, those will use the authentication key.
601 //
602 // We'll also have the ability to SWITCH the key which is important because it
603 // raises the
604 // question, how do we CHOOSE the key? On my phone I might use a different key
605 // than on my iPad.
606 // theNym should either know already (GetPrivateKey being intelligent) or it
607 // must be passed in
608 // (Into the below versions of SignContract.)
609 //
610 // If theKey knows its type (A|E|S) the next question is, does it know its other
611 // metadata?
612 // It certainly CAN know, can't it? Especially if it's being loaded from
613 // credentials in the
614 // first place. And if not, well then the data's not there and it's not added to
615 // the signature.
616 // (Simple.) So I will put the Signature Metadata into its own class, so not
617 // only a signature
618 // can use it, but also the OTAsymmetricKey class can use it and also
619 // OTSubcredential can use it.
620 // Then OTContract just uses it if it's there. Also we don't have to pass it in
621 // here as separate
622 // parameters. At most we have to figure out which private key to get above, in
623 // theNym.GetPrivateKey()
624 // Worst case maybe put a loop, and see which of the private keys inside that
625 // Nym, in its credentials,
626 // is actually loaded and available. Then just have GetPrivateKey return THAT
627 // one. Similarly, later
628 // on, in VerifySignature, we'll pass the signature itself into the Nym so that
629 // the Nym can use it
630 // to help search for the proper public key to use for verifying, based on that
631 // metadata.
632 //
633 // This is all great because it means the only real change I need to do here now
634 // is to see if
635 // theKey.HasMetadata and if so, just copy it directly over to theSignature's
636 // Metadata.
637 //
638 
639 // The output signature will be in theSignature.
640 // It is NOT attached to the contract. This is just a utility function.
641 //
642 bool OTContract::SignContract(const OTAsymmetricKey& theKey,
643  OTSignature& theSignature,
644  const OTString& strHashType,
645  const OTPasswordData* pPWData)
646 {
647  // We assume if there's any important metadata, it will already
648  // be on the key, so we just copy it over to the signature.
649  //
650  if (nullptr != theKey.m_pMetadata) {
651  theSignature.getMetaData() = *(theKey.m_pMetadata);
652  }
653 
654  // Update the contents, (not always necessary, many contracts are read-only)
655  // This is where we provide an overridable function for the child classes
656  // that
657  // need to update their contents at this point.
658  // But the OTContract version of this function is actually empty, since the
659  // default behavior is that contract contents don't change.
660  // (Accounts and Messages being two big exceptions.)
661  //
662  UpdateContents();
663 
664  if (false ==
665  OTCrypto::It()->SignContract(m_xmlUnsigned, theKey, theSignature,
666  strHashType, pPWData)) {
667  otErr << "OTContract::SignContract: "
668  "OTCrypto::It()->SignContract returned false.\n";
669  return false;
670  }
671 
672  return true;
673 }
674 
675 // Todo: make this private so we can see if anyone is calling it.
676 // Might want to ditch it if possible, since the metadata isn't
677 // stored in that cert file...
678 
679 // Sign the Contract using a private key from a file.
680 // theSignature will contain the output.
681 bool OTContract::SignContract(const char* szFoldername,
682  const char* szFilename, // for Certfile, for
683  // private key.
684  OTSignature& theSignature, // output
685  const OTPasswordData* pPWData)
686 {
687  OT_ASSERT(nullptr != szFoldername);
688  OT_ASSERT(nullptr != szFilename);
689 
690  const char* szFunc = "OTContract::SignContract";
691 
692  if (!OTDB::Exists(szFoldername, szFilename)) {
693  otErr << szFunc << ": File does not exist: " << szFoldername
694  << OTLog::PathSeparator() << szFilename << "\n";
695  return false;
696  }
697 
698  const std::string strCertFileContents(OTDB::QueryPlainString(
699  szFoldername, szFilename)); // <=== LOADING FROM DATA STORE.
700 
701  if (strCertFileContents.length() < 2) {
702  otErr << szFunc << ": Error reading file: " << szFoldername
703  << OTLog::PathSeparator() << szFilename << "\n";
704  return false;
705  }
706 
707  OTPasswordData thePWData(
708  "(OTContract::SignContract is trying to read the private key...)");
709  if (nullptr == pPWData) pPWData = &thePWData;
710 
711  // Update the contents, (not always necessary, many contracts are read-only)
712  // This is where we provide an overridable function for the child classes
713  // that
714  // need to update their contents at this point.
715  // But the OTContract version of this function is actually empty, since the
716  // default behavior is that contract contents don't change.
717  // (Accounts and Messages being two big exceptions.)
718  //
719  UpdateContents();
720 
721  if (false ==
722  OTCrypto::It()->SignContract(m_xmlUnsigned, m_strSigHashType,
723  strCertFileContents, theSignature,
724  pPWData)) {
725  otErr << szFunc << ": OTCrypto::It()->SignContract returned false, "
726  "using Cert file: " << szFoldername
727  << OTLog::PathSeparator() << szFilename << "\n";
728  return false;
729  }
730 
731  return true;
732 }
733 
734 // Presumably the Signature passed in here was just loaded as part of this
735 // contract and is
736 // somewhere in m_listSignatures. Now it is being verified.
737 //
738 bool OTContract::VerifySignature(
739  const char* szFoldername, const char* szFilename, // for Cert.
740  const OTSignature& theSignature,
741  const OTPasswordData* pPWData) const // optional
742  // in/out
743 {
745  nullptr != szFoldername,
746  "Null foldername pointer passed to OTContract::VerifySignature");
748  nullptr != szFilename,
749  "Null filename pointer passed to OTContract::VerifySignature");
750 
751  const char* szFunc = __FUNCTION__;
752 
753  // Read public key
754  otInfo << szFunc << ": Reading public key from certfile in order to verify "
755  "signature...\n";
756 
757  if (!OTDB::Exists(szFoldername, szFilename)) {
758  otErr << szFunc << ": File does not exist: " << szFoldername
759  << OTLog::PathSeparator() << szFilename << "\n";
760  return false;
761  }
762 
763  const std::string strCertFileContents(OTDB::QueryPlainString(
764  szFoldername, szFilename)); // <=== LOADING FROM DATA STORE.
765 
766  if (strCertFileContents.length() < 2) {
767  otErr << szFunc << ": Error reading file: " << szFoldername
768  << OTLog::PathSeparator() << szFilename << "\n";
769  return false;
770  }
771 
772  OTPasswordData thePWData("Reading the public key...");
773  if (nullptr == pPWData) pPWData = &thePWData;
774 
775  if (false ==
776  OTCrypto::It()->VerifySignature(m_xmlUnsigned, m_strSigHashType,
777  strCertFileContents, theSignature,
778  pPWData)) {
779  otLog4 << szFunc << ": OTCrypto::It()->VerifySignature returned false, "
780  "using Cert file: " << szFoldername
781  << OTLog::PathSeparator() << szFilename << "\n";
782  return false;
783  }
784 
785  return true;
786 }
787 
788 bool OTContract::VerifySigAuthent(const OTPseudonym& theNym,
789  const OTPasswordData* pPWData) const
790 {
791  OTString strNymID;
792  theNym.GetIdentifier(strNymID);
793  char cNymID = '0';
794  uint32_t nIndex = 0;
795  const bool bNymID = strNymID.At(nIndex, cNymID);
796 
797  for (auto& it : m_listSignatures) {
798  OTSignature* pSig = it;
799  OT_ASSERT(nullptr != pSig);
800 
801  if (bNymID && pSig->getMetaData().HasMetadata()) {
802  // If the signature has metadata, then it knows the first character
803  // of the NymID that signed it. We know the first character of the
804  // NymID
805  // who's trying to verify it. Thus, if they don't match, we can skip
806  // this
807  // signature without having to try to verify it at all.
808  //
809  if (pSig->getMetaData().FirstCharNymID() != cNymID) continue;
810  }
811 
812  if (VerifySigAuthent(theNym, *pSig, pPWData)) return true;
813  }
814 
815  return false;
816 }
817 
818 bool OTContract::VerifySignature(const OTPseudonym& theNym,
819  const OTPasswordData* pPWData) const
820 {
821  OTString strNymID;
822  theNym.GetIdentifier(strNymID);
823  char cNymID = '0';
824  uint32_t nIndex = 0;
825  const bool bNymID = strNymID.At(nIndex, cNymID);
826 
827  for (auto& it : m_listSignatures) {
828  OTSignature* pSig = it;
829  OT_ASSERT(nullptr != pSig);
830 
831  if (bNymID && pSig->getMetaData().HasMetadata()) {
832  // If the signature has metadata, then it knows the first character
833  // of the NymID that signed it. We know the first character of the
834  // NymID
835  // who's trying to verify it. Thus, if they don't match, we can skip
836  // this
837  // signature without having to try to verify it at all.
838  //
839  if (pSig->getMetaData().FirstCharNymID() != cNymID) continue;
840  }
841 
842  if (VerifySignature(theNym, *pSig, pPWData)) return true;
843  }
844 
845  return false;
846 }
847 
848 bool OTContract::VerifyWithKey(const OTAsymmetricKey& theKey,
849  const OTPasswordData* pPWData) const
850 {
851  for (auto& it : m_listSignatures) {
852  OTSignature* pSig = it;
853  OT_ASSERT(nullptr != pSig);
854 
855  if (theKey.m_pMetadata && theKey.m_pMetadata->HasMetadata() &&
856  pSig->getMetaData().HasMetadata()) {
857  // Since key and signature both have metadata, we can use it
858  // to skip signatures which don't match this key.
859  //
860  if (pSig->getMetaData() != *(theKey.m_pMetadata)) continue;
861  }
862 
863  OTPasswordData thePWData("OTContract::VerifyWithKey");
864  if (VerifySignature(theKey, *pSig, m_strSigHashType,
865  (nullptr != pPWData) ? pPWData : &thePWData))
866  return true;
867  }
868 
869  return false;
870 }
871 
872 // Like VerifySignature, except it uses the authentication key instead of the
873 // signing key.
874 // (Like for sent messages or stored files, where you want a signature but you
875 // don't want
876 // a legally binding signature, just a technically secure signature.)
877 //
878 bool OTContract::VerifySigAuthent(const OTPseudonym& theNym,
879  const OTSignature& theSignature,
880  const OTPasswordData* pPWData) const
881 {
882 
883  OTPasswordData thePWData("OTContract::VerifySigAuthent 1");
884  listOfAsymmetricKeys listOutput;
885 
886  const int32_t nCount = theNym.GetPublicKeysBySignature(
887  listOutput, theSignature, 'A'); // 'A' for authentication key.
888 
889  if (nCount > 0) // Found some (potentially) matching keys...
890  {
891  for (auto& it : listOutput) {
892  OTAsymmetricKey* pKey = it;
893  OT_ASSERT(nullptr != pKey);
894 
895  if (VerifySignature(*pKey, theSignature, m_strSigHashType,
896  (nullptr != pPWData) ? pPWData : &thePWData))
897  return true;
898  }
899  }
900  else {
901  OTString strNymID;
902  theNym.GetIdentifier(strNymID);
903  otWarn << __FUNCTION__
904  << ": Tried to grab a list of keys from this Nym (" << strNymID
905  << ") which might match this signature, "
906  "but recovered none. Therefore, will attempt to verify using "
907  "the Nym's default public "
908  "AUTHENTICATION key.\n";
909  }
910  // else found no keys.
911 
912  return VerifySignature(theNym.GetPublicAuthKey(), theSignature,
913  m_strSigHashType,
914  (nullptr != pPWData) ? pPWData : &thePWData);
915 }
916 
917 // The only different between calling this with a Nym and calling it with an
918 // Asymmetric Key is that
919 // the key gives you the choice of hash algorithm, whereas the nym version uses
920 // m_strHashType to decide
921 // for you. Choose the function you prefer, you can do it either way.
922 //
923 bool OTContract::VerifySignature(const OTPseudonym& theNym,
924  const OTSignature& theSignature,
925  const OTPasswordData* pPWData) const
926 {
927 
928  OTPasswordData thePWData("OTContract::VerifySignature 1");
929  listOfAsymmetricKeys listOutput;
930 
931  const int32_t nCount = theNym.GetPublicKeysBySignature(
932  listOutput, theSignature, 'S'); // 'S' for signing key.
933 
934  if (nCount > 0) // Found some (potentially) matching keys...
935  {
936  for (auto& it : listOutput) {
937  OTAsymmetricKey* pKey = it;
938  OT_ASSERT(nullptr != pKey);
939 
940  if (VerifySignature(*pKey, theSignature, m_strSigHashType,
941  (nullptr != pPWData) ? pPWData : &thePWData))
942  return true;
943  }
944  }
945  else {
946  OTString strNymID;
947  theNym.GetIdentifier(strNymID);
948  otWarn << __FUNCTION__
949  << ": Tried to grab a list of keys from this Nym (" << strNymID
950  << ") which might match this signature, "
951  "but recovered none. Therefore, will attempt to verify using "
952  "the Nym's default public "
953  "SIGNING key.\n";
954  }
955  // else found no keys.
956 
957  return VerifySignature(theNym.GetPublicSignKey(), theSignature,
958  m_strSigHashType,
959  (nullptr != pPWData) ? pPWData : &thePWData);
960 }
961 
962 bool OTContract::VerifySignature(const OTAsymmetricKey& theKey,
963  const OTSignature& theSignature,
964  const OTString& strHashType,
965  const OTPasswordData* pPWData) const
966 {
967  // See if this key could possibly have even signed this signature.
968  // (The metadata may eliminate it as a possibility.)
969  //
970  if ((nullptr != theKey.m_pMetadata) && theKey.m_pMetadata->HasMetadata() &&
971  theSignature.getMetaData().HasMetadata()) {
972  if (theSignature.getMetaData() != *(theKey.m_pMetadata)) return false;
973  }
974 
975  OTPasswordData thePWData("OTContract::VerifySignature 2");
976 
977  if (false ==
978  OTCrypto::It()->VerifySignature(
979  m_xmlUnsigned, theKey, theSignature, strHashType,
980  (nullptr != pPWData) ? pPWData : &thePWData)) {
981  otLog4 << __FUNCTION__
982  << ": OTCrypto::It()->VerifySignature returned false.\n";
983  return false;
984  }
985 
986  return true;
987 }
988 
989 void OTContract::ReleaseSignatures()
990 {
991 
992  while (!m_listSignatures.empty()) {
993  OTSignature* pSig = m_listSignatures.front();
994  m_listSignatures.pop_front();
995  delete pSig;
996  }
997 }
998 
999 bool OTContract::DisplayStatistics(OTString& strContents) const
1000 {
1001  // Subclasses may override this.
1002  strContents.Concatenate(
1003  const_cast<char*>("ERROR: OTContract::DisplayStatistics was called "
1004  "instead of a subclass...\n"));
1005 
1006  return false;
1007 }
1008 
1009 bool OTContract::SaveContractWallet(OTString&) const
1010 {
1011  // Subclasses may use this.
1012 
1013  return false;
1014 }
1015 
1016 bool OTContract::SaveContents(std::ofstream& ofs) const
1017 {
1018  ofs << m_xmlUnsigned;
1019 
1020  return true;
1021 }
1022 
1023 // Saves the unsigned XML contents to a string
1024 bool OTContract::SaveContents(OTString& strContents) const
1025 {
1026  strContents.Concatenate(m_xmlUnsigned.Get());
1027 
1028  return true;
1029 }
1030 
1031 // Save the contract member variables into the m_strRawFile variable
1032 bool OTContract::SaveContract()
1033 {
1034  OTString strTemp;
1035  bool bSuccess = RewriteContract(strTemp);
1036 
1037  if (bSuccess) {
1038  m_strRawFile.Set(strTemp);
1039 
1040  // RewriteContract() already does this.
1041  //
1042  // std::string str_Trim(strTemp.Get());
1043  // std::string str_Trim2 = OTString::trim(str_Trim);
1044  // m_strRawFile.Set(str_Trim2.c_str());
1045  }
1046 
1047  return bSuccess;
1048 }
1049 
1050 void OTContract::UpdateContents()
1051 {
1052  // Deliberately left blank.
1053  //
1054  // Some child classes may need to perform work here
1055  // (OTAccount and OTMessage, for example.)
1056  //
1057  // This function is called just prior to the signing of a contract.
1058 
1059  // Update: MOST child classes actually use this.
1060  // The server and asset contracts are not meant to ever change after
1061  // they are signed. However, many other contracts are meant to change
1062  // and be re-signed. (You cannot change something without signing it.)
1063  // (So most child classes override this method.)
1064 }
1065 
1066 // CreateContract is great if you already know what kind of contract to
1067 // instantiate
1068 // and have already done so. Otherwise this function will take ANY flat text and
1069 // use
1070 // a generic OTContract instance to sign it and then write it to strOutput. This
1071 // is
1072 // due to the fact that OT was never really designed for signing flat text, only
1073 // contracts.
1074 //
1075 // static
1076 bool OTContract::SignFlatText(OTString& strFlatText,
1077  const OTString& strContractType,
1078  const OTPseudonym& theSigner, OTString& strOutput)
1079 {
1080  const char* szFunc = "OTContract::SignFlatText";
1081 
1082  // Trim the input to remove any extraneous whitespace
1083  //
1084  std::string str_Trim(strFlatText.Get());
1085  std::string str_Trim2 = OTString::trim(str_Trim);
1086 
1087  strFlatText.Set(str_Trim2.c_str());
1088 
1089  char cNewline = 0;
1090  const uint32_t lLength = strFlatText.GetLength();
1091 
1092  if ((3 > lLength) || !strFlatText.At(lLength - 1, cNewline)) {
1093  otErr << szFunc
1094  << ": Invalid input: text is less than 3 bytes "
1095  "int64_t, or unable to read a byte from the end where "
1096  "a newline is meant to be.\n";
1097  return false;
1098  }
1099 
1100  // ADD a newline, if necessary.
1101  // (The -----BEGIN part needs to start on its OWN LINE...)
1102  //
1103  // If length is 10, then string goes from 0..9.
1104  // Null terminator will be at 10.
1105  // Therefore the final newline should be at 9.
1106  // Therefore if char_at_index[lLength-1] != '\n'
1107  // Concatenate one!
1108 
1109  OTString strInput;
1110  if ('\n' == cNewline) // It already has a newline
1111  strInput = strFlatText;
1112  else
1113  strInput.Format("%s\n", strFlatText.Get());
1114 
1115  OTSignature theSignature;
1116  OTPasswordData thePWData("Signing flat text (need private key)");
1117 
1118  if (false ==
1119  OTCrypto::It()->SignContract(strInput, theSigner.GetPrivateSignKey(),
1120  theSignature, // the output
1121  OTIdentifier::DefaultHashAlgorithm,
1122  &thePWData)) {
1123  otErr << szFunc << ": SignContract failed. Contents:\n\n" << strInput
1124  << "\n\n\n";
1125  return false;
1126  }
1127 
1128  listOfSignatures listSignatures;
1129  listSignatures.push_back(&theSignature);
1130 
1131  const bool bBookends = OTContract::AddBookendsAroundContent(
1132  strOutput, // the output (other params are input.)
1133  strInput, strContractType, OTIdentifier::DefaultHashAlgorithm,
1134  listSignatures);
1135 
1136  return bBookends;
1137 }
1138 
1139 // Saves the raw (pre-existing) contract text to any string you want to pass in.
1140 bool OTContract::SaveContractRaw(OTString& strOutput) const
1141 {
1142  strOutput.Concatenate("%s", m_strRawFile.Get());
1143 
1144  return true;
1145 }
1146 
1147 // static
1148 bool OTContract::AddBookendsAroundContent(
1149  OTString& strOutput, const OTString& strContents,
1150  const OTString& strContractType, const OTString& strHashType,
1151  const listOfSignatures& listSignatures)
1152 {
1153  OTString strTemp;
1154 
1155  strTemp.Concatenate("-----BEGIN SIGNED %s-----\nHash: %s\n\n",
1156  strContractType.Get(), strHashType.Get());
1157 
1158  strTemp.Concatenate("%s", strContents.Get());
1159 
1160  for (const auto& it : listSignatures) {
1161  OTSignature* pSig = it;
1162  OT_ASSERT(nullptr != pSig);
1163 
1164  strTemp.Concatenate("-----BEGIN %s SIGNATURE-----\n"
1165  "Version: Open Transactions %s\n"
1166  "Comment: "
1167  "http://github.com/FellowTraveler/"
1168  "Open-Transactions/wiki\n",
1169  strContractType.Get(), OTLog::Version());
1170 
1171  if (pSig->getMetaData().HasMetadata())
1172  strTemp.Concatenate("Meta: %c%c%c%c\n",
1173  pSig->getMetaData().GetKeyType(),
1174  pSig->getMetaData().FirstCharNymID(),
1176  pSig->getMetaData().FirstCharSubCredID());
1177 
1178  strTemp.Concatenate("\n%s",
1179  pSig->Get()); // <=== *** THE SIGNATURE ITSELF ***
1180  strTemp.Concatenate("-----END %s SIGNATURE-----\n\n",
1181  strContractType.Get());
1182  }
1183 
1184  std::string str_Trim(strTemp.Get());
1185  std::string str_Trim2 = OTString::trim(str_Trim);
1186  strOutput.Set(str_Trim2.c_str());
1187 
1188  return true;
1189 }
1190 
1191 // Takes the pre-existing XML contents (WITHOUT signatures) and re-writes
1192 // into strOutput the appearance of m_strRawData, adding the pre-existing
1193 // signatures along with new signature bookends.. (The caller actually passes
1194 // m_strRawData into this function...)
1195 //
1196 bool OTContract::RewriteContract(OTString& strOutput) const
1197 {
1198  OTString strContents;
1199  SaveContents(strContents);
1200 
1201  return OTContract::AddBookendsAroundContent(
1202  strOutput, strContents, m_strContractType, m_strSigHashType,
1203  m_listSignatures);
1204 }
1205 
1206 bool OTContract::SaveContract(const char* szFoldername, const char* szFilename)
1207 {
1208  OT_ASSERT_MSG(nullptr != szFilename,
1209  "Null filename sent to OTContract::SaveContract\n");
1210  OT_ASSERT_MSG(nullptr != szFoldername,
1211  "Null foldername sent to OTContract::SaveContract\n");
1212 
1213  m_strFoldername.Set(szFoldername);
1214  m_strFilename.Set(szFilename);
1215 
1216  OT_ASSERT(m_strFoldername.GetLength() > 2);
1217  OT_ASSERT(m_strFilename.GetLength() > 2);
1218 
1219  if (!m_strRawFile.Exists()) {
1220  otErr << "OTContract::SaveContract: Error saving file (contract "
1221  "contents are empty): " << szFoldername
1222  << OTLog::PathSeparator() << szFilename << "\n";
1223  return false;
1224  }
1225 
1226  OTString strFinal;
1227 
1228  OTASCIIArmor ascTemp(m_strRawFile);
1229 
1230  if (false ==
1231  ascTemp.WriteArmoredString(strFinal, m_strContractType.Get())) {
1232  otErr << "OTContract::SaveContract: Error saving file (failed writing "
1233  "armored string): " << szFoldername << OTLog::PathSeparator()
1234  << szFilename << "\n";
1235  return false;
1236  }
1237 
1238  bool bSaved =
1239  OTDB::StorePlainString(strFinal.Get(), szFoldername, szFilename);
1240 
1241  if (!bSaved) {
1242  otErr << "OTContract::SaveContract: Error saving file: " << szFoldername
1243  << OTLog::PathSeparator() << szFilename << "\n";
1244  return false;
1245  }
1246 
1247  return true;
1248 }
1249 
1250 // assumes m_strFilename is already set.
1251 // Then it reads that file into a string.
1252 // Then it parses that string into the object.
1253 bool OTContract::LoadContract()
1254 {
1255  Release();
1256  LoadContractRawFile(); // opens m_strFilename and reads into m_strRawFile
1257 
1258  return ParseRawFile(); // Parses m_strRawFile into the various member
1259  // variables.
1260 }
1261 
1262 // The entire Raw File, signatures and all, is used to calculate the hash
1263 // value that becomes the ID of the contract. If you change even one letter,
1264 // then you get a different ID.
1265 // This applies to all contracts except accounts, since their contents must
1266 // change periodically, their ID is not calculated from a hash of the file,
1267 // but instead is chosen at random when the account is created.
1268 bool OTContract::LoadContractRawFile()
1269 {
1270  const char* szFoldername = m_strFoldername.Get();
1271  const char* szFilename = m_strFilename.Get();
1272 
1273  if (!m_strFoldername.Exists() || !m_strFilename.Exists()) return false;
1274 
1275  if (!OTDB::Exists(szFoldername, szFilename)) {
1276  otErr << __FUNCTION__ << ": File does not exist: " << szFoldername
1277  << OTLog::PathSeparator() << szFilename << "\n";
1278  return false;
1279  }
1280 
1281  OTString strFileContents(OTDB::QueryPlainString(
1282  szFoldername, szFilename)); // <=== LOADING FROM DATA STORE.
1283 
1284  if (!strFileContents.Exists()) {
1285  otErr << __FUNCTION__ << ": Error reading file: " << szFoldername
1286  << OTLog::PathSeparator() << szFilename << "\n";
1287  return false;
1288  }
1289 
1290  if (false ==
1291  strFileContents.DecodeIfArmored()) // bEscapedIsAllowed=true by default.
1292  {
1293  otErr << __FUNCTION__ << ": Input string apparently was encoded and "
1294  "then failed decoding. Contents: \n"
1295  << strFileContents << "\n";
1296  return false;
1297  }
1298 
1299  // At this point, strFileContents contains the actual contents, whether they
1300  // were originally ascii-armored OR NOT. (And they are also now trimmed,
1301  // either way.)
1302  //
1303  m_strRawFile.Set(strFileContents);
1304 
1305  return m_strRawFile.Exists();
1306 }
1307 
1308 bool OTContract::LoadContract(const char* szFoldername, const char* szFilename)
1309 {
1310  Release();
1311 
1312  m_strFoldername.Set(szFoldername);
1313  m_strFilename.Set(szFilename);
1314 
1315  // opens m_strFilename and reads into m_strRawFile
1316  if (LoadContractRawFile())
1317  return ParseRawFile(); // Parses m_strRawFile into the various member
1318  // variables.
1319  else {
1320  otErr << "Failed loading raw contract file: " << m_strFoldername
1321  << OTLog::PathSeparator() << m_strFilename << "\n";
1322  }
1323  return false;
1324 }
1325 
1326 // Just like it says. If you have a contract in string form, pass it in
1327 // here to import it.
1328 bool OTContract::LoadContractFromString(const OTString& theStr)
1329 {
1330  Release();
1331 
1332  if (!theStr.Exists()) {
1333  otErr << __FUNCTION__ << ": ERROR: Empty string passed in...\n";
1334  return false;
1335  }
1336 
1337  OTString strContract(theStr);
1338 
1339  if (false ==
1340  strContract.DecodeIfArmored()) // bEscapedIsAllowed=true by default.
1341  {
1342  otErr << __FUNCTION__ << ": ERROR: Input string apparently was encoded "
1343  "and then failed decoding. "
1344  "Contents: \n" << theStr << "\n";
1345  return false;
1346  }
1347 
1348  m_strRawFile.Set(strContract);
1349 
1350  // This populates m_xmlUnsigned with the contents of m_strRawFile (minus
1351  // bookends, signatures, etc. JUST the XML.)
1352  bool bSuccess =
1353  ParseRawFile(); // It also parses into the various member variables.
1354 
1355  // Removed:
1356  // This was the bug where the version changed from 75 to 75c, and suddenly
1357  // contract ID was wrong...
1358  //
1359  // If it was a success, save back to m_strRawFile again so
1360  // the format is consistent and hashes will calculate properly.
1361  // if (bSuccess)
1362  // {
1363  // // Basically we take the m_xmlUnsigned that we parsed out of the
1364  // raw file before,
1365  // // then we use that to generate the raw file again, re-attaching
1366  // the signatures.
1367  // // This function does that.
1368  // SaveContract();
1369  // }
1370 
1371  return bSuccess;
1372 }
1373 
1374 bool OTContract::ParseRawFile()
1375 {
1376  char buffer1[2100]; // a bit bigger than 2048, just for safety reasons.
1377  OTSignature* pSig = nullptr;
1378 
1379  std::string line;
1380 
1381  bool bSignatureMode = false; // "currently in signature mode"
1382  bool bContentMode = false; // "currently in content mode"
1383  bool bHaveEnteredContentMode = false; // "have yet to enter content mode"
1384 
1385  if (!m_strRawFile.GetLength()) {
1386  otErr << "Empty m_strRawFile in OTContract::ParseRawFile. Filename: "
1387  << m_strFoldername << OTLog::PathSeparator() << m_strFilename
1388  << ".\n";
1389  return false;
1390  }
1391 
1392  // This is redundant (I thought) but the problem hasn't cleared up yet.. so
1393  // trying to really nail it now.
1394  std::string str_Trim(m_strRawFile.Get());
1395  std::string str_Trim2 = OTString::trim(str_Trim);
1396  m_strRawFile.Set(str_Trim2.c_str());
1397 
1398  bool bIsEOF = false;
1399  m_strRawFile.reset();
1400 
1401  do {
1402  // Just a fresh start at the top of the loop block... probably
1403  // unnecessary.
1404  memset(buffer1, 0, 2100); // todo remove this in optimization. (might be
1405  // removed already...)
1406 
1407  // the call returns true if there's more to read, and false if there
1408  // isn't.
1409  bIsEOF = !(m_strRawFile.sgets(buffer1, 2048));
1410 
1411  line = buffer1;
1412  const char* pConstBuf = line.c_str();
1413  char* pBuf = (char*)pConstBuf;
1414 
1415  if (line.length() < 2) {
1416  if (bSignatureMode) continue;
1417  }
1418 
1419  // if we're on a dashed line...
1420  else if (line.at(0) == '-') {
1421  if (bSignatureMode) {
1422  // we just reached the end of a signature
1423  // otErr << "%s\n", pSig->Get());
1424  pSig = nullptr;
1425  bSignatureMode = false;
1426  continue;
1427  }
1428 
1429  // if I'm NOT in signature mode, and I just hit a dash, that means
1430  // there
1431  // are only four options:
1432 
1433  // a. I have not yet even entered content mode, and just now
1434  // entering it for the first time.
1435  if (!bHaveEnteredContentMode) {
1436  if ((line.length() > 3) &&
1437  (line.find("BEGIN") != std::string::npos) &&
1438  line.at(1) == '-' && line.at(2) == '-' &&
1439  line.at(3) == '-') {
1440  // otErr << "\nProcessing contract...
1441  // \n";
1442  bHaveEnteredContentMode = true;
1443  bContentMode = true;
1444  continue;
1445  }
1446  else {
1447  continue;
1448  }
1449 
1450  }
1451 
1452  // b. I am now entering signature mode!
1453  else if (line.length() > 3 &&
1454  line.find("SIGNATURE") != std::string::npos &&
1455  line.at(1) == '-' && line.at(2) == '-' &&
1456  line.at(3) == '-') {
1457  // if (bContentMode)
1458  // otLog3 << "Finished reading contract.\n\nReading a
1459  // signature at the bottom of the contract...\n");
1460  // else
1461  // otLog3 << "Reading another signature...\n");
1462 
1463  bSignatureMode = true;
1464  bContentMode = false;
1465 
1466  pSig = new OTSignature();
1467 
1468  OT_ASSERT_MSG(nullptr != pSig, "Error allocating memory for "
1469  "Signature in "
1470  "OTContract::ParseRawFile\n");
1471 
1472  m_listSignatures.push_back(pSig);
1473 
1474  continue;
1475  }
1476  // c. There is an error in the file!
1477  else if (line.length() < 3 || line.at(1) != ' ' ||
1478  line.at(2) != '-') {
1479  otOut
1480  << "Error in contract " << m_strFilename
1481  << ": a dash at the beginning of the "
1482  "line should be followed by a space and another dash:\n"
1483  << m_strRawFile << "\n";
1484  return false;
1485  }
1486  // d. It is an escaped dash, and therefore kosher, so I merely
1487  // remove the escape and add it.
1488  // I've decided not to remove the dashes but to keep them as part of
1489  // the signed content.
1490  // It's just much easier to deal with that way. The input code will
1491  // insert the extra dashes.
1492  // pBuf += 2;
1493  }
1494 
1495  // Else we're on a normal line, not a dashed line.
1496  else {
1497  if (bHaveEnteredContentMode) {
1498  if (bSignatureMode) {
1499  if (line.length() < 2) {
1500  otLog3 << "Skipping short line...\n";
1501 
1502  if (bIsEOF || !m_strRawFile.sgets(buffer1, 2048)) {
1503  otOut << "Error in signature for contract "
1504  << m_strFilename
1505  << ": Unexpected EOF after short line.\n";
1506  return false;
1507  }
1508 
1509  continue;
1510  }
1511  else if (line.compare(0, 8, "Version:") == 0) {
1512  otLog3 << "Skipping version section...\n";
1513 
1514  if (bIsEOF || !m_strRawFile.sgets(buffer1, 2048)) {
1515  otOut << "Error in signature for contract "
1516  << m_strFilename
1517  << ": Unexpected EOF after \"Version:\"\n";
1518  return false;
1519  }
1520 
1521  continue;
1522  }
1523  else if (line.compare(0, 8, "Comment:") == 0) {
1524  otLog3 << "Skipping comment section...\n";
1525 
1526  if (bIsEOF || !m_strRawFile.sgets(buffer1, 2048)) {
1527  otOut << "Error in signature for contract "
1528  << m_strFilename
1529  << ": Unexpected EOF after \"Comment:\"\n";
1530  return false;
1531  }
1532 
1533  continue;
1534  }
1535  if (line.compare(0, 5, "Meta:") == 0) {
1536  otLog3 << "Collecting signature metadata...\n";
1537 
1538  if (line.length() !=
1539  13) // "Meta: knms" (It will always be exactly 13
1540  // characters int64_t.) knms represents the
1541  // first characters of the Key type, NymID,
1542  // Master Cred ID, and Subcred ID. Key type is
1543  // (A|E|S) and the others are base62.
1544  {
1545  otOut << "Error in signature for contract "
1546  << m_strFilename << ": Unexpected length for "
1547  "\"Meta:\" comment.\n";
1548  return false;
1549  }
1550 
1551  OT_ASSERT(nullptr != pSig);
1552  if (false ==
1553  pSig->getMetaData().SetMetadata(
1554  line.at(9), line.at(10), line.at(11),
1555  line.at(12))) // "knms" from "Meta: knms"
1556  {
1557  otOut << "Error in signature for contract "
1558  << m_strFilename
1559  << ": Unexpected metadata in the \"Meta:\" "
1560  "comment.\nLine: " << line << "\n";
1561  return false;
1562  }
1563 
1564  if (bIsEOF || !m_strRawFile.sgets(buffer1, 2048)) {
1565  otOut << "Error in signature for contract "
1566  << m_strFilename
1567  << ": Unexpected EOF after \"Meta:\"\n";
1568  return false;
1569  }
1570 
1571  continue;
1572  }
1573  }
1574  if (bContentMode) {
1575  if (line.compare(0, 6, "Hash: ") == 0) {
1576  otLog3 << "Collecting message digest algorithm from "
1577  "contract header...\n";
1578 
1579  std::string strTemp = line.substr(6);
1580  m_strSigHashType = strTemp.c_str();
1581  m_strSigHashType.ConvertToUpperCase();
1582 
1583  if (bIsEOF || !m_strRawFile.sgets(buffer1, 2048)) {
1584  otOut << "Error in contract " << m_strFilename
1585  << ": Unexpected EOF after \"Hash:\"\n";
1586  return false;
1587  }
1588  continue;
1589  }
1590  }
1591  }
1592  }
1593 
1594  if (bSignatureMode) {
1595  OT_ASSERT_MSG(nullptr != pSig,
1596  "Error: Null Signature pointer WHILE "
1597  "processing signature, in "
1598  "OTContract::ParseRawFile");
1599 
1600  pSig->Concatenate("%s\n", pBuf);
1601  }
1602  else if (bContentMode)
1603  m_xmlUnsigned.Concatenate("%s\n", pBuf);
1604  } while (!bIsEOF);
1605  // while(!bIsEOF && (!bHaveEnteredContentMode || bContentMode ||
1606  // bSignatureMode));
1607 
1608  if (!bHaveEnteredContentMode) {
1609  otErr << "Error in OTContract::ParseRawFile: Found no BEGIN for signed "
1610  "content.\n";
1611  return false;
1612  }
1613  else if (bContentMode) {
1614  otErr << "Error in OTContract::ParseRawFile: EOF while reading xml "
1615  "content.\n";
1616  return false;
1617  }
1618  else if (bSignatureMode) {
1619  otErr << "Error in OTContract::ParseRawFile: EOF while reading "
1620  "signature.\n";
1621  OT_FAIL_MSG("gimme a call stack!");
1622  }
1623  else if (!LoadContractXML()) {
1624  otErr << "Error in OTContract::ParseRawFile: unable to load XML "
1625  "portion of contract into memory.\n";
1626  return false;
1627  }
1628  // Verification code and loading code are now called separately.
1629  // else if (!VerifyContractID())
1630  // {
1631  // otErr << "Error in OTContract::ParseRawFile: Contract ID does not
1632  // match hashed contract file.\n";
1633  // return false;
1634  // }
1635  else {
1636  return true;
1637  }
1638 }
1639 
1640 // This function assumes that m_xmlUnsigned is ready to be processed.
1641 // This function only processes that portion of the contract.
1642 bool OTContract::LoadContractXML()
1643 {
1644  int32_t retProcess = 0;
1645 
1646  if (!m_xmlUnsigned.Exists()) {
1647  return false;
1648  }
1649 
1650  m_xmlUnsigned.reset();
1651 
1652  IrrXMLReader* xml = irr::io::createIrrXMLReader(m_xmlUnsigned);
1653  OT_ASSERT_MSG(nullptr != xml, "Memory allocation issue with xml reader in "
1654  "OTContract::LoadContractXML()\n");
1655  std::unique_ptr<IrrXMLReader> xmlAngel(xml);
1656 
1657  // parse the file until end reached
1658  while (xml->read()) {
1659  OTString strNodeType;
1660 
1661  switch (xml->getNodeType()) {
1662  case EXN_NONE:
1663  strNodeType.Set("EXN_NONE");
1664  goto switch_log;
1665  case EXN_COMMENT:
1666  strNodeType.Set("EXN_COMMENT");
1667  goto switch_log;
1668  case EXN_ELEMENT_END:
1669  strNodeType.Set("EXN_ELEMENT_END");
1670  goto switch_log;
1671  case EXN_CDATA:
1672  strNodeType.Set("EXN_CDATA");
1673  goto switch_log;
1674 
1675  switch_log:
1676  // otErr << "SKIPPING %s element in
1677  // OTContract::LoadContractXML: "
1678  // "type: %d, name: %s, value: %s\n",
1679  // strNodeType.Get(),
1680  // xml->getNodeType(), xml->getNodeName(), xml->getNodeData());
1681 
1682  break;
1683 
1684  case EXN_TEXT: {
1685  // unknown element type
1686  // otErr << "SKIPPING unknown text element type in
1687  // OTContract::LoadContractXML: %s, value: %s\n",
1688  // xml->getNodeName(),
1689  // xml->getNodeData());
1690  } break;
1691  case EXN_ELEMENT: {
1692  retProcess = ProcessXMLNode(xml);
1693 
1694  // an error was returned. file format or whatever.
1695  if ((-1) == retProcess) {
1696  otErr << "OTContract::LoadContractXML: (Cancelling this "
1697  "contract load; an error occurred.)\n";
1698  return false;
1699  }
1700  // No error, but also the node wasn't found...
1701  else if (0 == retProcess) {
1702  // unknown element type
1703  otErr << "UNKNOWN element type in OTContract::LoadContractXML: "
1704  << xml->getNodeName() << ", value: " << xml->getNodeData()
1705  << "\n";
1706  }
1707  // else if 1 was returned, that means the node was processed.
1708  } break;
1709  default: {
1710  // otErr << "SKIPPING (default case) element in
1711  // OTContract::LoadContractXML: %d, value: %s\n",
1712  // xml->getNodeType(),
1713  // xml->getNodeData());
1714  }
1715  continue;
1716  }
1717  }
1718 
1719  return true;
1720 }
1721 
1722 // static
1723 bool OTContract::SkipToElement(IrrXMLReader*& xml)
1724 {
1725  OT_ASSERT_MSG(nullptr != xml,
1726  "OTContract::SkipToElement -- assert: nullptr != xml");
1727 
1728  const char* szFunc = "OTContract::SkipToElement";
1729 
1730  while (xml->read() && (xml->getNodeType() != EXN_ELEMENT)) {
1731  // otOut << szFunc << ": Looping to skip non-elements: currently
1732  // on: " << xml->getNodeName() << " \n";
1733 
1734  if (xml->getNodeType() == EXN_NONE) {
1735  otOut << "*** " << szFunc << ": EXN_NONE (skipping)\n";
1736  continue;
1737  } // SKIP
1738  else if (xml->getNodeType() == EXN_COMMENT) {
1739  otOut << "*** " << szFunc << ": EXN_COMMENT (skipping)\n";
1740  continue;
1741  } // SKIP
1742  else if (xml->getNodeType() == EXN_ELEMENT_END)
1743  // { otOut << "*** OTContract::SkipToElement: EXN_ELEMENT_END
1744  // (ERROR)\n"; return false; }
1745  {
1746  otWarn << "*** " << szFunc << ": EXN_ELEMENT_END (skipping "
1747  << xml->getNodeName() << ")\n";
1748  continue;
1749  }
1750  else if (xml->getNodeType() == EXN_CDATA) {
1751  otOut << "*** " << szFunc
1752  << ": EXN_CDATA (ERROR -- unexpected CData)\n";
1753  return false;
1754  }
1755  else if (xml->getNodeType() == EXN_TEXT) {
1756  otErr << "*** " << szFunc << ": EXN_TEXT\n";
1757  return false;
1758  }
1759  else if (xml->getNodeType() == EXN_ELEMENT) {
1760  otOut << "*** " << szFunc << ": EXN_ELEMENT\n";
1761  break;
1762  } // (Should never happen due to while() second condition.) Still
1763  // returns true.
1764  else {
1765  otErr << "*** " << szFunc
1766  << ": SHOULD NEVER HAPPEN (Unknown element type!)\n";
1767  return false;
1768  } // Failure / Error
1769  }
1770 
1771  return true;
1772 }
1773 
1774 // static
1775 bool OTContract::SkipToTextField(IrrXMLReader*& xml)
1776 {
1777  OT_ASSERT_MSG(nullptr != xml,
1778  "OTContract::SkipToTextField -- assert: nullptr != xml");
1779 
1780  const char* szFunc = "OTContract::SkipToTextField";
1781 
1782  while (xml->read() && (xml->getNodeType() != EXN_TEXT)) {
1783  if (xml->getNodeType() == EXN_NONE) {
1784  otOut << "*** " << szFunc << ": EXN_NONE (skipping)\n";
1785  continue;
1786  } // SKIP
1787  else if (xml->getNodeType() == EXN_COMMENT) {
1788  otOut << "*** " << szFunc << ": EXN_COMMENT (skipping)\n";
1789  continue;
1790  } // SKIP
1791  else if (xml->getNodeType() == EXN_ELEMENT_END)
1792  // { otOut << "*** OTContract::SkipToTextField:
1793  // EXN_ELEMENT_END (skipping)\n"; continue; } // SKIP
1794  // (debugging...)
1795  {
1796  otOut << "*** " << szFunc << ": EXN_ELEMENT_END (ERROR)\n";
1797  return false;
1798  }
1799  else if (xml->getNodeType() == EXN_CDATA) {
1800  otOut << "*** " << szFunc
1801  << ": EXN_CDATA (ERROR -- unexpected CData)\n";
1802  return false;
1803  }
1804  else if (xml->getNodeType() == EXN_ELEMENT) {
1805  otOut << "*** " << szFunc << ": EXN_ELEMENT\n";
1806  return false;
1807  }
1808  else if (xml->getNodeType() == EXN_TEXT) {
1809  otErr << "*** " << szFunc << ": EXN_TEXT\n";
1810  break;
1811  } // (Should never happen due to while() second condition.) Still
1812  // returns true.
1813  else {
1814  otErr << "*** " << szFunc
1815  << ": SHOULD NEVER HAPPEN (Unknown element type!)\n";
1816  return false;
1817  } // Failure / Error
1818  }
1819 
1820  return true;
1821 }
1822 
1823 // AFTER you read an element or text field, there is some whitespace, and you
1824 // just want to bring your cursor back to wherever it should be for the next
1825 // guy.
1826 // So you call this function..
1827 //
1828 // static
1829 bool OTContract::SkipAfterLoadingField(IrrXMLReader*& xml)
1830 {
1831  OT_ASSERT_MSG(
1832  nullptr != xml,
1833  "OTContract::SkipAfterLoadingField -- assert: nullptr != xml");
1834 
1835  if (EXN_ELEMENT_END != xml->getNodeType()) // If we're not ALREADY on the
1836  // ending element, then go there.
1837  {
1838  const char* szFunc = "OTContract::SkipAfterLoadingField";
1839  // move to the next node which SHOULD be the expected element_end.
1840  //
1841  while (xml->read()) {
1842  if (xml->getNodeType() == EXN_NONE) {
1843  otOut << "*** " << szFunc << ": EXN_NONE (skipping)\n";
1844  continue;
1845  } // SKIP
1846  else if (xml->getNodeType() == EXN_COMMENT) {
1847  otOut << "*** " << szFunc << ": EXN_COMMENT (skipping)\n";
1848  continue;
1849  } // SKIP
1850  else if (xml->getNodeType() == EXN_ELEMENT_END) {
1851  otLog5 << "*** " << szFunc << ": EXN_ELEMENT_END (success)\n";
1852  break;
1853  } // Success...
1854  else if (xml->getNodeType() == EXN_CDATA) {
1855  otOut << "*** " << szFunc << ": EXN_CDATA (Unexpected!)\n";
1856  return false;
1857  } // Failure / Error
1858  else if (xml->getNodeType() == EXN_ELEMENT) {
1859  otOut << "*** " << szFunc << ": EXN_ELEMENT (Unexpected!)\n";
1860  return false;
1861  } // Failure / Error
1862  else if (xml->getNodeType() == EXN_TEXT) {
1863  otErr << "*** " << szFunc << ": EXN_TEXT (Unexpected!)\n";
1864  return false;
1865  } // Failure / Error
1866  else {
1867  otErr << "*** " << szFunc
1868  << ": SHOULD NEVER HAPPEN (Unknown element type!)\n";
1869  return false;
1870  } // Failure / Error
1871  }
1872  }
1873 
1874  // else ... (already on the ending element.)
1875  //
1876 
1877  return true;
1878 }
1879 
1880 // Loads it up and also decodes it to a string.
1881 //
1882 // static
1883 bool OTContract::LoadEncodedTextField(IrrXMLReader*& xml, OTString& strOutput)
1884 {
1885  OTASCIIArmor ascOutput;
1886 
1887  if (OTContract::LoadEncodedTextField(xml, ascOutput) &&
1888  ascOutput.GetLength() > 2) {
1889  return ascOutput.GetString(strOutput, true); // linebreaks = true
1890  }
1891 
1892  return false;
1893 }
1894 
1895 // static
1896 bool OTContract::LoadEncodedTextField(IrrXMLReader*& xml,
1897  OTASCIIArmor& ascOutput)
1898 {
1899  OT_ASSERT_MSG(nullptr != xml,
1900  "OTContract::LoadEncodedTextField -- assert: nullptr != xml");
1901 
1902  const char* szFunc = "OTContract::LoadEncodedTextField";
1903 
1904  // If we're not ALREADY on a text field, maybe there is some whitespace, so
1905  // let's skip ahead...
1906  //
1907  if (EXN_TEXT != xml->getNodeType()) {
1908  otLog4 << szFunc << ": Skipping non-text field... \n";
1909 
1910  // move to the next node which SHOULD be the expected text field.
1911  //
1912  if (!SkipToTextField(xml)) {
1913  otOut << szFunc
1914  << ": Failure: Unable to find expected text field.\n";
1915  return false;
1916  }
1917  otLog4 << szFunc
1918  << ": Finished skipping non-text field. (Successfully.)\n";
1919  }
1920 
1921  if (EXN_TEXT == xml->getNodeType()) // SHOULD always be true, in fact this
1922  // could be an assert().
1923  {
1924  OTString strNodeData = xml->getNodeData();
1925 
1926  // Sometimes the XML reads up the data with a prepended newline.
1927  // This screws up my own objects which expect a consistent in/out
1928  // So I'm checking here for that prepended newline, and removing it.
1929  //
1930  char cNewline;
1931  if (strNodeData.Exists() && strNodeData.GetLength() > 2 &&
1932  strNodeData.At(0, cNewline)) {
1933  if ('\n' == cNewline) {
1934  ascOutput.Set(strNodeData.Get() + 1);
1935  }
1936  else {
1937  ascOutput.Set(strNodeData.Get());
1938  }
1939 
1940  // SkipAfterLoadingField() only skips ahead if it's not ALREADY
1941  // sitting on an element_end node.
1942  //
1943  xml->read(); // THIS PUTS us on the CLOSING TAG.
1944  // <========================
1945 
1946  // The below call won't advance any further if it's ALREADY on the
1947  // closing tag (e.g. from the above xml->read() call.)
1948  if (!SkipAfterLoadingField(xml)) {
1949  otOut << "*** " << szFunc
1950  << ": Bad data? Expected EXN_ELEMENT_END here, but "
1951  "didn't get it. Returning false.\n";
1952  return false;
1953  }
1954 
1955  return true;
1956  }
1957  }
1958  else
1959  otOut << szFunc << ": Failure: Unable to find expected text field. 2\n";
1960 
1961  return false;
1962 }
1963 
1964 // Loads it up and also decodes it to a string.
1965 // static
1966 bool OTContract::LoadEncodedTextFieldByName(IrrXMLReader*& xml,
1967  OTString& strOutput,
1968  const char*& szName,
1969  OTString::Map* pmapExtraVars)
1970 {
1971  OT_ASSERT(nullptr != szName);
1972 
1973  OTASCIIArmor ascOutput;
1974 
1975  if (OTContract::LoadEncodedTextFieldByName(xml, ascOutput, szName,
1976  pmapExtraVars) &&
1977  ascOutput.GetLength() > 2) {
1978  return ascOutput.GetString(strOutput, true); // linebreaks = true
1979  }
1980 
1981  return false;
1982 }
1983 
1984 // Loads it up and keeps it encoded in an ascii-armored object.
1985 // static
1986 bool OTContract::LoadEncodedTextFieldByName(IrrXMLReader*& xml,
1987  OTASCIIArmor& ascOutput,
1988  const char*& szName,
1989  OTString::Map* pmapExtraVars)
1990 {
1991  OT_ASSERT(nullptr != szName);
1992 
1993  const char* pElementExpected = szName;
1994 
1995  // If we're not ALREADY on an element, maybe there is some whitespace, so
1996  // let's skip ahead...
1997  //
1998  if ((EXN_ELEMENT != xml->getNodeType()) || // If we're not already on a
1999  // node, OR if the node's
2000  !(strcmp(pElementExpected, xml->getNodeName()) ==
2001  0)) // name doesn't match the one expected.
2002  {
2003  // move to the next node which SHOULD be the expected name.
2004  //
2005  if (!SkipToElement(xml)) {
2006  otOut << __FUNCTION__
2007  << ": Failure: Unable to find expected element: " << szName
2008  << ". \n";
2009  return false;
2010  }
2011  }
2012 
2013  if (EXN_ELEMENT == xml->getNodeType()) // SHOULD always be true...
2014  {
2015  if (!strcmp(pElementExpected, xml->getNodeName())) {
2016 
2017  if (nullptr !=
2018  pmapExtraVars) // If the caller wants values for certain
2019  // names expected to be on this node.
2020  {
2021  OTString::Map& mapExtraVars = (*pmapExtraVars);
2022 
2023  for (auto& it : mapExtraVars) {
2024  std::string first = it.first;
2025  OTString strTemp = xml->getAttributeValue(first.c_str());
2026 
2027  if (strTemp.Exists()) {
2028  mapExtraVars[first] = strTemp.Get();
2029 
2030  // mapExtraVars.erase(first);
2031  // mapExtraVars.insert(std::pair<std::string,
2032  // std::string>(first, strTemp.Get()));
2033  }
2034  }
2035  } // Any attribute names passed in, now have their corresponding
2036  // values set on mapExtraVars (for caller.)
2037 
2038  if (false ==
2039  OTContract::LoadEncodedTextField(
2040  xml,
2041  ascOutput)) // <====================================================
2042  {
2043  otErr << __FUNCTION__ << ": Error loading " << pElementExpected
2044  << " field.\n";
2045  return false; // error condition
2046  }
2047  else {
2048 
2049  // SkipAfterLoadingField() only skips ahead if it's not ALREADY
2050  // sitting on an element_end node.
2051  //
2052  // Update: Above, LoadEncodedTextField() already does this
2053  // (below).
2054  //
2055  // if (!SkipAfterLoadingField(xml))
2056  // { otOut << "*** %s: Bad data? Expected
2057  // EXN_ELEMENT_END here, but "
2058  // "didn't get it. Returning
2059  // false.\n", __FUNCTION__); return false; }
2060 
2061  return true; // <============ SUCCESS!!!!
2062  }
2063  }
2064  else {
2065  otErr << __FUNCTION__ << ": Error: missing " << pElementExpected
2066  << " element.\n";
2067  return false; // error condition
2068  }
2069  }
2070  else {
2071  otErr << __FUNCTION__ << ": Error: Expected " << pElementExpected
2072  << " element with text field.\n";
2073  return false; // error condition
2074  }
2075 }
2076 
2077 // Make sure you escape any lines that begin with dashes using "- "
2078 // So "---BEGIN " at the beginning of a line would change to: "- ---BEGIN"
2079 // This function expects that's already been done.
2080 // This function assumes there is only unsigned contents, and not a signed
2081 // contract.
2082 // This function is intended to PRODUCE said signed contract.
2083 // NOTE: This function also assumes you already instantiated a contract
2084 // of the proper type. For example, if it's an OTServerContract, then you
2085 // INSTANTIATED an OTServerContract. Because if you tried to do this using
2086 // an OTContract but then the strContract was for an OTServerContract, then
2087 // this function will fail when it tries to "LoadContractFromString()" since it
2088 // is not actually the proper type to handle those data members.
2089 //
2090 // Therefore I need to make an entirely different (but similar) function which
2091 // can be used for signing a piece of unsigned XML where the actual contract
2092 // type
2093 // is unknown.
2094 //
2095 bool OTContract::CreateContract(const OTString& strContract,
2096  const OTPseudonym& theSigner)
2097 {
2098  Release();
2099 
2100  char cNewline =
2101  0; // this is about to contain a byte read from the end of the contract.
2102  const uint32_t lLength = strContract.GetLength();
2103 
2104  if ((3 > lLength) || !strContract.At(lLength - 1, cNewline)) {
2105  otErr << __FUNCTION__
2106  << ": Invalid input: contract is less than 3 bytes "
2107  "int64_t, or unable to read a byte from the end where a "
2108  "newline is meant to be.\n";
2109  return false;
2110  }
2111 
2112  // ADD a newline, if necessary.
2113  // (The -----BEGIN part needs to start on its OWN LINE...)
2114  //
2115  // If length is 10, then string goes from 0..9.
2116  // Null terminator will be at 10.
2117  // Therefore the final newline should be at 9.
2118  // Therefore if char_at_index[lLength-1] != '\n'
2119  // Concatenate one!
2120 
2121  if ('\n' == cNewline) // It already has a newline
2122  m_xmlUnsigned = strContract;
2123  else
2124  m_xmlUnsigned.Format("%s\n", strContract.Get());
2125 
2126  // This function assumes that m_xmlUnsigned is ready to be processed.
2127  // This function only processes that portion of the contract.
2128  //
2129  bool bLoaded = LoadContractXML();
2130 
2131  if (bLoaded) {
2132 
2133  // Add theSigner to the contract, if he's not already there.
2134  //
2135  if (nullptr == GetContractPublicNym()) {
2136  const bool bHasCredentials =
2137  (theSigner.GetMasterCredentialCount() > 0);
2138 
2139  if (!bHasCredentials) {
2140  OTString strPubkey;
2141  if (theSigner.GetPublicSignKey().GetPublicKey(
2142  strPubkey) && // bEscaped=true by default.
2143  strPubkey.Exists()) {
2144  InsertNym("contract", strPubkey);
2145  }
2146  }
2147  else // theSigner has Credentials, so we'll add him to the
2148  // contract.
2149  {
2150  OTString strCredList, strSignerNymID;
2151  OTString::Map mapCredFiles;
2152  theSigner.GetIdentifier(strSignerNymID);
2153  theSigner.GetPublicCredentials(strCredList, &mapCredFiles);
2154 
2155  std::unique_ptr<OTPseudonym> pNym(new OTPseudonym);
2156 
2157  pNym->SetIdentifier(strSignerNymID);
2158  pNym->SetNymIDSource(theSigner.GetNymIDSource());
2159  pNym->SetAltLocation(theSigner.GetAltLocation());
2160 
2161  if (!pNym->LoadFromString(strCredList, &mapCredFiles)) {
2162  otErr << __FUNCTION__ << ": Failure loading nym "
2163  << strSignerNymID << " from credential string.\n";
2164  }
2165  // Now that the Nym has been loaded up from the two strings,
2166  // including the list of credential IDs, and the map containing
2167  // the
2168  // credentials themselves, let's try to Verify the pseudonym. If
2169  // we
2170  // verify, then we're safe to add the Nym to the contract.
2171  //
2172  else if (!pNym->VerifyPseudonym()) {
2173  otErr
2174  << __FUNCTION__ << ": Loaded nym " << strSignerNymID
2175  << " from credentials, but then it failed verifying.\n";
2176  }
2177  else // Okay, we loaded the Nym up from the credentials, AND
2178  { // verified the Nym (including the credentials.)
2179  // So let's add it to the contract...
2180  // Add pNym to the contract's
2181  m_mapNyms["signer"] = pNym.release();
2182  // internal list of nyms.
2183  }
2184  }
2185  }
2186  // This re-writes the contract internally based on its data members,
2187  // similar to UpdateContents. (Except specifically intended for the
2188  // initial creation of the contract.)
2189  // Since theSigner was just added, he will be included here now as well,
2190  // just prior to the actual signing below.
2191  //
2192  CreateContents();
2193 
2194  OTPasswordData thePWData("OTContract::CreateContract needs the private "
2195  "key to sign the contract...");
2196 
2197  if (!SignContract(theSigner, &thePWData)) {
2198  otErr << __FUNCTION__ << ": SignContract failed.\n";
2199  return false;
2200  }
2201 
2202  SaveContract();
2203 
2204  OTString strTemp;
2205  SaveContractRaw(strTemp);
2206 
2207  Release();
2208  LoadContractFromString(strTemp); // The ultimate test is, once
2209  // we've created the serialized
2210  // string for this contract, is
2211  // to then load it up from that
2212  // string.
2213 
2214  OTIdentifier NEW_ID;
2215  CalculateContractID(NEW_ID);
2216  m_ID = NEW_ID;
2217 
2218  return true;
2219  }
2220  else
2221  otErr << __FUNCTION__
2222  << ": LoadContractXML failed. strContract contents:\n\n"
2223  << strContract << "\n\n";
2224 
2225  return false;
2226 }
2227 
2228 // Overrides of CreateContents call this in order to add some common internals.
2229 //
2230 void OTContract::CreateInnerContents()
2231 {
2232  // CONDITIONS
2233  //
2234  if (!m_mapConditions.empty()) {
2235  m_xmlUnsigned.Concatenate("<!-- CONDITIONS -->\n\n");
2236 
2237  for (auto& it : m_mapConditions) {
2238  std::string str_condition_name = it.first;
2239  std::string str_condition_value = it.second;
2240 
2241  m_xmlUnsigned.Concatenate(
2242  "<condition name=\"%s\">%s</condition>\n\n",
2243  str_condition_name.c_str(), str_condition_value.c_str());
2244  }
2245  }
2246 
2247  // KEYS (old) / CREDENTIALS (new)
2248  //
2249  if (!m_mapNyms.empty()) {
2250  OTString strTemp;
2251 
2252  // KEYS (Note: deprecated in favor of NymID source and credentials.)
2253  for (auto& it : m_mapNyms) {
2254  std::string str_name = it.first;
2255  OTPseudonym* pNym = it.second;
2256  OT_ASSERT_MSG(nullptr != pNym,
2257  "1: nullptr pseudonym pointer in "
2258  "OTContract::CreateInnerContents.\n");
2259 
2260  if (("contract" == str_name) || ("certification" == str_name) ||
2261  ("serverCertification" == str_name)) {
2262  OTString strPubkey;
2263  if (pNym->GetPublicSignKey().GetPublicKey(
2264  strPubkey) && // bEscaped=true by default.
2265  strPubkey.Exists()) {
2266  strTemp.Concatenate("<key name=\"%s\">\n%s</key>\n\n",
2267  str_name.c_str(), strPubkey.Get());
2268  }
2269  }
2270  }
2271 
2272  if (strTemp.Exists()) {
2273  m_xmlUnsigned.Concatenate("<!-- KEYS -->\n\n%s", strTemp.Get());
2274  strTemp.Release();
2275  }
2276 
2277  // NEW CREDENTIALS, based on NymID and Source, and credential IDs.
2278  for (auto& it : m_mapNyms) {
2279  std::string str_name = it.first;
2280  OTPseudonym* pNym = it.second;
2281  OT_ASSERT_MSG(nullptr != pNym,
2282  "2: nullptr pseudonym pointer in "
2283  "OTContract::CreateInnerContents.\n");
2284 
2285  if ("signer" == str_name) {
2286  const bool bHasCredentials =
2287  (pNym->GetMasterCredentialCount() > 0);
2288 
2289  OTString strNymID;
2290  pNym->GetIdentifier(strNymID);
2291 
2292  OTASCIIArmor ascAltLocation;
2293  if (pNym->GetAltLocation().Exists())
2294  ascAltLocation.SetString(pNym->GetAltLocation(),
2295  false); // bLineBreaks=true by
2296  // default. But here, no
2297  // line breaks.
2298 
2299  strTemp.Concatenate("<%s hasCredentials=\"%s\"\n"
2300  " nymID=\"%s\"\n"
2301  " altLocation=\"%s\""
2302  ">\n\n",
2303  str_name.c_str(), //"signer"
2304  bHasCredentials ? "true" : "false",
2305  strNymID.Get(), ascAltLocation.Get());
2306 
2307  if (pNym->GetNymIDSource().Exists()) {
2308  OTASCIIArmor ascNymIDSource(pNym->GetNymIDSource());
2309  strTemp.Concatenate("<nymIDSource>\n%s</nymIDSource>\n\n",
2310  ascNymIDSource.Get());
2311  }
2312 
2313  // credentialList
2314  // credentials
2315  //
2316  if (bHasCredentials) {
2317 
2318  // Create a new OTDB::StringMap object.
2319  //
2320  std::unique_ptr<OTDB::Storable> pStorable(
2322  OTDB::StringMap* pMap = nullptr;
2323 
2324  pMap =
2325  (nullptr == pStorable)
2326  ? nullptr
2327  : dynamic_cast<OTDB::StringMap*>(pStorable.get());
2328 
2329  if (nullptr == pMap)
2330  otErr << __FUNCTION__ << ": Error: failed trying to "
2331  "load or create a "
2332  "STORED_OBJ_STRING_MAP.\n";
2333  else // It instantiated.
2334  {
2335  OTString strCredList;
2336  OTString::Map& theMap = pMap->the_map;
2337 
2338  pNym->GetPublicCredentials(strCredList, &theMap);
2339 
2340  // Serialize the StringMap to a string...
2341  //
2342  if (strCredList.Exists() &&
2343  (!theMap.empty())) // Won't bother if there are
2344  // zero credentials somehow.
2345  {
2346  std::string str_Encoded = OTDB::EncodeObject(*pMap);
2347  const bool bSuccessEncoding =
2348  (str_Encoded.size() > 0);
2349  if (bSuccessEncoding) {
2350  OTASCIIArmor armor1(strCredList), armor2;
2351  armor2.Set(str_Encoded.c_str());
2352  if (armor1.Exists())
2353  strTemp.Concatenate("<credentialList>\n%s</"
2354  "credentialList>\n\n",
2355  armor1.Get());
2356  if (armor2.Exists())
2357  strTemp.Concatenate(
2358  "<credentials>\n%s</credentials>\n\n",
2359  armor2.Get());
2360  }
2361  }
2362  }
2363  }
2364 
2365  strTemp.Concatenate("</%s>\n\n", str_name.c_str()); //"signer"
2366 
2367  } // "signer"
2368  }
2369 
2370  if (strTemp.Exists()) {
2371  m_xmlUnsigned.Concatenate("<!-- NYMS -->\n\n%s", strTemp.Get());
2372  strTemp.Release();
2373  }
2374 
2375  } // if (m_mapNyms.size() > 0)
2376 }
2377 
2378 // Only used when first generating an asset or server contract.
2379 // Meant for contracts which never change after that point.
2380 // Otherwise does the same thing as UpdateContents.
2381 // (But meant for a different purpose.)
2382 // See OTServerContract.cpp and OTAssetContract.cpp
2383 //
2384 void OTContract::CreateContents()
2385 {
2386  OT_FAIL_MSG("ASSERT: OTContract::CreateContents should never be called, "
2387  "but should be overrided. (In this case, it wasn't.)");
2388 }
2389 
2390 // return -1 if error, 0 if nothing, and 1 if the node was processed.
2391 int32_t OTContract::ProcessXMLNode(IrrXMLReader*& xml)
2392 {
2393  const OTString strNodeName(xml->getNodeName());
2394 
2395  if (strNodeName.Compare("entity")) {
2396  m_strEntityShortName = xml->getAttributeValue("shortname");
2397  if (!m_strName.Exists()) // only set it if it's not already set, since
2398  // the wallet may have already had a user label
2399  // set.
2400  m_strName = m_strEntityShortName; // m_strName may later be changed
2401  // again in
2402  // OTAssetContract::ProcessXMLNode
2403 
2404  m_strEntityLongName = xml->getAttributeValue("longname");
2405  m_strEntityEmail = xml->getAttributeValue("email");
2406 
2407  otWarn << "Loaded Entity, shortname: " << m_strEntityShortName
2408  << "\nLongname: " << m_strEntityLongName
2409  << ", email: " << m_strEntityEmail << "\n----------\n";
2410 
2411  return 1;
2412  }
2413  else if (strNodeName.Compare("condition")) {
2414  // todo security: potentially start ascii-encoding these.
2415  // (Are they still "human readable" if you can easily decode them?)
2416  //
2417  OTString strConditionName;
2418  OTString strConditionValue;
2419 
2420  strConditionName = xml->getAttributeValue("name");
2421 
2422  if (!SkipToTextField(xml)) {
2423  otOut << "OTContract::ProcessXMLNode: Failure: Unable to find "
2424  "expected text field for xml node named: "
2425  << xml->getNodeName() << "\n";
2426  return (-1); // error condition
2427  }
2428 
2429  if (EXN_TEXT == xml->getNodeType()) {
2430  strConditionValue = xml->getNodeData();
2431  }
2432  else {
2433  otErr << "Error in OTContract::ProcessXMLNode: Condition without "
2434  "value: " << strConditionName << "\n";
2435  return (-1); // error condition
2436  }
2437 
2438  // Add the conditions to a list in memory on this object.
2439  //
2440  m_mapConditions.insert(std::pair<std::string, std::string>(
2441  strConditionName.Get(), strConditionValue.Get()));
2442 
2443  otWarn << "---- Loaded condition \"" << strConditionName << "\"\n";
2444  // otWarn << "Loading condition \"%s\": %s----------(END
2445  // DATA)----------\n", strConditionName.Get(),
2446  // strConditionValue.Get());
2447 
2448  return 1;
2449  }
2450  else if (strNodeName.Compare("signer")) {
2451  const OTString strSignerNymID = xml->getAttributeValue("nymID");
2452  const OTString strHasCredentials =
2453  xml->getAttributeValue("hasCredentials");
2454  const OTASCIIArmor ascAltLocation =
2455  xml->getAttributeValue("altLocation");
2456  OTString strAltLocation, strSignerSource;
2457 
2458  if (ascAltLocation.Exists())
2459  ascAltLocation.GetString(strAltLocation,
2460  false); // bLineBreaks=true by default.
2461 
2462  bool bHasCredentials = strHasCredentials.Compare("true");
2463  const bool bHasAltLocation = strAltLocation.Exists();
2464 
2465  if (!strSignerNymID.Exists()) {
2466  otErr << "Error in " << __FUNCTION__
2467  << ": "
2468  "Expected nymID attribute on signer element.\n";
2469  return (-1); // error condition
2470  }
2471  OTASCIIArmor ascArmor; // For credential list.
2472  OTASCIIArmor ascArmor2; // For credentials.
2473 
2474  const char* pElementExpected = "nymIDSource";
2475  otWarn << __FUNCTION__ << ": Loading " << pElementExpected << "...\n";
2476  if (!OTContract::LoadEncodedTextFieldByName(xml, strSignerSource,
2477  pElementExpected)) {
2478  otErr << "Error in " << __FILE__ << " line " << __LINE__
2479  << ": failed loading expected " << pElementExpected
2480  << " field:\n\n" << m_xmlUnsigned << "\n\n\n";
2481  return (-1); // error condition
2482  }
2483  // TODO: hash the source right here and compare it to the NymID, just to
2484  // be safe.
2485 
2486  if (!bHasCredentials) {
2487  // If there are no credentials provided (which is proper) then we
2488  // should
2489  // just download them from the source.
2490  // ...Unless it's one of those where you can't discover such things
2491  // from the source,
2492  // in which case an alternate location must be provided.
2493  //
2494  if (bHasAltLocation) {
2495  otErr << __FUNCTION__
2496  << ": WARNING: No credentials provided. An alternate "
2497  "location is "
2498  "listed, but that's not yet supported in the "
2499  "code.\nLocation: " << strAltLocation << "\n";
2500 
2501  // A signer ideally just has a NymID and source.
2502  // Then we can directly just download the credentials from the
2503  // source.
2504  // But let's say the source doesn't include download info (like
2505  // if it contains DN info.)
2506  // We can have this optional attribute "altLocation" for the
2507  // alternate download location.
2508  // We can also optionally allow people to just directly put the
2509  // credentials inside the
2510  // contract (credentialList, and credentials). That's why
2511  // hasCredentials can be true or false.
2512  // Ideally, people will not do that. Instead, we can download
2513  // them from the source, or from
2514  // the alternate location, if the source cannot supply. But
2515  // worst case, they can directly embed
2516  // the credentials, though it's not best practice for a real
2517  // contract, it can be useful for
2518  // testing.
2519  //
2520  // If we eventually add the download code here, put the
2521  // credential list into ascArmor,
2522  // and the credentials into ascArmor2.
2523  }
2524  else // There's no alternate location, and no credentials
2525  // provided,
2526  { // Therefore we be must expected to download them based on the
2527  // source
2528  // string, and if we can't, then we've failed to load.
2529  //
2530  otErr << __FUNCTION__
2531  << ": WARNING: Alternate location not listed, and no "
2532  "credentials provided, so we need to download"
2533  " them from the source--but that's not yet supported "
2534  "in the code.\nNymID Source String: "
2535  << strSignerSource << "\n";
2536  //
2537  // If we eventually add the download code here, put the
2538  // credential list into ascArmor,
2539  // and the credentials into ascArmor2.
2540  }
2541  return (-1); // for now, since this block is incomplete.
2542  }
2543  else // (bHasCredentials)
2544  {
2545  pElementExpected = "credentialList";
2546 
2547  if (!OTContract::LoadEncodedTextFieldByName(xml, ascArmor,
2548  pElementExpected)) {
2549  otErr << "Error in " << __FUNCTION__ << ": "
2550  "Expected "
2551  << pElementExpected << " element with text field.\n";
2552  return (-1); // error condition
2553  }
2554 
2555  pElementExpected = "credentials";
2556 
2557  if (!OTContract::LoadEncodedTextFieldByName(xml, ascArmor2,
2558  pElementExpected)) {
2559  otErr << "Error in " << __FUNCTION__ << ": "
2560  "Expected "
2561  << pElementExpected << " element with text field.\n";
2562  return (-1); // error condition
2563  }
2564  }
2565 
2566  bHasCredentials = (ascArmor.Exists() && ascArmor2.Exists());
2567 
2568  // bHasCredentials might have gotten set to true in the block above the
2569  // above block,
2570  // after downloading, checking alternate location, etc. Otherwise, in
2571  // the above block,
2572  // it was loaded from the contract itself.
2573  if (bHasCredentials) {
2574  // credentialList
2575  //
2576  OTString strCredentialList;
2577  ascArmor.GetString(strCredentialList);
2578 
2579  if (strCredentialList.Exists()) {
2580  std::unique_ptr<OTDB::Storable> pStorable(OTDB::DecodeObject(
2581  OTDB::STORED_OBJ_STRING_MAP, ascArmor2.Get()));
2582  OTDB::StringMap* pMap =
2583  (nullptr == pStorable)
2584  ? nullptr
2585  : dynamic_cast<OTDB::StringMap*>(pStorable.get());
2586 
2587  if (nullptr == pMap)
2588  otOut << __FUNCTION__
2589  << ": Failed decoding StringMap object.\n";
2590  else // IF the list saved, then we save the credentials
2591  // themselves...
2592  {
2593  OTString::Map& theMap = pMap->the_map;
2594 
2595  std::unique_ptr<OTPseudonym> pNym(new OTPseudonym);
2596  pNym->SetIdentifier(strSignerNymID);
2597 
2598  if (false ==
2599  pNym->LoadFromString(strCredentialList, &theMap)) {
2600  otErr << __FUNCTION__ << ": Failure loading nym "
2601  << strSignerNymID << " from credential string.\n";
2602  }
2603  // Now that the Nym has been loaded up from the two strings,
2604  // including the list of credential IDs, and the map
2605  // containing the
2606  // credentials themselves, let's try to Verify the
2607  // pseudonym. If we
2608  // verify, then we're safe to add the Nym to the contract.
2609  //
2610  else if (!pNym->VerifyPseudonym()) {
2611  otErr << __FUNCTION__ << ": Loaded nym "
2612  << strSignerNymID
2613  << " from credentials, but then it failed "
2614  "verifying.\n";
2615  }
2616  else // Okay, we loaded the Nym up from the credentials in
2617  // the contract, AND
2618  { // verified the Nym (including the credentials.)
2619  // So let's add it to the contract...
2620  //
2621 
2622  m_mapNyms[strNodeName.Get() /*"signer"*/] =
2623  pNym.release();
2624  // Add pNym to the contract's internal list of nyms.
2625 
2626  return 1; // <==== Success!
2627  }
2628  }
2629  } // credential list exists, after base64-decoding.
2630 
2631  } // Has Credentials.
2632 
2633  return (-1);
2634  }
2635  else if (strNodeName.Compare("key")) {
2636  OTString strKeyName;
2637  OTString strKeyValue;
2638 
2639  strKeyName = xml->getAttributeValue("name");
2640 
2641  if (!SkipToTextField(xml)) {
2642  otOut << "OTContract::ProcessXMLNode: Failure: Unable to find "
2643  "expected text "
2644  "field for xml node named: " << xml->getNodeName() << "\n";
2645  return (-1); // error condition
2646  }
2647 
2648  if (EXN_TEXT == xml->getNodeType()) {
2649  strKeyValue = xml->getNodeData();
2650  }
2651  else {
2652  otErr << "Error in OTContract::ProcessXMLNode: Key without value: "
2653  << strKeyName << "\n";
2654  return (-1); // error condition
2655  }
2656  // Create a new nym for this public key (or x509 cert, it works either
2657  // way)
2658  // and add it to the contract's internal list of nyms.
2659  //
2660  // Later on, if someone needs to get the Public Key for this contract
2661  // and
2662  // use it to verify the signature on the contract, or to verify a
2663  // message
2664  // from the server, the contract can iterate the list of Nyms and get
2665  // the public contract key based on a standard name such as the
2666  // "contract" key.
2667  // (Versus the "server" key or the "certification" key, etc.
2668 
2669  if (!InsertNym(strKeyName, strKeyValue))
2670  otErr << "Error performing OTContract::InsertNym.\n";
2671 
2672  return 1;
2673  }
2674 
2675  return 0;
2676 }
2677 
2678 // If you have a Public Key or Cert that you would like to add as one of the
2679 // keys on this contract,
2680 // just call this function. Usually you'd never want to do that because you
2681 // would never want to actually
2682 // change the text of the contract (or the signatures will stop verifying.)
2683 // But in unique situations, for example when first creating a contract, you
2684 // might want to insert some
2685 // keys into it. You might also call this function when LOADING the contract, to
2686 // populate it.
2687 //
2688 bool OTContract::InsertNym(const OTString& strKeyName,
2689  const OTString& strKeyValue)
2690 {
2691  bool bResult = false;
2692  OTPseudonym* pNym = new OTPseudonym;
2693 
2694  OT_ASSERT_MSG(
2695  nullptr != pNym,
2696  "Error allocating memory for new Nym in OTContract::InsertNym\n");
2697 
2698  // This is the version of SetCertificate that handles escaped bookends. ( -
2699  // -----BEGIN CERTIFICATE-----)
2700  if (strKeyValue.Contains("CERTIFICATE") &&
2701  pNym->SetCertificate(strKeyValue,
2702  true)) // it also defaults to true, FYI.
2703  {
2704  m_mapNyms[strKeyName.Get()] = pNym;
2705  pNym->SetIdentifierByPubkey();
2706  otWarn << "---- Loaded certificate \"" << strKeyName << "\"\n";
2707  bResult = true;
2708  }
2709  else if (strKeyValue.Contains("PUBLIC KEY") &&
2710  pNym->SetPublicKey(strKeyValue,
2711  true)) // it also defaults to true, FYI.
2712  {
2713  m_mapNyms[strKeyName.Get()] = pNym;
2714  pNym->SetIdentifierByPubkey();
2715  otWarn << "---- Loaded public key \"" << strKeyName << "\"\n";
2716  bResult = true;
2717  }
2718  else {
2719  delete pNym;
2720  pNym = nullptr;
2721  otOut << "\nLoaded key \"" << strKeyName
2722  << "\" but FAILED adding the"
2723  " Nym to the Contract:\n--->" << strKeyValue << "<---\n";
2724  }
2725 
2726  return bResult;
2727 }
2728 
2729 } // namespace opentxs
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 void GetPublicCredentials(OTString &strCredList, OTString::Map *pmapCredFiles=nullptr) const
std::map< std::string, std::string > Map
Definition: OTString.hpp:162
EXPORT Storable * CreateObject(StoredObjectType eType)
Definition: OTStorage.cpp:530
bool SetMetadata(char metaKeyType, char metaNymID, char metaMasterCredID, char metaSubCredID)
EXPORT bool SetPublicKey(const OTString &strKey, bool bEscaped=true)
std::list< OTAsymmetricKey * > listOfAsymmetricKeys
EXPORT bool CalculateDigest(const OTData &dataInput)
EXPORT void GetIdentifier(OTIdentifier &theIdentifier) const
OTSignatureMetadata * m_pMetadata
EXPORT bool SetCertificate(const OTString &strCert, bool bEscaped=true)
OTLOG_IMPORT OTLogStream otOut
OTLOG_IMPORT OTLogStream otLog3
EXPORT uint32_t GetLength() const
Definition: OTString.cpp:1040
EXPORT void Concatenate(const char *arg,...)
Definition: OTString.cpp:1334
EXPORT bool WriteArmoredString(OTString &strOutput, const std::string str_type, bool bEscaped=false) const
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)
EXPORT std::string EncodeObject(Storable &theContents)
Definition: OTStorage.cpp:818
EXPORT void Format(const char *fmt,...)
Definition: OTString.cpp:1319
EXPORT bool Compare(const char *compare) const
Definition: OTString.cpp:1102
EXPORT void Set(const char *data, uint32_t enforcedMaxLength=0)
Definition: OTString.cpp:1055
EXPORT std::string QueryPlainString(std::string strFolder, std::string oneStr="", std::string twoStr="", std::string threeStr="")
Definition: OTStorage.cpp:728
EXPORT bool GetPublicKey(OTASCIIArmor &strKey) const
EXPORT const OTAsymmetricKey & GetPublicAuthKey() const
EXPORT bool SetIdentifierByPubkey()
EXPORT int32_t GetPublicKeysBySignature(listOfAsymmetricKeys &listOutput, const OTSignature &theSignature, char cKeyType= '0') const
bool sgets(char *buffer, uint32_t size)
Definition: OTString.cpp:1380
const OTAsymmetricKey & GetPrivateAuthKey() const
#define OT_ASSERT(x)
Definition: Assert.hpp:150
OTSignatureMetadata & getMetaData()
#define OT_ASSERT_MSG(x, s)
Definition: Assert.hpp:155
OTLOG_IMPORT OTLogStream otInfo
EXPORT const OTString & GetAltLocation() const
EXPORT bool At(uint32_t index, char &c) const
Definition: OTString.cpp:1025
EXPORT const OTAsymmetricKey & GetPublicSignKey() const
#define OT_FAIL_MSG(s)
Definition: Assert.hpp:144
OTLOG_IMPORT OTLogStream otWarn
EXPORT const char * Get() const
Definition: OTString.cpp:1045
OTLOG_IMPORT OTLogStream otErr
std::map< std::string, std::string > the_map
Definition: OTStorage.hpp:981
EXPORT void GetString(OTString &theStr) const
EXPORT bool Exists(std::string strFolder, std::string oneStr="", std::string twoStr="", std::string threeStr="")
Definition: OTStorage.cpp:584
EXPORT const OTString & GetNymIDSource() const
EXPORT bool Contains(const char *compare) const
Definition: OTString.cpp:1137
EXPORT Storable * DecodeObject(StoredObjectType theObjectType, std::string strInput)
Definition: OTStorage.cpp:830
const OTAsymmetricKey & GetPrivateSignKey() const
EXPORT bool GetString(OTString &theData, bool bLineBreaks=true) const
virtual EXPORT void Release()
Definition: OTData.cpp:257
EXPORT size_t GetMasterCredentialCount() const
std::list< OTSignature * > listOfSignatures
Definition: OTContract.hpp:158
virtual EXPORT void Release()
Definition: OTString.cpp:765
OTLOG_IMPORT OTLogStream otLog5