Open-Transactions  0.93.0-ge03d287
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
UserCommandProcessor.cpp
Go to the documentation of this file.
1 /************************************************************
2  *
3  * UserCommandProcessor.cpp
4  *
5  */
6 
7 /************************************************************
8  -----BEGIN PGP SIGNED MESSAGE-----
9  Hash: SHA1
10 
11  * OPEN TRANSACTIONS
12  *
13  * Financial Cryptography and Digital Cash
14  * Library, Protocol, API, Server, CLI, GUI
15  *
16  * -- Anonymous Numbered Accounts.
17  * -- Untraceable Digital Cash.
18  * -- Triple-Signed Receipts.
19  * -- Cheques, Vouchers, Transfers, Inboxes.
20  * -- Basket Currencies, Markets, Payment Plans.
21  * -- Signed, XML, Ricardian-style Contracts.
22  * -- Scripted smart contracts.
23  *
24  * Copyright (C) 2010-2013 by "Fellow Traveler" (A pseudonym)
25  *
26  * EMAIL:
28  *
29  * BITCOIN: 1NtTPVVjDsUfDWybS4BwvHpG2pdS9RnYyQ
30  *
31  * KEY FINGERPRINT (PGP Key in license file):
32  * 9DD5 90EB 9292 4B48 0484 7910 0308 00ED F951 BB8E
33  *
34  * OFFICIAL PROJECT WIKI(s):
35  * https://github.com/FellowTraveler/Moneychanger
36  * https://github.com/FellowTraveler/Open-Transactions/wiki
37  *
38  * WEBSITE:
39  * http://www.OpenTransactions.org/
40  *
41  * Components and licensing:
42  * -- Moneychanger..A Java client GUI.....LICENSE:.....GPLv3
43  * -- otlib.........A class library.......LICENSE:...LAGPLv3
44  * -- otapi.........A client API..........LICENSE:...LAGPLv3
45  * -- opentxs/ot....Command-line client...LICENSE:...LAGPLv3
46  * -- otserver......Server Application....LICENSE:....AGPLv3
47  * Github.com/FellowTraveler/Open-Transactions/wiki/Components
48  *
49  * All of the above OT components were designed and written by
50  * Fellow Traveler, with the exception of Moneychanger, which
51  * was contracted out to Vicky C ([email protected]).
52  * The open-source community has since actively contributed.
53  *
54  * -----------------------------------------------------
55  *
56  * LICENSE:
57  * This program is free software: you can redistribute it
58  * and/or modify it under the terms of the GNU Affero
59  * General Public License as published by the Free Software
60  * Foundation, either version 3 of the License, or (at your
61  * option) any later version.
62  *
63  * ADDITIONAL PERMISSION under the GNU Affero GPL version 3
64  * section 7: (This paragraph applies only to the LAGPLv3
65  * components listed above.) If you modify this Program, or
66  * any covered work, by linking or combining it with other
67  * code, such other code is not for that reason alone subject
68  * to any of the requirements of the GNU Affero GPL version 3.
69  * (==> This means if you are only using the OT API, then you
70  * don't have to open-source your code--only your changes to
71  * Open-Transactions itself must be open source. Similar to
72  * LGPLv3, except it applies to software-as-a-service, not
73  * just to distributing binaries.)
74  *
75  * Extra WAIVER for OpenSSL, Lucre, and all other libraries
76  * used by Open Transactions: This program is released under
77  * the AGPL with the additional exemption that compiling,
78  * linking, and/or using OpenSSL is allowed. The same is true
79  * for any other open source libraries included in this
80  * project: complete waiver from the AGPL is hereby granted to
81  * compile, link, and/or use them with Open-Transactions,
82  * according to their own terms, as long as the rest of the
83  * Open-Transactions terms remain respected, with regard to
84  * the Open-Transactions code itself.
85  *
86  * Lucre License:
87  * This code is also "dual-license", meaning that Ben Lau-
88  * rie's license must also be included and respected, since
89  * the code for Lucre is also included with Open Transactions.
90  * See Open-Transactions/src/otlib/lucre/LUCRE_LICENSE.txt
91  * The Laurie requirements are light, but if there is any
92  * problem with his license, simply remove the Lucre code.
93  * Although there are no other blind token algorithms in Open
94  * Transactions (yet. credlib is coming), the other functions
95  * will continue to operate.
96  * See Lucre on Github: https://github.com/benlaurie/lucre
97  * -----------------------------------------------------
98  * You should have received a copy of the GNU Affero General
99  * Public License along with this program. If not, see:
100  * http://www.gnu.org/licenses/
101  *
102  * If you would like to use this software outside of the free
103  * software license, please contact FellowTraveler.
104  * (Unfortunately many will run anonymously and untraceably,
105  * so who could really stop them?)
106  *
107  * DISCLAIMER:
108  * This program is distributed in the hope that it will be
109  * useful, but WITHOUT ANY WARRANTY; without even the implied
110  * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
111  * PURPOSE. See the GNU Affero General Public License for
112  * more details.
113 
114  -----BEGIN PGP SIGNATURE-----
115  Version: GnuPG v1.4.9 (Darwin)
116 
117  iQIcBAEBAgAGBQJRSsfJAAoJEAMIAO35UbuOQT8P/RJbka8etf7wbxdHQNAY+2cC
118  vDf8J3X8VI+pwMqv6wgTVy17venMZJa4I4ikXD/MRyWV1XbTG0mBXk/7AZk7Rexk
119  KTvL/U1kWiez6+8XXLye+k2JNM6v7eej8xMrqEcO0ZArh/DsLoIn1y8p8qjBI7+m
120  aE7lhstDiD0z8mwRRLKFLN2IH5rAFaZZUvj5ERJaoYUKdn4c+RcQVei2YOl4T0FU
121  LWND3YLoH8naqJXkaOKEN4UfJINCwxhe5Ke9wyfLWLUO7NamRkWD2T7CJ0xocnD1
122  sjAzlVGNgaFDRflfIF4QhBx1Ddl6wwhJfw+d08bjqblSq8aXDkmFA7HeunSFKkdn
123  oIEOEgyj+veuOMRJC5pnBJ9vV+7qRdDKQWaCKotynt4sWJDGQ9kWGWm74SsNaduN
124  TPMyr9kNmGsfR69Q2Zq/FLcLX/j8ESxU+HYUB4vaARw2xEOu2xwDDv6jt0j3Vqsg
125  x7rWv4S/Eh18FDNDkVRChiNoOIilLYLL6c38uMf1pnItBuxP3uhgY6COm59kVaRh
126  nyGTYCDYD2TK+fI9o89F1297uDCwEJ62U0Q7iTDp5QuXCoxkPfv8/kX6lS6T3y9G
127  M9mqIoLbIQ1EDntFv7/t6fUTS2+46uCrdZWbQ5RjYXdrzjij02nDmJAm2BngnZvd
128  kamH0Y/n11lCvo1oQxM+
129  =uSzz
130  -----END PGP SIGNATURE-----
131 **************************************************************/
132 
133 #include "UserCommandProcessor.hpp"
134 #include "OTServer.hpp"
135 #include "ClientConnection.hpp"
136 #include "Macros.hpp"
137 #include "ServerSettings.hpp"
139 #include <opentxs/basket/Basket.hpp>
145 #include <opentxs/core/OTLog.hpp>
146 #include <opentxs/core/OTString.hpp>
151 #include <opentxs/core/OTLedger.hpp>
152 #include <opentxs/cash/Mint.hpp>
154 
155 namespace opentxs
156 {
157 
159  : server_(server)
160 {
161 }
162 
163 // this function will create the Nym if it's not passed in. We pass it in so the
164 // caller has the option to query things about the Nym (like if it actually
165 // exists.)
167  OTMessage& msgOut,
168  ClientConnection* pConnection,
169  OTPseudonym* pNym)
170 {
171  msgOut.m_strRequestNum.Set(theMessage.m_strRequestNum);
172 
175  0) || // AND (there's no Override Nym ID listed --OR-- the Override
176  // Nym ID doesn't
177  (0 !=
179  (theMessage.m_strNymID.Get()))))) // match the Nym's ID who
180  // sent this message)
181  {
183  0, "UserCommandProcessor::ProcessUserCommand: Nym %s: failed "
184  "attempt to message the server, while server is in "
185  "**LOCK DOWN MODE**.\n",
186  theMessage.m_strNymID.Get());
187  return false;
188  }
189 
190  // Validate the server ID, to keep users from intercepting a valid requst
191  // and sending it to the wrong server.
192  if (!(server_->m_strServerID == theMessage.m_strServerID)) {
193  OTLog::Error("UserCommandProcessor::ProcessUserCommand: Invalid server "
194  "ID sent in "
195  "command request.\n");
196  return false;
197  }
198  else {
199  OTLog::Output(4, "Received valid Server ID with command request.\n");
200  }
201  // NYM WAS PASSED IN
202  //
203  OTPseudonym theNym(theMessage.m_strNymID);
204 
205  if (nullptr == pNym)
206  pNym = &theNym; // If one wasn't passed in, we'll use the one
207  // constructed here. (One line up.)
208  else if (!pNym->CompareID(theNym)) {
209  OTString strTempNymID;
210  pNym->GetIdentifier(strTempNymID);
212  "UserCommandProcessor::ProcessUserCommand: NymID on the optional "
213  "Nym passed in "
214  "(%s) "
215  "does NOT match the NymID on theMessage (%s). (Returning false.)\n",
216  strTempNymID.Get(), theMessage.m_strNymID.Get());
217  return false;
218  }
219  // NYM IS ACTUALLY SERVER
220 
221  // For special cases where the Nym sending the transaction has the same
222  // public key as
223  // the server itself. (IE it IS the server Nym, then we'd want to use the
224  // already-loaded
225  // server nym object instead of loading a fresh one, so the two don't
226  // overwrite each other.)
227  //
228  const bool bNymIsServerNym =
229  (server_->m_strServerUserID.Compare(theMessage.m_strNymID) ? true
230  : false);
231  // OTPseudonym * pNym = &theNym; // this is now done higher up in this
232  // function.
233 
234  if (bNymIsServerNym) pNym = &server_->m_nymServer;
235 
236  // This command is special because the User sent his public key, not just
237  // his ID.
238  // We have to verify the two together.
239  //
240  // At this point the user doesn't even have an account, so there is no
241  // public key
242  // to look up from the database.
243  //
244  // If the ServerID in the reply matches the ID calculated from the Server
245  // Contract,
246  // that means the user, without asking for the server's public key, can just
247  // extract
248  // the public key from the contract from which the serverID was first
249  // calculated. (The
250  // ID is a hash of the contract.)
251  //
252  // In other words, the user reads a contract. It's signed. The signature is
253  // verified
254  // by a public key that is embedded in the contract. If the server, a URL
255  // also embedded in
256  // the contract, acknowledges the ServerID, then the user can encrypt
257  // everything to the
258  // public key in the contract, without asking the server for a copy of that
259  // key.
260  //
261  // Only the private key who signed that contract will be able to read the
262  // communications from
263  // the user.
264  //
265  // I definitely have to build in an option for x509 certs to be used in lieu
266  // of public keys.
267  // Otherwise the key is not ever revokable -- yet it's in a contract! What
268  // is the issuer supposed
269  // to do if that key is stolen? Make a public announcement?
270  //
271  // UPDATE ONE-LINE NOTE: THE TRUE SOLUTION TO THIS WHOLE ISSUE IS: ***
272  // NAMECOIN ***
273  // (Now continuing back to my old comments from 18 months ago...)
274  //
275  // In such a case, the issuer would have to put a "check this URL to make
276  // sure contract still good"
277  // variable into the contract so that the users have the chance to make sure
278  // the contract is still
279  // good and the contract's private key hasn't been stolen. Well guess what?
280  // That's what x509 does.
281  // Therefore the appropriate solution is for the server to support x509s,
282  // and to look up the authority
283  // and verify certs, so that users have recourse in the event their private
284  // key is stolen. (They can
285  // just use their Cert to issue a new public key, which the transaction
286  // server would be smart enough
287  // to use, once the certificate authority signs off on it. (Since the user
288  // uses an x509 from a
289  // specific authority, then I can trust that whatever that authority says,
290  // that user wanted it to say.)
291  // Without knowing the authority itself, I can now trust it because the user
292  // has asked me to trust it.
293  // Fair enough!
294  //
295  // Similarly a user should be able to use his x509 Cert instead of his
296  // public key, and the server
297  // should verify that cert whenever it's used to make sure it's up to date.
298  // This takes the
299  // problem off of the user's hands by way of a trusted authority.
300  //
301  // In fact this transaction server is really just a transaction VERIFIER.
302  // It's just another form
303  // of trusted 3rd party. Just like Verisign is an authority who ceritifies
304  // an identity, so this
305  // server is an authority who certifies a transaction. It's like a
306  // timestamping server. In fact
307  // it should have timestamping built in as one of the functions.
308  //
309  // Transactions do not actually occur on the server, per se. They occur
310  // between the USERS.
311  // All the server does it certify that the numbers are correct. It's like
312  // accounting software.
313  // Ultimately the users are the ones making a transaction, and they are the
314  // ones who are
315  // responsible to back up their promises in real life and potentially in
316  // court. All the software
317  // does is CERTIFY that the users DID make certain agreements at certain
318  // times, and digitally sign
319  // those certifications.
320  //
321  // Thus, this server is very similar to Verisign. It is a trusted 3rd party
322  // who users can trust
323  // to authenticate their transactions. Instead of authenticating
324  // certifications like Verisign does,
325  // it authenticates transactions.
326  //
327  // UPDATE: May not want x509's after all, since it provides an opening for
328  // governments to
329  // serve warrants on the authority site and switch certs whenever they want
330  // to (BAD THING!)
331  //
332  OTString strMsgNymID;
333  pNym->GetIdentifier(strMsgNymID);
334 
335  if (theMessage.m_strCommand.Compare("checkServerID")) {
336  OTLog::vOutput(0,
337  "\n==> Received a checkServerID message. Nym: %s ...\n",
338  strMsgNymID.Get());
340  std::unique_ptr<OTAsymmetricKey> pNymAuthentKey(
342  std::unique_ptr<OTAsymmetricKey> pNymEncryptKey(
344  OT_ASSERT(nullptr != pNymAuthentKey);
345  OT_ASSERT(nullptr != pNymEncryptKey);
346  OTAsymmetricKey& nymAuthentKey = *pNymAuthentKey;
347  OTAsymmetricKey& nymEncryptionKey = *pNymEncryptKey;
348  const bool bIfNymPublicKey =
349  (nymAuthentKey.SetPublicKey(theMessage.m_strNymPublicKey,
350  true /*bEscaped*/) &&
351  nymEncryptionKey.SetPublicKey(theMessage.m_strNymID2,
352  true /*bEscaped*/));
353 
354  if (bIfNymPublicKey) {
355  if (theMessage.VerifyWithKey(nymAuthentKey)) // Not all contracts
356  // are signed with the
357  // authentication key,
358  // but messages are.
359  {
361  3, "Signature verified! The message WAS signed by "
362  "the Private Authentication Key inside the message.\n");
363 
364  // This is only for verified Nyms, (and we're verified in here!)
365  // We do this so that
366  // we have the option later to encrypt the replies back to the
367  // client...(using the
368  // client's public key that we set here.)
369  if (nullptr != pConnection)
370  pConnection->SetPublicKey(
371  theMessage.m_strNymID2); // theMessage.m_strNymID2
372  // contains the public
373  // encryption key for sending
374  // an encrypted reply.
375 
376  UserCmdCheckServerID(*pNym, theMessage, msgOut);
377  return true;
378  }
379  else {
381  0, "checkServerID: Signature verification failed!\n");
382  return false;
383  }
384  }
385  else {
386  OTLog::Error("Failure reading Nym's signing and/or encryption keys "
387  "from message.\n");
388  return false;
389  }
390  }
391 
392  // The below block is now COMPLETE. (For credentials new system.)
393  //
394  // Next, make sure the client side is properly forming the new version of
395  // this message,
396  // and make sure it creates credentials when necessary, if they don't
397  // already exist
398  // (Since this new server version ONLY accepts credentials, and not
399  // old-style public keys.)
400  //
401  // This command is also special because again, the User sent his public key,
402  // not just his ID.
403  // We have to verify the two together.
404  // UPDATE: now the Nym sends not a public key, but a full set of credentials
405  // along with
406  // a list of credential IDs. You load the list of credential IDs as if you
407  // are loading the Nym
408  // from a string. (It's like a nym that only contains the credential parts.)
409  // Then in the process
410  // of loading the Nym, it will load the credentials from the mapOfStrings.
411  //
412  else if (theMessage.m_strCommand.Compare("createUserAccount")) {
414  0, "\n==> Received a createUserAccount message. Nym: %s ...\n",
415  strMsgNymID.Get());
417  if (bNymIsServerNym) {
418  OTLog::Output(0,
419  "**** Sorry, the server Nym is forbidden from using "
420  "the createUserAccount message as a client. "
421  "PLEASE REMOVE THAT NYM FROM YOUR WALLET!! Create a "
422  "fresh Nym to use. ***\n");
423  return false;
424  }
425  // First try to get Credentials, if there are any.
426  //
427  OTASCIIArmor& ascArmor = theMessage.m_ascPayload; // credentialList
428  // (New style!
429  // Credentials.)
430  OTASCIIArmor& ascArmor2 = theMessage.m_ascPayload2; // credentials
431  const bool bHasCredentials = (ascArmor.Exists() && ascArmor2.Exists());
432  if (bHasCredentials) // New style of doing things, for Nym keys.
433  // Credentials!
434  {
435  // credentialList
436  //
437  OTString strCredentialList(ascArmor);
438 
439  if (strCredentialList.Exists()) {
440  std::unique_ptr<OTDB::Storable> pStorable(OTDB::DecodeObject(
441  OTDB::STORED_OBJ_STRING_MAP, ascArmor2.Get()));
442  OTDB::StringMap* pMap =
443  dynamic_cast<OTDB::StringMap*>(pStorable.get());
444  if (nullptr == pMap)
445  OTLog::vOutput(0, "%s: @createUserAccount: Failed decoding "
446  "StringMap object.\n",
447  __FUNCTION__);
448  else {
449  auto& theMap = pMap->the_map;
450  // NOTE: This action may very well be a malicious attacker
451  // saving a false
452  // credential list and a false set of credentials under a
453  // certain Nym ID!
454  // However, a Nym is always verified after loading, before
455  // being used for
456  // anything. (AND MUST BE.) And that includes before being
457  // saved to disk.
458  //
459  // DILEMMA at this point was, I don't want to save the
460  // credentials into the
461  // actual folder locations BEFORE they have been verified...
462  // SO I had to add "LoadFromString" functions to
463  // OTCredential (which I have done.)
464  // So now I should be able to continue here, load the
465  // credentials up from string,
466  // verify them, and if verified, THEN save them to disk...
467  // OTPseudonym::LoadFromString now allows you to load
468  // credentials from the map passed
469  // in (from the message) versus just reading them from local
470  // storage.
471  //
472  if (false ==
473  pNym->LoadFromString(strCredentialList, &theMap)) {
475  "%s: @createUserAccount: Failure loading nym %s "
476  "from credential string.\n",
477  __FUNCTION__, theMessage.m_strNymID.Get());
478  }
479  // Now that the Nym has been loaded up from the message
480  // parameters,
481  // including the list of credential IDs, and the map
482  // containing the
483  // credentials themselves, let's try to Verify the
484  // pseudonym. If we
485  // verify, then we're safe to save the credentials to
486  // storage.
487  //
488  else if (!pNym->VerifyPseudonym()) {
490  "%s: @createUserAccount: Loaded nym %s "
491  "from credentials, but then it failed verifying.\n",
492  __FUNCTION__, theMessage.m_strNymID.Get());
493  }
494  else // Okay, we loaded the Nym up from the credentials in
495  // the message, AND
496  { // verified the Nym (including the credentials.)
497  // So let's save it to local storage...
498  //
499 
500  OTLog::Output(3, "Pseudonym verified!\n");
501  // Okay, now that the Nym is verified, let's verify the
502  // message itself...
503  //
504  if (false ==
505  theMessage.VerifySignature(*pNym)) // FYI, OTMessage
506  // overrides
507  // VerifySignature with
508  // VerifySigAuthent.
509  { // (Because we use authentication keys, not signing
510  // keys, for messages.)
511  OTLog::Output(0, "@createUserAccount: "
512  "Authentication signature -- "
513  "verification failed!\n");
514  return false;
515  }
516  else {
518  3,
519  "Signature verified! The message WAS signed by "
520  "the Nym\'s private authentication key.\n");
521  // SAVE the credentials to local storage, now that
522  // things are verified.
523  //
524  std::string str_nym_id =
525  theMessage.m_strNymID.Get();
526  OTString strFilename;
527  strFilename.Format("%s.cred", str_nym_id.c_str());
528 
529  bool bStoredList = false;
530  OTString strOutput;
531 
532  if (ascArmor.Exists() &&
533  ascArmor.WriteArmoredString(
534  strOutput,
535  "CREDENTIAL LIST") && // bEscaped=false by
536  // default.
537  strOutput.Exists())
538  bStoredList = OTDB::StorePlainString(
539  strOutput.Get(), OTFolders::Pubcred().Get(),
540  strFilename.Get());
541  if (!bStoredList)
542  OTLog::vError("%s: @createUserAccount: Failed "
543  "trying to armor or store: %s\n",
544  __FUNCTION__, strFilename.Get());
545  else // IF the list saved, then we save the
546  // credentials themselves...
547  {
548  OTLog::vOutput(1, "@createUserAccount: Success "
549  "saving public credential "
550  "list for Nym: %s\n",
551  str_nym_id.c_str());
552  for (auto& it : theMap) {
553  std::string str_cred_id = it.first;
554  OTString strCredential(it.second);
555  bool bStoredCredential = false;
556  strOutput.Release();
557  OTASCIIArmor ascLoopArmor(strCredential);
558  if (ascLoopArmor.Exists() &&
559  ascLoopArmor.WriteArmoredString(
560  strOutput,
561  "CREDENTIAL") && // bEscaped=false
562  // by default.
563  strOutput.Exists())
564  bStoredCredential =
566  strOutput.Get(),
568  str_nym_id, str_cred_id);
569  if (!bStoredCredential)
571  "%s: @createUserAccount: Failed "
572  "trying to store credential %s for "
573  "nym %s.\n",
574  __FUNCTION__, str_cred_id.c_str(),
575  str_nym_id.c_str());
576  else
577  OTLog::vOutput(0, "@createUserAccount: "
578  "Success saving "
579  "public credential "
580  "ID: %s\n",
581  str_cred_id.c_str());
582  }
583  } // else (bStoredList)
584  // Make sure we are encrypting the message we send
585  // back, if possible.
586  //
587  OTString strPublicEncrKey, strPublicSignKey;
588  OTAsymmetricKey& thePublicEncrKey =
589  (OTAsymmetricKey&)
590  pNym->GetPublicEncrKey(); // todo cast
591  OTAsymmetricKey& thePublicSignKey =
592  (OTAsymmetricKey&)
593  pNym->GetPublicSignKey(); // todo cast
594 
595  thePublicEncrKey.GetPublicKey(
596  strPublicEncrKey,
597  false); // bEscaped=true by default
598  thePublicSignKey.GetPublicKey(
599  strPublicSignKey,
600  false); // bEscaped=true by default
601 
602  // We also (for now) set the Nym's keypair (which is
603  // being phased out entirely,
604  // and being replaced with credentials.)
605  //
606  if (strPublicSignKey.Exists())
607  pNym->SetPublicKey(
608  strPublicSignKey,
609  false); // bEscaped=true by default
610 
611  // This is only for verified Nyms, (and we're
612  // verified in here!) We do this so that
613  // we have the option later to encrypt the replies
614  // back to the client...(using the
615  // client's public key that we set here.)
616  if (strPublicEncrKey.Exists() &&
617  (nullptr != pConnection))
618  pConnection->SetPublicKey(thePublicEncrKey);
619  // Look up the NymID and see if it's already a valid
620  // user account.
621  //
622  // If it is, then we can't very well create it
623  // twice, can we?
624  //
625  // UPDATE: Actually we should, in such cases, just
626  // return true with
627  // a copy of the Nymfile. Helps prevent sync errors,
628  // and gives people
629  // a way to grab the server's copy of their nymfile,
630  // if they need it.
631  //
633  0, "Verifying account doesn't already exist... "
634  "(IGNORE ANY ERRORS, IMMEDIATELY BELOW, "
635  "ABOUT FAILURE OPENING FILES)\n");
636 
637  // Prepare to send success or failure back to user.
638  // (1) set up member variables
639  msgOut.m_strCommand =
640  "@createUserAccount"; // reply to
641  // createUserAccount
642  msgOut.m_strNymID = theMessage.m_strNymID; // UserID
643  msgOut.m_strServerID =
644  server_->m_strServerID; // ServerID, a hash of
645  // the server
646  // contract.
647  msgOut.m_bSuccess = false;
648 
649  // already done, top of this function.
650  // msgOut.m_strRequestNum.Set(theMessage.m_strRequestNum);
651  // // to prevent replay attacks.
652 
653  // We send the user's message back to him,
654  // ascii-armored,
655  // as part of our response.
656  OTString tempInMessage;
657  theMessage.SaveContractRaw(tempInMessage);
658  msgOut.m_ascInReferenceTo.SetString(tempInMessage);
659 
660  bool bLoadedSignedNymfile =
661  pNym->LoadSignedNymfile(server_->m_nymServer);
662 
663  // He ALREADY exists. We'll set success to true, and
664  // send him a copy of his own nymfile.
665  // (Signature is verified already anyway, by this
666  // point.)
667  //
668  if (bLoadedSignedNymfile &&
669  (false == pNym->IsMarkedForDeletion())) {
671  0,
672  "(Allowed in order to prevent sync issues) "
673  "==> User is registering nym that already "
674  "exists: %s\n",
675  theMessage.m_strNymID.Get());
676 
677  OTString strNymContents;
678  pNym->SavePseudonym(strNymContents);
679  OTIdentifier theNewNymID,
680  SERVER_ID(server_->m_strServerID);
681  pNym->GetIdentifier(theNewNymID);
682  OTLedger theNymbox(theNewNymID, theNewNymID,
683  SERVER_ID);
684  bool bSuccessLoadingNymbox =
685  theNymbox.LoadNymbox();
686 
687  if (true == bSuccessLoadingNymbox)
688  bSuccessLoadingNymbox =
689  (theNymbox.VerifyContractID() &&
690  theNymbox.VerifyAccount(
691  server_->m_nymServer));
692  // bSuccessLoadingNymbox
693  // =
694  // (theNymbox.VerifyAccount(server_->m_nymServer));
695  // //
696  // (No need here to load all the Box Receipts)
697  else {
698  bSuccessLoadingNymbox =
699  theNymbox.GenerateLedger(
700  theNewNymID, SERVER_ID,
702  true); // bGenerateFile=true
703 
704  if (bSuccessLoadingNymbox) {
705  bSuccessLoadingNymbox =
706  theNymbox.SignContract(
707  server_->m_nymServer);
708 
709  if (bSuccessLoadingNymbox) {
710  bSuccessLoadingNymbox =
711  theNymbox.SaveContract();
712 
713  if (bSuccessLoadingNymbox)
714  bSuccessLoadingNymbox =
715  theNymbox.SaveNymbox();
716  }
717  }
718  }
719  // by this point, the nymbox DEFINITELY exists
720  // -- or not. (generation might have failed, or
721  // verification.)
722  //
723  if (!bSuccessLoadingNymbox) {
724  OTLog::vError("Error during user account "
725  "re-registration. Failed "
726  "verifying or generating "
727  "nymbox for user: %s\n",
728  theMessage.m_strNymID.Get());
729  }
730  msgOut.m_ascPayload.SetString(strNymContents);
731  msgOut.m_bSuccess = bSuccessLoadingNymbox;
732  msgOut.SignContract(server_->m_nymServer);
733  msgOut.SaveContract();
734  return true;
735  }
736  else
737  // ((pNym->IsMarkedForDeletion()
738  // && (true == bLoadedPublicKey)) || // We
739  // allow people to resurrect deleted Nyms.
744  // (false ==
745  // bLoadedPublicKey))
746  // // can still buy usage credits.
747  {
748  if (pNym->IsMarkedForDeletion())
749  pNym->MarkAsUndeleted();
750 
751  // Good -- this means the account doesn't
752  // already exist.
753  // Let's create it.
754 
755  msgOut.m_bSuccess = theMessage.SaveContract(
756  OTFolders::UserAcct().Get(),
757  theMessage.m_strNymID.Get());
758 
759  // First we save the createUserAccount message
760  // in the accounts folder...
761  if (msgOut.m_bSuccess) {
762  OTLog::Output(0, "Success saving new user "
763  "account verification "
764  "file.\n");
765 
766  OTIdentifier theNewNymID,
767  SERVER_ID(server_->m_strServerID);
768  pNym->GetIdentifier(theNewNymID);
769  OTLedger theNymbox(theNewNymID, theNewNymID,
770  SERVER_ID);
771  bool bSuccessLoadingNymbox =
772  theNymbox.LoadNymbox();
773 
774  if (true == bSuccessLoadingNymbox) // that's
775  // strange, this
776  // user didn't
777  // exist... but
778  // maybe I allow
779  // people to drop
780  // notes anyway,
781  // so then the
782  // nymbox might
783  // already exist,
784  // with usage
785  // tokens and
786  // messages
787  // inside....
788  bSuccessLoadingNymbox =
789  (theNymbox.VerifyContractID() &&
790  theNymbox.VerifyAccount(
791  server_->m_nymServer));
792  // bSuccessLoadingNymbox
793  // =
794  // (theNymbox.VerifyAccount(server_->m_nymServer));
795  // // (No need here to load all the Box
796  // Receipts)
797  else {
798  bSuccessLoadingNymbox =
799  theNymbox.GenerateLedger(
800  theNewNymID, SERVER_ID,
802  true); // bGenerateFile=true
803  if (bSuccessLoadingNymbox) {
804  bSuccessLoadingNymbox =
805  theNymbox.SignContract(
806  server_->m_nymServer);
807  if (bSuccessLoadingNymbox) {
808  bSuccessLoadingNymbox =
809  theNymbox.SaveContract();
810 
811  if (bSuccessLoadingNymbox)
812  bSuccessLoadingNymbox =
813  theNymbox.SaveNymbox();
814  }
815  }
816  }
817  // by this point, the nymbox DEFINITELY
818  // exists -- or not. (generation might have
819  // failed, or verification.)
820 
821  if (!bSuccessLoadingNymbox) {
823  "Error during user account "
824  "registration. Failed verifying or "
825  "generating nymbox for user: %s\n",
826  theMessage.m_strNymID.Get());
827  }
828  // Either we loaded it up (it already
829  // existed) or we didn't, in which case we
830  // should
831  // save it now (to create it.)
832  //
833  else if (bLoadedSignedNymfile ||
834  pNym->SaveSignedNymfile(
835  server_->m_nymServer)) {
836  OTLog::vOutput(0, "Success creating "
837  "new Nym. (User "
838  "account fully "
839  "created.)\n");
840 
841  OTString strNymContents;
842  pNym->SavePseudonym(strNymContents);
843  msgOut.m_ascPayload.SetString(
844  strNymContents);
845  msgOut.m_bSuccess = true;
846  msgOut.SignContract(
847  server_->m_nymServer);
848  msgOut.SaveContract();
849  return true;
850  }
851  else {
852  msgOut.SignContract(
853  server_->m_nymServer);
854  msgOut.SaveContract();
855  return true;
856  }
857  }
858  else {
859  OTLog::Error("Error saving new user "
860  "account verification "
861  "file.\n");
862  msgOut.SignContract(server_->m_nymServer);
863  msgOut.SaveContract();
864  return true;
865  }
866  }
867  return true;
868  }
869  } // Success loading and verifying the Nym based on his
870  // credentials.
871  } // Success decoding the map of credentials from the message.
872  } // credential list exists, after base64-decoding.
873  } // Has Credentials.
874  }
875  // Look up the NymID and see if it's a valid user account.
876  //
877  // If we didn't receive a public key (above)
878  // Or read one from our files (below)
879  // ... then we'd have no way of validating the requests.
880  //
881  // If it is, then we read the public key from that Pseudonym and use it to
882  // verify any
883  // requests bearing that NymID.
884  if (!bNymIsServerNym &&
885  (false == pNym->LoadPublicKey()) // && // Old style. (Deprecated, but
886  // fine for now since it calls
887  // LoadCredentials.)
888  ) {
889  OTLog::vError("Failure loading public credentials for Nym: %s\n",
890  theMessage.m_strNymID.Get());
891  return false;
892  }
893  if (!bNymIsServerNym && pNym->IsMarkedForDeletion()) {
894  OTLog::vOutput(0,
895  "(Failed) attempt by client to use a deleted Nym: %s\n",
896  theMessage.m_strNymID.Get());
897  return false;
898  }
899  // Okay, the file was read into memory and Public Key was successfully
900  // extracted!
901  // Next, let's use that public key to verify (1) the NymID and (2) the
902  // signature
903  // on the message that we're processing.
904 
905  if (pNym->VerifyPseudonym()) {
906  OTLog::Output(3, "Pseudonym verified!\n");
907 
908  // So far so good. Now let's see if the signature matches...
909  if (theMessage.VerifySignature(*pNym)) {
910  OTLog::Output(3, "Signature verified! The message WAS signed by "
911  "the Nym\'s private key.\n");
912 
913  // Get the public key from pNym, and set it into the connection.
914  // This is only for verified Nyms, (and we're verified in here!) We
915  // do this so that
916  // we have the option later to encrypt the replies back to the
917  // client...(using the
918  // client's public key that we set here.)
919  if (nullptr != pConnection)
920  pConnection->SetPublicKey(pNym->GetPublicEncrKey());
921 
922  // Now we might as well load up the rest of the Nym.
923  // Notice I use the || to only load the nymfile if it's NOT the
924  // server Nym.
925  if (bNymIsServerNym ||
926  pNym->LoadSignedNymfile(server_->m_nymServer)) {
927  OTLog::Output(2, "Successfully loaded Nymfile into memory.\n");
928 
929  // ENTERING THE INNER SANCTUM OF SECURITY. If the user got all
930  // the way to here,
931  // Then he has passed multiple levels of security, and all
932  // commands below will
933  // assume the Nym is secure, validated, and loaded into memory
934  // for use.
935  //
936  // But still need to verify the Request Number for all other
937  // commands except
938  // Get Request Number itself...
939 
940  // Request numbers start at 100 (currently). (Since certain
941  // special messages USE 1 already...
942  // Such as messages that occur before requestnumbers are
943  // possible, like CreateUserAccount.)
944  //
945  int64_t lRequestNumber = 0;
946 
947  if (false ==
948  pNym->GetCurrentRequestNum(server_->m_strServerID,
949  lRequestNumber)) {
950  OTLog::Output(0, "Nym file request number doesn't exist. "
951  "Apparently first-ever request to "
952  "server--but everything checks out. "
953  "(Shouldn't this request number have been "
954  "created already when the NymFile was "
955  "first created???????\n");
956  // FIRST TIME! This account has never before made a single
957  // request to this server.
958  // The above call always succeeds unless the number just
959  // isn't there for that server.
960  // Therefore, since it's the first time, we'll create it
961  // now:
962  pNym->IncrementRequestNum(server_->m_nymServer,
963  server_->m_strServerID);
964 
965  // Call it again so that lRequestNumber is set to 1 also
966  if (pNym->GetCurrentRequestNum(server_->m_strServerID,
967  lRequestNumber)) {
968  OTLog::Output(0, "Created first request number in Nym "
969  "file, apparently first-ever request. "
970  "(Shouldn't this have been created "
971  "already when the NymFile was first "
972  "created???????\n");
973  }
974  else {
975  OTLog::Error("ERROR creating first request number in "
976  "Nym file.\n");
977  return false;
978  }
979  }
980 
981  // At this point, I now have the current request number for this
982  // nym in lRequestNumber
983  // Let's compare it to the one that was sent in the message...
984  // (This prevents attackers
985  // from repeat-sending intercepted messages to the server.)
986  if (false ==
987  theMessage.m_strCommand.Compare(
988  "getRequest")) // IF it's NOT a getRequest CMD,
989  // (therefore requires a request
990  // number)
991  {
992  if (lRequestNumber !=
993  atol(theMessage.m_strRequestNum.Get())) // AND the
994  // request
995  // number
996  // attached does
997  // not match
998  // what we just
999  // read out of
1000  // the file...
1001  {
1002  OTLog::vOutput(0, "Request number sent in this message "
1003  "%ld does not match the one in the "
1004  "file! (%ld)\n",
1005  atol(theMessage.m_strRequestNum.Get()),
1006  lRequestNumber);
1007  return false;
1008  }
1009  else // it's not a getRequest CMD, and the request number
1010  // sent DOES match what we read out of the file!!
1011  {
1012  // USAGE CREDITS...
1013  // Since (just below) we IncrementRequestNum() and
1014  // therefore save the Nym,
1015  // I figured it's a good spot to do our Usage Credits
1016  // code, so we don't have
1017  // to save twice.
1018  // IF (the OT Server is in "require usage credits" mode)
1019  // AND the User isn't magically FREE from
1020  // having to use usage credits (-1 is a
1021  // get-out-of-jail-free-card.)
1022  // AND (there's no Override Nym ID listed
1023  // --OR-- the Override Nym ID doesn't
1024  // match the Nym's ID who sent this message
1026  pNym->GetUsageCredits() >= 0 &&
1027  (ServerSettings::GetOverrideNymID().size() <= 0 ||
1028  (0 !=
1030  (theMessage.m_strNymID.Get()))))) {
1031  const int64_t& lUsageCredits =
1032  pNym->GetUsageCredits();
1033 
1034  if (0 == lUsageCredits) // If the User has ZERO
1035  // USAGE CREDITS LEFT. (Too
1036  // bad, even 1 would have
1037  // squeezed him by here.)
1038  {
1039  OTLog::vOutput(0, "Nym %s: ALL OUT of Usage "
1040  "Credits, while server is in "
1041  "**REQUIRE USAGE CREDITS "
1042  "MODE**!\n",
1043  theMessage.m_strNymID.Get());
1044  return false;
1045  }
1046 
1047  const int64_t lUsageFinal = (lUsageCredits - 1);
1048  pNym->SetUsageCredits(lUsageFinal);
1049  }
1050 
1051  OTLog::vOutput(3, "Request number sent in this message "
1052  "%ld DOES match the one in the "
1053  "file!\n",
1054  lRequestNumber);
1055 
1056  // At this point, it is some OTHER command (besides
1057  // getRequest)
1058  // AND the request number verifies, so we're going to
1059  // increment
1060  // the number, and let the command process.
1061  pNym->IncrementRequestNum(server_->m_nymServer,
1062  server_->m_strServerID);
1063 
1064  // **INSIDE** THE INNER SANCTUM OF SECURITY. If the user
1065  // got all the way to here,
1066  // Then he has passed multiple levels of security, and
1067  // all commands below will
1068  // assume the Nym is secure, validated, and loaded into
1069  // memory for use. They can
1070  // also assume that the request number has been verified
1071  // on this message.
1072  // EVERYTHING checks out.
1073 
1074  // NO RETURN HERE!!!! ON PURPOSE!!!!
1075  }
1076 
1077  }
1078  else // If you entered this else, that means it IS a
1079  // getRequest command
1080  // So we allow it to go through without verifying this step,
1081  // and without incrementing the counter.
1082  {
1083  // pNym->IncrementRequestNum(server_->m_strServerID); //
1084  // commented
1085  // out cause this is the one case where we DON'T increment
1086  // this number.
1087  // We allow the user to get the number, we DON'T increment
1088  // it, and now the user
1089  // can send it on his next request for some other command,
1090  // and it will verify
1091  // properly. This prevents repeat messages.
1092 
1093  // NO RETURN HERE!!!! ON PURPOSE!!!!
1094  }
1095 
1096  // At this point, we KNOW that it is EITHER a GetRequest
1097  // command, which doesn't require a request number,
1098  // OR it was some other command, but the request number they
1099  // sent in the command MATCHES the one that we
1100  // just read out of the file.
1101 
1102  // Therefore, we can process ALL messages below this
1103  // point KNOWING that the Nym is properly verified in all ways.
1104  // No messages need to worry about verifying the Nym, or about
1105  // dealing with the Request Number. It's all handled in here.
1106 
1107  }
1108  else {
1109  OTLog::vError("Error loading Nymfile: %s\n",
1110  theMessage.m_strNymID.Get());
1111  return false;
1112  }
1113  }
1114  else {
1115  OTLog::Output(0, "Signature verification failed!\n");
1116  return false;
1117  }
1118  }
1119  else {
1120  OTLog::Output(
1121  0, "Pseudonym failed to verify. Hash of public key doesn't match "
1122  "Nym ID that was sent.\n");
1123  return false;
1124  }
1125 
1126  // If you made it down this far, that means the Pseudonym verifies! The
1127  // message is legit.
1128  //
1129  // (Server ID was good, NymID is a valid hash of User's public key, and the
1130  // Signature on
1131  // the message was signed by the user's private key.)
1132  //
1133  // Now we can process the message.
1134  //
1135  // All the commands below here, it is assumed that the user account exists
1136  // and is
1137  // referenceable via pNym. (An OTPseudonym object.)
1138  //
1139  // ALL commands below can assume the Nym is real, and that the NymID and
1140  // Public Key are
1141  // available for use -- and that they verify -- without having to check
1142  // again and again.
1143 
1144  // ACKNOWLEDGMENTS OF REPLIES ALREADY RECEIVED (FOR OPTIMIZATION.)
1145 
1146  // On the client side, whenever the client is DEFINITELY made aware of the
1147  // existence of a
1148  // server reply, he adds its request number to this list, which is sent
1149  // along with all client-side
1150  // requests to the server.
1151  // The server reads the list on the incoming client message (and it uses
1152  // these same functions
1153  // to store its own internal list.) If the # already appears on its internal
1154  // list, then it does
1155  // nothing. Otherwise, it loads up the Nymbox and removes the replyNotice,
1156  // and then adds the #
1157  // to its internal list.
1158  // For any numbers on the internal list but NOT on the client's list, the
1159  // server removes from
1160  // the internal list. (The client removed them when it saw the server's
1161  // internal list, which the
1162  // server sends with its replies.)
1163  //
1164  // This entire protocol, densely described, is unnecessary for OT to
1165  // function, but is great for
1166  // optimization, as it enables OT to avoid downloading all Box Receipts
1167  // containing replyNotices,
1168  // as long as the original reply was properly received when the request was
1169  // originally sent (which
1170  // is MOST of the time...)
1171  // Thus we can eliminate most replyNotice downloads, and likely a large % of
1172  // box receipt downloads
1173  // as well.
1174  //
1175 
1176  const OTIdentifier SERVER_ID(server_->m_strServerID);
1177 
1178  // The server reads the list of acknowledged replies from the incoming
1179  // client message...
1180  //
1181  bool bIsDirtyNym = false; // if we add any acknowledged replies to the
1182  // server-side list, we will want to save (at the
1183  // end.)
1184  std::set<int64_t> numlist_ack_reply;
1185  if (theMessage.m_AcknowledgedReplies.Output(
1186  numlist_ack_reply)) // returns false if the numlist was empty.
1187  {
1188  // Load Nymbox
1189  //
1190  OTLedger theNymbox(pNym->GetConstID(), pNym->GetConstID(), SERVER_ID);
1191 
1192  if (theNymbox.LoadNymbox() &&
1193  theNymbox.VerifySignature(server_->m_nymServer)) {
1194  // if we remove any replyNotices from the Nymbox, then we will want
1195  // to save the Nymbox (at the end.)
1196  bool bIsDirtyNymbox = false;
1197 
1198  for (auto& it : numlist_ack_reply) {
1199  const int64_t lRequestNum = it;
1200  // If the # already appears on its internal list, then it does
1201  // nothing. (It must have already done
1202  // whatever it needed to do, since it already has the number
1203  // recorded as acknowledged.)
1204  //
1205  // Otherwise, if the # does NOT already appear on server's
1206  // internal list, then it loads up the
1207  // Nymbox and removes the replyNotice, and then adds the # to
1208  // its internal list for safe-keeping.
1209  //
1210  if (false ==
1211  pNym->VerifyAcknowledgedNum(server_->m_strServerID,
1212  lRequestNum)) {
1213  // Verify whether a replyNotice exists in the Nymbox, with
1214  // that lRequestNum
1215  //
1216  OTTransaction* pReplyNotice =
1217  theNymbox.GetReplyNotice(lRequestNum);
1218 
1219  if (nullptr != pReplyNotice) {
1220  // If so, remove it...
1221  //
1222  const bool bDeleted =
1223  pReplyNotice->DeleteBoxReceipt(theNymbox);
1224  const bool bRemoved = theNymbox.RemoveTransaction(
1225  pReplyNotice->GetTransactionNum()); // deletes
1226  pReplyNotice = nullptr;
1227  // (pReplyNotice is deleted, below this point,
1228  // automatically by the above Remove call.)
1229 
1230  if (!bDeleted || !bRemoved)
1231  OTLog::Error(
1232  "UserCommandProcessor::ProcessUserCommand: "
1233  "Failed trying "
1234  "to delete a box receipt, or "
1235  "while removing its stub from the Nymbox.\n");
1236 
1237  // ...and add lRequestNum to server's acknowledgment
1238  // list. (So this can't happen twice with same #.)
1239  //
1240  if (pNym->AddAcknowledgedNum(
1241  server_->m_strServerID,
1242  lRequestNum)) // doesn't save (here).
1243  bIsDirtyNym = true; // So we don't have to save EACH
1244  // iteration, but instead just
1245  // once at the bottom.
1246 
1247  if (bRemoved)
1248  bIsDirtyNymbox = true; // So we don't have to save
1249  // EACH iteration, but
1250  // instead just once at the
1251  // bottom.
1252  }
1253  } // If server didn't already have a record of this acknowledged
1254  // request #.
1255  }
1256 
1257  if (bIsDirtyNymbox) {
1258  theNymbox.ReleaseSignatures();
1259  theNymbox.SignContract(server_->m_nymServer);
1260  theNymbox.SaveContract();
1261  theNymbox.SaveNymbox();
1262  }
1263  } // If nymbox loaded and verified.
1264  }
1265 
1266  // For any numbers on the server's internal list but NOT on the client's
1267  // list, the server removes from
1268  // the internal list. (Because the client must have seen my acknowledgment
1269  // and thus removed the number
1270  // from its own list, so the server doesn't need to display it anymore.)
1271  //
1272  // Thus: iterate through the server's list of numbers, and see if each is on
1273  // the client's list. If not,
1274  // then remove it from my own (server's) internal list as well.
1275  //
1276  OTNumList numlist_to_remove; // a temp variable where we will put the
1277  // numbers "to be removed" (so we can remove
1278  // them all at once, after the loop.)
1279  const int32_t nAcknowledgedNumCount =
1280  pNym->GetAcknowledgedNumCount(SERVER_ID);
1281 
1282  if (nAcknowledgedNumCount > 0) {
1283  for (int32_t i = 0; i < nAcknowledgedNumCount; i++) {
1284  const int64_t lAcknowledgedNum =
1285  pNym->GetAcknowledgedNum(SERVER_ID, i); // index
1286 
1287  // For any numbers on the server's internal list but NOT on the
1288  // client's list (according
1289  // to the incoming message) the server removes them from its
1290  // internal list. (If the client
1291  // is done with them, then so is the server.)
1292  //
1293  if (false ==
1294  theMessage.m_AcknowledgedReplies.Verify(lAcknowledgedNum)) {
1295  numlist_to_remove.Add(lAcknowledgedNum);
1296  }
1297  } // for
1298  if (numlist_to_remove.Count() > 0) {
1299  std::set<int64_t> set_server_ack;
1300  if (numlist_to_remove.Output(set_server_ack)) {
1301  for (auto& it : set_server_ack) {
1302  const int64_t lRequestNum = it;
1303  if (pNym->RemoveAcknowledgedNum(
1304  server_->m_nymServer, server_->m_strServerID,
1305  lRequestNum, false)) // bSave=false
1306  bIsDirtyNym = true;
1307  }
1308  }
1309  }
1310  } // if there are server-side ack numbers that could potentially be removed,
1311  // if client's message doesn't list them.
1312 
1313  if (bIsDirtyNym) {
1314  pNym->SaveSignedNymfile(server_->m_nymServer); // we save here.
1315  }
1316 
1317  // Note: in the ultimate future, we wouldn't even save the Nym down here,
1318  // but we'll let the entire message process
1319  // and then save the Nym at the end.
1320  // Then again -- you'd still want to know if the Nym was locked, at each
1321  // "save attempt" along the way. Because even
1322  // though the Nym might not actually save at each of those signposts, it
1323  // should still CANCEL OUT IF IT WOULD FAIL TRYING.
1324  // Of course we still only want to save the Nym once, but we still want each
1325  // step along the way -- each vital step that
1326  // would normally have saved each time -- to know whether or not it will
1327  // actually work, and if not, to fail the message
1328  // AT THAT POINT and not somewhere much later, at the bottom, after all
1329  // kinds of other processing has been done.
1330  //
1331  // Therefore in the new version we will probably still "Save" the Nym at
1332  // each critical point, but INTERNALLY, it won't
1333  // actually save until the bottom. BUT, even though it won't actually save,
1334  // it will still know if the TIMESTAMP IS WITHIN
1335  // VALID RANGE (each time), and it will still know that it has definitely
1336  // locked the resource (which happens the first time)
1337  // and it will still want to set the resource as dirty, internally, even
1338  // when it doesn't save it right away, because otherwise
1339  // it wouldn't know to save it later, either.
1340 
1341  msgOut.m_strServerID = server_->m_strServerID;
1342  msgOut.SetAcknowledgments(*pNym); // Must be called AFTER
1343  // msgOut.m_strServerID is already set.
1344  // (It uses it.)
1345 
1346  if (theMessage.m_strCommand.Compare("getRequest")) // This command is
1347  // special because it's
1348  // the only one that
1349  // doesn't require a
1350  // request number.
1351  // All of the other commands, below, will fail above if the proper
1352  // request number isn't included
1353  // in the message. They will already have failed by this point if they
1354  // didn't verify.
1355  {
1356  OTLog::vOutput(0, "\n==> Received a getRequest message. Nym: %s ...\n",
1357  strMsgNymID.Get());
1358 
1360 
1361  UserCmdGetRequest(*pNym, theMessage, msgOut);
1362 
1363  return true;
1364  }
1365  else if (theMessage.m_strCommand.Compare("getTransactionNum")) {
1367  0, "\n==> Received a getTransactionNum message. Nym: %s ...\n",
1368  strMsgNymID.Get());
1369 
1371 
1372  UserCmdGetTransactionNum(*pNym, theMessage, msgOut);
1373 
1374  return true;
1375  }
1376  else if (theMessage.m_strCommand.Compare("checkUser")) {
1377  OTLog::vOutput(0, "\n==> Received a checkUser message. Nym: %s ...\n",
1378  strMsgNymID.Get());
1379 
1381 
1382  UserCmdCheckUser(*pNym, theMessage, msgOut);
1383 
1384  return true;
1385  }
1386  else if (theMessage.m_strCommand.Compare("sendUserMessage")) {
1388  0, "\n==> Received a sendUserMessage message. Nym: %s ...\n",
1389  strMsgNymID.Get());
1390 
1392 
1393  UserCmdSendUserMessage(*pNym, theMessage, msgOut);
1394 
1395  return true;
1396  }
1397  else if (theMessage.m_strCommand.Compare("sendUserInstrument")) {
1399  0, "\n==> Received a sendUserInstrument message. Nym: %s ...\n",
1400  strMsgNymID.Get());
1401 
1403 
1404  UserCmdSendUserInstrument(*pNym, theMessage, msgOut);
1405 
1406  return true;
1407  }
1408  else if (theMessage.m_strCommand.Compare("deleteUserAccount")) {
1410  0, "\n==> Received a deleteUserAccount message. Nym: %s ...\n",
1411  strMsgNymID.Get());
1412 
1414 
1415  UserCmdDeleteUser(*pNym, theMessage, msgOut);
1416 
1417  return true;
1418  }
1419  else if (theMessage.m_strCommand.Compare("deleteAssetAccount")) {
1421  0, "\n==> Received a deleteAssetAccount message. Nym: %s ...\n",
1422  strMsgNymID.Get());
1423 
1425 
1426  UserCmdDeleteAssetAcct(*pNym, theMessage, msgOut);
1427 
1428  return true;
1429  }
1430  else if (theMessage.m_strCommand.Compare("createAccount")) {
1431  OTLog::vOutput(0,
1432  "\n==> Received a createAccount message. Nym: %s ...\n",
1433  strMsgNymID.Get());
1434 
1436 
1437  UserCmdCreateAccount(*pNym, theMessage, msgOut);
1438 
1439  return true;
1440  }
1441  else if (theMessage.m_strCommand.Compare("issueAssetType")) {
1443  0, "\n==> Received an issueAssetType message. Nym: %s ...\n",
1444  strMsgNymID.Get());
1445 
1447 
1448  UserCmdIssueAssetType(*pNym, theMessage, msgOut);
1449 
1450  return true;
1451  }
1452  else if (theMessage.m_strCommand.Compare("issueBasket")) {
1453  OTLog::vOutput(0,
1454  "\n==> Received an issueBasket message. Nym: %s ...\n",
1455  strMsgNymID.Get());
1456 
1458 
1459  UserCmdIssueBasket(*pNym, theMessage, msgOut);
1460 
1461  return true;
1462  }
1463  else if (theMessage.m_strCommand.Compare("notarizeTransactions")) {
1464  OTLog::vOutput(0, "\n==> Received a notarizeTransactions message. "
1465  "Acct: %s Nym: %s ...\n",
1466  theMessage.m_strAcctID.Get(), strMsgNymID.Get());
1467 
1469 
1470  UserCmdNotarizeTransactions(*pNym, theMessage, msgOut);
1471 
1472  return true;
1473  }
1474  else if (theMessage.m_strCommand.Compare("getNymbox")) {
1475  OTLog::vOutput(0, "\n==> Received a getNymbox message. Nym: %s ...\n",
1476  strMsgNymID.Get());
1477 
1479 
1480  UserCmdGetNymbox(*pNym, theMessage, msgOut);
1481 
1482  return true;
1483  }
1484  else if (theMessage.m_strCommand.Compare("getBoxReceipt")) {
1485  OTLog::vOutput(0,
1486  "\n==> Received a getBoxReceipt message. Nym: %s ...\n",
1487  strMsgNymID.Get());
1488 
1489  bool bRunIt = true;
1490  if (0 == theMessage.m_lDepth)
1492  else if (1 == theMessage.m_lDepth)
1494  else if (2 == theMessage.m_lDepth)
1496  else
1497  bRunIt = false;
1498 
1499  if (bRunIt) UserCmdGetBoxReceipt(*pNym, theMessage, msgOut);
1500 
1501  return true;
1502  }
1503  else if (theMessage.m_strCommand.Compare("getInbox")) {
1505  0, "\n==> Received a getInbox message. Acct: %s Nym: %s ...\n",
1506  theMessage.m_strAcctID.Get(), strMsgNymID.Get());
1507 
1509 
1510  UserCmdGetInbox(*pNym, theMessage, msgOut);
1511 
1512  return true;
1513  }
1514  else if (theMessage.m_strCommand.Compare("getOutbox")) {
1516  0, "\n==> Received a getOutbox message. Acct: %s Nym: %s ...\n",
1517  theMessage.m_strAcctID.Get(), strMsgNymID.Get());
1518 
1520 
1521  UserCmdGetOutbox(*pNym, theMessage, msgOut);
1522 
1523  return true;
1524  }
1525  else if (theMessage.m_strCommand.Compare("getAccount")) {
1527  0, "\n==> Received a getAccount message. Acct: %s Nym: %s ...\n",
1528  theMessage.m_strAcctID.Get(), strMsgNymID.Get());
1529 
1531 
1532  UserCmdGetAccount(*pNym, theMessage, msgOut);
1533 
1534  return true;
1535  }
1536  else if (theMessage.m_strCommand.Compare("getAccountFiles")) {
1537  OTLog::vOutput(0, "\n==> Received a getAccountFiles message. Acct: %s "
1538  "Nym: %s ...\n",
1539  theMessage.m_strAcctID.Get(), strMsgNymID.Get());
1540 
1544 
1545  UserCmdGetAccountFiles(*pNym, theMessage, msgOut);
1546 
1547  return true;
1548  }
1549  else if (theMessage.m_strCommand.Compare("processNymbox")) {
1550  OTLog::vOutput(0,
1551  "\n==> Received a processNymbox message. Nym: %s ...\n",
1552  strMsgNymID.Get());
1553 
1555 
1556  UserCmdProcessNymbox(*pNym, theMessage, msgOut);
1557 
1558  return true;
1559  }
1560  else if (theMessage.m_strCommand.Compare("processInbox")) {
1562  0, "\n==> Received a processInbox message. Acct: %s Nym: %s ...\n",
1563  theMessage.m_strAcctID.Get(), strMsgNymID.Get());
1564 
1566 
1567  UserCmdProcessInbox(*pNym, theMessage, msgOut);
1568 
1569  return true;
1570  }
1571  else if (theMessage.m_strCommand.Compare("queryAssetTypes")) {
1573  0, "\n==> Received a queryAssetTypes message. Nym: %s ...\n",
1574  strMsgNymID.Get());
1575 
1577 
1578  UserCmdQueryAssetTypes(*pNym, theMessage, msgOut);
1579 
1580  return true;
1581  }
1582  else if (theMessage.m_strCommand.Compare("getContract")) {
1583  OTLog::vOutput(0, "\n==> Received a getContract message. Nym: %s ...\n",
1584  strMsgNymID.Get());
1585 
1587 
1588  UserCmdGetContract(*pNym, theMessage, msgOut);
1589 
1590  return true;
1591  }
1592  else if (theMessage.m_strCommand.Compare("getMint")) {
1593  OTLog::vOutput(0, "\n==> Received a getMint message. Nym: %s ...\n",
1594  strMsgNymID.Get());
1595 
1597 
1598  UserCmdGetMint(*pNym, theMessage, msgOut);
1599 
1600  return true;
1601  }
1602  else if (theMessage.m_strCommand.Compare("getMarketList")) {
1603  OTLog::vOutput(0,
1604  "\n==> Received a getMarketList message. Nym: %s ...\n",
1605  strMsgNymID.Get());
1606 
1608 
1609  UserCmdGetMarketList(*pNym, theMessage, msgOut);
1610 
1611  return true;
1612  }
1613  else if (theMessage.m_strCommand.Compare("getMarketOffers")) {
1615  0, "\n==> Received a getMarketOffers message. Nym: %s ...\n",
1616  strMsgNymID.Get());
1617 
1619 
1620  UserCmdGetMarketOffers(*pNym, theMessage, msgOut);
1621 
1622  return true;
1623  }
1624  else if (theMessage.m_strCommand.Compare("getMarketRecentTrades")) {
1626  0, "\n==> Received a getMarketRecentTrades message. Nym: %s ...\n",
1627  strMsgNymID.Get());
1628 
1631 
1632  UserCmdGetMarketRecentTrades(*pNym, theMessage, msgOut);
1633 
1634  return true;
1635  }
1636  else if (theMessage.m_strCommand.Compare("getNym_MarketOffers")) {
1638  0, "\n==> Received a getNym_MarketOffers message. Nym: %s ...\n",
1639  strMsgNymID.Get());
1640 
1642 
1643  UserCmdGetNym_MarketOffers(*pNym, theMessage, msgOut);
1644 
1645  return true;
1646  }
1647  else if (theMessage.m_strCommand.Compare("triggerClause")) {
1648  OTLog::vOutput(0,
1649  "\n==> Received a triggerClause message. Nym: %s ...\n",
1650  strMsgNymID.Get());
1651 
1653 
1654  UserCmdTriggerClause(*pNym, theMessage, msgOut);
1655 
1656  return true;
1657  }
1658  else if (theMessage.m_strCommand.Compare("usageCredits")) {
1659  OTLog::vOutput(0,
1660  "\n==> Received a usageCredits message. Nym: %s ...\n",
1661  strMsgNymID.Get());
1662 
1664 
1665  UserCmdUsageCredits(*pNym, theMessage, msgOut);
1666 
1667  return true;
1668  }
1669  else {
1670  OTLog::vError("Unknown command type in the XML, or missing payload, in "
1671  "ProcessMessage.\n");
1672 
1673  OTString strTemp;
1674  strTemp.Format("@%s", theMessage.m_strCommand.Get()); // Todo security.
1675  // Review this.
1676 
1677  msgOut.m_strCommand = strTemp;
1678  msgOut.m_strAcctID = theMessage.m_strAcctID;
1679  msgOut.m_strServerID = theMessage.m_strServerID;
1680  msgOut.m_strNymID = theMessage.m_strNymID;
1681 
1682  msgOut.m_bSuccess = false;
1683 
1684  OTString strRef(theMessage);
1685 
1686  msgOut.m_ascInReferenceTo.SetString(strRef);
1687 
1688  msgOut.SignContract(server_->m_nymServer);
1689  msgOut.SaveContract();
1690 
1691  return false;
1692  }
1693 }
1694 
1695 // Get the list of markets on this server.
1696 void UserCommandProcessor::UserCmdGetMarketList(OTPseudonym&, OTMessage& MsgIn,
1697  OTMessage& msgOut)
1698 {
1699  // (1) set up member variables
1700  msgOut.m_strCommand = "@getMarketList"; // reply to getMarketList
1701  msgOut.m_strNymID = MsgIn.m_strNymID; // UserID
1702  // msgOut.m_strServerID = m_strServerID; // This is already set in
1703  // ProcessUserCommand.
1704 
1705  OTASCIIArmor ascOutput;
1706  int32_t nMarketCount = 0;
1707 
1708  msgOut.m_bSuccess = server_->m_Cron.GetMarketList(ascOutput, nMarketCount);
1709 
1710  // If success,
1711  if ((true == msgOut.m_bSuccess) && (nMarketCount > 0)) {
1712  msgOut.m_ascPayload.Set(ascOutput);
1713 
1714  OTString strCount;
1715  strCount.Format("%d", nMarketCount);
1716  msgOut.m_lDepth = atol(strCount.Get());
1717  }
1718  // if Failed, we send the user's message back to him, ascii-armored as part
1719  // of response.
1720  else if (!msgOut.m_bSuccess) {
1721  OTString tempInMessage(MsgIn);
1722  msgOut.m_ascInReferenceTo.SetString(tempInMessage);
1723  }
1724 
1725  // (2) Sign the Message
1726  msgOut.SignContract(server_->m_nymServer);
1727 
1728  // (3) Save the Message (with signatures and all, back to its internal
1729  // member m_strRawFile.)
1730  //
1731  // FYI, SaveContract takes m_xmlUnsigned and wraps it with the signatures
1732  // and ------- BEGIN bookends
1733  // If you don't pass a string in, then SaveContract saves the new version to
1734  // its member, m_strRawFile
1735  msgOut.SaveContract();
1736 }
1737 
1738 // Get the publicly-available list of offers on a specific market.
1739 void UserCommandProcessor::UserCmdGetMarketOffers(OTPseudonym&,
1740  OTMessage& MsgIn,
1741  OTMessage& msgOut)
1742 {
1743  // (1) set up member variables
1744  msgOut.m_strCommand = "@getMarketOffers"; // reply to getMarketOffers
1745  msgOut.m_strNymID = MsgIn.m_strNymID; // UserID
1746  msgOut.m_strNymID2 = MsgIn.m_strNymID2; // Market ID.
1747  // msgOut.m_strServerID = m_strServerID; // This is already set in
1748  // ProcessUserCommand.
1749 
1750  int64_t lDepth = MsgIn.m_lDepth;
1751  if (lDepth < 0) lDepth = 0;
1752 
1753  const OTIdentifier MARKET_ID(MsgIn.m_strNymID2);
1754 
1755  OTMarket* pMarket = server_->m_Cron.GetMarket(MARKET_ID);
1756 
1757  // If success,
1758  if ((msgOut.m_bSuccess =
1759  ((pMarket != nullptr) ? true : false))) // if assigned true
1760  {
1761  OTASCIIArmor ascOutput;
1762  int32_t nOfferCount = 0;
1763 
1764  msgOut.m_bSuccess =
1765  pMarket->GetOfferList(ascOutput, lDepth, nOfferCount);
1766 
1767  if ((true == msgOut.m_bSuccess) && (nOfferCount > 0)) {
1768  msgOut.m_ascPayload = ascOutput;
1769  msgOut.m_lDepth = nOfferCount;
1770  }
1771  }
1772 
1773  // if Failed, we send the user's message back to him, ascii-armored as part
1774  // of response.
1775  if (!msgOut.m_bSuccess) {
1776  OTString tempInMessage(MsgIn);
1777  msgOut.m_ascInReferenceTo.SetString(tempInMessage);
1778  }
1779 
1780  // (2) Sign the Message
1781  msgOut.SignContract(server_->m_nymServer);
1782 
1783  // (3) Save the Message (with signatures and all, back to its internal
1784  // member m_strRawFile.)
1785  //
1786  // FYI, SaveContract takes m_xmlUnsigned and wraps it with the signatures
1787  // and ------- BEGIN bookends
1788  // If you don't pass a string in, then SaveContract saves the new version to
1789  // its member, m_strRawFile
1790  msgOut.SaveContract();
1791 }
1792 
1793 // Get a report of recent trades that have occurred on a specific market.
1794 void UserCommandProcessor::UserCmdGetMarketRecentTrades(OTPseudonym&,
1795  OTMessage& MsgIn,
1796  OTMessage& msgOut)
1797 {
1798  // (1) set up member variables
1799  msgOut.m_strCommand =
1800  "@getMarketRecentTrades"; // reply to getMarketRecentTrades
1801  msgOut.m_strNymID = MsgIn.m_strNymID; // UserID
1802  msgOut.m_strNymID2 = MsgIn.m_strNymID2; // Market ID.
1803  // msgOut.m_strServerID = m_strServerID; // This is already set in
1804  // ProcessUserCommand.
1805 
1806  const OTIdentifier MARKET_ID(MsgIn.m_strNymID2);
1807 
1808  OTMarket* pMarket = server_->m_Cron.GetMarket(MARKET_ID);
1809 
1810  // If success,
1811  if ((msgOut.m_bSuccess =
1812  ((pMarket != nullptr) ? true : false))) // if assigned true
1813  {
1814  OTASCIIArmor ascOutput;
1815  int32_t nTradeCount = 0;
1816 
1817  msgOut.m_bSuccess = pMarket->GetRecentTradeList(ascOutput, nTradeCount);
1818 
1819  if (true == msgOut.m_bSuccess) {
1820  msgOut.m_lDepth = nTradeCount;
1821 
1822  if (nTradeCount > 0) msgOut.m_ascPayload = ascOutput;
1823  }
1824  }
1825 
1826  // if Failed, we send the user's message back to him, ascii-armored as part
1827  // of response.
1828  if (!msgOut.m_bSuccess) {
1829  OTString tempInMessage(MsgIn);
1830  msgOut.m_ascInReferenceTo.SetString(tempInMessage);
1831  }
1832 
1833  // (2) Sign the Message
1834  msgOut.SignContract(server_->m_nymServer);
1835 
1836  // (3) Save the Message (with signatures and all, back to its internal
1837  // member m_strRawFile.)
1838  //
1839  // FYI, SaveContract takes m_xmlUnsigned and wraps it with the signatures
1840  // and ------- BEGIN bookends
1841  // If you don't pass a string in, then SaveContract saves the new version to
1842  // its member, m_strRawFile
1843  msgOut.SaveContract();
1844 }
1845 
1846 // Get the offers that a specific Nym has placed on a specific market.
1847 //
1848 void UserCommandProcessor::UserCmdGetNym_MarketOffers(OTPseudonym& theNym,
1849  OTMessage& MsgIn,
1850  OTMessage& msgOut)
1851 {
1852  // (1) set up member variables
1853  msgOut.m_strCommand = "@getNym_MarketOffers"; // reply to getMarketOffers
1854  msgOut.m_strNymID = MsgIn.m_strNymID; // UserID
1855  // msgOut.m_strServerID = m_strServerID; // This is already set in
1856  // ProcessUserCommand.
1857 
1858  OTIdentifier NYM_ID;
1859  theNym.GetIdentifier(NYM_ID);
1860 
1861  OTASCIIArmor ascOutput;
1862  int32_t nOfferCount = 0;
1863 
1864  msgOut.m_bSuccess =
1865  server_->m_Cron.GetNym_OfferList(ascOutput, NYM_ID, nOfferCount);
1866 
1867  if ((true == msgOut.m_bSuccess) && (nOfferCount > 0)) {
1868  msgOut.m_ascPayload = ascOutput;
1869  msgOut.m_lDepth = nOfferCount;
1870  }
1871  // if Failed, we send the user's message back to him, ascii-armored as part
1872  // of response.
1873  if (!msgOut.m_bSuccess) {
1874  OTString tempInMessage(MsgIn);
1875  msgOut.m_ascInReferenceTo.SetString(tempInMessage);
1876  }
1877 
1878  // (2) Sign the Message
1879  msgOut.SignContract(server_->m_nymServer);
1880 
1881  // (3) Save the Message (with signatures and all, back to its internal
1882  // member m_strRawFile.)
1883  //
1884  // FYI, SaveContract takes m_xmlUnsigned and wraps it with the signatures
1885  // and ------- BEGIN bookends
1886  // If you don't pass a string in, then SaveContract saves the new version to
1887  // its member, m_strRawFile
1888  msgOut.SaveContract();
1889 }
1890 
1891 void UserCommandProcessor::UserCmdCheckServerID(OTPseudonym&, OTMessage& MsgIn,
1892  OTMessage& msgOut)
1893 {
1894  // (1) set up member variables
1895  msgOut.m_strCommand = "@checkServerID"; // reply to checkServerID
1896  msgOut.m_strNymID = MsgIn.m_strNymID; // UserID
1897  // msgOut.m_strServerID = m_strServerID; // This is already set in
1898  // ProcessUserCommand.
1899 
1900  // already at the top of ProcessUserCommand, which calls this.
1901  // msgOut.m_strRequestNum.Set(MsgIn.m_strRequestNum);
1902 
1903  if (MsgIn.m_strServerID ==
1904  server_->m_strServerID) // ServerID, a hash of the server contract.
1905  msgOut.m_bSuccess = true;
1906  else
1907  msgOut.m_bSuccess = false;
1908 
1909  // (2) Sign the Message
1910  msgOut.SignContract(server_->m_nymServer);
1911 
1912  // (3) Save the Message (with signatures and all, back to its internal
1913  // member m_strRawFile.)
1914  //
1915  // FYI, SaveContract takes m_xmlUnsigned and wraps it with the signatures
1916  // and ------- BEGIN bookends
1917  // If you don't pass a string in, then SaveContract saves the new version to
1918  // its member, m_strRawFile
1919  msgOut.SaveContract();
1920 }
1921 
1922 void UserCommandProcessor::UserCmdGetTransactionNum(OTPseudonym& theNym,
1923  OTMessage& MsgIn,
1924  OTMessage& msgOut)
1925 {
1926  // (1) set up member variables
1927  msgOut.m_strCommand = "@getTransactionNum"; // reply to getTransactionNum
1928  msgOut.m_strNymID = MsgIn.m_strNymID; // UserID
1929  // msgOut.m_strServerID = m_strServerID; // This is already set in
1930  // ProcessUserCommand.
1931 
1932  // already at the top of ProcessUserCommand, which calls this.
1933  // msgOut.m_strRequestNum.Set(MsgIn.m_strRequestNum);
1934 
1935  const OTIdentifier SERVER_ID(server_->m_strServerID);
1936 
1937  // A few client requests, and a few server replies (not exactly matched up)
1938  // will include a copy of the NymboxHash. The server may reject certain
1939  // client requests that have a bad value here (since it would be out of sync
1940  // anyway); the client is able to see the server's hash and realize to
1941  // re-download the nymbox and other intermediary files.
1942  //
1943  int32_t nCount = theNym.GetTransactionNumCount(SERVER_ID);
1944  const OTIdentifier theMsgNymboxHash(
1945  MsgIn.m_strNymboxHash); // theMsgNymboxHash is the hash sent by the
1946  // client side
1947  OTIdentifier EXISTING_NYMBOX_HASH;
1948 
1949  const bool bGotNymboxHashServerSide =
1950  theNym.GetNymboxHashServerSide(SERVER_ID, EXISTING_NYMBOX_HASH);
1951  const bool bGotNymboxHashClientSide = MsgIn.m_strNymboxHash.Exists();
1952 
1953  if (bGotNymboxHashServerSide) // EXISTING_NYMBOX_HASH is the hash stored on
1954  // the server side
1955  EXISTING_NYMBOX_HASH.GetString(msgOut.m_strNymboxHash);
1956  if ((bGotNymboxHashServerSide && bGotNymboxHashClientSide &&
1957  (theMsgNymboxHash != EXISTING_NYMBOX_HASH)) ||
1958  (bGotNymboxHashServerSide && !bGotNymboxHashClientSide)) {
1959  OTLog::Output(
1960  0, "UserCommandProcessor::UserCmdGetTransactionNum: Rejecting "
1961  "message since nymbox hash "
1962  "doesn't match. (Send a getNymbox message to grab the "
1963  "newest one.)\n");
1964 
1965  }
1966  else if (nCount > 50) // todo no hardcoding. (max transaction nums allowed
1967  // out at a single time.)
1968  {
1970  0,
1971  "UserCommandProcessor::UserCmdGetTransactionNum: Failure: Nym %s "
1972  "already has "
1973  "more than 50 unused transaction numbers signed out. (He needs to "
1974  "use those first. "
1975  "Tell him to download his latest Nymbox.)\n",
1976  MsgIn.m_strNymID.Get());
1977  }
1978  else {
1979  OTIdentifier USER_ID, NYMBOX_HASH;
1980  theNym.GetIdentifier(USER_ID);
1981 
1982  bool bSuccess = true;
1983  bool bSavedNymbox = false;
1984  OTLedger theLedger(USER_ID, USER_ID, SERVER_ID); // Nymbox
1985 
1986  // We'll store the transaction numbers here immediately after they're
1987  // issued,
1988  // before adding them to the Nymbox.
1989  //
1990  OTNumList theNumlist;
1991 
1992  int64_t lFirstTransNum =
1993  0; // While there may be 20 transaction numbers on this tranasction,
1994  // ONE of them (the first one) is the "official" number of this
1995  // transaction. The rest are just attached in an extra variable.
1996 
1997  // Update: Now we're going to grab 20 or 30 transaction numbers,
1998  // instead of just 1 like before!!!
1999  //
2000  for (int32_t i = 0; i < 100; i++) // todo, hardcoding!!!! (But notice we
2001  // grab 100 transaction numbers at a
2002  // time now.)
2003  {
2004  int64_t lTransNum = 0;
2005  // This call will save the new transaction number to the nym's file.
2006  // ??? Why did I say that, when clearly the last parameter is false?
2007  // AHHHH Because I drop it into the Nymbox instead, and make him
2008  // sign for it!
2009 
2010  if (false ==
2011  server_->transactor_.issueNextTransactionNumber(
2012  theNym, lTransNum, false)) // bool bStoreTheNumber = false
2013  {
2014  lTransNum = 0;
2015  OTLog::Error("UserCommandProcessor::UserCmdGetTransactionNu: "
2016  "Error issuing "
2017  "next transaction number!\n");
2018  bSuccess = false;
2019  break;
2020  }
2021 
2022  theNumlist.Add(lTransNum); // <=========
2023  if (0 == i) // First iteration
2024  lFirstTransNum = lTransNum;
2025  }
2026 
2027  if (!bSuccess) {
2028  // Apparently nothing. Also, plenty of logs just above already, if
2029  // this ever happens.
2030  }
2031  else if (!theLedger.LoadNymbox()) {
2032  OTLog::Error("Error loading Nymbox in "
2033  "UserCommandProcessor::UserCmdGetTransactionNum\n");
2034  }
2035  // Drop in the Nymbox
2036  else if ((msgOut.m_bSuccess = (
2037  // theLedger.VerifyAccount(server_->m_nymServer)
2038  // && // This forces ALL box receipts to load.
2039  theLedger.VerifyContractID() && // We don't need them
2040  // right now, so we verify
2041  theLedger.VerifySignature(
2042  server_->m_nymServer) // everything else without
2043  // loading them.
2044  ) // if loaded and verified.
2045  )) // if success
2046  {
2047  // Note: I decided against adding newly-requested transaction
2048  // numbers to existing OTTransaction::blanks in the Nymbox.
2049  // Why not? Because once the user downloads the Box Receipt, he will
2050  // think he has it already, when the Server meanwhile
2051  // has a new version of that same Box Receipt. But the user will
2052  // never re-download it if he believes that he already has
2053  // it.
2054  // Since the transaction can contain 10, 20, or 50 transaction
2055  // numbers now, we don't NEED to be able to combine them
2056  // anyway, since the problem is still effectively solved.
2057 
2058  OTTransaction* pTransaction = OTTransaction::GenerateTransaction(
2059  theLedger, OTTransaction::blank,
2060  lFirstTransNum); // Generate a new OTTransaction::blank
2061 
2062  if (nullptr !=
2063  pTransaction) // The above has an OT_ASSERT within, but
2064  // I just like to check my pointers.
2065  {
2066  // ADD the contents of theNumlist (the 20 new transaction
2067  // numbers we're giving the user)
2068  // to this OTTransaction::blank.
2069  //
2070  pTransaction->AddNumbersToTransaction(theNumlist);
2071 
2072  pTransaction->SignContract(server_->m_nymServer);
2073  pTransaction->SaveContract();
2074 
2075  theLedger.AddTransaction(*pTransaction);
2076 
2077  theLedger.ReleaseSignatures();
2078  theLedger.SignContract(server_->m_nymServer);
2079  theLedger.SaveContract();
2080 
2081  bSavedNymbox = true;
2082  theLedger.SaveNymbox(&NYMBOX_HASH);
2083 
2084  // Any inbox/nymbox/outbox ledger will only itself contain
2085  // abbreviated versions of the receipts, including their hashes.
2086  //
2087  // The rest is stored separately, in the box receipt, which is
2088  // created
2089  // whenever a receipt is added to a box, and deleted after a
2090  // receipt
2091  // is removed from a box.
2092  //
2093  pTransaction->SaveBoxReceipt(theLedger);
2094  }
2095  else
2096  theLedger.CalculateNymboxHash(NYMBOX_HASH);
2097  }
2098  else {
2099  OTLog::Error("Error verifying Nymbox in "
2100  "UserCommandProcessor::UserCmdGetTransactionNum\n");
2101  }
2102  std::set<int64_t> theList;
2103  theNumlist.Output(theList);
2104 
2105  for (auto& it : theList) {
2106  const int64_t lTransNum = it;
2107  server_->transactor_.removeTransactionNumber(theNym, lTransNum,
2108  false); // bSave=false
2109  server_->transactor_.removeIssuedNumber(
2110  theNym, lTransNum, false); // I'll drop it in his
2111  // Nymbox -- he can
2112  // SIGN for it.
2113  // Then why was it added in the first place? Because we originally
2114  // sent it back in the reply directly,
2115  // so IssueNext was designed to work that way originally.
2116  }
2117 
2118  if (bSavedNymbox) {
2119  theNym.SetNymboxHashServerSide(NYMBOX_HASH);
2120  theNym.SaveSignedNymfile(server_->m_nymServer);
2121 
2122  NYMBOX_HASH.GetString(msgOut.m_strNymboxHash);
2123  }
2124  else if (true == msgOut.m_bSuccess) {
2125  theLedger.CalculateNymboxHash(NYMBOX_HASH);
2126 
2127  theNym.SetNymboxHashServerSide(
2128  NYMBOX_HASH); // Save the hash onto the Nym
2129  theNym.SaveSignedNymfile(server_->m_nymServer);
2130 
2131  NYMBOX_HASH.GetString(
2132  msgOut.m_strNymboxHash); // Get the hash onto the message
2133  }
2134  // else EXISTING_NYMBOX_HASH.GetString(msgOut.m_strNymboxHash); (above)
2135  }
2136 
2137  // (2) Sign the Message
2138  msgOut.SignContract(server_->m_nymServer);
2139 
2140  // (3) Save the Message (with signatures and all, back to its internal
2141  // member m_strRawFile.)
2142  //
2143  // FYI, SaveContract takes m_xmlUnsigned and wraps it with the signatures
2144  // and ------- BEGIN bookends
2145  // If you don't pass a string in, then SaveContract saves the new version to
2146  // its member, m_strRawFile
2147  msgOut.SaveContract();
2148 }
2149 
2150 void UserCommandProcessor::UserCmdGetRequest(OTPseudonym& theNym,
2151  OTMessage& MsgIn,
2152  OTMessage& msgOut)
2153 {
2154  // (1) set up member variables
2155  msgOut.m_strCommand = "@getRequest"; // reply to getRequest
2156  msgOut.m_strNymID = MsgIn.m_strNymID; // UserID
2157  // msgOut.m_strServerID = m_strServerID; // This is already set in
2158  // ProcessUserCommand.
2159 
2160  msgOut.m_strRequestNum.Set(MsgIn.m_strRequestNum); // Outoing reply contains
2161  // same request num
2162  // coming in (1).
2163 
2164  int64_t lReqNum = 1; // The request number being REQUESTED (in this message)
2165  // will be sent in msgOut.m_lNewRequestNum
2166 
2167  msgOut.m_bSuccess =
2168  theNym.GetCurrentRequestNum(server_->m_strServerID, lReqNum);
2169 
2170  // Server was unable to load ReqNum, which is unusual because the calling
2171  // function
2172  // should have already insured its existence.
2173  if (!msgOut.m_bSuccess) {
2174  OTLog::Error("Error loading request number in "
2175  "UserCommandProcessor::UserCmdGetRequest\n");
2176  }
2177  else
2178  msgOut.m_lNewRequestNum = lReqNum;
2179  // msgOut.m_strRequestNum.Format("%ld", lReqNum); // This will now
2180  // contain the same req num (1) that came in, with the new one stored in
2181  // msgOut.m_lNewRequestNum instead.
2182  const OTIdentifier SERVER_ID(server_->m_strServerID);
2183  OTIdentifier EXISTING_NYMBOX_HASH;
2184  if (theNym.GetNymboxHashServerSide(SERVER_ID, EXISTING_NYMBOX_HASH))
2185  EXISTING_NYMBOX_HASH.GetString(msgOut.m_strNymboxHash);
2186  else {
2187  const OTIdentifier theNymID(theNym);
2188  OTLedger theLedger(theNymID, theNymID, SERVER_ID);
2189 
2190  if (theLedger.LoadNymbox() && theLedger.VerifyContractID() &&
2191  theLedger.VerifySignature(server_->m_nymServer)) {
2192  theLedger.CalculateNymboxHash(EXISTING_NYMBOX_HASH);
2193 
2194  theNym.SetNymboxHashServerSide(EXISTING_NYMBOX_HASH);
2195  theNym.SaveSignedNymfile(server_->m_nymServer);
2196 
2197  EXISTING_NYMBOX_HASH.GetString(msgOut.m_strNymboxHash);
2198  }
2199  }
2200 
2201  // (2) Sign the Message
2202  msgOut.SignContract(server_->m_nymServer);
2203 
2204  // (3) Save the Message (with signatures and all, back to its internal
2205  // member m_strRawFile.)
2206  //
2207  // FYI, SaveContract takes m_xmlUnsigned and wraps it with the signatures
2208  // and ------- BEGIN bookends
2209  // If you don't pass a string in, then SaveContract saves the new version to
2210  // its member, m_strRawFile
2211  msgOut.SaveContract();
2212 }
2213 
2214 void UserCommandProcessor::UserCmdSendUserMessage(OTPseudonym& theNym,
2215  OTMessage& MsgIn,
2216  OTMessage& msgOut)
2217 {
2218  // (1) set up member variables
2219  msgOut.m_strCommand = "@sendUserMessage"; // reply to sendUserMessage
2220  msgOut.m_strNymID = MsgIn.m_strNymID; // UserID
2221  msgOut.m_strNymID2 = MsgIn.m_strNymID2; // UserID of recipient pubkey
2222  // msgOut.m_strServerID = m_strServerID; // This is already
2223  // set in ProcessUserCommand.
2224 
2225  const OTString strInMessage(MsgIn);
2226  const OTIdentifier SENDER_USER_ID(theNym),
2227  RECIPIENT_USER_ID(MsgIn.m_strNymID2), SERVER_ID(server_->m_strServerID);
2228  msgOut.m_ascInReferenceTo.SetString(strInMessage);
2229  const bool bSent =
2230  SendMessageToNym(SERVER_ID, SENDER_USER_ID, RECIPIENT_USER_ID,
2231  &MsgIn); // pstrMessage=nullptr
2232 
2233  if (!bSent) {
2234  OTLog::vError("UserCommandProcessor::UserCmdSendUserMessage: Failed "
2235  "while calling "
2236  "SendMessageToNym.\n");
2237  msgOut.m_bSuccess = false;
2238  }
2239  else {
2240  msgOut.m_bSuccess = true;
2241  }
2242  // (2) Sign the Message
2243  msgOut.SignContract(server_->m_nymServer);
2244 
2245  // (3) Save the Message (with signatures and all, back to its internal
2246  // member m_strRawFile.)
2247  //
2248  // FYI, SaveContract takes m_xmlUnsigned and wraps it with the signatures
2249  // and ------- BEGIN bookends
2250  // If you don't pass a string in, then SaveContract saves the new version to
2251  // its member, m_strRawFile
2252  msgOut.SaveContract();
2253 }
2254 
2255 void UserCommandProcessor::UserCmdSendUserInstrument(OTPseudonym& theNym,
2256  OTMessage& MsgIn,
2257  OTMessage& msgOut)
2258 {
2259  // (1) set up member variables
2260  msgOut.m_strCommand = "@sendUserInstrument"; // reply to sendUserInstrument
2261  msgOut.m_strNymID = MsgIn.m_strNymID; // UserID
2262  msgOut.m_strNymID2 = MsgIn.m_strNymID2; // UserID of recipient pubkey
2263  // msgOut.m_strServerID = m_strServerID; // This is already
2264  // set in ProcessUserCommand.
2265 
2266  const OTString strInMessage(MsgIn);
2267  const OTIdentifier SENDER_USER_ID(theNym),
2268  RECIPIENT_USER_ID(MsgIn.m_strNymID2), SERVER_ID(server_->m_strServerID);
2269  msgOut.m_ascInReferenceTo.SetString(strInMessage);
2270  const bool bSent = server_->SendInstrumentToNym(
2271  SERVER_ID, SENDER_USER_ID, RECIPIENT_USER_ID,
2272  &MsgIn); // pPayment=nullptr, szCommand=nullptr
2273 
2274  if (!bSent) {
2275  OTLog::vError(
2276  "UserCommandProcessor::UserCmdSendUserInstrument: Failed while "
2277  "calling SendInstrumentToNym.\n");
2278  msgOut.m_bSuccess = false;
2279  }
2280  else {
2281  msgOut.m_bSuccess = true;
2282  }
2283  // (2) Sign the Message
2284  msgOut.SignContract(server_->m_nymServer);
2285 
2286  // (3) Save the Message (with signatures and all, back to its internal
2287  // member m_strRawFile.)
2288  //
2289  // FYI, SaveContract takes m_xmlUnsigned and wraps it with the signatures
2290  // and ------- BEGIN bookends
2291  // If you don't pass a string in, then SaveContract saves the new version to
2292  // its member, m_strRawFile
2293  msgOut.SaveContract();
2294 }
2295 
2296 void UserCommandProcessor::UserCmdCheckUser(OTPseudonym&, OTMessage& MsgIn,
2297  OTMessage& msgOut)
2298 {
2299  // (1) set up member variables
2300  msgOut.m_strCommand = "@checkUser"; // reply to checkUser
2301  msgOut.m_strNymID = MsgIn.m_strNymID; // UserID
2302  msgOut.m_strNymID2 =
2303  MsgIn.m_strNymID2; // UserID of public key requested by user.
2304  // msgOut.m_strServerID = m_strServerID; // This is already set in
2305  // ProcessUserCommand.
2306 
2307  OTPseudonym nym2;
2308  nym2.SetIdentifier(MsgIn.m_strNymID2);
2309 
2310  bool bLoaded = nym2.LoadPublicKey(); // This calls LoadCredentials inside.
2311  msgOut.m_bSuccess = (bLoaded && nym2.VerifyPseudonym());
2312 
2313  // If success, we send the Nym2's public key back to the user.
2314  if (msgOut.m_bSuccess) {
2315  nym2.GetPublicEncrKey().GetPublicKey(msgOut.m_strNymPublicKey, true);
2316 
2317  // NEW: Also attach the public credentials to the response
2318  // (not just a public key.)
2319  //
2320  if (nym2.GetMasterCredentialCount() > 0) {
2321  // Create an OTDB::StringMap object.
2322 
2323  // this asserts already, on failure.
2324  std::unique_ptr<OTDB::Storable> pStorable(
2326  OTDB::StringMap* pMap =
2327  dynamic_cast<OTDB::StringMap*>(pStorable.get());
2328 
2329  if (nullptr == pMap) {
2330  OTLog::vError("%s: Error: failed trying to create a "
2331  "STORED_OBJ_STRING_MAP.\n",
2332  __FUNCTION__);
2333  msgOut.m_bSuccess = false;
2334  }
2335  else {
2336  OTString strCredList;
2337  auto& theMap = pMap->the_map;
2338 
2339  nym2.GetPublicCredentials(strCredList, &theMap);
2340  // Serialize the StringMap to a string...
2341  //
2342  if (!theMap.empty()) // Won't bother if zero credentials
2343  {
2344  std::string str_Encoded = OTDB::EncodeObject(*pMap);
2345  const bool bSuccessEncoding = (str_Encoded.size() > 0);
2346  if (bSuccessEncoding) {
2347  msgOut.m_ascPayload.SetString(
2348  strCredList); // <========== Success
2349  msgOut.m_ascPayload2.Set(
2350  str_Encoded.c_str()); // Payload contains
2351  // credentials list, payload2
2352  // contains actual
2353  // credentials.
2354  }
2355  }
2356  }
2357  } // bLoadedCredentials
2358  } // msgOut.m_bSuccess
2359  // if Failed, we send the user's message back to him, ascii-armored as part
2360  // of response.
2361  else {
2362  OTString tempInMessage(MsgIn);
2363  msgOut.m_ascInReferenceTo.SetString(tempInMessage);
2364  }
2365 
2366  // (2) Sign the Message
2367  msgOut.SignContract(server_->m_nymServer);
2368 
2369  // (3) Save the Message (with signatures and all, back to its internal
2370  // member m_strRawFile.)
2371  //
2372  // FYI, SaveContract takes m_xmlUnsigned and wraps it with the signatures
2373  // and ------- BEGIN bookends
2374  // If you don't pass a string in, then SaveContract saves the new version to
2375  // its member, m_strRawFile
2376  msgOut.SaveContract();
2377 }
2378 
2379 /*
2380  Allows ANY Nym to GET AND SET the Usage Credits for ANY other Nym!
2381  UPDATE: Only the override Nym can change the credits,
2382  You might ask, "But what if I don't want users to be able to set the Usage
2383  Credits?"
2384  That makes sense: Go to ~/.ot/server.cfg and set cmd_usage_credits=false
2385  (which is its default BTW.)
2386  That way, NO ONE can set credits, or view them for other people. (People can
2387  still view their own.)
2388  But you might ask, "But what if I want the ADMIN to still be able to set and
2389  view credits?"
2390  That makes sense: Just make sure the override_nym_id in server.cfg is set to
2391  your admin Nym, and
2392  that Nym will STILL be able to use this message:
2393 */
2394 void UserCommandProcessor::UserCmdUsageCredits(OTPseudonym& theNym,
2395  OTMessage& MsgIn,
2396  OTMessage& msgOut)
2397 {
2398  // (1) set up member variables
2399  msgOut.m_strCommand = "@usageCredits"; // reply to usageCredits
2400  msgOut.m_strNymID = MsgIn.m_strNymID; // UserID
2401  msgOut.m_strNymID2 = MsgIn.m_strNymID2; // UserID of user whose usage
2402  // credits are being examined /
2403  // adjusted.
2404  // msgOut.m_strServerID = m_strServerID; // This is already set in
2405  // ProcessUserCommand.
2406  const bool bIsPrivilegedNym =
2408  0) && // And if there's an override Nym...
2409  (0 ==
2411  (MsgIn.m_strNymID.Get())))); // And if the acting Nym IS the
2412  // override Nym...
2413  // The amount the usage credits are being ADJUSTED by.
2414  const int64_t lAdjustment =
2415  (bIsPrivilegedNym && ServerSettings::__admin_usage_credits)
2416  ? MsgIn.m_lDepth
2417  : 0;
2418 
2419  msgOut.m_lDepth = 0; // Returns total Usage Credits on Nym at the end.
2420  OTPseudonym nym2;
2421  OTIdentifier nym2ID, SERVER_ID(server_->m_strServerID);
2422  nym2.SetIdentifier(MsgIn.m_strNymID2);
2423  nym2.GetIdentifier(nym2ID);
2424 
2425  const bool bIsSameNym = nym2.CompareID(theNym);
2426  OTPseudonym* pNym = nullptr;
2427 
2428  bool bErrorCondition = false;
2429 
2430  // If nym2 and theNym are already the same Nym, then pNym points to theNym
2431  // by now already.
2432  // (And we'll skip this block.) Otherwise we load up nym2, and point pNym to
2433  // nym2 instead.
2434  //
2435  if (bIsSameNym)
2436  pNym = &theNym;
2437  else // theNym and nym2 are different Nyms, so let's load it up.
2438  {
2439  bool bLoadedPublicKey =
2440  nym2.LoadPublicKey() &&
2441  nym2.VerifyPseudonym(); // Old style (deprecated.) For now, this
2442  // calls LoadCredentials inside (which is
2443  // the new style.) Eventually we'll just
2444  // call that here directly.
2445  bool bLoadSignedNymfile = nym2.LoadSignedNymfile(server_->m_nymServer);
2446  if (!bLoadSignedNymfile &&
2447  !bLoadedPublicKey) // Nym didn't already exist.
2448  {
2449  pNym = &nym2;
2450  }
2451  else if (bLoadedPublicKey && !bLoadSignedNymfile) // Error -- if key
2452  // was there, then
2453  // nymfile should
2454  // have been also.
2455  {
2456  OTLog::vError(
2457  "%s: Nym public key (%s) exists, but nymfile doesn't! "
2458  "Could be error reading from storage. (Failure.)\n",
2459  __FUNCTION__, MsgIn.m_strNymID2.Get());
2460  bErrorCondition = true;
2461  }
2462  else {
2463  pNym = &nym2;
2464  }
2465  }
2466  if (!MsgIn.m_strNymID.Compare(MsgIn.m_strNymID2)) // If the Nym is
2467  // not performing
2468  // this on
2469  // himself...
2470  {
2471  // Either this is a Nym performing the action on himself (which is
2472  // read-only.)
2473  // Or he is the "override Nym" (special powers) and he is allowed to do
2474  // it on anybody (adjusting the credits up or down.)
2475  // But if he's NOT the override Nym, then he can NOT do it, even
2476  // read-only, on anyone OTHER than himself.
2477  //
2478  // Inside this block, we've said, "If the Nym is NOT doing this on
2479  // himself... (But on someone else)"
2480  // ...Then we KNOW, if that's true, that the Nym had BETTER have special
2481  // powers, or there's an error.
2482  //
2483  if (!((ServerSettings::GetOverrideNymID().size() > 0) &&
2484  (0 ==
2486  (MsgIn.m_strNymID.Get()))))) // ...And if he's
2487  // not the special
2488  // "override Nym"...
2489  {
2490  OTLog::vError("%s: Failed attempt by a normal Nym to view or "
2491  "adjust usage credits on a different Nym (you're "
2492  "only allowed to do this to yourself, unless your "
2493  "nym is the specially-empowered 'override nym'.)\n",
2494  __FUNCTION__);
2495  bErrorCondition = true;
2496  }
2497  }
2498  OTLedger theNymbox(nym2ID, nym2ID, SERVER_ID);
2499  bool bSuccessLoadingNymbox = theNymbox.LoadNymbox();
2500 
2501  if (bSuccessLoadingNymbox)
2502  bSuccessLoadingNymbox = (theNymbox.VerifyContractID() &&
2503  theNymbox.VerifyAccount(server_->m_nymServer));
2504  else {
2505  bSuccessLoadingNymbox = theNymbox.GenerateLedger(
2506  nym2ID, SERVER_ID, OTLedger::nymbox, true); // bGenerateFile=true
2507 
2508  if (bSuccessLoadingNymbox) {
2509  bSuccessLoadingNymbox =
2510  theNymbox.SignContract(server_->m_nymServer);
2511 
2512  if (bSuccessLoadingNymbox) {
2513  bSuccessLoadingNymbox = theNymbox.SaveContract();
2514 
2515  if (bSuccessLoadingNymbox)
2516  bSuccessLoadingNymbox = theNymbox.SaveNymbox();
2517  }
2518  }
2519  }
2520  if (!bSuccessLoadingNymbox) bErrorCondition = true;
2521  // By this point, pNym points to the correct Nym, if bErrorCondition=false;
2522  //
2523  if (!bErrorCondition) {
2524  // Get the current usage credits, which will be sent in the reply.
2525  //
2526  const int64_t& lOldCredits = pNym->GetUsageCredits();
2527  const int64_t lTentativeNew = lOldCredits + lAdjustment;
2528  const int64_t lNewCredits =
2529  (lTentativeNew < 0)
2530  ? (-1)
2531  : lTentativeNew; // It can never be less than -1.
2532 
2533  // if adjustment is non-zero, and the acting Nym has authority to make
2534  // adjustments...
2535  // if ((0 != lAdjustment) && bIsPrivilegedNym)
2536  //
2537  // Note: if the adjustment is non-zero, then we ALREADY know the acting
2538  // Nym has the authority.
2539  // How do we know?
2540  //
2541  // int64_t lAdjustment = (bIsPrivilegedNym &&
2542  // ServerSettings::__admin_usage_credits) ? MsgIn.m_lDepth : 0;
2543  //
2544  // (Therefore we also know that the server is in usage credits mode, as
2545  // well.)
2546  //
2547  if (0 != lAdjustment) {
2548  // Only the override Nym can get inside this block and set the
2549  // credits.
2550  // And ONLY in the case where usage credits are turned on, on the
2551  // server side.
2552  // Any other Nym can use UsageCredits message but as read-only, to
2553  // retrieve
2554  // the value, not to actually set it. In that case, the adjustment
2555  // is always
2556  // interpreted as "0", and the return value usage credits is always
2557  // set to -1.
2558  //
2559  pNym->SetUsageCredits(lNewCredits);
2560  msgOut.m_bSuccess = pNym->SaveSignedNymfile(
2561  server_->m_nymServer); // We changed it, so let's save pNym...
2562  }
2563  else
2564  msgOut.m_bSuccess = true; // No adjustment -- we're just returning
2565  // the current usage credits or -1,
2566  // depending on whether server is in usage
2567  // mode.
2568  //
2569  // This is because we always return credits of -1 in this case, so we
2570  // don't want to be secretly
2571  // continuing to adjust the credits farther and farther while
2572  // simultaneously returning -1.
2573  // Either way (even if adjustment is zero) then lNewCredits contains the
2574  // value being sent back...
2575  //
2576  if (ServerSettings::__admin_usage_credits) // If the server has usage
2577  // credits
2578  // turned on...
2579  msgOut.m_lDepth = lNewCredits; // ...then adjustment or not, we send
2580  // the current usage credits balance
2581  // back in the server reply.
2582  else // Else if the server does NOT have usage credits turned on...
2583  msgOut.m_lDepth = -1; // ...then we always return -1, so the client
2584  // doesn't pop up any error messages related
2585  // to usage credits.
2586  }
2587  // (2) Sign the Message
2588  msgOut.SignContract(server_->m_nymServer);
2589 
2590  // (3) Save the Message (with signatures and all, back to its internal
2591  // member m_strRawFile.)
2592  //
2593  // FYI, SaveContract takes m_xmlUnsigned and wraps it with the signatures
2594  // and ------- BEGIN bookends
2595  // If you don't pass a string in, then SaveContract saves the new version to
2596  // its member, m_strRawFile
2597  msgOut.SaveContract();
2598 }
2599 
2601 void UserCommandProcessor::UserCmdIssueAssetType(OTPseudonym& theNym,
2602  OTMessage& MsgIn,
2603  OTMessage& msgOut)
2604 {
2605  const char* szFunc = "UserCommandProcessor::UserCmdIssueAssetType";
2606 
2607  // (1) set up member variables
2608  msgOut.m_strCommand = "@issueAssetType"; // reply to issueAssetType
2609  msgOut.m_strNymID = MsgIn.m_strNymID; // UserID
2610  msgOut.m_strAssetID =
2611  MsgIn.m_strAssetID; // Asset Type ID, a hash of the asset contract.
2612  // msgOut.m_strServerID = m_strServerID; // This is already set in
2613  // ProcessUserCommand.
2614 
2615  // already at the top of ProcessUserCommand, which calls this.
2616  // msgOut.m_strRequestNum.Set(MsgIn.m_strRequestNum);
2617 
2618  const OTIdentifier USER_ID(theNym), SERVER_ID(server_->m_strServerID),
2619  ASSET_TYPE_ID(MsgIn.m_strAssetID);
2620 
2621  OTAssetContract* pAssetContract =
2622  server_->transactor_.getAssetContract(ASSET_TYPE_ID);
2623 
2624  // Make sure the contract isn't already available on this server.
2625  //
2626  if (nullptr != pAssetContract) // it exists already.
2627  {
2628  OTLog::vError(
2629  "%s: Error: Attempt to issue asset type that already exists.\n",
2630  szFunc);
2631  }
2632  else {
2633  // Pull the contract out of the message and verify it.
2634  OTString strFoldername(OTFolders::Contract().Get()),
2635  strFilename(MsgIn.m_strAssetID.Get());
2636 
2637  OTString strContract(MsgIn.m_ascPayload);
2638  pAssetContract = new OTAssetContract(MsgIn.m_strAssetID, strFoldername,
2639  strFilename, MsgIn.m_strAssetID);
2640 
2641  OTIdentifier ASSET_USER_ID;
2642  bool bSuccessCalculateDigest = false;
2643 
2644  if (nullptr == pAssetContract) {
2645  OTLog::vOutput(0, "%s: Failed trying to instantiate asset "
2646  "contract. Asset ID: %s\n",
2647  szFunc, MsgIn.m_strAssetID.Get());
2648  }
2649  else // success instantiating contract.
2650  {
2651  bool bSuccessLoadingContract =
2652  pAssetContract->LoadContractFromString(strContract);
2653 
2654  if (!bSuccessLoadingContract) {
2655  OTLog::vOutput(0, "%s: Failed trying to load asset contract "
2656  "from string. Asset ID: %s\n",
2657  szFunc, MsgIn.m_strAssetID.Get());
2658  OTLog::vOutput(1, "%s: Failed trying to load asset contract "
2659  "from string. Contract:\n\n%s\n\n",
2660  szFunc, strContract.Get());
2661  }
2662  else if (pAssetContract->GetBasketInfo().Exists()) {
2663  OTLog::vOutput(0, "%s: Prevented attempt by user to issue a "
2664  "basket currency contract. (He needs to use "
2665  "the issueBasket message for that.)\n");
2666  }
2667  else // success loading contract from string.
2668  {
2669  OTPseudonym* pNym = const_cast<OTPseudonym*>(
2670  pAssetContract->GetContractPublicNym());
2671 
2672  if (nullptr == pNym) {
2673  OTLog::vOutput(0, "%s: Failed trying to retrieve Issuer's "
2674  "public key from asset "
2675  "contract. Asset ID: %s\n",
2676  szFunc, MsgIn.m_strAssetID.Get());
2677  }
2678  else // success retrieving issuer Nym's public key from asset
2679  // contract.
2680  {
2681  pNym->GetIdentifier(ASSET_USER_ID);
2682 
2683  bSuccessCalculateDigest = true;
2684 
2685  // OTString strPublicKey;
2686  // bool bGotPublicKey =
2687  // pNym->GetPublicSignKey().GetPublicKey(strPublicKey);
2688  //
2689  // if (!bGotPublicKey)
2690  // {
2691  // OTLog::vError("%s: Error getting
2692  // public key in
2693  // UserCommandProcessor::UserCmdIssueAssetType.\n",
2694  // szFunc);
2695  // }
2696  // else // success retrieving public key
2697  // from Nym
2698  // {
2699  // bSuccessCalculateDigest =
2700  // ASSET_USER_ID.CalculateDigest(strPublicKey);
2701  //
2702  // if (!bSuccessCalculateDigest)
2703  // {
2704  // OTLog::vError("%s: Error
2705  // calculating digest in
2706  // UserCommandProcessor::UserCmdIssueAssetType.\n",
2707  // szFunc);
2708  // }
2709  // }
2710  }
2711  }
2712  }
2713 
2714  // Make sure the public key in the contract is the public key of the
2715  // Nym.
2716  // If we successfully loaded the contract from the string, and the
2717  // contract
2718  // internally verifies (the ID matches the hash of the contract, and the
2719  // signature verifies with the contract key that's inside the contract),
2720  // AND the Nym making this request has the same ID as the Nym in the
2721  // asset contract. (ONLY the issuer of that contract can connect to this
2722  // server and issue his currency.)
2723  // TODO make sure a receipt is issued that the issuer can post on his
2724  // website, to verify that he has indeed issued the currency at the
2725  // specified
2726  // transaction processor. That way, users can double-check.
2727  if (bSuccessCalculateDigest) {
2728  if ((ASSET_USER_ID == USER_ID))
2729  // The ID of the user who signed the contract must be the ID of
2730  // the user
2731  // whose public key is associated with this user account. They
2732  // are one.
2733  {
2734  if (pAssetContract->VerifyContract()) {
2735  // Create an ISSUER account (like a normal account, except
2736  // it can go negative)
2737 
2738  std::unique_ptr<OTAccount> pNewAccount(
2740  USER_ID, SERVER_ID, server_->m_nymServer, MsgIn,
2742 
2743  // If we successfully create the account, then bundle it in
2744  // the message XML payload
2745  if (nullptr !=
2746  pNewAccount) // This last parameter generates an
2747  // ISSUER account
2748  { // instead of the default SIMPLE.
2749  OTString tempPayload(*pNewAccount);
2750  msgOut.m_ascPayload.SetString(tempPayload);
2751 
2752  // Attach the new account number to the outgoing
2753  // message.
2754  pNewAccount->GetIdentifier(msgOut.m_strAcctID);
2755 
2756  // Now that the account is actually created, let's add
2757  // the new asset contract
2758  // to the server's list.
2759  server_->transactor_.addAssetContract(
2760  *pAssetContract); // Do NOT clean this
2761  // up unless failure!
2762  // Server will clean
2763  // it up.
2764  server_->mainFile_.SaveMainFile(); // So the main xml
2765  // file knows
2766  // to load
2767  // this asset type next time we run.
2768 
2769  // Make sure the contracts/%s file is created for next
2770  // time.
2771  pAssetContract->SaveContract(
2772  OTFolders::Contract().Get(), strFilename.Get());
2773  OTIdentifier theNewAccountID;
2774  pNewAccount->GetIdentifier(theNewAccountID);
2775  OTLog::Output(
2776  0,
2777  "Generating inbox/outbox for new issuer acct. \n");
2778 
2779  OTLedger theOutbox(USER_ID, theNewAccountID, SERVER_ID),
2780  theInbox(USER_ID, theNewAccountID, SERVER_ID);
2781 
2782  bool bSuccessLoadingInbox = theInbox.LoadInbox();
2783  bool bSuccessLoadingOutbox = theOutbox.LoadOutbox();
2784  // ...or generate them otherwise...
2785 
2786  if (true ==
2787  bSuccessLoadingInbox) // WEIRD IF THIS HAPPENED...
2788  bSuccessLoadingInbox = theInbox.VerifyAccount(
2789  server_->m_nymServer); // todo -- this should
2790  // NEVER
2791  // happen, the ID was just
2792  // RANDOMLY generated, so HOW did
2793  // the inbox already exist???
2794  else {
2795  bSuccessLoadingInbox = theInbox.GenerateLedger(
2796  theNewAccountID, SERVER_ID, OTLedger::inbox,
2797  true); // bGenerateFile=true
2798 
2799  if (bSuccessLoadingInbox) {
2800  bSuccessLoadingInbox =
2801  theInbox.SignContract(server_->m_nymServer);
2802 
2803  if (bSuccessLoadingInbox) {
2804  bSuccessLoadingInbox =
2805  theInbox.SaveContract();
2806 
2807  if (bSuccessLoadingInbox)
2808  bSuccessLoadingInbox =
2809  pNewAccount->SaveInbox(theInbox);
2810  }
2811  }
2812  }
2813  if (true ==
2814  bSuccessLoadingOutbox) // WEIRD IF THIS HAPPENED....
2815  bSuccessLoadingOutbox = theOutbox.VerifyAccount(
2816  server_->m_nymServer); // todo -- this should
2817  // NEVER
2818  // happen, the ID was just
2819  // RANDOMLY generated, so HOW did
2820  // the outbox already exist???
2821  else {
2822  bSuccessLoadingOutbox = theOutbox.GenerateLedger(
2823  theNewAccountID, SERVER_ID, OTLedger::outbox,
2824  true); // bGenerateFile=true
2825 
2826  if (bSuccessLoadingOutbox) {
2827  bSuccessLoadingOutbox = theOutbox.SignContract(
2828  server_->m_nymServer);
2829 
2830  if (bSuccessLoadingOutbox) {
2831  bSuccessLoadingOutbox =
2832  theOutbox.SaveContract();
2833 
2834  if (bSuccessLoadingOutbox)
2835  bSuccessLoadingOutbox =
2836  pNewAccount->SaveOutbox(theOutbox);
2837  }
2838  }
2839  }
2840  if (!bSuccessLoadingInbox) {
2841  OTString strNewAcctID(theNewAccountID);
2842 
2843  OTLog::vError("ERROR generating inbox ledger in "
2844  "UserCommandProcessor::"
2845  "UserCmdIssueAssetType:\n%"
2846  "s\n",
2847  strNewAcctID.Get());
2848  }
2849  else if (!bSuccessLoadingOutbox) {
2850  OTString strNewAcctID(theNewAccountID);
2851 
2852  OTLog::vError("ERROR generating outbox ledger in "
2853  "UserCommandProcessor::"
2854  "UserCmdIssueAssetType:\n%"
2855  "s\n",
2856  strNewAcctID.Get());
2857  }
2858  else {
2859  msgOut.m_bSuccess = true; // <==== SUCCESS!!
2860 
2861  // On the server side, each nym stores a list of its
2862  // asset accounts (IDs).
2863  //
2864  std::set<std::string>& theAccountSet =
2865  theNym.GetSetAssetAccounts();
2866  theAccountSet.insert(msgOut.m_strAcctID.Get());
2867 
2868  theNym.SaveSignedNymfile(server_->m_nymServer);
2869 
2870  // TODO fire off a separate process here to create
2871  // the mint.
2872  //
2873  // THE PROGRAM ALREADY EXISTS (CreateMint) and you
2874  // can RUN IT BY HAND FOR NOW.
2875  // But in actual production environment, we'll
2876  // trigger that executable here,
2877  // and within a few minutes, users will be able to
2878  // getMint successfully (and
2879  // thus withdraw cash.)
2880  }
2881  }
2882  else
2883  OTLog::Error(
2884  "Failure generating new issuer account in "
2885  "UserCommandProcessor::UserCmdIssueAssetType.\n");
2886  }
2887  else
2888  OTLog::Error(
2889  "Failure verifying asset contract in "
2890  "UserCommandProcessor::UserCmdIssueAssetType.\n");
2891  }
2892  else {
2893  OTString strAssetUserID(ASSET_USER_ID), strUserID;
2894  theNym.GetIdentifier(strUserID);
2895  OTLog::vError(
2896  "User ID on this user account (%s) does NOT match User ID "
2897  "for public key used in asset contract: %s\n",
2898  strUserID.Get(), strAssetUserID.Get());
2899  }
2900  }
2901  else
2902  OTLog::vError("%s: Failure loading asset contract from client.\n",
2903  __FUNCTION__);
2904  if (pAssetContract && !msgOut.m_bSuccess) // We only clean it up here,
2905  // if the Server didn't take
2906  // ownership of it.
2907  {
2908  delete pAssetContract;
2909  pAssetContract = nullptr;
2910  }
2911  }
2912 
2913  // Either way, we need to send the user's command back to him as well.
2914  {
2915  OTString tempInMessage(MsgIn);
2916  msgOut.m_ascInReferenceTo.SetString(tempInMessage);
2917  }
2918 
2919  // (2) Sign the Message
2920  msgOut.SignContract(server_->m_nymServer);
2921 
2922  // (3) Save the Message (with signatures and all, back to its internal
2923  // member m_strRawFile.)
2924  //
2925  // FYI, SaveContract takes m_xmlUnsigned and wraps it with the signatures
2926  // and ------- BEGIN bookends
2927  // If you don't pass a string in, then SaveContract saves the new version to
2928  // its member, m_strRawFile
2929  msgOut.SaveContract();
2930 
2931  // (You are in UserCmdIssueAssetType.)
2932 
2933  // *************************************************************
2934  // REPLY NOTICE TO NYMBOX
2935  //
2936  // Now that we signed / saved the reply message...
2937  //
2938  // After specific messages, we drop a notice with a copy of the server's
2939  // reply
2940  // into the Nymbox. This way we are GUARANTEED that the Nym will receive
2941  // and process
2942  // it. (And thus never get out of sync.)
2943  //
2944  if (msgOut.m_bSuccess) {
2945  const OTString strReplyMessage(msgOut);
2946  const int64_t lReqNum = atol(MsgIn.m_strRequestNum.Get());
2947  // If it fails, it logs already.
2948  DropReplyNoticeToNymbox(SERVER_ID, USER_ID, strReplyMessage, lReqNum,
2949  false, // trans success (not a transaction...)
2950  &theNym);
2951  }
2952 }
2953 
2956 void UserCommandProcessor::UserCmdIssueBasket(OTPseudonym& theNym,
2957  OTMessage& MsgIn,
2958  OTMessage& msgOut)
2959 {
2960  // (1) set up member variables
2961  msgOut.m_strCommand = "@issueBasket"; // reply to issueBasket
2962  msgOut.m_strNymID = MsgIn.m_strNymID; // UserID
2963  // msgOut.m_strServerID = m_strServerID; // This is already set in
2964  // ProcessUserCommand.
2965 
2966  // Either way, we need to send the user's command back to him as well.
2967  {
2968  OTString tempInMessage(MsgIn);
2969  msgOut.m_ascInReferenceTo.SetString(tempInMessage);
2970  }
2971 
2972  const OTIdentifier USER_ID(theNym), SERVER_ID(server_->m_strServerID),
2973  SERVER_USER_ID(server_->m_nymServer);
2974 
2975  OTString strBasket(MsgIn.m_ascPayload);
2976  Basket theBasket;
2977 
2978  if (!theBasket.LoadContractFromString(strBasket)) {
2979  OTLog::vError("%s: Failed trying to load basket from string.\n",
2980  __FUNCTION__);
2981  }
2982  else if (!theBasket.VerifySignature(theNym)) {
2983  OTLog::vError("%s: Failed verifying signature on basket.\n",
2984  __FUNCTION__);
2985  }
2986  else {
2987  // The basket ID should be the same on all servers.
2988  // The basket contract ID will be unique on each server.
2989  //
2990  // The contract ID of the basket is calculated based on the UNSIGNED
2991  // portion of the contract
2992  // (so it is unique on every server) and for the same reason with the
2993  // AccountID removed before calculating.
2994  OTIdentifier BASKET_ID, BASKET_ACCOUNT_ID, BASKET_CONTRACT_ID;
2995  theBasket.CalculateContractID(BASKET_ID);
2996 
2997  // Use BASKET_ID to look up the Basket account and see if it already
2998  // exists (the server keeps a list.)
2999  bool bFoundBasket = server_->transactor_.lookupBasketAccountID(
3000  BASKET_ID, BASKET_ACCOUNT_ID);
3001 
3002  if (bFoundBasket) {
3003  OTLog::vError("%s: Rejected: user tried to create basket currency "
3004  "that already exists.\n",
3005  __FUNCTION__);
3006  }
3007  else // Basket doesn't already exist -- so perhaps we can create it
3008  // then.
3009  {
3010  // Let's make sure that all the sub-currencies for this basket are
3011  // available on this server.
3012  // NOTE: this also prevents someone from using another basket as a
3013  // sub-currency UNLESS it already
3014  // exists on this server. (For example, they couldn't use a basket
3015  // contract from some other
3016  // server, since it wouldn't be issued here...) Also note that
3017  // issueAssetType explicitly prevents
3018  // baskets from being issued -- you HAVE to use issueBasket for
3019  // creating any basket currency.
3020  // Taken in tandem, this insures that the only possible way to have
3021  // a basket currency as a sub-currency
3022  // is if it's already issued on this server.
3023  //
3024  bool bSubCurrenciesAllExist = true;
3025 
3026  for (int32_t i = 0; i < theBasket.Count(); i++) {
3027  BasketItem* pItem = theBasket.At(i);
3028  OT_ASSERT(nullptr != pItem);
3029 
3030  if (nullptr ==
3031  server_->transactor_.getAssetContract(
3032  pItem->SUB_CONTRACT_ID)) // Sub-currency
3033  // not found.
3034  {
3035  const OTString strSubID(pItem->SUB_CONTRACT_ID);
3036  OTLog::vError("%s: Failed: Sub-currency for basket is not "
3037  "issued on this server: %s\n",
3038  __FUNCTION__, strSubID.Get());
3039  bSubCurrenciesAllExist = false;
3040  break;
3041  }
3042  }
3043  // By this point we know that the basket currency itself does NOT
3044  // already exist (good.)
3045  // We also know that all the subcurrencies DO already exist (good.)
3046  //
3047  if (bSubCurrenciesAllExist) {
3048  // GenerateNewAccount also expects the NymID to be stored in
3049  // m_strNymID.
3050  // Since we want the SERVER to be the user for basket accounts,
3051  // I'm setting it that
3052  // way in MsgIn so that GenerateNewAccount will create the
3053  // sub-account with the server
3054  // as the owner, instead of the user.
3055  SERVER_USER_ID.GetString(MsgIn.m_strNymID);
3056 
3057  // We need to actually create all the sub-accounts.
3058  // This loop also sets the Account ID onto the basket items
3059  // (which formerly was blank, from the client.)
3060  // This loop also adds the BASKET_ID and the NEW ACCOUNT ID to a
3061  // map on the server for later reference.
3062  for (int32_t i = 0; i < theBasket.Count(); i++) {
3063  BasketItem* pItem = theBasket.At(i);
3064  OT_ASSERT(nullptr != pItem);
3065 
3066  /*
3067  // Just make sure theMessage has these members populated:
3068  //
3069  // theMessage.m_strNymID;
3070  // theMessage.m_strAssetID;
3071  // theMessage.m_strServerID;
3072 
3073  // static method (call it without an instance, using
3074  notation: OTAccount::GenerateNewAccount)
3075  OTAccount * OTAccount::GenerateNewAccount( const
3076  OTIdentifier & theUserID, const OTIdentifier &
3077  theServerID,
3078  const OTPseudonym & theServerNym, const OTMessage &
3079  theMessage,
3080  const OTAccount::AccountType eAcctType=OTAccount::simple)
3081 
3082  // The above method uses this one internally...
3083  bool OTAccount::GenerateNewAccount(const OTPseudonym &
3084  theServer, const OTMessage & theMessage,
3085  const OTAccount::AccountType eAcctType=OTAccount::simple)
3086  */
3087 
3088  OTAccount* pNewAccount = nullptr;
3089 
3090  // GenerateNewAccount expects the Asset ID to be in MsgIn.
3091  // So we'll just put it there to make things easy...
3092  //
3093  pItem->SUB_CONTRACT_ID.GetString(MsgIn.m_strAssetID);
3094 
3095  pNewAccount = OTAccount::GenerateNewAccount(
3096  SERVER_USER_ID, SERVER_ID, server_->m_nymServer, MsgIn,
3098 
3099  // If we successfully create the account, then bundle it
3100  // in the message XML payload
3101  //
3102  if (nullptr != pNewAccount) {
3103  msgOut.m_bSuccess = true;
3104 
3105  // Now the item finally has its account ID. Let's grab
3106  // it.
3107  pNewAccount->GetIdentifier(pItem->SUB_ACCOUNT_ID);
3108 
3109  delete pNewAccount;
3110  pNewAccount = nullptr;
3111  }
3112  else {
3113  OTLog::vError("%s: Failed while calling: "
3114  "OTAccount::GenerateNewAccount(SERVER_"
3115  "USER_ID, SERVER_ID, m_nymServer, "
3116  "MsgIn, OTAccount::basketsub)\n",
3117  __FUNCTION__);
3118  msgOut.m_bSuccess = false;
3119  break;
3120  }
3121  } // for
3122 
3123  if (true == msgOut.m_bSuccess) {
3124  // Generate a new OTAssetContract -- the ID will be a hash
3125  // of THAT contract, which includes theBasket as well as
3126  // the server's public key as part of its contents.
3127  // Therefore, the actual Asset Type ID of the basket
3128  // currency
3129  // will be different from server to server.
3130  //
3131  // BUT!! Because we can also generate a hash of
3132  // theBasket.m_xmlUnsigned (which is what
3133  // Basket::CalculateContractID
3134  // does) then we have a way of obtaining a number that will
3135  // be the same from server to server, for cross-server
3136  // transfers of basket assets.
3137  //
3138  // The way it will work is, when the cross-server transfer
3139  // request is generated, the server will check the asset
3140  // contract
3141  // for the "from" account and see if it is for a basket
3142  // currency. If it is, there will be a function on the
3143  // contract
3144  // that returns the Basket ID, which can be included in the
3145  // message to the target server, which uses the ID to look
3146  // for its own basket issuer account for the same basket
3147  // asset type. This allows the target server to translate
3148  // the
3149  // Asset Type ID to its own corresponding ID for the same
3150  // basket.
3151  theBasket.ReleaseSignatures();
3152  theBasket.SignContract(server_->m_nymServer);
3153  theBasket.SaveContract();
3154 
3155  // The basket does not yet exist on this server. Create a
3156  // new Asset Contract to support it...
3157 
3158  // Put the Server's Public Key into the "contract" key field
3159  // of the new Asset Contract...
3160  // This adds a "contract" key to the asset contract (the
3161  // server's public key)
3162  // Asset Contracts are verified by a key found internal to
3163  // the contract, so it's
3164  // necessary to put the key in there so it will verify
3165  // later.
3166  // This also updates the m_xmlUnsigned contents, signs the
3167  // contract, saves it,
3168  // and calculates the new ID.
3169  OTAssetContract* pBasketContract =
3170  new BasketContract(theBasket, server_->m_nymServer);
3171 
3172  // Grab the new asset ID for the new basket currency
3173  pBasketContract->GetIdentifier(BASKET_CONTRACT_ID);
3174  OTString STR_BASKET_CONTRACT_ID(BASKET_CONTRACT_ID);
3175 
3176  // set the new Asset Type ID, aka ContractID, onto the
3177  // outgoing message.
3178  msgOut.m_strAssetID = STR_BASKET_CONTRACT_ID;
3179 
3180  // Save the new Asset Contract to disk
3181  const OTString strFoldername(OTFolders::Contract().Get()),
3182  strFilename(STR_BASKET_CONTRACT_ID.Get());
3183 
3184  // Save the new basket contract to the contracts folder
3185  // (So the users can use it the same as they would use any
3186  // other contract.)
3187  pBasketContract->SaveContract(strFoldername.Get(),
3188  strFilename.Get());
3189 
3190  server_->transactor_.addAssetContract(*pBasketContract);
3191  // I don't save this here. Instead, I wait for
3192  // AddBasketAccountID and then I call SaveMainFile after
3193  // that. See below.
3194  // TODO need better code for reverting when something screws
3195  // up halfway through a change.
3196  // If I add this contract, it's not enough to just "not
3197  // save" the file. I actually need to re-load the file
3198  // in order to TRULY "make sure" this won't screw something
3199  // up on down the line.
3200 
3201  // Once the new Asset Type is generated, from which the
3202  // BasketID can be requested at will, next we need to create
3203  // the issuer account for that new Asset Type. (We have the
3204  // asset type ID and the contract file. Now let's create
3205  // the issuer account the same as we would for any normal
3206  // issuer account.)
3207  //
3208  // The issuer account is special compared to a normal issuer
3209  // account, because within its walls, it must store an
3210  // OTAccount for EACH sub-contract, in order to store the
3211  // reserves. That's what makes the basket work.
3212 
3213  OTAccount* pBasketAccount = nullptr;
3214 
3215  // GenerateNewAccount expects the Asset ID to be in MsgIn.
3216  // So we'll just put it there to make things easy...
3217  MsgIn.m_strAssetID = STR_BASKET_CONTRACT_ID;
3218 
3219  pBasketAccount = OTAccount::GenerateNewAccount(
3220  SERVER_USER_ID, SERVER_ID, server_->m_nymServer, MsgIn,
3222 
3223  if (nullptr != pBasketAccount) {
3224  msgOut.m_bSuccess = true;
3225 
3226  pBasketAccount->GetIdentifier(
3227  msgOut.m_strAcctID); // string
3228  pBasketAccount->GetAssetTypeID().GetString(
3229  msgOut.m_strAssetID);
3230 
3231  pBasketAccount->GetIdentifier(BASKET_ACCOUNT_ID); // id
3232 
3233  // So the server can later use the BASKET_ID (which is
3234  // universal)
3235  // to lookup the account ID on this server corresponding
3236  // to that basket.
3237  // (The account ID will be different from server to
3238  // server, thus the need
3239  // to be able to look it up via the basket ID.)
3240  server_->transactor_.addBasketAccountID(
3241  BASKET_ID, BASKET_ACCOUNT_ID, BASKET_CONTRACT_ID);
3242 
3243  server_->mainFile_.SaveMainFile(); // So the main xml
3244  // file loads
3245  // this
3246  // basket info next time we run.
3247 
3248  delete pBasketAccount;
3249  pBasketAccount = nullptr;
3250  }
3251  else {
3252  msgOut.m_bSuccess = false;
3253  }
3254 
3255  } // if true == msgOut.m_bSuccess
3256  } // Subcurrencies all do exist.
3257  } // basket doesn't already exist (creating it)
3258  }
3259 
3260  // (2) Sign the Message
3261  msgOut.SignContract(server_->m_nymServer);
3262 
3263  // (3) Save the Message (with signatures and all, back to its internal
3264  // member m_strRawFile.)
3265  //
3266  // FYI, SaveContract takes m_xmlUnsigned and wraps it with the signatures
3267  // and ------- BEGIN bookends
3268  // If you don't pass a string in, then SaveContract saves the new version to
3269  // its member, m_strRawFile
3270  msgOut.SaveContract();
3271 }
3272 
3274 void UserCommandProcessor::UserCmdCreateAccount(OTPseudonym& theNym,
3275  OTMessage& MsgIn,
3276  OTMessage& msgOut)
3277 {
3278  // (1) set up member variables
3279  msgOut.m_strCommand = "@createAccount"; // reply to createAccount
3280  msgOut.m_strNymID = MsgIn.m_strNymID; // UserID
3281  // msgOut.m_strServerID = m_strServerID; // This is already set in
3282  // ProcessUserCommand.
3283 
3284  // Either way, we need to send the user's command back to him as well.
3285  OTString tempInMessage(MsgIn);
3286  msgOut.m_ascInReferenceTo.SetString(tempInMessage);
3287 
3288  const OTIdentifier USER_ID(theNym), SERVER_ID(server_->m_strServerID);
3289 
3290  std::unique_ptr<OTAccount> pNewAccount(OTAccount::GenerateNewAccount(
3291  USER_ID, SERVER_ID, server_->m_nymServer, MsgIn));
3292 
3293  // If we successfully create the account, then bundle it in the message XML
3294  // payload
3295  if (nullptr != pNewAccount) {
3296  const char* szFunc = "UserCommandProcessor::UserCmdCreateAccount";
3297  OTAssetContract* pContract = server_->transactor_.getAssetContract(
3298  pNewAccount->GetAssetTypeID());
3299 
3300  if (nullptr == pContract) {
3301  const OTString strAssetID(pNewAccount->GetAssetTypeID());
3302  OTLog::vError(
3303  "%s: Error: Unable to get AssetContract for asset type: %s\n",
3304  szFunc, strAssetID.Get());
3305  }
3306  else if (pContract->IsShares()) {
3307  // The asset type keeps a list of all accounts for that type.
3308  // (For shares, not for currencies.)
3309  //
3310  const bool bAdded = pContract->AddAccountRecord(*pNewAccount);
3311  if (!bAdded) {
3312  const OTString strAssetID(pNewAccount->GetAssetTypeID());
3313  OTLog::vError(
3314  "%s: ERROR Adding Account Record: %s ... Aborting.\n",
3315  __FUNCTION__, strAssetID.Get());
3316  return; // error
3317  }
3318  }
3319  OTIdentifier theNewAccountID;
3320  pNewAccount->GetIdentifier(theNewAccountID);
3321 
3322  // OTLog::Error("DEBUG: GenerateNewAccount successfully returned
3323  // account pointer. Contents:\n%s\n", tempPayload.Get());
3324 
3325  OTLedger theOutbox(USER_ID, theNewAccountID, SERVER_ID),
3326  theInbox(USER_ID, theNewAccountID, SERVER_ID);
3327 
3328  bool bSuccessLoadingInbox = theInbox.LoadInbox();
3329  bool bSuccessLoadingOutbox = theOutbox.LoadOutbox();
3330 
3331  // ...or generate them otherwise...
3332 
3333  if (true == bSuccessLoadingInbox) // WEIRD IF THIS HAPPENED...
3334  bSuccessLoadingInbox = theInbox.VerifyAccount(
3335  server_->m_nymServer); // todo -- this should NEVER happen, the
3336  // ID was
3337  // just RANDOMLY generated, so HOW did the inbox
3338  // already exist???
3339  else {
3340  bSuccessLoadingInbox = theInbox.GenerateLedger(
3341  theNewAccountID, SERVER_ID, OTLedger::inbox,
3342  true); // bGenerateFile=true
3343 
3344  if (bSuccessLoadingInbox) {
3345  bSuccessLoadingInbox =
3346  theInbox.SignContract(server_->m_nymServer);
3347 
3348  if (bSuccessLoadingInbox) {
3349  bSuccessLoadingInbox = theInbox.SaveContract();
3350 
3351  if (bSuccessLoadingInbox)
3352  bSuccessLoadingInbox = pNewAccount->SaveInbox(theInbox);
3353  }
3354  }
3355  }
3356 
3357  if (true == bSuccessLoadingOutbox) // WEIRD IF THIS HAPPENED....
3358  bSuccessLoadingOutbox = theOutbox.VerifyAccount(
3359  server_->m_nymServer); // todo -- this should NEVER happen, the
3360  // ID was
3361  // just RANDOMLY generated, so HOW did the outbox
3362  // already exist???
3363  else {
3364  bSuccessLoadingOutbox = theOutbox.GenerateLedger(
3365  theNewAccountID, SERVER_ID, OTLedger::outbox,
3366  true); // bGenerateFile=true
3367 
3368  if (bSuccessLoadingOutbox) {
3369  bSuccessLoadingOutbox =
3370  theOutbox.SignContract(server_->m_nymServer);
3371 
3372  if (bSuccessLoadingOutbox) {
3373  bSuccessLoadingOutbox = theOutbox.SaveContract();
3374 
3375  if (bSuccessLoadingOutbox)
3376  bSuccessLoadingOutbox =
3377  pNewAccount->SaveOutbox(theOutbox);
3378  }
3379  }
3380  }
3381 
3382  if (!bSuccessLoadingInbox) {
3383  const OTString strNewAcctID(theNewAccountID);
3384 
3385  OTLog::vError("%s: ERROR generating inbox ledger: %s\n", szFunc,
3386  strNewAcctID.Get());
3387  }
3388  else if (!bSuccessLoadingOutbox) {
3389  const OTString strNewAcctID(theNewAccountID);
3390 
3391  OTLog::vError("%s: ERROR generating outbox ledger: %s\n", szFunc,
3392  strNewAcctID.Get());
3393  }
3394  else {
3395  msgOut.m_bSuccess = true; // <==== SUCCESS!!
3396 
3397  pNewAccount->GetIdentifier(msgOut.m_strAcctID);
3398 
3399  // On the server side, each nym stores a list of its asset accounts
3400  // (IDs).
3401  //
3402  std::set<std::string>& theAccountSet = theNym.GetSetAssetAccounts();
3403  theAccountSet.insert(msgOut.m_strAcctID.Get());
3404 
3405  theNym.SaveSignedNymfile(server_->m_nymServer);
3406 
3407  OTString tempPayload(*pNewAccount);
3408  msgOut.m_ascPayload.SetString(tempPayload);
3409  }
3410  }
3411 
3412  // (2) Sign the Message
3413  msgOut.SignContract(server_->m_nymServer);
3414 
3415  // (3) Save the Message (with signatures and all, back to its internal
3416  // member m_strRawFile.)
3417  //
3418  // FYI, SaveContract takes m_xmlUnsigned and wraps it with the signatures
3419  // and ------- BEGIN bookends
3420  // If you don't pass a string in, then SaveContract saves the new version to
3421  // its member, m_strRawFile
3422  msgOut.SaveContract();
3423 
3424  // (You are in UserCmdCreateAcct.)
3425 
3426  // *************************************************************
3427  // REPLY NOTICE TO NYMBOX
3428  //
3429  // Now that we signed / saved the reply message...
3430  //
3431  // After specific messages, we drop a notice with a copy of the server's
3432  // reply
3433  // into the Nymbox. This way we are GUARANTEED that the Nym will receive
3434  // and process
3435  // it. (And thus never get out of sync.)
3436  //
3437  if (msgOut.m_bSuccess) {
3438  const OTString strReplyMessage(msgOut);
3439  const int64_t lReqNum = atol(MsgIn.m_strRequestNum.Get());
3440 
3441  // If it fails, it logs already.
3442  DropReplyNoticeToNymbox(
3443  SERVER_ID, USER_ID, strReplyMessage,
3444  lReqNum, // No need to update the NymboxHash in this case.
3445  false); // trans success (not a transaction)
3446  // DropReplyNoticeToNymbox(SERVER_ID, USER_ID,
3447  // strReplyMessage, lReqNum, &theNym);
3448  }
3449 }
3450 
3451 // Deprecated (replaced by UserCmdGetAccountFiles)
3452 void UserCommandProcessor::UserCmdGetAccount(OTPseudonym&, OTMessage& MsgIn,
3453  OTMessage& msgOut)
3454 {
3455  // (1) set up member variables
3456  msgOut.m_strCommand = "@getAccount"; // reply to getAccount
3457  msgOut.m_strNymID = MsgIn.m_strNymID; // UserID
3458  // msgOut.m_strServerID = m_strServerID; // This is already set in
3459  // ProcessUserCommand.
3460  msgOut.m_strAcctID = MsgIn.m_strAcctID; // The Account ID in question
3461 
3462  const OTIdentifier USER_ID(MsgIn.m_strNymID), ACCOUNT_ID(MsgIn.m_strAcctID),
3463  SERVER_ID(MsgIn.m_strServerID);
3464 
3465  OTAccount* pAccount = OTAccount::LoadExistingAccount(ACCOUNT_ID, SERVER_ID);
3466  bool bSuccessLoadingAccount = ((pAccount != nullptr) ? true : false);
3467 
3468  // Yup the account exists. Yup it has the same user ID.
3469  if (bSuccessLoadingAccount && (pAccount->GetUserID() == USER_ID)) {
3470  msgOut.m_bSuccess = true;
3471  // extract the account in ascii-armored form on the outgoing message
3472  OTString strPayload(
3473  *pAccount); // first grab it in plaintext string form
3474  msgOut.m_ascPayload.SetString(strPayload); // now the outgoing message
3475  // has the account in its
3476  // payload in base64 form.
3477  }
3478  // Send the user's command back to him if failure.
3479  else {
3480  msgOut.m_bSuccess = false;
3481  OTString tempInMessage(
3482  MsgIn); // Grab the incoming message in plaintext form
3483  msgOut.m_ascInReferenceTo.SetString(tempInMessage); // Set it into the
3484  // base64-encoded
3485  // object on the
3486  // outgoing message
3487  }
3488 
3489  // (2) Sign the Message
3490  msgOut.SignContract((const OTPseudonym&)server_->m_nymServer);
3491 
3492  // (3) Save the Message (with signatures and all, back to its internal
3493  // member m_strRawFile.)
3494  //
3495  // FYI, SaveContract takes m_xmlUnsigned and wraps it with the signatures
3496  // and ------- BEGIN bookends
3497  // If you don't pass a string in, then SaveContract saves the new version to
3498  // its member, m_strRawFile
3499  msgOut.SaveContract();
3500 }
3501 
3502 void UserCommandProcessor::UserCmdGetAccountFiles(OTPseudonym&,
3503  OTMessage& MsgIn,
3504  OTMessage& msgOut)
3505 {
3506  // (1) set up member variables
3507  msgOut.m_strCommand = "@getAccountFiles"; // reply to getAccountFiles
3508  msgOut.m_strNymID = MsgIn.m_strNymID; // UserID
3509  // msgOut.m_strServerID = m_strServerID; // This is already set
3510  // in ProcessUserCommand.
3511  msgOut.m_strAcctID = MsgIn.m_strAcctID; // The Account ID in question
3512 
3513  const OTIdentifier USER_ID(MsgIn.m_strNymID), ACCOUNT_ID(MsgIn.m_strAcctID),
3514  SERVER_ID(MsgIn.m_strServerID);
3515 
3516  OTString strAccount, strInbox, strOutbox, strInboxHash, strOutboxHash;
3517  OTAccount* pAccount = OTAccount::LoadExistingAccount(ACCOUNT_ID, SERVER_ID);
3518  bool bSuccessLoadingAccount = ((pAccount != nullptr) ? true : false);
3519  bool bSuccessLoadingInbox = false;
3520  bool bSuccessLoadingOutbox = false;
3521  if (bSuccessLoadingAccount)
3522  bSuccessLoadingAccount = (pAccount->GetUserID() == USER_ID);
3523  // Yup the account exists. Yup it has the same user ID.
3524  if (bSuccessLoadingAccount) {
3525  // extract the account in ascii-armored form on the outgoing message
3526  pAccount->SaveContractRaw(
3527  strAccount); // first grab it in plaintext string form
3528 
3529  // Get the Inbox.
3530  //
3531  {
3532  OTLedger theInbox(USER_ID, ACCOUNT_ID, SERVER_ID);
3533 
3534  bSuccessLoadingInbox = theInbox.LoadInbox();
3535 
3536  if (!bSuccessLoadingInbox)
3537  OTLog::vError("%s: Failed trying to load Inbox from storage.\n",
3538  __FUNCTION__);
3539  else {
3540  // We do NOT call VerifyAccount in this function (because we
3541  // don't need to) and thus we do NOT
3542  // force the box receipts to be loaded here (which happens
3543  // inside that call.) But we DO verify
3544  // the IDs and the Signature, of course.
3545  //
3546  bSuccessLoadingInbox =
3547  (theInbox.VerifyContractID() &&
3548  theInbox.VerifySignature(server_->m_nymServer));
3549 
3550  // If we loaded old data in this file... (when whole receipts
3551  // used to be stored in boxes.)
3552  //
3553  if (bSuccessLoadingInbox &&
3554  theInbox.LoadedLegacyData()) // (which automatically saves
3555  // the box receipt as the old
3556  // data is loaded...)
3557  {
3558  // bSuccessLoadingInbox =
3559  // theInbox.VerifyAccount(server_->m_nymServer); // Then
3560  // Verify,
3561  // which forces a LoadBoxReceipts... (
3562 
3563  theInbox.ReleaseSignatures(); // UPDATE: We do NOT force the
3564  // loading here, since they
3565  // aren't needed.
3566  theInbox.SignContract(
3567  server_->m_nymServer); // Waste of resources.
3568  // Instead, we recognize
3569  // that it was old data,
3570  // and so
3571  theInbox.SaveContract(); // we gracefully re-save in the new
3572  // format, so it won't repeatedly
3573  // be
3574  theInbox.SaveInbox(); // loaded over and over again in the
3575  // large filesize.
3576  }
3577 
3578  if (!bSuccessLoadingInbox)
3579  OTLog::vError(
3580  "%s: Verification failed on Inbox after loading.\n",
3581  __FUNCTION__);
3582  }
3583  if (bSuccessLoadingInbox) {
3584  theInbox.SaveContractRaw(strInbox);
3585 
3586  OTIdentifier theHash;
3587  if (theInbox.CalculateInboxHash(theHash))
3588  theHash.GetString(strInboxHash);
3589  }
3590  }
3591  // Now get the OUTBOX.
3592  //
3593  if (bSuccessLoadingInbox) // (Which we don't bother to do unless the
3594  // inbox was already successful.)
3595  {
3596  OTLedger theOutbox(USER_ID, ACCOUNT_ID, SERVER_ID);
3597 
3598  bSuccessLoadingOutbox = theOutbox.LoadOutbox();
3599 
3600  if (!bSuccessLoadingOutbox)
3601  OTLog::vError(
3602  "%s: Failed trying to load Outbox from storage.\n",
3603  __FUNCTION__);
3604  else {
3605  // We do NOT call VerifyAccount in this function (because we
3606  // don't need to) and thus we do NOT
3607  // force the box receipts to be loaded here (which happens
3608  // inside that call.) But we DO verify
3609  // the IDs and the Signature, of course.
3610  //
3611  bSuccessLoadingOutbox =
3612  (theOutbox.VerifyContractID() &&
3613  theOutbox.VerifySignature(server_->m_nymServer));
3614 
3615  // If we loaded old data in this file... (when whole receipts
3616  // used to be stored in boxes.)
3617  //
3618  if (bSuccessLoadingOutbox &&
3619  theOutbox.LoadedLegacyData()) // (which automatically saves
3620  // the box receipt as the old
3621  // data is loaded...)
3622  {
3623  // bSuccessLoadingOutbox =
3624  // theOutbox.VerifyAccount(server_->m_nymServer); // Then
3625  // Verify,
3626  // which forces a LoadBoxReceipts... (
3627 
3628  theOutbox.ReleaseSignatures(); // UPDATE: We do NOT force
3629  // the loading here, since
3630  // they aren't needed.
3631  theOutbox.SignContract(
3632  server_->m_nymServer); // Waste of resources.
3633  // Instead, we
3634  // recognize that it
3635  // was old data, and so
3636  theOutbox.SaveContract(); // we gracefully re-save in the
3637  // new format, so it won't
3638  // repeatedly be
3639  theOutbox.SaveOutbox(); // loaded over and over again in the
3640  // large filesize.
3641  }
3642 
3643  if (!bSuccessLoadingOutbox)
3644  OTLog::vError(
3645  "%s: Verification Failed on Outbox after loading.\n",
3646  __FUNCTION__);
3647  }
3648  if (bSuccessLoadingOutbox) {
3649  theOutbox.SaveContractRaw(strOutbox);
3650 
3651  OTIdentifier theHash;
3652  if (theOutbox.CalculateOutboxHash(theHash))
3653  theHash.GetString(strOutboxHash);
3654  }
3655  }
3656  }
3657  // TODO optimize: Really only !SuccessLoadingOutbox is needed here.
3658  // If it is false, then the others are definitely false as well.
3659  //
3660  if (!bSuccessLoadingOutbox || !bSuccessLoadingInbox ||
3661  !bSuccessLoadingAccount) {
3662  // FAILURE: (Send the user's command back to him.)
3663  //
3664  msgOut.m_bSuccess = false;
3665  OTString tempInMessage(
3666  MsgIn); // Grab the incoming message in plaintext form
3667  msgOut.m_ascInReferenceTo.SetString(tempInMessage); // Set it into the
3668  // base64-encoded
3669  // object on the
3670  // outgoing message
3671  }
3672  else // SUCCESS.
3673  {
3674  // Create an OTDB::StringMap object.
3675  // (To return the three files in.)
3676 
3677  // this asserts already, on failure.
3678  std::unique_ptr<OTDB::Storable> pStorable(
3680  OTDB::StringMap* pMap = dynamic_cast<OTDB::StringMap*>(pStorable.get());
3681  // It exists.
3682  //
3683  if (nullptr == pMap)
3684  OTLog::vError(
3685  "%s: Error: failed trying to create a STORED_OBJ_STRING_MAP.\n",
3686  __FUNCTION__);
3687  else {
3688  auto& theMap = pMap->the_map;
3689  theMap.insert(std::pair<std::string, std::string>(
3690  "account", strAccount.Get()));
3691  theMap.insert(
3692  std::pair<std::string, std::string>("inbox", strInbox.Get()));
3693  theMap.insert(
3694  std::pair<std::string, std::string>("outbox", strOutbox.Get()));
3695  // Serialize the StringMap to a string...
3696  //
3697  std::string str_Encoded = OTDB::EncodeObject(*pMap);
3698  const bool bSuccessEncoding = (str_Encoded.size() > 0);
3699 
3700  if (!bSuccessEncoding)
3701  OTLog::vError("%s: Error: failed trying to encode a "
3702  "STORED_OBJ_STRING_MAP.\n",
3703  __FUNCTION__);
3704  else {
3705  msgOut.m_ascPayload.Set(str_Encoded.c_str()); // <============
3706  msgOut.m_strInboxHash = strInboxHash;
3707  msgOut.m_strOutboxHash = strOutboxHash;
3708  msgOut.m_bSuccess = true;
3709  }
3710  }
3711  }
3712  // (2) Sign the Message
3713  msgOut.SignContract((const OTPseudonym&)server_->m_nymServer);
3714 
3715  // (3) Save the Message (with signatures and all, back to its internal
3716  // member m_strRawFile.)
3717  //
3718  // FYI, SaveContract takes m_xmlUnsigned and wraps it with the signatures
3719  // and ------- BEGIN bookends
3720  // If you don't pass a string in, then SaveContract saves the new version to
3721  // its member, m_strRawFile
3722  msgOut.SaveContract();
3723 }
3724 
3725 // Deprecated (replaced by UserCmdGetAccountFiles)
3726 void UserCommandProcessor::UserCmdGetInbox(OTPseudonym&, OTMessage& MsgIn,
3727  OTMessage& msgOut)
3728 {
3729  // (1) set up member variables
3730  msgOut.m_strCommand = "@getInbox"; // reply to getInbox
3731  msgOut.m_strNymID = MsgIn.m_strNymID; // UserID
3732  // msgOut.m_strServerID = m_strServerID; // This is already set
3733  // in ProcessUserCommand.
3734  msgOut.m_strAcctID = MsgIn.m_strAcctID; // The Account ID in question
3735 
3736  const OTIdentifier USER_ID(MsgIn.m_strNymID), ACCOUNT_ID(MsgIn.m_strAcctID),
3737  SERVER_ID(MsgIn.m_strServerID);
3738 
3739  OTLedger theLedger(USER_ID, ACCOUNT_ID, SERVER_ID);
3740 
3741  msgOut.m_bSuccess = theLedger.LoadInbox();
3742 
3743  if (!msgOut.m_bSuccess)
3744  OTLog::vError("%s: Failed trying to load Inbox from storage.\n",
3745  __FUNCTION__);
3746  else {
3747  // We do NOT call VerifyAccount in this function (because we don't need
3748  // to) and thus we do NOT
3749  // force the box receipts to be loaded here (which happens inside that
3750  // call.) But we DO verify
3751  // the IDs and the Signature, of course.
3752  //
3753  msgOut.m_bSuccess = (theLedger.VerifyContractID() &&
3754  theLedger.VerifySignature(server_->m_nymServer));
3755 
3756  // If we loaded old data in this file... (when whole receipts were
3757  // stored in boxes.)
3758  //
3759  if (msgOut.m_bSuccess &&
3760  theLedger.LoadedLegacyData()) // (which automatically saves the box
3761  // receipt as the old data is
3762  // loaded...)
3763  {
3764  // msgOut.m_bSuccess =
3765  // theLedger.VerifyAccount(server_->m_nymServer); // Then Verify,
3766  // which
3767  // forces a LoadBoxReceipts... (
3768 
3769  theLedger.ReleaseSignatures(); // UPDATE: We do NOT force the
3770  // loading here, since they aren't
3771  // needed.
3772  theLedger.SignContract(
3773  server_->m_nymServer); // Waste of resources. Instead,
3774  // we recognize that it was old
3775  // data, and so
3776  theLedger.SaveContract(); // we gracefully re-save in the new
3777  // format, so it won't repeatedly be
3778  theLedger.SaveInbox(); // loaded over and over again in the large
3779  // filesize.
3780  }
3781 
3782  if (!msgOut.m_bSuccess)
3783  OTLog::vError("%s: Verification failed on Inbox after loading.\n",
3784  __FUNCTION__);
3785  }
3786 
3787  if (msgOut.m_bSuccess) {
3788  // extract the ledger in ascii-armored form on the outgoing message
3789  OTString strPayload(
3790  theLedger); // first grab it in plaintext string form
3791  msgOut.m_ascPayload.SetString(strPayload); // now the outgoing message
3792  // has the inbox ledger in
3793  // its payload in base64
3794  // form.
3795 
3796  OTIdentifier theHash;
3797  if (theLedger.CalculateInboxHash(theHash))
3798  theHash.GetString(msgOut.m_strInboxHash);
3799  }
3800  // Send the user's command back to him if failure.
3801  else {
3802  OTString tempInMessage(
3803  MsgIn); // Grab the incoming message in plaintext form
3804  msgOut.m_ascInReferenceTo.SetString(tempInMessage); // Set it into the
3805  // base64-encoded
3806  // object on the
3807  // outgoing message
3808  }
3809 
3810  // (2) Sign the Message
3811  msgOut.SignContract(
3812  (const OTPseudonym&)server_->m_nymServer); // todo const cast
3813 
3814  // (3) Save the Message (with signatures and all, back to its internal
3815  // member m_strRawFile.)
3816  //
3817  // FYI, SaveContract takes m_xmlUnsigned and wraps it with the signatures
3818  // and ------- BEGIN bookends
3819  // If you don't pass a string in, then SaveContract saves the new version to
3820  // its member, m_strRawFile
3821  msgOut.SaveContract();
3822 }
3823 
3824 // Deprecated (replaced by UserCmdGetAccountFiles)
3825 void UserCommandProcessor::UserCmdGetOutbox(OTPseudonym&, OTMessage& MsgIn,
3826  OTMessage& msgOut)
3827 {
3828  // (1) set up member variables
3829  msgOut.m_strCommand = "@getOutbox"; // reply to getOutbox
3830  msgOut.m_strNymID = MsgIn.m_strNymID; // UserID
3831  // msgOut.m_strServerID = m_strServerID; // This is already set
3832  // in ProcessUserCommand.
3833  msgOut.m_strAcctID = MsgIn.m_strAcctID; // The Account ID in question
3834 
3835  const OTIdentifier USER_ID(MsgIn.m_strNymID), ACCOUNT_ID(MsgIn.m_strAcctID),
3836  SERVER_ID(MsgIn.m_strServerID);
3837 
3838  OTLedger theLedger(USER_ID, ACCOUNT_ID, SERVER_ID);
3839 
3840  msgOut.m_bSuccess = theLedger.LoadOutbox();
3841 
3842  if (!msgOut.m_bSuccess)
3843  OTLog::vError("%s: Failed trying to load Outbox from storage.\n",
3844  __FUNCTION__);
3845  else {
3846  // We do NOT call VerifyAccount in this function (because we don't need
3847  // to) and thus we do NOT
3848  // force the box receipts to be loaded here (which happens inside that
3849  // call.) But we DO verify
3850  // the IDs and the Signature, of course.
3851  //
3852  msgOut.m_bSuccess = (theLedger.VerifyContractID() &&
3853  theLedger.VerifySignature(server_->m_nymServer));
3854 
3855  // If we loaded old data in this file... (when whole receipts were
3856  // stored in boxes.)
3857  //
3858  if (msgOut.m_bSuccess &&
3859  theLedger.LoadedLegacyData()) // (which automatically saves the box
3860  // receipt as the old data is
3861  // loaded...)
3862  {
3863  // msgOut.m_bSuccess =
3864  // theLedger.VerifyAccount(server_->m_nymServer); // Then Verify,
3865  // which
3866  // forces a LoadBoxReceipts... (
3867 
3868  theLedger.ReleaseSignatures(); // UPDATE: We do NOT force the
3869  // loading here, since they aren't
3870  // needed.
3871  theLedger.SignContract(
3872  server_->m_nymServer); // Waste of resources. Instead,
3873  // we recognize that it was old
3874  // data, and so
3875  theLedger.SaveContract(); // we gracefully re-save in the new
3876  // format, so it won't repeatedly be
3877  theLedger.SaveOutbox(); // loaded over and over again in the large
3878  // filesize.
3879  }
3880 
3881  if (!msgOut.m_bSuccess)
3882  OTLog::vError("%s: Verification Failed on Outbox after loading.\n",
3883  __FUNCTION__);
3884  }
3885 
3886  if (msgOut.m_bSuccess) {
3887  // extract the ledger in ascii-armored form on the outgoing message
3888  OTString strPayload(
3889  theLedger); // first grab it in plaintext string form
3890  msgOut.m_ascPayload.SetString(strPayload); // now the outgoing message
3891  // has the outbox ledger in
3892  // its payload in base64
3893  // form.
3894 
3895  OTIdentifier theHash;
3896  if (theLedger.CalculateOutboxHash(theHash))
3897  theHash.GetString(msgOut.m_strOutboxHash);
3898  }
3899  // Send the user's command back to him if failure.
3900  else {
3901  OTString tempInMessage(
3902  MsgIn); // Grab the incoming message in plaintext form
3903  msgOut.m_ascInReferenceTo.SetString(tempInMessage); // Set it into the
3904  // base64-encoded
3905  // object on the
3906  // outgoing message
3907  }
3908 
3909  // (2) Sign the Message
3910  msgOut.SignContract((const OTPseudonym&)server_->m_nymServer);
3911 
3912  // (3) Save the Message (with signatures and all, back to its internal
3913  // member m_strRawFile.)
3914  //
3915  // FYI, SaveContract takes m_xmlUnsigned and wraps it with the signatures
3916  // and ------- BEGIN bookends
3917  // If you don't pass a string in, then SaveContract saves the new version to
3918  // its member, m_strRawFile
3919  msgOut.SaveContract();
3920 }
3921 
3922 void UserCommandProcessor::UserCmdQueryAssetTypes(OTPseudonym&,
3923  OTMessage& MsgIn,
3924  OTMessage& msgOut)
3925 {
3926  // (1) set up member variables
3927  msgOut.m_strCommand = "@queryAssetTypes"; // reply to queryAssetTypes
3928  msgOut.m_strNymID = MsgIn.m_strNymID; // UserID
3929  // msgOut.m_strServerID = m_strServerID; // This is already set in
3930  // ProcessUserCommand.
3931  msgOut.m_bSuccess = false; // so far.
3932 
3933  // Send the user's command back to him whether success or failure.
3934  OTString tempInMessage(
3935  MsgIn); // Grab the incoming message in plaintext form
3936  msgOut.m_ascInReferenceTo.SetString(tempInMessage); // Set it into the
3937  // base64-encoded object
3938  // on the outgoing
3939  // message
3940 
3941  if (MsgIn.m_ascPayload.Exists()) // (which it should)
3942  {
3943  std::unique_ptr<OTDB::Storable> pStorable(OTDB::DecodeObject(
3944  OTDB::STORED_OBJ_STRING_MAP, MsgIn.m_ascPayload.Get()));
3945  OTDB::StringMap* pMap = dynamic_cast<OTDB::StringMap*>(pStorable.get());
3946 
3947  if (nullptr != pMap) // There was definitely a StringMap in the payload.
3948  {
3949  msgOut.m_bSuccess = true;
3950 
3951  std::map<std::string, std::string>& theMap = pMap->the_map;
3952  std::map<std::string, std::string> theNewMap;
3953 
3954  for (auto& it : theMap) {
3955  const std::string& str1 =
3956  it.first; // Containing the asset type ID.
3957  const std::string& str2 =
3958  it.second; // Containing the phrase "exists". (More are
3959  // possible in the future.)
3960 
3961  // todo security: limit on length of this map? (sent through
3962  // user message...)
3963 
3964  // "exists" means, "Here's an asset ID. Please tell me
3965  // whether or not it's actually issued on this server."
3966  // Future options might include "issue", "audit", "contract",
3967  // etc.
3968  //
3969  if ((str1.size() > 0) &&
3970  (str2.compare("exists") == 0)) // todo hardcoding
3971  {
3972  const OTIdentifier theAssetID(str1.c_str());
3973  OTAssetContract* pAssetContract =
3974  server_->transactor_.getAssetContract(theAssetID);
3975  if (nullptr != pAssetContract) // Yes, it exists.
3976  theNewMap[str1] = "true";
3977  else
3978  theNewMap[str1] = "false";
3979  }
3980  }
3981 
3982  // Replace contents of old map with contents of new map.
3983  //
3984  theMap.clear();
3985  theMap = theNewMap;
3986  // Serialize the StringMap back to a string...
3987 
3988  std::string str_Encoded = OTDB::EncodeObject(*pMap);
3989 
3990  if (str_Encoded.size() > 0)
3991  msgOut.m_ascPayload =
3992  str_Encoded.c_str(); // now the outgoing message has the
3993  // response map in its payload, in
3994  // base64 form.
3995  else
3996  msgOut.m_bSuccess = false; // Something went wrong.
3997  } // if pMap exists.
3998  }
3999  else {
4000  msgOut.m_bSuccess = false;
4001  }
4002 
4003  // (2) Sign the Message
4004  msgOut.SignContract((const OTPseudonym&)server_->m_nymServer);
4005 
4006  // (3) Save the Message (with signatures and all, back to its internal
4007  // member m_strRawFile.)
4008  //
4009  // FYI, SaveContract takes m_xmlUnsigned and wraps it with the signatures
4010  // and ------- BEGIN bookends
4011  // If you don't pass a string in, then SaveContract saves the new version to
4012  // its member, m_strRawFile
4013  msgOut.SaveContract();
4014 }
4015 
4016 void UserCommandProcessor::UserCmdGetContract(OTPseudonym&, OTMessage& MsgIn,
4017  OTMessage& msgOut)
4018 {
4019  // (1) set up member variables
4020  msgOut.m_strCommand = "@getContract"; // reply to getContract
4021  msgOut.m_strNymID = MsgIn.m_strNymID; // UserID
4022  // msgOut.m_strServerID = m_strServerID; // This is already set in
4023  // ProcessUserCommand.
4024  msgOut.m_strAssetID = MsgIn.m_strAssetID; // The Asset Type ID in question
4025 
4026  const OTIdentifier ASSET_TYPE_ID(MsgIn.m_strAssetID);
4027 
4028  OTAssetContract* pContract =
4029  server_->transactor_.getAssetContract(ASSET_TYPE_ID);
4030 
4031  bool bSuccessLoadingContract = ((pContract != nullptr) ? true : false);
4032 
4033  // Yup the asset contract exists.
4034  if (bSuccessLoadingContract) {
4035  msgOut.m_bSuccess = true;
4036  // extract the account in ascii-armored form on the outgoing message
4037  OTString strPayload(
4038  *pContract); // first grab it in plaintext string form
4039  msgOut.m_ascPayload.SetString(strPayload); // now the outgoing message
4040  // has the contract in its
4041  // payload in base64 form.
4042  }
4043  // Send the user's command back to him if failure.
4044  else {
4045  msgOut.m_bSuccess = false;
4046  OTString tempInMessage(
4047  MsgIn); // Grab the incoming message in plaintext form
4048  msgOut.m_ascInReferenceTo.SetString(tempInMessage); // Set it into the
4049  // base64-encoded
4050  // object on the
4051  // outgoing message
4052  }
4053 
4054  // (2) Sign the Message
4055  msgOut.SignContract(
4056  (const OTPseudonym&)server_->m_nymServer);
4057 
4058  // (3) Save the Message (with signatures and all, back to its internal
4059  // member m_strRawFile.)
4060  //
4061  // FYI, SaveContract takes m_xmlUnsigned and wraps it with the signatures
4062  // and ------- BEGIN bookends
4063  // If you don't pass a string in, then SaveContract saves the new version to
4064  // its member, m_strRawFile
4065  msgOut.SaveContract();
4066 }
4067 
4068 // Done.
4069 //
4070 void UserCommandProcessor::UserCmdTriggerClause(OTPseudonym& theNym,
4071  OTMessage& MsgIn,
4072  OTMessage& msgOut)
4073 {
4074  OTString strInReferenceTo(
4075  MsgIn); // Grab the incoming message in plaintext form
4076  msgOut.m_ascInReferenceTo.SetString(strInReferenceTo);
4077  // (1) set up member variables
4078  msgOut.m_strCommand = "@triggerClause"; // reply to triggerClause
4079  msgOut.m_strNymID = MsgIn.m_strNymID; // UserID
4080  // msgOut.m_strServerID = m_strServerID; // This is already set in
4081  // ProcessUserCommand.
4082  msgOut.m_bSuccess = false; // Default value.
4083  const OTIdentifier SERVER_ID(server_->m_strServerID),
4084  theMsgNymboxHash(MsgIn.m_strNymboxHash); // theMsgNymboxHash is the hash
4085  // sent by the client side
4086  OTIdentifier theSrvrNymboxHash;
4087 
4088  bool bGotNymboxHashServerSide =
4089  theNym.GetNymboxHashServerSide(SERVER_ID, theSrvrNymboxHash);
4090  const bool bGotNymboxHashClientSide = MsgIn.m_strNymboxHash.Exists();
4091 
4092  if (bGotNymboxHashServerSide) // theSrvrNymboxHash is the hash stored on the
4093  // server side
4094  theSrvrNymboxHash.GetString(msgOut.m_strNymboxHash);
4095  if ((bGotNymboxHashServerSide && bGotNymboxHashClientSide &&
4096  (theMsgNymboxHash != theSrvrNymboxHash)) ||
4097  (bGotNymboxHashServerSide && !bGotNymboxHashClientSide)) {
4098  OTLog::vOutput(0,
4099  "%s: Rejecting message since nymbox hash doesn't match. "
4100  "(Send a getNymbox message to grab the newest one.)\n",
4101  __FUNCTION__);
4102  }
4103  else {
4104  OTSmartContract* pSmartContract = nullptr;
4105  OTCronItem* pCronItem =
4106  server_->m_Cron.GetItemByValidOpeningNum(MsgIn.m_lTransactionNum);
4107 
4108  if (nullptr == pCronItem) {
4109  OTLog::vOutput(0, "%s: Couldn't find smart contract based on "
4110  "transaction #: %ld \n",
4111  __FUNCTION__, MsgIn.m_lTransactionNum);
4112  }
4113  // Also: CAN this guy trigger it?
4114  else if (nullptr ==
4115  (pSmartContract = dynamic_cast<OTSmartContract*>(pCronItem))) {
4117  0, "%s: Found cron item %ld based on %ld, but it wasn't a "
4118  "smart contract. \n",
4119  __FUNCTION__, pCronItem->GetTransactionNum(),
4120  MsgIn.m_lTransactionNum);
4121  }
4122  else {
4123  // FIND THE PARTY / PARTY NAME
4124  OTAgent* pAgent = nullptr;
4125  OTParty* pParty =
4126  pSmartContract->FindPartyBasedOnNymAsAgent(theNym, &pAgent);
4127 
4128  if (nullptr == pParty) {
4129  OTLog::vOutput(0, "%s: Unable to find party to this contract "
4130  "(%ld based on %ld) "
4131  "based on Nym as agent: %s",
4132  __FUNCTION__, pCronItem->GetTransactionNum(),
4133  MsgIn.m_lTransactionNum, MsgIn.m_strNymID.Get());
4134  }
4135  else {
4136  bool bSuccess = false;
4137  const std::string str_clause_name = MsgIn.m_strNymID2.Get();
4138 
4139  if (pSmartContract->CanExecuteClause(
4140  pParty->GetPartyName(),
4141  str_clause_name)) // This calls (if available) the
4142  // scripted clause: bool
4143  // party_may_execute_clause(party_name,
4144  // clause_name)
4145  {
4146  //
4147  // Execute the clause.
4148  //
4149  mapOfClauses theMatchingClauses;
4150  OTClause* pClause =
4151  pSmartContract->GetClause(str_clause_name);
4152 
4153  if (nullptr != pClause) {
4154  OTLog::vOutput(0, "%s: At party request, processing "
4155  "smart contract clause: %s \n",
4156  __FUNCTION__, str_clause_name.c_str());
4157 
4158  theMatchingClauses.insert(
4159  std::pair<std::string, OTClause*>(str_clause_name,
4160  pClause));
4161 
4162  pSmartContract->ExecuteClauses(
4163  theMatchingClauses); // <============================================
4164 
4165  if (pSmartContract->IsFlaggedForRemoval()) {
4166  OTLog::vOutput(0, "%s: Removing smart contract "
4167  "from cron processing: %ld\n",
4168  __FUNCTION__,
4169  pSmartContract->GetTransactionNum());
4170  }
4171  bSuccess = true;
4172  }
4173  else {
4174  OTLog::vOutput(0, "%s: Failed attempt to process "
4175  "clause (%s) on smart contract: %ld "
4176  "\n",
4177  __FUNCTION__, str_clause_name.c_str(),
4178  pSmartContract->GetTransactionNum());
4179  }
4180  }
4181 
4182  // If we just removed the smart contract from cron, that means a
4183  // finalReceipt was just dropped
4184  // into the inboxes for the relevant asset accounts. Once I
4185  // process that receipt out of my
4186  // inbox, (which will require my processing out all related
4187  // marketReceipts) then the closing
4188  // number will be removed from my list of responsibility.
4189 
4190  if (bSuccess) {
4191  // Now we can set the response item as an acknowledgement
4192  // instead of the default (rejection)
4194  0,
4195  "%s: Party (%s) successfully triggered clause: %s.\n",
4196  __FUNCTION__, pParty->GetPartyName().c_str(),
4197  str_clause_name.c_str());
4198 
4199  msgOut.m_bSuccess = true;
4200  }
4201  else
4202  OTLog::vOutput(0, "%s: Unable to trigger clause %s at "
4203  "request of party %s. "
4204  "(Either the permission wasn't there, or "
4205  "the clause wasn't found.)\n",
4206  __FUNCTION__, str_clause_name.c_str(),
4207  pParty->GetPartyName().c_str());
4208  } // pParty != nullptr
4209  } // else found smart contract.
4210  } // NymboxHash matches.
4211  bGotNymboxHashServerSide =
4212  theNym.GetNymboxHashServerSide(SERVER_ID, theSrvrNymboxHash);
4213 
4214  if (bGotNymboxHashServerSide) // theSrvrNymboxHash is the hash stored on the
4215  // server side
4216  theSrvrNymboxHash.GetString(msgOut.m_strNymboxHash);
4217  // (2) Sign the Message
4218  msgOut.SignContract(
4219  (const OTPseudonym&)server_->m_nymServer); // todo change this cast.
4220 
4221  // (3) Save the Message (with signatures and all, back to its internal
4222  // member m_strRawFile.)
4223  //
4224  // FYI, SaveContract takes m_xmlUnsigned and wraps it with the signatures
4225  // and ------- BEGIN bookends
4226  // If you don't pass a string in, then SaveContract saves the new version to
4227  // its member, m_strRawFile
4228  msgOut.SaveContract();
4229 }
4230 
4231 void UserCommandProcessor::UserCmdGetMint(OTPseudonym&, OTMessage& MsgIn,
4232  OTMessage& msgOut)
4233 {
4234  // (1) set up member variables
4235  msgOut.m_strCommand = "@getMint"; // reply to getMint
4236  msgOut.m_strNymID = MsgIn.m_strNymID; // UserID
4237  // msgOut.m_strServerID = m_strServerID; // This is already set in
4238  // ProcessUserCommand.
4239  msgOut.m_strAssetID = MsgIn.m_strAssetID; // The Asset Type ID in question
4240 
4241  const OTIdentifier ASSET_TYPE_ID(MsgIn.m_strAssetID);
4242  const OTString ASSET_ID_STR(ASSET_TYPE_ID);
4243  bool bSuccessLoadingMint = false;
4244 
4245  std::unique_ptr<Mint> pMint(
4246  Mint::MintFactory(server_->m_strServerID, ASSET_ID_STR));
4247  OT_ASSERT(nullptr != pMint);
4248  if (true == (bSuccessLoadingMint = pMint->LoadMint(".PUBLIC"))) {
4249  // You cannot hash the Mint to get its ID.
4250  // (The ID is a hash of the asset contract, not the mint contract.)
4251  // Instead, you must READ the ID from the Mint file, and then compare it
4252  // to the one expected
4253  // to see if they match (similar to how Account IDs are verified.)
4254 
4255  bSuccessLoadingMint = pMint->VerifyMint(server_->m_nymServer);
4256 
4257  // Yup the asset contract exists.
4258  if (bSuccessLoadingMint) {
4259  msgOut.m_bSuccess = true;
4260 
4261  // extract the account in ascii-armored form on the outgoing message
4262  OTString strPayload(
4263  *pMint); // first grab it in plaintext string form
4264  msgOut.m_ascPayload.SetString(strPayload); // now the outgoing
4265  // message has the inbox
4266  // ledger in its payload
4267  // in base64 form.
4268  }
4269  // Send the user's command back to him if failure.
4270  }
4271 
4272  if (!bSuccessLoadingMint) {
4273  msgOut.m_bSuccess = false;
4274  OTString tempInMessage(
4275  MsgIn); // Grab the incoming message in plaintext form
4276  msgOut.m_ascInReferenceTo.SetString(tempInMessage); // Set it into the
4277  // base64-encoded
4278  // object on the
4279  // outgoing message
4280  }
4281 
4282  // (2) Sign the Message
4283  msgOut.SignContract((const OTPseudonym&)server_->m_nymServer);
4284 
4285  // (3) Save the Message (with signatures and all, back to its internal
4286  // member m_strRawFile.)
4287  //
4288  // FYI, SaveContract takes m_xmlUnsigned and wraps it with the signatures
4289  // and ------- BEGIN bookends
4290  // If you don't pass a string in, then SaveContract saves the new version to
4291  // its member, m_strRawFile
4292  msgOut.SaveContract();
4293 }
4294 
4295 // If a user requests to delete his own Nym, the server will allow it.
4296 // IF: If the transaction numbers are all closable (available on both lists).
4297 // AND if the Nymbox is empty. AND if there are no cron items open, AND if
4298 // there are no asset accounts! (Delete them / Close them all FIRST! Or this
4299 // fails.)
4300 //
4301 void UserCommandProcessor::UserCmdDeleteUser(OTPseudonym& theNym,
4302  OTMessage& MsgIn,
4303  OTMessage& msgOut)
4304 {
4305  // (1) set up member variables
4306  msgOut.m_strCommand = "@deleteUserAccount"; // reply to deleteUserAccount
4307  msgOut.m_strNymID = MsgIn.m_strNymID; // UserID
4308  // msgOut.m_strServerID = m_strServerID; // This is already set in
4309  // ProcessUserCommand.
4310 
4311  const OTIdentifier USER_ID(MsgIn.m_strNymID),
4312  SERVER_ID(MsgIn.m_strServerID);
4313 
4314  OTLedger theLedger(USER_ID, USER_ID, SERVER_ID);
4315 
4316  std::set<int64_t>& theSetofCronItemIDs = theNym.GetSetOpenCronItems();
4317 
4318  // If success loading Nymbox, and there are transactions still inside, THEN
4319  // FAIL!!!
4320  // (Can't delete a Nym with open receipts...)
4321  //
4322  const bool bSuccessLoadNymbox =
4323  (theLedger.LoadNymbox() &&
4324  theLedger.VerifyAccount(server_->m_nymServer));
4325  if (!bSuccessLoadNymbox) {
4326  OTLog::Output(3, "Tried to delete Nym, but failed loading or verifying "
4327  "the Nymbox.\n");
4328  msgOut.m_bSuccess = false;
4329  }
4330  else if (theLedger.GetTransactionCount() > 0) {
4331  OTLog::Output(3, "Tried to delete Nym, but there are still receipts in "
4332  "the Nymbox. (Process them first.)\n");
4333  msgOut.m_bSuccess = false;
4334  }
4335  // This Nym still has items open on Cron!
4336  //
4337  else if (!theSetofCronItemIDs.empty()) {
4338  OTLog::Output(3, "Tried to delete Nym, but there are still open Cron "
4339  "Items. (Close them first.)\n");
4340  msgOut.m_bSuccess = false;
4341  }
4342  else if (theNym.GetSetAssetAccounts().size() > 0) {
4343  OTLog::Output(3, "Tried to delete Nym, but there are still Asset "
4344  "Accounts open for that Nym. (Close them first.)\n");
4345  msgOut.m_bSuccess = false;
4346  }
4347  // The Nym has used some of his transaction numbers, but hasn't closed them
4348  // out yet.
4349  // Close those transactions first.
4350  else if (theNym.GetTransactionNumCount(SERVER_ID) !=
4351  theNym.GetIssuedNumCount(SERVER_ID)) {
4352  OTLog::Output(3, "Tried to delete Nym, but there are still "
4353  "transactions open for that Nym. (Close them "
4354  "first.)\n");
4355  msgOut.m_bSuccess = false;
4356  }
4357  else // SUCCESS!
4358  {
4359  msgOut.m_bSuccess = true;
4360 
4361  // The Nym may have some numbers signed out, but none of them have come
4362  // through
4363  // and been "used but not closed" yet. (That is, removed from
4364  // transaction num list but still
4365  // on issued num list.) If they had (i.e. if the previous elseif just
4366  // above had discovered
4367  // mismatched counts) then we wouldn't be able to delete the Nym until
4368  // those transactions were
4369  // closed.
4370  // Since we know the counts match perfectly, here we remove all the
4371  // numbers.
4372  // The client side must know to remove all the numbers as well, when it
4373  // receives a successful
4374  // reply that the nym was "deleted."
4375  //
4376  while (theNym.GetTransactionNumCount(SERVER_ID) > 0) {
4377  int64_t lTemp = theNym.GetTransactionNum(SERVER_ID, 0); // index 0
4378  server_->transactor_.removeTransactionNumber(
4379  theNym, lTemp, false); // bSave = false
4380  }
4381 
4382  while (theNym.GetIssuedNumCount(SERVER_ID) > 0) {
4383  int64_t lTemp = theNym.GetIssuedNum(SERVER_ID, 0); // index 0
4384  server_->transactor_.removeIssuedNumber(theNym, lTemp,
4385  false); // bSave = false
4386  }
4387  //
4388  theNym.MarkForDeletion(); // The nym isn't actually deleted yet, just
4389  // marked for deletion.
4390  // It will get cleaned up later, during server maintenance.
4391 
4392  // SAVE the Nym... (now marked for deletion and with all of its
4393  // transaction numbers removed.)
4394  //
4395  theNym.SaveSignedNymfile(server_->m_nymServer);
4396  }
4397 
4398  // Send the user's command back to him (success or failure.)
4399  // if (!msgOut.m_bSuccess)
4400  {
4401  OTString tempInMessage(
4402  MsgIn); // Grab the incoming message in plaintext form
4403  msgOut.m_ascInReferenceTo.SetString(tempInMessage); // Set it into the
4404  // base64-encoded
4405  // object on the
4406  // outgoing message
4407  }
4408 
4409  // (2) Sign the Message
4410  msgOut.SignContract((const OTPseudonym&)server_->m_nymServer);
4411 
4412  // (3) Save the Message (with signatures and all, back to its internal
4413  // member m_strRawFile.)
4414  //
4415  // FYI, SaveContract takes m_xmlUnsigned and wraps it with the signatures
4416  // and ------- BEGIN bookends
4417  // If you don't pass a string in, then SaveContract saves the new version to
4418  // its member, m_strRawFile
4419  msgOut.SaveContract();
4420 
4421  // (You are in UserCmdDeleteUser.)
4422 
4423  // TODO: We may also need to mark the Nymbox, as well as the credential
4424  // files, as "Marked For Deletion."
4425 
4426  // REPLY NOTICE TO NYMBOX
4427  //
4428  // Now that we signed / saved the reply message...
4429  //
4430  // After specific messages, we drop a notice with a copy of the server's
4431  // reply
4432  // into the Nymbox. This way we are GUARANTEED that the Nym will receive
4433  // and process
4434  // it. (And thus never get out of sync.)
4435  //
4436  if (msgOut.m_bSuccess) {
4437  const OTString strReplyMessage(msgOut);
4438  const int64_t lReqNum = atol(MsgIn.m_strRequestNum.Get());
4439 
4440  // If it fails, it logs already.
4441  DropReplyNoticeToNymbox(SERVER_ID, USER_ID, strReplyMessage, lReqNum,
4442  false, // trans success
4443  &theNym);
4444  }
4445 }
4446 
4447 // the "accountID" on this message will contain the NymID if retrieving a
4448 // boxreceipt for
4449 // the Nymbox. Otherwise it will contain an AcctID if retrieving a boxreceipt
4450 // for an Asset Acct.
4451 //
4452 void UserCommandProcessor::UserCmdGetBoxReceipt(OTPseudonym&, OTMessage& MsgIn,
4453  OTMessage& msgOut)
4454 {
4455  // (1) set up member variables
4456  msgOut.m_strCommand = "@getBoxReceipt"; // reply to getBoxReceipt
4457  msgOut.m_strNymID = MsgIn.m_strNymID; // UserID
4458  // msgOut.m_strServerID = m_strServerID; // This is
4459  // already set in ProcessUserCommand.
4460  msgOut.m_strAcctID = MsgIn.m_strAcctID; // the asset account ID
4461  // (inbox/outbox), or Nym ID
4462  // (nymbox)
4463  msgOut.m_lTransactionNum =
4464  MsgIn.m_lTransactionNum; // TransactionNumber for the receipt in the box
4465  // (unique to the box.)
4466  msgOut.m_lDepth = MsgIn.m_lDepth;
4467  msgOut.m_bSuccess = false;
4468 
4469  const OTIdentifier USER_ID(MsgIn.m_strNymID),
4470  SERVER_ID(MsgIn.m_strServerID), ACCOUNT_ID(MsgIn.m_strAcctID);
4471 
4472  OTLedger* pLedger = nullptr;
4473  std::unique_ptr<OTLedger> theLedgerAngel;
4474 
4475  bool bErrorCondition = false;
4476  bool bSuccessLoading = false;
4477 
4478  switch (MsgIn.m_lDepth) {
4479  case 0: // Nymbox
4480  if (USER_ID == ACCOUNT_ID) {
4481  pLedger = new OTLedger(USER_ID, USER_ID, SERVER_ID);
4482  OT_ASSERT(nullptr != pLedger);
4483  theLedgerAngel.reset(pLedger);
4484  bSuccessLoading = pLedger->LoadNymbox(); // It's verified using
4485  // VerifyAccount() below
4486  // this switch block.
4487  }
4488  else // Inbox / Outbox.
4489  {
4490  OTLog::vError(
4491  "UserCommandProcessor::UserCmdGetBoxReceipt: User requested "
4492  "Nymbox, but "
4493  "failed to provide the "
4494  "UserID (%s) in the AccountID (%s) field as expected.\n",
4495  MsgIn.m_strNymID.Get(), MsgIn.m_strAcctID.Get());
4496  bErrorCondition = true;
4497  }
4498  break;
4499  case 1: // Inbox
4500  if (USER_ID == ACCOUNT_ID) {
4501  OTLog::vError(
4502  "UserCommandProcessor::UserCmdGetBoxReceipt: User requested "
4503  "Inbox, but erroneously provided the "
4504  "UserID (%s) in the AccountID (%s) field.\n",
4505  MsgIn.m_strNymID.Get(), MsgIn.m_strAcctID.Get());
4506  bErrorCondition = true;
4507  }
4508  else {
4509  pLedger = new OTLedger(USER_ID, ACCOUNT_ID, SERVER_ID);
4510  OT_ASSERT(nullptr != pLedger);
4511  theLedgerAngel.reset(pLedger);
4512  bSuccessLoading = pLedger->LoadInbox(); // It's verified using
4513  // VerifyAccount() below
4514  // this switch block.
4515  }
4516  break;
4517  case 2: // Outbox
4518  if (USER_ID == ACCOUNT_ID) {
4519  OTLog::vError(
4520  "UserCommandProcessor::UserCmdGetBoxReceipt: User requested "
4521  "Outbox, but erroneously provided the "
4522  "UserID (%s) in the AccountID (%s) field.\n",
4523  MsgIn.m_strNymID.Get(), MsgIn.m_strAcctID.Get());
4524  bErrorCondition = true;
4525  }
4526  else {
4527  pLedger = new OTLedger(USER_ID, ACCOUNT_ID, SERVER_ID);
4528  OT_ASSERT(nullptr != pLedger);
4529  theLedgerAngel.reset(pLedger);
4530  bSuccessLoading = pLedger->LoadOutbox(); // It's verified using
4531  // VerifyAccount() below
4532  // this switch block.
4533  }
4534  break;
4535  default:
4536  OTLog::vError("UserCommandProcessor::UserCmdGetBoxReceipt: Unknown box "
4537  "type: %ld\n",
4538  MsgIn.m_lDepth);
4539  bErrorCondition = true;
4540  break;
4541  }
4542  // At this point, we have the box loaded. Now let's use it to
4543  // load the appropriate box receipt...
4544 
4545  if (bSuccessLoading && !bErrorCondition &&
4546  // pLedger->VerifyAccount(server_->m_nymServer) && // This
4547  // call
4548  // causes all the Box Receipts to be loaded up and we don't need them
4549  // here, except
4550  pLedger->VerifyContractID() && // for just one, so we're going to
4551  // VerifyContractID and Signature
4552  // instead. Then below, we'll
4553  pLedger->VerifySignature(
4554  server_->m_nymServer) // just load the one we actually need.
4555  ) {
4556  OTTransaction* pTransaction =
4557  pLedger->GetTransaction(MsgIn.m_lTransactionNum);
4558  if (nullptr == pTransaction) {
4559  OTLog::vError(
4560  "UserCommandProcessor::UserCmdGetBoxReceipt: User requested a "
4561  "transaction number "
4562  "(%ld) that's not in the %s. UserID (%s) and "
4563  "AccountID (%s) FYI.\n",
4564  MsgIn.m_lTransactionNum,
4565  (MsgIn.m_lDepth == 0)
4566  ? "nymbox"
4567  : ((MsgIn.m_lDepth == 1) ? "inbox"
4568  : "outbox"), // outbox is 2.
4569  MsgIn.m_strNymID.Get(),
4570  MsgIn.m_strAcctID.Get());
4571  }
4572  else {
4573  pLedger->LoadBoxReceipt(MsgIn.m_lTransactionNum);
4574 
4575  // The above call will replace pTransaction, inside pLedger, with
4576  // the full version
4577  // (instead of the abbreviated version) of that transaction, meaning
4578  // that the pTransaction
4579  // pointer is now a bad pointer, if that call was successful.
4580  // Therefore we just call GetTransaction() AGAIN. This way, whether
4581  // LoadBoxReceipt()
4582  // failed or not (perhaps it's legacy data and is already not
4583  // abbreviated, and thus the
4584  // LoadBoxReceipt call failed, but that's doesn't mean we're going
4585  // to fail HERE, now does it?)
4586  //
4587  pTransaction = pLedger->GetTransaction(MsgIn.m_lTransactionNum);
4588 
4589  if ((nullptr != pTransaction) && !pTransaction->IsAbbreviated() &&
4590  pTransaction->VerifyContractID() &&
4591  pTransaction->VerifySignature(server_->m_nymServer)) {
4592  // Okay so after finding it, then calling LoadBoxReceipt(), then
4593  // finding it again,
4594  // it's definitely not abbreviated by this point. Success!
4595  // LoadBoxReceipt() already calls VerifyBoxReceipt(), FYI.
4596  //
4597  const OTString strBoxReceipt(*pTransaction);
4598  OT_ASSERT(strBoxReceipt.Exists());
4599 
4600  msgOut.m_ascPayload.SetString(
4601  strBoxReceipt); // <=================
4602  msgOut.m_bSuccess = true;
4603 
4605  3, "UserCommandProcessor::UserCmdGetBoxReceipt: Success: "
4606  "User is "
4607  "retrieving the box receipt for transaction number "
4608  "%ld in the %s for UserID (%s) AccountID (%s).\n",
4609  MsgIn.m_lTransactionNum,
4610  (MsgIn.m_lDepth == 0)
4611  ? "nymbox"
4612  : ((MsgIn.m_lDepth == 1) ? "inbox"
4613  : "outbox"), // outbox is 2.
4614  MsgIn.m_strNymID.Get(),
4615  MsgIn.m_strAcctID.Get());
4616  }
4617  else {
4618  OTLog::vError(
4619  "UserCommandProcessor::UserCmdGetBoxReceipt: User "
4620  "requested a "
4621  "transaction number (%ld) that's "
4622  "failing to retrieve from the %s, AFTER calling "
4623  "LoadBoxReceipt(). (Though it worked BEFORE calling it.) "
4624  "UserID (%s) and AccountID (%s) FYI. IsAbbreviated == %s\n",
4625  MsgIn.m_lTransactionNum,
4626  (MsgIn.m_lDepth == 0)
4627  ? "nymbox"
4628  : ((MsgIn.m_lDepth == 1) ? "inbox"
4629  : "outbox"), // outbox is 2.
4630  MsgIn.m_strNymID.Get(),
4631  MsgIn.m_strAcctID.Get(),
4632  (nullptr == pTransaction)
4633  ? "nullptr"
4634  : (pTransaction->IsAbbreviated()) ? "true" : "false");
4635  }
4636  }
4637  }
4638  else {
4639  OTLog::vError(
4640  "UserCommandProcessor::UserCmdGetBoxReceipt: Failed loading or "
4641  "verifying %s. "
4642  "Transaction (%ld), UserID (%s) and AccountID (%s) FYI.\n",
4643  (MsgIn.m_lDepth == 0)
4644  ? "nymbox"
4645  : ((MsgIn.m_lDepth == 1) ? "inbox" : "outbox"), // outbox is 2.
4646  MsgIn.m_lTransactionNum,
4647  MsgIn.m_strNymID.Get(), MsgIn.m_strAcctID.Get());
4648  }
4649 
4650  // Send the user's command back to him (success or failure.)
4651  // if (!msgOut.m_bSuccess)
4652  {
4653  const OTString tempInMessage(
4654  MsgIn); // Grab the incoming message in plaintext form
4655  msgOut.m_ascInReferenceTo.SetString(tempInMessage); // Set it into the
4656  // base64-encoded
4657  // object on the
4658  // outgoing message
4659  }
4660 
4661  // (2) Sign the Message
4662  msgOut.SignContract((const OTPseudonym&)server_->m_nymServer);
4663 
4664  // (3) Save the Message (with signatures and all, back to its internal
4665  // member m_strRawFile.)
4666  //
4667  // FYI, SaveContract takes m_xmlUnsigned and wraps it with the signatures
4668  // and ------- BEGIN bookends
4669  // If you don't pass a string in, then SaveContract saves the new version to
4670  // its member, m_strRawFile
4671  msgOut.SaveContract();
4672 }
4673 
4674 // If the client wants to delete an asset account, the server will allow it...
4675 // ...IF: the Inbox and Outbox are both EMPTY. AND the Balance must be empty as
4676 // well!
4677 //
4678 void UserCommandProcessor::UserCmdDeleteAssetAcct(OTPseudonym& theNym,
4679  OTMessage& MsgIn,
4680  OTMessage& msgOut)
4681 {
4682  const char* szFunc = "UserCommandProcessor::UserCmdDeleteAssetAcct";
4683 
4684  // (1) set up member variables
4685  msgOut.m_strCommand = "@deleteAssetAccount"; // reply to deleteAssetAccount
4686  msgOut.m_strNymID = MsgIn.m_strNymID; // UserID
4687  // msgOut.m_strServerID = m_strServerID; // This is already set in
4688  // ProcessUserCommand.
4689  msgOut.m_strAcctID = MsgIn.m_strAcctID; // the asset account being deleted.
4690 
4691  const OTIdentifier USER_ID(MsgIn.m_strNymID),
4692  SERVER_ID(MsgIn.m_strServerID), ACCOUNT_ID(MsgIn.m_strAcctID);
4693 
4694  std::unique_ptr<OTAccount> pAccount(
4695  OTAccount::LoadExistingAccount(ACCOUNT_ID, SERVER_ID));
4696 
4697  if (nullptr == pAccount || !pAccount->VerifyAccount(server_->m_nymServer)) {
4698  OTLog::vError("%s: Error loading or verifying account: %s\n", szFunc,
4699  MsgIn.m_strAcctID.Get());
4700  }
4701  else if (pAccount->GetBalance() != 0) {
4702  OTLog::vOutput(1, "%s: Failed while trying to delete asset account %s: "
4703  "Balance must be zero to do this!\n",
4704  szFunc, MsgIn.m_strAcctID.Get());
4705  }
4706  else {
4707  std::unique_ptr<OTLedger> pInbox(
4708  pAccount->LoadInbox(server_->m_nymServer));
4709  std::unique_ptr<OTLedger> pOutbox(
4710  pAccount->LoadOutbox(server_->m_nymServer));
4711 
4712  if (nullptr ==
4713  pInbox) // || !pInbox->VerifyAccount(server_->m_nymServer)) // NOTE:
4714  // OTAccount::LoadInbox already verifies.
4715  {
4716  OTLog::vError("%s: Error loading or verifying inbox: %s\n", szFunc,
4717  MsgIn.m_strAcctID.Get());
4718  }
4719  else if (nullptr ==
4720  pOutbox) // || !pOutbox->VerifyAccount(server_->m_nymServer))
4721  // // NOTE: OTAccount::LoadOutbox already
4722  // verifies.
4723  {
4724  OTLog::vError("%s: Error loading or verifying outbox: %s\n", szFunc,
4725  MsgIn.m_strAcctID.Get());
4726  }
4727  else if (pInbox->GetTransactionCount() > 0) {
4729  3, "%s: Tried to delete asset account, but there are still "
4730  "receipts in the Inbox. (Process them first.)\n",
4731  szFunc);
4732  msgOut.m_bSuccess = false;
4733  }
4734  else if (pOutbox->GetTransactionCount() > 0) {
4736  3, "%s: Tried to delete asset account, but there are still "
4737  "receipts in the Outbox. (Process them first.)\n",
4738  szFunc);
4739  msgOut.m_bSuccess = false;
4740  }
4741  else // SUCCESS!
4742  {
4743  msgOut.m_bSuccess = true;
4744 
4745  std::set<std::string>& theAccountSet = theNym.GetSetAssetAccounts();
4746  theAccountSet.erase(MsgIn.m_strAcctID.Get());
4747 
4748  theNym.SaveSignedNymfile(server_->m_nymServer);
4749  OTAssetContract* pContract = server_->transactor_.getAssetContract(
4750  pAccount->GetAssetTypeID());
4751 
4752  if (nullptr == pContract) {
4753  const OTString strAssetID(pAccount->GetAssetTypeID());
4754  OTLog::vError("%s: Error: Unable to get AssetContract for "
4755  "asset type: %s\n",
4756  szFunc, strAssetID.Get());
4757  }
4758  else if (pContract->IsShares()) {
4759  // The asset type keeps a list of all accounts for that type.
4760  // (For shares, not for currencies.)
4761  //
4762  const bool bErased =
4763  pContract->EraseAccountRecord(pAccount->GetAssetTypeID());
4764  if (!bErased) {
4765  const OTString strAssetID(pAccount->GetAssetTypeID());
4766  OTLog::vError(
4767  "%s: ERROR Erasing Account Record: %s ... Aborting.\n",
4768  __FUNCTION__, strAssetID.Get());
4769  return; // error
4770  }
4771  }
4772  //
4773  pAccount->MarkForDeletion(); // The account isn't actually deleted
4774  // yet, just marked for deletion.
4775  // It will get cleaned up later, during server maintenance.
4776 
4777  // SAVE the Account... (NOW THAT IT IS MARKED FOR DELETION.)
4778  //
4779  pAccount->ReleaseSignatures();
4780  pAccount->SignContract(server_->m_nymServer);
4781  pAccount->SaveContract();
4782  pAccount->SaveAccount();
4783  }
4784  } // pAccount verifies.
4785 
4786  // Send the user's command back to him (success or failure.)
4787  // if (!msgOut.m_bSuccess)
4788  {
4789  OTString tempInMessage(
4790  MsgIn); // Grab the incoming message in plaintext form
4791  msgOut.m_ascInReferenceTo.SetString(tempInMessage); // Set it into the
4792  // base64-encoded
4793  // object on the
4794  // outgoing message
4795  }
4796 
4797  // (2) Sign the Message
4798  msgOut.SignContract((const OTPseudonym&)server_->m_nymServer);
4799 
4800  // (3) Save the Message (with signatures and all, back to its internal
4801  // member m_strRawFile.)
4802  //
4803  // FYI, SaveContract takes m_xmlUnsigned and wraps it with the signatures
4804  // and ------- BEGIN bookends
4805  // If you don't pass a string in, then SaveContract saves the new version to
4806  // its member, m_strRawFile
4807  msgOut.SaveContract();
4808 
4809  // (You are in UserCmdDeleteAssetAcct.)
4810 
4811  // REPLY NOTICE TO NYMBOX
4812  //
4813  // Now that we signed / saved the reply message...
4814  //
4815  // After specific messages, we drop a notice with a copy of the server's
4816  // reply
4817  // into the Nymbox. This way we are GUARANTEED that the Nym will receive
4818  // and process
4819  // it. (And thus never get out of sync.)
4820  //
4821  if (msgOut.m_bSuccess) {
4822  const OTString strReplyMessage(msgOut);
4823  const int64_t lReqNum = atol(MsgIn.m_strRequestNum.Get());
4824 
4825  // If it fails, it logs already.
4826  DropReplyNoticeToNymbox(SERVER_ID, USER_ID, strReplyMessage, lReqNum,
4827  false, // trans success (not a transaction.)
4828  &theNym);
4829  }
4830 }
4831 
4832 void UserCommandProcessor::UserCmdGetNymbox(OTPseudonym& theNym,
4833  OTMessage& MsgIn, OTMessage& msgOut)
4834 {
4835  // (1) set up member variables
4836  msgOut.m_strCommand = "@getNymbox"; // reply to getNymbox
4837  msgOut.m_strNymID = MsgIn.m_strNymID; // UserID
4838  // msgOut.m_strServerID = m_strServerID; // This is already set in
4839  // ProcessUserCommand.
4840 
4841  const OTIdentifier USER_ID(MsgIn.m_strNymID),
4842  SERVER_ID(MsgIn.m_strServerID);
4843  OTIdentifier NYMBOX_HASH;
4844  bool bSavedNymbox = false;
4845 
4846  OTLedger theLedger(USER_ID, USER_ID, SERVER_ID);
4847 
4848  msgOut.m_bSuccess = theLedger.LoadNymbox();
4849 
4850  if (!msgOut.m_bSuccess)
4851  OTLog::Error("UserCommandProcessor::UserCmdGetNymbox: Failed trying to "
4852  "load Nymbox "
4853  "from storage.\n");
4854  else {
4855  // We do NOT call VerifyAccount in this function (because we don't need
4856  // to) and thus we do NOT
4857  // force the box receipts to be loaded here (which happens inside that
4858  // call.) But we DO verify
4859  // the IDs and the Signature, of course.
4860  //
4861  msgOut.m_bSuccess = (theLedger.VerifyContractID() &&
4862  theLedger.VerifySignature(server_->m_nymServer));
4863 
4864  // If we loaded old data in this file... (when whole receipts were
4865  // stored in boxes.)
4866  //
4867  if (msgOut.m_bSuccess &&
4868  theLedger.LoadedLegacyData()) // (which automatically saves the box
4869  // receipt as the old data is
4870  // loaded...)
4871  {
4872  // msgOut.m_bSuccess =
4873  // theLedger.VerifyAccount(server_->m_nymServer); // Then Verify,
4874  // which
4875  // forces a LoadBoxReceipts... (
4876 
4877  theLedger.ReleaseSignatures(); // UPDATE: We do NOT force the
4878  // loading here, since they aren't
4879  // needed.
4880  theLedger.SignContract(
4881  server_->m_nymServer); // Waste of resources. Instead,
4882  // we recognize that it was old
4883  // data, and so
4884  theLedger.SaveContract(); // we gracefully re-save in the new
4885  // format, so it won't repeatedly be
4886  theLedger.SaveNymbox(&NYMBOX_HASH); // loaded over and over again in
4887  // the large filesize.
4888 
4889  bSavedNymbox = true;
4890  }
4891  if (!msgOut.m_bSuccess)
4892  OTLog::Error("UserCommandProcessor::UserCmdGetNymbox: Verification "
4893  "failed on "
4894  "Nymbox after loading.\n");
4895  }
4896 
4897  if (true == msgOut.m_bSuccess) {
4898  // extract the ledger in ascii-armored form on the outgoing message
4899  OTString strPayload(
4900  theLedger); // first grab it in plaintext string form
4901  msgOut.m_ascPayload.SetString(strPayload); // now the outgoing message
4902  // has the nymbox ledger in
4903  // its payload in base64
4904  // form.
4905  }
4906  // Send the user's command back to him if failure.
4907  else {
4908  OTString tempInMessage(
4909  MsgIn); // Grab the incoming message in plaintext form
4910  msgOut.m_ascInReferenceTo.SetString(tempInMessage); // Set it into the
4911  // base64-encoded
4912  // object on the
4913  // outgoing message
4914  }
4915 
4916  if (bSavedNymbox) {
4917  // Todo: make objects (like nyms) "saveable", and ability to get
4918  // "dirty". (To prevent multiple
4919  // redundant saves.)
4920  theNym.SetNymboxHashServerSide(
4921  NYMBOX_HASH); // Save the hash onto the Nym
4922  theNym.SaveSignedNymfile(server_->m_nymServer);
4923 
4924  NYMBOX_HASH.GetString(
4925  msgOut.m_strNymboxHash); // Get the hash onto the message
4926  }
4927  else if (true == msgOut.m_bSuccess) {
4928  theLedger.CalculateNymboxHash(NYMBOX_HASH);
4929 
4930  theNym.SetNymboxHashServerSide(
4931  NYMBOX_HASH); // Save the hash onto the Nym
4932  theNym.SaveSignedNymfile(server_->m_nymServer);
4933 
4934  NYMBOX_HASH.GetString(
4935  msgOut.m_strNymboxHash); // Get the hash onto the message
4936  }
4937  else {
4938  OTIdentifier EXISTING_NYMBOX_HASH;
4939  if (theNym.GetNymboxHashServerSide(
4940  SERVER_ID,
4941  EXISTING_NYMBOX_HASH)) // if hash exists already for nym...
4942  EXISTING_NYMBOX_HASH.GetString(
4943  msgOut.m_strNymboxHash); // ...then set it onto the message.
4944  }
4945 
4946  // (2) Sign the Message
4947  msgOut.SignContract(
4948  (const OTPseudonym&)server_->m_nymServer); // todo const_cast
4949 
4950  // (3) Save the Message (with signatures and all, back to its internal
4951  // member m_strRawFile.)
4952  //
4953  // FYI, SaveContract takes m_xmlUnsigned and wraps it with the signatures
4954  // and ------- BEGIN bookends
4955  // If you don't pass a string in, then SaveContract saves the new version to
4956  // its member, m_strRawFile
4957  msgOut.SaveContract();
4958 }
4959 
4960 void UserCommandProcessor::UserCmdProcessNymbox(OTPseudonym& theNym,
4961  OTMessage& MsgIn,
4962  OTMessage& msgOut)
4963 {
4964  // (1) set up member variables
4965  msgOut.m_strCommand = "@processNymbox"; // reply to processNymbox
4966  msgOut.m_strNymID = MsgIn.m_strNymID; // UserID
4967  // msgOut.m_strServerID = m_strServerID; // This is already set in
4968  // ProcessUserCommand.
4969 
4970  const OTIdentifier USER_ID(msgOut.m_strNymID),
4971  SERVER_ID(server_->m_strServerID), SERVER_USER_ID(server_->m_nymServer);
4972 
4973  OTLedger theLedger(USER_ID, USER_ID, SERVER_ID); // These are ledgers used
4974  // as messages. The one we
4975  // received
4976  // and the one we're sending back.
4977  std::unique_ptr<OTLedger> pResponseLedger(OTLedger::GenerateLedger(
4978  SERVER_USER_ID, USER_ID, SERVER_ID, OTLedger::message, false));
4979 
4980  // Grab the string (containing the request ledger) out of ascii-armored
4981  // form.
4982  OTString strLedger(MsgIn.m_ascPayload);
4983 
4984  bool bTransSuccess = false;
4985 
4986  const OTIdentifier theMsgNymboxHash(
4987  MsgIn.m_strNymboxHash); // theMsgNymboxHash is the hash sent by the
4988  // client side
4989  OTIdentifier theSrvrNymboxHash;
4990 
4991  bool bGotNymboxHashServerSide =
4992  theNym.GetNymboxHashServerSide(SERVER_ID, theSrvrNymboxHash);
4993 
4994  if (bGotNymboxHashServerSide) // theSrvrNymboxHash is the hash stored on the
4995  // server side
4996  theSrvrNymboxHash.GetString(msgOut.m_strNymboxHash);
4997  else {
4999  1, "%s: We cannot obtain server side nymbox hash, will continue.\n",
5000  __FUNCTION__);
5001  }
5002 
5003  const bool bGotNymboxHashClientSide = MsgIn.m_strNymboxHash.Exists();
5004 
5005  if (!bGotNymboxHashClientSide) {
5007  1, "%s: We don't have a client side nymbox hash, will continue\n",
5008  __FUNCTION__);
5009  }
5010 
5011  if (bGotNymboxHashServerSide && bGotNymboxHashClientSide)
5012  if (theMsgNymboxHash != theSrvrNymboxHash) {
5013  OTLog::vOutput(0, "%s: The server and client nymbox hashes "
5014  "missmatch! rejecting message.\n",
5015  __FUNCTION__);
5016  goto send_message;
5017  }
5018 
5019  // theLedger contains a single transaction from the client, with an item
5020  // inside
5021  // for each inbox transaction the client wants to accept or reject.
5022  // Let's see if we can load it from the string that came in the message...
5023  //
5024  msgOut.m_bSuccess = theLedger.LoadContractFromString(strLedger);
5025  if (msgOut.m_bSuccess) // Yes, that is an assignment operator.
5026  {
5027  // In this case we need to process the transaction items from the ledger
5028  // and create a corresponding transaction where each of the new items
5029  // contains the answer to the transaction item sent.
5030  // Then we send that new "response ledger" back to the user in
5031  // MsgOut.Payload
5032  // as an @processNymbox message.
5033 
5034  if (theLedger.GetTransactionCount() == 0) {
5035  OTTransaction* pTranResponse = OTTransaction::GenerateTransaction(
5036  *pResponseLedger, OTTransaction::error_state, 0);
5037  pTranResponse->SignContract(server_->m_nymServer);
5038  pTranResponse->SaveContract();
5039 
5040  // Add the response transaction to the response ledger.
5041  // That will go into the response message and be sent back to the
5042  // client.
5043  pResponseLedger->AddTransaction(*pTranResponse);
5044  }
5045  for (auto& it : theLedger.GetTransactionMap()) {
5046  OTTransaction* pTransaction = it.second;
5047  OT_ASSERT_MSG(nullptr != pTransaction,
5048  "nullptr transaction pointer in "
5049  "UserCommandProcessor::UserCmdProcessNymbox\n");
5050 
5051  // for each transaction in the ledger, we create a transaction
5052  // response and add
5053  // that to the response ledger.
5054  OTTransaction* pTranResponse = OTTransaction::GenerateTransaction(
5055  *pResponseLedger, OTTransaction::error_state,
5056  pTransaction->GetTransactionNum());
5057 
5058  // Add the response transaction to the response ledger.
5059  // That will go into the response message and be sent back to the
5060  // client.
5061  pResponseLedger->AddTransaction(*pTranResponse);
5062 
5063  // Now let's make sure the response transaction has a copy of the
5064  // transaction
5065  // it is responding to.
5066  //
5067  // OTString strResponseTo;
5068  // pTransaction->SaveContract(strResponseTo);
5069  // pTranResponse->m_ascInReferenceTo.SetString(strResponseTo);
5070  //
5071  // I commented out the above because we are keeping too many copies.
5072  // Message contains a copy of the message it's responding to.
5073  // Then each transaction contains a copy of the transaction
5074  // responding to...
5075  // Then each ITEM in each transaction contains a copy of each item
5076  // it's responding to.
5077  //
5078  // Therefore, for the "processNymbox" message, I have decided (for
5079  // now) to have
5080  // the extra copy in the items themselves, and in the overall
5081  // message, but not in the
5082  // transactions. Thus, the above is commented out.
5083 
5084  // It should always return something. Success, or failure, that goes
5085  // into pTranResponse.
5086  // I don't think there's need for more return value than that. The
5087  // user has gotten deep
5088  // enough that they deserve SOME sort of response.
5089  //
5090  // This function also SIGNS the transaction, so there is no need to
5091  // sign it after this.
5092  // There's also no point to change it after this, unless you plan to
5093  // sign it twice.
5094  server_->notary_.NotarizeProcessNymbox(
5095  theNym, *pTransaction, *pTranResponse, bTransSuccess);
5096 
5097  pTranResponse = nullptr; // at this point, the ledger now "owns" the
5098  // response, and will handle deleting it.
5099  }
5100 
5101  // DONE (Notices go to Nymbox now): should consider saving a copy of the
5102  // response
5103  // ledger here on the server.
5104  // Until the user signs off of the responses, maybe the user didn't
5105  // receive them.
5106  // The server should be able to re-send them until confirmation, then
5107  // delete them.
5108  // So might want to consider a SAVE TO FILE here of that ledger we're
5109  // sending out...
5110  }
5111  else {
5112  OTLog::Error("ERROR loading ledger from message in "
5113  "UserCommandProcessor::UserCmdProcessNymbox\n");
5114  }
5115 
5116 send_message:
5117 
5118  // sign the ledger
5119  pResponseLedger->SignContract(server_->m_nymServer);
5120  pResponseLedger->SaveContract();
5121  // extract the ledger in ascii-armored form
5122  OTString strPayload(*pResponseLedger);
5123  // now the outgoing message has the response ledger in its payload.
5124  msgOut.m_ascPayload.SetString(strPayload);
5125 
5126  // todo: consider commenting this out since the transaction reply items
5127  // already include a copy
5128  // of the original client communication that the server is responding to. No
5129  // point beating a
5130  // dead horse.
5131  //
5132  // Send the user's command back to him as well.
5133  {
5134  OTString tempInMessage(MsgIn);
5135  msgOut.m_ascInReferenceTo.SetString(tempInMessage);
5136  }
5137 
5138  // UPDATE NYMBOX HASH IN OUTGOING MESSAGE
5139  //
5140  // We already grabbed the server's NymboxHash near the top of this function,
5141  // and attached it to the outgoing reply message.
5142  //
5143  // However, the above block may have CHANGED this hash! Therefore, we grab
5144  // it
5145  // AGAIN, just in case. This way a failed message will receive the old hash,
5146  // and a successful message will receive the new hash.
5147  //
5148  bGotNymboxHashServerSide =
5149  theNym.GetNymboxHashServerSide(SERVER_ID, theSrvrNymboxHash);
5150  if (bGotNymboxHashServerSide) // theSrvrNymboxHash is the hash stored on the
5151  // server side
5152  theSrvrNymboxHash.GetString(msgOut.m_strNymboxHash);
5153 
5154  // (2) Sign the Message
5155  msgOut.SignContract(server_->m_nymServer);
5156 
5157  // (3) Save the Message (with signatures and all, back to its internal
5158  // member m_strRawFile.)
5159  //
5160  // FYI, SaveContract takes m_xmlUnsigned and wraps it with the signatures
5161  // and ------- BEGIN bookends
5162  // If you don't pass a string in, then SaveContract saves the new version to
5163  // its member, m_strRawFile
5164  msgOut.SaveContract();
5165 
5166  // (You are in UserCmdProcessNymbox.)
5167 
5168  // REPLY NOTICE TO NYMBOX
5169  //
5170  // Now that we signed / saved the reply message...
5171  //
5172  // After specific messages, we drop a notice with a copy of the server's
5173  // reply
5174  // into the Nymbox. This way we are GUARANTEED that the Nym will receive
5175  // and process
5176  // it. (And thus never get out of sync.)
5177  //
5178  if (msgOut.m_bSuccess) {
5179  const OTString strReplyMessage(msgOut);
5180  const int64_t lReqNum = atol(MsgIn.m_strRequestNum.Get());
5181 
5182  // If it fails, it logs already.
5183  DropReplyNoticeToNymbox(
5184  SERVER_ID, USER_ID, strReplyMessage,
5185  lReqNum, // (We don't want to update the NymboxHash on the Nym, here
5186  // in processNymbox, at least, not at this current point
5187  // AFTER the reply message has already been signed.)
5188  bTransSuccess);
5189  // DropReplyNoticeToNymbox(SERVER_ID, USER_ID,
5190  // strReplyMessage, lReqNum, bTransSuccess, &theNym); // Only pass
5191  // theNym if you want it to contain the LATEST hash. (Some messages
5192  // don't.)
5193  }
5194 }
5195 
5196 void UserCommandProcessor::UserCmdProcessInbox(OTPseudonym& theNym,
5197  OTMessage& MsgIn,
5198  OTMessage& msgOut)
5199 {
5200  // (1) set up member variables
5201  msgOut.m_strCommand = "@processInbox"; // reply to processInbox
5202  msgOut.m_strNymID = MsgIn.m_strNymID; // UserID
5203  // msgOut.m_strServerID = m_strServerID; // This is already set in
5204  // ProcessUserCommand.
5205  msgOut.m_strAcctID = MsgIn.m_strAcctID; // The Account ID in question
5206 
5207  const OTIdentifier USER_ID(msgOut.m_strNymID),
5208  ACCOUNT_ID(MsgIn.m_strAcctID), SERVER_ID(server_->m_strServerID),
5209  SERVER_USER_ID(server_->m_nymServer);
5210 
5211  OTLedger theLedger(USER_ID, ACCOUNT_ID, SERVER_ID); // These are ledgers
5212  // used as messages. The
5213  // one we received,
5214  // and the one we're sending back.
5215  std::unique_ptr<OTLedger> pResponseLedger(OTLedger::GenerateLedger(
5216  SERVER_USER_ID, ACCOUNT_ID, SERVER_ID, OTLedger::message, false));
5217  OT_ASSERT_MSG(nullptr != pResponseLedger, "UserCommandProcessor::"
5218  "UserCmdProcessInbox: ASSERT: "
5219  "nullptr != pResponseLedger");
5220  OTTransaction* pTranResponse = nullptr;
5221 
5222  // Grab the string (containing the request ledger) out of ascii-armored
5223  // form.
5224  OTString strLedger(MsgIn.m_ascPayload);
5225 
5226  bool bTransSuccess = false;
5227  const OTIdentifier theMsgNymboxHash(
5228  MsgIn.m_strNymboxHash); // theMsgNymboxHash is the hash sent by the
5229  // client side
5230  OTIdentifier theSrvrNymboxHash;
5231 
5232  bool bGotNymboxHashServerSide =
5233  theNym.GetNymboxHashServerSide(SERVER_ID, theSrvrNymboxHash);
5234 
5235  if (bGotNymboxHashServerSide) // theSrvrNymboxHash is the hash stored on the
5236  // server side
5237  theSrvrNymboxHash.GetString(msgOut.m_strNymboxHash);
5238  else {
5240  1, "%s: We cannot obtain server side nymbox hash, will continue.\n",
5241  __FUNCTION__);
5242  }
5243 
5244  const bool bGotNymboxHashClientSide = MsgIn.m_strNymboxHash.Exists();
5245 
5246  if (!bGotNymboxHashClientSide) {
5248  1, "%s: We don't have a client side nymbox hash, will continue\n",
5249  __FUNCTION__);
5250  }
5251 
5252  if (bGotNymboxHashServerSide && bGotNymboxHashClientSide)
5253  if (theMsgNymboxHash != theSrvrNymboxHash) {
5254  OTLog::vOutput(0, "%s: The server and client nymbox hashes "
5255  "missmatch! rejecting message.\n",
5256  __FUNCTION__);
5257  goto send_message;
5258  }
5259 
5260  // theLedger contains a single transaction from the client, with an item
5261  // inside
5262  // for each inbox transaction the client wants to accept or reject.
5263  // Let's see if we can load it from the string that came in the message...
5264  msgOut.m_bSuccess = theLedger.LoadContractFromString(strLedger);
5265  if (msgOut.m_bSuccess) {
5266  OTAccount theAccount(USER_ID, ACCOUNT_ID, SERVER_ID);
5267 
5268  // Make sure the "from" account even exists...
5269  if (!theAccount.LoadContract()) {
5270  const OTString strAcctID(ACCOUNT_ID);
5271  OTLog::vOutput(0, "UserCommandProcessor::UserCmdProcessInbox: "
5272  "Failed loading account: %s\n",
5273  strAcctID.Get());
5274  }
5275  // Make sure the account isn't marked for deletion.
5276  else if (theAccount.IsMarkedForDeletion()) {
5278  0, "UserCommandProcessor::UserCmdProcessInbox: Failed attempt "
5279  "to use an Asset account that was marked for "
5280  "deletion.\n");
5281  }
5282  // Make sure the Account ID loaded from the file matches the one we just
5283  // set and used as the filename.
5284  else if (!theAccount.VerifyContractID()) {
5285  // this should never happen. How did the wrong ID get into the
5286  // account file, if the right
5287  // ID is on the filename itself? and vice versa.
5288  OTLog::Error("Error verifying account ID in "
5289  "UserCommandProcessor::UserCmdProcessInbox\n");
5290  }
5291  // Make sure the nymID loaded up in the account as its actual owner
5292  // matches the nym who was
5293  // passed in to this function requesting a transaction on this
5294  // account... otherwise any asshole
5295  // could do transactions on your account, no?
5296  else if (!theAccount.VerifyOwner(theNym)) {
5297  OTLog::vOutput(0, "Failed verifying account ownership in "
5298  "UserCommandProcessor::UserCmdProcessInbox\n");
5299  }
5300  // Make sure I, the server, have signed this file.
5301  else if (!theAccount.VerifySignature(server_->m_nymServer)) {
5302  OTLog::Error("Error verifying server signature on account in "
5303  "UserCommandProcessor::UserCmdProcessInbox\n");
5304  }
5305  // No need to call VerifyAccount() here since the above calls go above
5306  // and beyond that method.
5307  else {
5308  // In this case we need to process the transaction items from the
5309  // ledger
5310  // and create a corresponding transaction where each of the new
5311  // items
5312  // contains the answer to the transaction item sent.
5313  // Then we send that new "response ledger" back to the user in
5314  // MsgOut.Payload
5315  // as an @processInbox message.
5316 
5317  OTTransaction* pTransaction =
5318  theLedger.GetTransaction(OTTransaction::processInbox);
5319 
5320  if (nullptr == pTransaction) // I'm assuming there's only one in the
5321  // ledger (for now anyways..)
5322  {
5323  OTLog::Error("Expected processInbox transaction in "
5324  "UserCommandProcessor::UserCmdProcessInbox\n");
5325  }
5326  else {
5327  const int64_t lTransactionNumber =
5328  pTransaction->GetTransactionNum();
5329 
5330  // We create a transaction response and add that to the response
5331  // ledger...
5332  //
5333  pTranResponse = OTTransaction::GenerateTransaction(
5334  *pResponseLedger, OTTransaction::error_state,
5335  lTransactionNumber);
5336  OT_ASSERT_MSG(nullptr != pTranResponse,
5337  "UserCommandProcessor::UserCmdProcessInbox: "
5338  "nullptr != pTranResponse");
5339 
5340  // Add the response transaction to the response ledger.
5341  // That will go into the response message and be sent back to
5342  // the client.
5343  pResponseLedger->AddTransaction(*pTranResponse);
5344 
5345  if (!server_->transactor_.verifyTransactionNumber(
5346  theNym, lTransactionNumber)) {
5347  // The user may not submit a transaction using a number he's
5348  // already used before.
5350  0, "UserCommandProcessor::UserCmdProcessInbox: Error "
5351  "verifying transaction num %ld for Nym "
5352  "%s\n",
5353  lTransactionNumber, msgOut.m_strNymID.Get());
5354  }
5355 
5356  // The items' acct and server ID were already checked in
5357  // VerifyContractID() when they were loaded.
5358  // Now this checks a little deeper, to verify ownership,
5359  // signatures, and transaction number
5360  // on each item. That way those things don't have to be checked
5361  // for security over and over
5362  // again in the subsequent calls.
5363  //
5364  else if (!pTransaction->VerifyItems(theNym)) {
5365  OTLog::Output(
5366  0, "Error verifying transaction items "
5367  "UserCommandProcessor::UserCmdProcessInbox\n");
5368  }
5369 
5370  // any other security stuff?
5371  // Todo do I need to verify the server ID here as well?
5372  else {
5373  // We don't want any transaction number being used twice.
5374  // (The number, at this point, is STILL issued to the user,
5375  // who is still responsible
5376  // for that number and must continue signing for it. All
5377  // this means here is that the
5378  // user no longer has the number on his AVAILABLE list.
5379  // Removal from issued list happens separately.)
5380  //
5381  if (false ==
5382  server_->transactor_.removeTransactionNumber(
5383  theNym, lTransactionNumber, true)) // bSave=true
5384  {
5385  OTLog::Error(
5386  "Error removing transaction number (as "
5387  "available) from user nym in "
5388  "UserCommandProcessor::UserCmdProcessInbox\n");
5389  }
5390  else {
5391  OTLog::Output(
5392  2, "UserCmdProcessInbox type: Process Inbox\n");
5393 
5394  server_->notary_.NotarizeProcessInbox(
5395  theNym, theAccount, *pTransaction, *pTranResponse,
5396  bTransSuccess);
5397  // Where appropriate, remove a transaction number from
5398  // my issued list
5399  // (the list of numbers I must sign for in every balance
5400  // agreement.)
5401 
5402  if (!server_->transactor_.removeIssuedNumber(
5403  theNym, lTransactionNumber,
5404  true)) // bSave=true
5405  {
5406  OTLog::vError("%s: Error removing issued number "
5407  "from user nym.\n",
5408  __FUNCTION__);
5409  }
5410  }
5411  }
5412  } // if pTransaction not nullptr
5413 
5414  // DONE: should consider saving a copy of the response ledger here
5415  // on the server.
5416  // Until the user signs off of the responses, maybe the user didn't
5417  // receive them.
5418  // The server should be able to re-send them until confirmation,
5419  // then delete them.
5420  // So might want to consider a SAVE TO FILE here of that ledger
5421  // we're sending out...
5422  // UPDATE this is done now: notices go to the Nymbox.
5423  }
5424  }
5425  else {
5426  OTLog::Error("ERROR loading ledger from message in "
5427  "UserCommandProcessor::UserCmdProcessInbox\n");
5428  }
5429 
5430 send_message:
5431 
5432  if (nullptr == pTranResponse) {
5433  pTranResponse = OTTransaction::GenerateTransaction(
5434  *pResponseLedger, OTTransaction::error_state, 0);
5435  OT_ASSERT_MSG(nullptr != pTranResponse, "UserCommandProcessor::"
5436  "UserCmdProcessInbox 2: "
5437  "nullptr != pTranResponse");
5438 
5439  // Add the response transaction to the response ledger.
5440  // That will go into the response message and be sent back to the
5441  // client.
5442  pResponseLedger->AddTransaction(*pTranResponse);
5443  }
5444 
5445  // sign the outoing transaction
5446  OT_ASSERT_MSG(nullptr != pTranResponse, "UserCommandProcessor::"
5447  "UserCmdProcessInbox 3: nullptr != "
5448  "pTranResponse");
5449 
5450  pTranResponse->ReleaseSignatures();
5451  pTranResponse->SignContract(server_->m_nymServer);
5452  pTranResponse->SaveContract(); // don't forget to save (to internal raw file
5453  // member)
5454 
5455  // sign the ledger
5456  pResponseLedger->SignContract(server_->m_nymServer);
5457  pResponseLedger->SaveContract();
5458  // extract the ledger in ascii-armored form
5459  OTString strPayload(*pResponseLedger);
5460  // now the outgoing message has the response ledger in its payload.
5461  msgOut.m_ascPayload.SetString(strPayload);
5462 
5463  // todo: consider commenting this out since the transaction reply items
5464  // already include a copy
5465  // of the original client communication that the server is responding to. No
5466  // point beating a
5467  // dead horse.
5468  //
5469  // Send the user's command back to him as well.
5470  {
5471  OTString tempInMessage(MsgIn);
5472  msgOut.m_ascInReferenceTo.SetString(tempInMessage);
5473  }
5474 
5475  // UPDATE NYMBOX HASH IN OUTGOING MESSAGE
5476  //
5477  // We already grabbed the server's NymboxHash near the top of this function,
5478  // and attached it to the outgoing reply message.
5479  //
5480  // However, the above block may have CHANGED this hash! Therefore, we grab
5481  // it
5482  // AGAIN, just in case. This way a failed message will receive the old hash,
5483  // and a successful message will receive the new hash.
5484  //
5485  bGotNymboxHashServerSide =
5486  theNym.GetNymboxHashServerSide(SERVER_ID, theSrvrNymboxHash);
5487  if (bGotNymboxHashServerSide) // theSrvrNymboxHash is the hash stored on the
5488  // server side
5489  theSrvrNymboxHash.GetString(msgOut.m_strNymboxHash);
5490 
5491  // (2) Sign the Message
5492  msgOut.SignContract(server_->m_nymServer);
5493 
5494  // (3) Save the Message (with signatures and all, back to its internal
5495  // member m_strRawFile.)
5496  //
5497  // FYI, SaveContract takes m_xmlUnsigned and wraps it with the signatures
5498  // and ------- BEGIN bookends
5499  // If you don't pass a string in, then SaveContract saves the new version to
5500  // its member, m_strRawFile
5501  msgOut.SaveContract();
5502 
5503  // (You are in UserCmdProcessInbox.)
5504 
5505  // REPLY NOTICE TO NYMBOX
5506  //
5507  // Now that we signed / saved the reply message...
5508  //
5509  // After specific messages, we drop a notice with a copy of the server's
5510  // reply
5511  // into the Nymbox. This way we are GUARANTEED that the Nym will receive
5512  // and process
5513  // it. (And thus never get out of sync.)
5514  //
5515  if (msgOut.m_bSuccess) {
5516  const OTString strReplyMessage(msgOut);
5517  const int64_t lReqNum = atol(MsgIn.m_strRequestNum.Get());
5518 
5519  // If it fails, it logs already.
5520  DropReplyNoticeToNymbox(SERVER_ID, USER_ID, strReplyMessage,
5521  lReqNum, // We don't want to update the
5522  // Nym's copy here in
5523  // processInbox (I don't think.)
5524  bTransSuccess);
5525  // DropReplyNoticeToNymbox(SERVER_ID, USER_ID,
5526  // strReplyMessage, lReqNum, bTransSuccess, &theNym);
5527  }
5528 }
5529 
5535 void UserCommandProcessor::UserCmdNotarizeTransactions(OTPseudonym& theNym,
5536  OTMessage& MsgIn,
5537  OTMessage& msgOut)
5538 {
5539  // (1) set up member variables
5540  msgOut.m_strCommand =
5541  "@notarizeTransactions"; // reply to notarizeTransactions
5542  msgOut.m_strNymID = MsgIn.m_strNymID; // UserID
5543  // msgOut.m_strServerID = m_strServerID; // This is already
5544  // set in ProcessUserCommand.
5545  msgOut.m_strAcctID = MsgIn.m_strAcctID; // The Account ID in question
5546 
5547  const OTIdentifier USER_ID(MsgIn.m_strNymID), ACCOUNT_ID(MsgIn.m_strAcctID),
5548  SERVER_ID(server_->m_strServerID), SERVER_USER_ID(server_->m_nymServer);
5549 
5550  OTLedger theLedger(USER_ID, ACCOUNT_ID, SERVER_ID); // These are ledgers
5551  // used as messages. The
5552  // one we received and
5553  // the one
5554  // that we're sending back in response.
5555  std::unique_ptr<OTLedger> pResponseLedger(OTLedger::GenerateLedger(
5556  SERVER_USER_ID, ACCOUNT_ID, SERVER_ID, OTLedger::message, false));
5557 
5558  bool bTransSuccess = false; // for the Nymbox notice.
5559  bool bCancelled = false; // for "failed" transactions that were actually
5560  // successful cancellations.
5561 
5562  int64_t lTransactionNumber = 0, lResponseNumber = 0;
5563  // Since the one going back (above) is a new ledger, we have to call
5564  // GenerateLedger.
5565  // Whereas the ledger we received from the server was generated there, so we
5566  // don't
5567  // have to generate it again. We just load it.
5568 
5569  OTString strLedger(MsgIn.m_ascPayload);
5570 
5571  const OTIdentifier theMsgNymboxHash(
5572  MsgIn.m_strNymboxHash); // theMsgNymboxHash is the hash sent by the
5573  // client side
5574  OTIdentifier theSrvrNymboxHash;
5575 
5576  bool bGotNymboxHashServerSide =
5577  theNym.GetNymboxHashServerSide(SERVER_ID, theSrvrNymboxHash);
5578 
5579  if (bGotNymboxHashServerSide) // theSrvrNymboxHash is the hash stored on the
5580  // server side
5581  theSrvrNymboxHash.GetString(msgOut.m_strNymboxHash);
5582  else {
5584  1, "%s: We cannot obtain server side nymbox hash, will continue.\n",
5585  __FUNCTION__);
5586  }
5587 
5588  const bool bGotNymboxHashClientSide = MsgIn.m_strNymboxHash.Exists();
5589 
5590  if (!bGotNymboxHashClientSide) {
5592  1, "%s: We don't have a client side nymbox hash, will continue\n",
5593  __FUNCTION__);
5594  }
5595 
5596  if (bGotNymboxHashServerSide && bGotNymboxHashClientSide)
5597  if (theMsgNymboxHash != theSrvrNymboxHash) {
5598  OTLog::vOutput(0, "%s: The server and client nymbox hashes "
5599  "missmatch! rejecting message.\n",
5600  __FUNCTION__);
5601  goto send_message;
5602  }
5603 
5604  // as long as the request ledger loads from the message into memory, success
5605  // is true
5606  // from there, the success or failure of the transactions within will be
5607  // carried in
5608  // their own status variables and those of the items inside those
5609  // transactions.
5610  msgOut.m_bSuccess = theLedger.LoadLedgerFromString(strLedger);
5611 
5612  if (msgOut.m_bSuccess) {
5613  // In this case we need to process the ledger items
5614  // and create a corresponding ledger where each of the new items
5615  // contains the answer to the ledger item sent.
5616  // Then we send that new "response ledger" back to the user in
5617  // MsgOut.Payload.
5618  // That is all done here. Until I write that, in the meantime,
5619  // let's just fprintf it out and see what it looks like.
5620  // OTLog::Error("Loaded ledger out of message payload:\n%s\n",
5621  // strLedger.Get());
5622  // OTLog::Error("Loaded ledger out of message payload.\n");
5623 
5624  // Loop through ledger transactions, and do a "NotarizeTransaction" call
5625  // for each one.
5626  // Inside that function it will do the various necessary authentication
5627  // and processing, not this one.
5628  // NOTE: In practice there is only ONE transaction, but in potential
5629  // there are many.
5630  // But so far, the code only actually has one, ever being sent.
5631  // Otherwise the messages
5632  // get too big IMO.
5633  //
5634  int32_t nCounter = 0;
5635  for (auto& it : theLedger.GetTransactionMap()) {
5636  OTTransaction* pTransaction = it.second;
5637  OT_ASSERT(nullptr != pTransaction);
5638  ++nCounter;
5639 
5640  if (1 != nCounter)
5641  OTLog::vError("WARNING: multiple transactions in a single "
5642  "message ledger.\n");
5643 
5644  // for each transaction in the ledger, we create a transaction
5645  // response and add
5646  // that to the response ledger.
5647 
5648  // I don't call transactor_.issueNextTransactionNumber here because
5649  // I'm not
5650  // creating a new transaction
5651  // in someone's inbox or outbox. Instead, I'm making a transaction
5652  // response to a transaction
5653  // request, with a MATCHING transaction number (so don't need to
5654  // issue a new one) to be sent
5655  // back to the client in a message.
5656  //
5657  // On this new "response transaction", I set the ACCT ID, the
5658  // serverID, and Transaction Number.
5659  OTTransaction* pTranResponse = OTTransaction::GenerateTransaction(
5660  *pResponseLedger, OTTransaction::error_state,
5661  pTransaction->GetTransactionNum());
5662  // Add the response transaction to the response ledger.
5663  // That will go into the response message and be sent back to the
5664  // client.
5665  pResponseLedger->AddTransaction(*pTranResponse);
5666 
5667  // Now let's make sure the response transaction has a copy of the
5668  // transaction
5669  // it is responding to.
5670  // OTString strResponseTo;
5671  // pTransaction->SaveContract(strResponseTo);
5672  // pTranResponse->m_ascInReferenceTo.SetString(strResponseTo);
5673  // I commented out the above because we are keeping too many copies.
5674  // Message contains a copy of the message it's responding to.
5675  // Then each transaction contains a copy of the transaction
5676  // responding to...
5677  // Then each ITEM in each transaction contains a copy of each item
5678  // it's responding to.
5679  //
5680  // Therefore, for the "notarizeTransactions" message, I have decided
5681  // (for now) to have
5682  // the extra copy in the items themselves, and in the overall
5683  // message, but not in the
5684  // transactions. Thus, the above is commented out.
5685 
5686  // It should always return something. Success, or failure, that goes
5687  // into pTranResponse.
5688  // I don't think there's need for more return value than that. The
5689  // user has gotten deep
5690  // enough that they deserve SOME sort of response.
5691  //
5692  // This function also SIGNS the transaction, so there is no need to
5693  // sign it after this.
5694  // There's also no point to change it after this, unless you plan to
5695  // sign it twice.
5696  //
5697  server_->notary_.NotarizeTransaction(theNym, *pTransaction,
5698  *pTranResponse, bTransSuccess);
5699 
5700  if (pTranResponse->IsCancelled()) bCancelled = true;
5701 
5702  lTransactionNumber = pTransaction->GetTransactionNum();
5703  lResponseNumber = pTranResponse->GetTransactionNum();
5704 
5705  OT_ASSERT_MSG(lTransactionNumber == lResponseNumber,
5706  "Transaction number and response number should "
5707  "always be the same. (But this time, they weren't.)");
5708 
5709  pTranResponse = nullptr; // at this point, the ledger now "owns" the
5710  // response, and will handle deleting it.
5711  }
5712 
5713  // TODO: should consider saving a copy of the response ledger here on
5714  // the server.
5715  // Until the user signs off of the responses, maybe the user didn't
5716  // receive them.
5717  // The server should be able to re-send them until confirmation, then
5718  // delete them.
5719  // So might want to consider a SAVE TO FILE here of that ledger we're
5720  // sending out...
5721 
5722  // sign the ledger
5723  pResponseLedger->SignContract(server_->m_nymServer);
5724  pResponseLedger->SaveContract();
5725 
5726  // extract the ledger in ascii-armored form
5727  OTString strPayload(*pResponseLedger);
5728 
5729  msgOut.m_ascPayload.SetString(strPayload); // now the outgoing message
5730  // has the response ledger in
5731  // its payload.
5732  }
5733  else {
5734  OTLog::Error("ERROR loading ledger from message in "
5735  "UserCommandProcessor::UserCmdNotarizeTransactions\n");
5736  }
5737 
5738 send_message:
5739  // todo: consider commenting this out since the transaction reply items
5740  // already include a copy
5741  // of the original client communication that the server is responding to. No
5742  // point beating a
5743  // dead horse.
5744  //
5745  // Send the user's command back to him as well.
5746  {
5747  OTString tempInMessage(MsgIn);
5748  msgOut.m_ascInReferenceTo.SetString(tempInMessage);
5749  }
5750 
5751  // UPDATE NYMBOX HASH IN OUTGOING MESSAGE
5752  //
5753  // We already grabbed the server's NymboxHash near the top of this function,
5754  // and attached it to the outgoing reply message.
5755  //
5756  // However, the above block may have CHANGED this hash! Therefore, we grab
5757  // it
5758  // AGAIN, just in case. This way a failed message will receive the old hash,
5759  // and a successful message will receive the new hash.
5760  //
5761  bGotNymboxHashServerSide =
5762  theNym.GetNymboxHashServerSide(SERVER_ID, theSrvrNymboxHash);
5763  if (bGotNymboxHashServerSide) // theSrvrNymboxHash is the hash stored on the
5764  // server side
5765  theSrvrNymboxHash.GetString(msgOut.m_strNymboxHash);
5766 
5767  // (2) Sign the Message
5768  msgOut.SignContract(server_->m_nymServer);
5769 
5770  // (3) Save the Message (with signatures and all, back to its internal
5771  // member m_strRawFile.)
5772  //
5773  // FYI, SaveContract takes m_xmlUnsigned and wraps it with the signatures
5774  // and ------- BEGIN bookends
5775  // If you don't pass a string in, then SaveContract saves the new version to
5776  // its member, m_strRawFile
5777  msgOut.SaveContract();
5778 
5779  // (You are in UserCmdNotarizeTransactions.)
5780 
5781  // REPLY NOTICE TO NYMBOX
5782  //
5783  // Now that we signed / saved the reply message...
5784  //
5785  // After EVERY / ANY transaction, we drop a notice with a copy of the
5786  // server's reply
5787  // into the Nymbox. This way we are GUARANTEED that the Nym will receive
5788  // and process
5789  // it. (And thus never get out of sync.)
5790  //
5791  if (msgOut.m_bSuccess) {
5792  const OTString strReplyMessage(msgOut);
5793  const int64_t lReqNum = atol(MsgIn.m_strRequestNum.Get());
5794 
5795  // If it fails, it logs already.
5796  // DropReplyNoticeToNymbox(SERVER_ID, USER_ID,
5797  // strReplyMessage, lReqNum, bTransSuccess, &theNym); // We don't want
5798  // to update the Nym in this case (I don't think.)
5799  DropReplyNoticeToNymbox(SERVER_ID, USER_ID, strReplyMessage, lReqNum,
5800  bTransSuccess); // trans success
5801  }
5802  if (bCancelled) {
5803  OTLog::vOutput(0, "Success: canceling transaction %ld for nym: %s \n",
5804  lTransactionNumber, msgOut.m_strNymID.Get());
5805  }
5806  else if (bTransSuccess) {
5807  OTLog::vOutput(0, "Success: processing transaction %ld for nym: %s \n",
5808  lTransactionNumber, msgOut.m_strNymID.Get());
5809  }
5810  else {
5811  OTLog::vOutput(0, "Failure: processing transaction %ld for nym: %s \n",
5812  lTransactionNumber, msgOut.m_strNymID.Get());
5813  }
5814 }
5815 
5816 // msg, the request msg from payer, which is attached WHOLE to the Nymbox
5817 // receipt. contains payment already.
5818 // or pass pPayment instead: we will create our own msg here (with payment
5819 // inside) to be attached to the receipt.
5820 bool UserCommandProcessor::SendMessageToNym(
5821  const OTIdentifier& SERVER_ID, const OTIdentifier& SENDER_USER_ID,
5822  const OTIdentifier& RECIPIENT_USER_ID,
5823  OTMessage* pMsg, // the request msg from payer, which is attached
5824  // WHOLE to the Nymbox receipt. contains message
5825  // already.
5826  const OTString* pstrMessage) // or pass this instead: we will
5827  // create our own msg here (with
5828  // message inside) to be attached to
5829  // the receipt.
5830 {
5831  return server_->DropMessageToNymbox(
5832  SERVER_ID, SENDER_USER_ID, RECIPIENT_USER_ID, OTTransaction::message,
5833  pMsg, pstrMessage); //, szCommand=nullptr
5834 }
5835 
5836 // After EVERY / ANY transaction, plus certain messages, we drop a copy of the
5837 // server's reply into
5838 // the Nymbox. This way we are GUARANTEED that the Nym will receive and process
5839 // it. (And thus
5840 // never get out of sync.) This is the function used for doing that.
5841 //
5842 void UserCommandProcessor::DropReplyNoticeToNymbox(
5843  const OTIdentifier& SERVER_ID, const OTIdentifier& USER_ID,
5844  const OTString& strMessage, const int64_t& lRequestNum,
5845  const bool bReplyTransSuccess, OTPseudonym* pActualNym)
5846 {
5847  OTLedger theNymbox(USER_ID, USER_ID, SERVER_ID);
5848 
5849  bool bSuccessLoadingNymbox = theNymbox.LoadNymbox();
5850 
5851  if (true == bSuccessLoadingNymbox)
5852  bSuccessLoadingNymbox =
5853  (theNymbox.VerifyContractID() &&
5854  theNymbox.VerifySignature(server_->m_nymServer));
5855  // bSuccessLoadingNymbox =
5856  // theNymbox.VerifyAccount(server_->m_nymServer);
5857  // // make sure it's all good.
5858 
5859  if (!bSuccessLoadingNymbox) {
5860  const OTString strNymID(USER_ID);
5861  OTLog::vOutput(0, "OTServer::DropReplyNoticeToNymbox: Failed loading "
5862  "or verifying Nymbox for user: %s\n",
5863  strNymID.Get());
5864  }
5865  else {
5866  int64_t lReplyNoticeTransNum = 0;
5867  bool bGotNextTransNum = server_->transactor_.issueNextTransactionNumber(
5868  server_->m_nymServer, lReplyNoticeTransNum,
5869  false); // bool bStoreTheNumber = false
5870 
5871  if (!bGotNextTransNum) {
5872  lReplyNoticeTransNum = 0;
5873  OTLog::Error("OTServer::DropReplyNoticeToNymbox: Error getting "
5874  "next transaction number for an "
5875  "OTTransaction::replyNotice.\n");
5876  }
5877  else { // Drop in the Nymbox
5878  //
5879  OTTransaction* pReplyNotice = OTTransaction::GenerateTransaction(
5880  theNymbox, OTTransaction::replyNotice, lReplyNoticeTransNum);
5881  OT_ASSERT(nullptr != pReplyNotice);
5882  OTItem* pReplyNoticeItem = OTItem::CreateItemFromTransaction(
5883  *pReplyNotice, OTItem::replyNotice);
5884  OT_ASSERT(nullptr != pReplyNoticeItem);
5885  pReplyNoticeItem->SetStatus(
5886  OTItem::acknowledgement); // Nymbox notice is always a success.
5887  // It's just a notice. (The message
5888  // inside it will have success/failure
5889  // also, and any transaction inside
5890  // that will also.)
5891  pReplyNoticeItem->SetAttachment(
5892  strMessage); // Purpose of this notice is to carry a copy of
5893  // server's reply message (to certain requests,
5894  // including all transactions.)
5895  pReplyNoticeItem->SignContract(server_->m_nymServer);
5896  pReplyNoticeItem->SaveContract();
5897  pReplyNotice->AddItem(*pReplyNoticeItem); // the Transaction's
5898  // destructor will cleanup
5899  // the item. It "owns" it
5900  // now.
5901  // So the client-side can quickly/easily match up the replyNotices
5902  // in
5903  // the Nymbox with the request numbers of the messages that were
5904  // sent.
5905  // I think this is actually WHY the server message low-level
5906  // functions
5907  // now RETURN the request number.
5908  // FYI: replyNotices will ONLY be in my Nymbox if the MESSAGE was
5909  // successful.
5910  // (Meaning, the balance agreement might have failed, and the
5911  // transaction
5912  // might have failed, but the MESSAGE ITSELF must be a success, in
5913  // order for
5914  // the replyNotice to appear in the Nymbox.)
5915  //
5916  pReplyNotice->SetRequestNum(lRequestNum);
5917  pReplyNotice->SetReplyTransSuccess(bReplyTransSuccess);
5918  pReplyNotice->SignContract(server_->m_nymServer);
5919  pReplyNotice->SaveContract();
5920  theNymbox.AddTransaction(*pReplyNotice); // Add the replyNotice to
5921  // the nymbox. It takes
5922  // ownership.
5923  theNymbox.ReleaseSignatures();
5924  theNymbox.SignContract(server_->m_nymServer);
5925  theNymbox.SaveContract();
5926 
5927  OTIdentifier NYMBOX_HASH;
5928  theNymbox.SaveNymbox(&NYMBOX_HASH);
5929 
5930  pReplyNotice->SaveBoxReceipt(theNymbox);
5931 
5932  if ((nullptr != pActualNym) && pActualNym->CompareID(USER_ID)) {
5933  pActualNym->SetNymboxHashServerSide(NYMBOX_HASH);
5934  pActualNym->SaveSignedNymfile(server_->m_nymServer);
5935  }
5936  else if (nullptr != pActualNym)
5937  OTLog::Error("OTServer::DropReplyNoticeToNymbox: ERROR: "
5938  "pActualNym was not nullptr, but it didn't match "
5939  "USER_ID.\n");
5940  }
5941  }
5942 }
5943 
5944 } // namespace opentxs
static EXPORT void vError(const char *szError,...)
Definition: OTLog.cpp:800
EXPORT bool StorePlainString(std::string strContents, std::string strFolder, std::string oneStr="", std::string twoStr="", std::string threeStr="")
Definition: OTStorage.cpp:698
OTASCIIArmor m_ascPayload2
Definition: OTMessage.hpp:218
static EXPORT OTAsymmetricKey * KeyFactory()
EXPORT Storable * CreateObject(StoredObjectType eType)
Definition: OTStorage.cpp:530
EXPORT bool SetPublicKey(const OTString &strKey, bool bEscaped=true)
static EXPORT OTTransaction * GenerateTransaction(const OTIdentifier &theUserID, const OTIdentifier &theAccountID, const OTIdentifier &theServerID, transactionType theType, int64_t lTransactionNum=0)
static EXPORT void Output(int32_t nVerbosity, const char *szOutput)
Definition: OTLog.cpp:710
virtual EXPORT bool SignContract(const OTPseudonym &theNym, const OTPasswordData *pPWData=nullptr)
Definition: OTMessage.cpp:3873
static EXPORT Mint * MintFactory()
Definition: Mint.cpp:154
OTString m_strAcctID
Definition: OTMessage.hpp:205
EXPORT bool LoadFromString(const OTString &strNym, OTString::Map *pMapCredentials=nullptr, OTString *pstrReason=nullptr, const OTPassword *pImportPassword=nullptr)
virtual EXPORT bool VerifySignature(const OTPseudonym &theNym, const OTPasswordData *pPWData=nullptr) const
Definition: OTMessage.cpp:3898
EXPORT void GetIdentifier(OTIdentifier &theIdentifier) const
static EXPORT const OTString & Pubcred()
Definition: OTFolders.cpp:343
EXPORT void SetAcknowledgments(OTPseudonym &theNym)
Definition: OTMessage.cpp:262
static bool __cmd_create_asset_acct
virtual EXPORT bool VerifyAccount(const OTPseudonym &theNym)
Definition: OTLedger.cpp:187
static const std::string & GetOverrideNymID()
bool issueNextTransactionNumber(OTPseudonym &nym, int64_t &txNumber, bool storeNumber=true)
Definition: Transactor.cpp:211
EXPORT bool DeleteBoxReceipt(OTLedger &theLedger)
EXPORT bool SaveContract()
static EXPORT OTAccount * GenerateNewAccount(const OTIdentifier &userId, const OTIdentifier &serverId, const OTPseudonym &serverNym, const OTMessage &message, AccountType acctType=simple, int64_t stashTransNum=0)
Definition: OTAccount.cpp:531
bool verifyTransactionNumber(OTPseudonym &nym, const int64_t &transactionNumber)
Definition: Transactor.cpp:278
EXPORT const OTAsymmetricKey & GetPublicEncrKey() const
EXPORT bool SaveContractRaw(OTString &strOutput) const
std::map< std::string, OTClause * > mapOfClauses
Definition: OTBylaw.hpp:145
void SetPublicKey(const OTString &publicKey)
EXPORT bool LoadSignedNymfile(OTPseudonym &SIGNER_NYM)
EXPORT OTCronItem * GetItemByValidOpeningNum(int64_t lOpeningNum)
Definition: OTCron.cpp:968
EXPORT bool VerifyWithKey(const OTAsymmetricKey &theKey, const OTPasswordData *pPWData=nullptr) const
Definition: OTContract.cpp:848
bool IsMarkedForDeletion() const
bool lookupBasketAccountID(const OTIdentifier &basketId, OTIdentifier &basketAccountId)
Definition: Transactor.cpp:511
EXPORT bool WriteArmoredString(OTString &strOutput, const std::string str_type, bool bEscaped=false) const
static EXPORT const OTString & Contract()
Definition: OTFolders.cpp:303
EXPORT const int64_t & GetUsageCredits() const
static EXPORT const OTString & UserAcct()
Definition: OTFolders.cpp:379
bool removeTransactionNumber(OTPseudonym &nym, const int64_t &transactionNumber, bool save=false)
Definition: Transactor.cpp:320
EXPORT bool LoadNymbox()
Definition: OTLedger.cpp:482
EXPORT bool VerifyPseudonym() const
static EXPORT OTItem * CreateItemFromTransaction(const OTTransaction &theOwner, OTItem::itemType theType, const OTIdentifier *pDestinationAcctID=nullptr)
Definition: OTItem.cpp:1451
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
void NotarizeProcessNymbox(OTPseudonym &nym, OTTransaction &tranIn, OTTransaction &tranOut, bool &outSuccess)
Definition: Notary.cpp:7402
static EXPORT void Error(const char *szError)
Definition: OTLog.cpp:831
EXPORT bool SetPublicKey(const OTASCIIArmor &strKey)
EXPORT void Format(const char *fmt,...)
Definition: OTString.cpp:1319
EXPORT bool LoadPublicKey()
EXPORT bool Compare(const char *compare) const
Definition: OTString.cpp:1102
void NotarizeProcessInbox(OTPseudonym &nym, OTAccount &account, OTTransaction &tranIn, OTTransaction &tranOut, bool &outSuccess)
Definition: Notary.cpp:8088
OTNumList m_AcknowledgedReplies
Definition: OTMessage.hpp:225
EXPORT void Set(const char *data, uint32_t enforcedMaxLength=0)
Definition: OTString.cpp:1055
EXPORT bool GetPublicKey(OTASCIIArmor &strKey) const
OTString m_strNymID2
Definition: OTMessage.hpp:200
bool removeIssuedNumber(OTPseudonym &nym, const int64_t &transactionNumber, bool save=false)
Definition: Transactor.cpp:354
EXPORT bool Output(std::set< int64_t > &theOutput) const
Definition: OTNumList.cpp:430
EXPORT bool GetCurrentRequestNum(const OTString &strServerID, int64_t &lReqNum) const
EXPORT void SetUsageCredits(const int64_t &lUsage)
#define OT_ASSERT(x)
Definition: Assert.hpp:150
EXPORT bool AddAcknowledgedNum(const OTString &strServerID, const int64_t &lRequestNum)
#define OT_ASSERT_MSG(x, s)
Definition: Assert.hpp:155
EXPORT bool RemoveAcknowledgedNum(OTPseudonym &SIGNER_NYM, const OTString &strServerID, const int64_t &lRequestNum, bool bSave)
static EXPORT OTLedger * GenerateLedger(const OTIdentifier &theUserID, const OTIdentifier &theAcctID, const OTIdentifier &theServerID, ledgerType theType, bool bCreateFile=false)
Definition: OTLedger.cpp:946
OTASCIIArmor m_ascInReferenceTo
Definition: OTMessage.hpp:211
EXPORT bool CompareID(const OTIdentifier &theIdentifier) const
EXPORT int32_t Count() const
Definition: OTNumList.cpp:460
static bool __cmd_get_nym_market_offers
bool addAssetContract(OTAssetContract &contract)
Definition: Transactor.cpp:411
EXPORT bool SaveNymbox(OTIdentifier *pNymboxHash=nullptr)
Definition: OTLedger.cpp:801
OTAssetContract * getAssetContract(const OTIdentifier &id)
Definition: Transactor.cpp:394
OTString m_strServerID
Definition: OTMessage.hpp:191
EXPORT const OTAsymmetricKey & GetPublicSignKey() const
EXPORT bool SavePseudonym()
EXPORT int32_t GetAcknowledgedNumCount(const OTIdentifier &theServerID) const
EXPORT const char * Get() const
Definition: OTString.cpp:1045
virtual EXPORT bool SignContract(const OTPseudonym &theNym, const OTPasswordData *pPWData=nullptr)
Definition: OTContract.cpp:484
EXPORT bool GetRecentTradeList(OTASCIIArmor &ascOutput, int32_t &nTradeCount)
Definition: OTMarket.cpp:408
EXPORT int64_t GetTransactionNum() const
std::map< std::string, std::string > the_map
Definition: OTStorage.hpp:981
OTString m_strRequestNum
Definition: OTMessage.hpp:207
OTASCIIArmor m_ascPayload
Definition: OTMessage.hpp:214
static bool __cmd_create_user_acct
EXPORT const OTIdentifier & GetConstID() const
EXPORT bool Verify(const int64_t &theValue) const
Definition: OTNumList.cpp:322
OTString m_strCommand
Definition: OTMessage.hpp:189
virtual EXPORT bool VerifyContractID() const
EXPORT int64_t GetAcknowledgedNum(const OTIdentifier &theServerID, int32_t nIndex) const
bool ProcessUserCommand(OTMessage &msgIn, OTMessage &msgOut, ClientConnection *connection, OTPseudonym *nym)
EXPORT Storable * DecodeObject(StoredObjectType theObjectType, std::string strInput)
Definition: OTStorage.cpp:830
EXPORT bool GetMarketList(OTASCIIArmor &ascOutput, int32_t &nMarketCount)
Definition: OTCron.cpp:281
EXPORT bool GetNym_OfferList(OTASCIIArmor &ascOutput, const OTIdentifier &NYM_ID, int32_t &nOfferCount)
Definition: OTCron.cpp:204
void NotarizeTransaction(OTPseudonym &nym, OTTransaction &tranIn, OTTransaction &tranOut, bool &outSuccess)
Definition: Notary.cpp:7023
#define OT_ENFORCE_PERMISSION_MSG(BOOL_VAR_NAME)
Definition: Macros.hpp:151
EXPORT OTMarket * GetMarket(const OTIdentifier &MARKET_ID)
Definition: OTCron.cpp:1110
static bool __cmd_get_market_offers
static bool __cmd_notarize_transaction
OTString m_strNymPublicKey
Definition: OTMessage.hpp:202
static EXPORT void vOutput(int32_t nVerbosity, const char *szOutput,...)
Definition: OTLog.cpp:768
static EXPORT OTAccount * LoadExistingAccount(const OTIdentifier &accountId, const OTIdentifier &serverId)
Definition: OTAccount.cpp:480
virtual EXPORT void Release()
Definition: OTString.cpp:765
EXPORT bool VerifyAcknowledgedNum(const OTString &strServerID, const int64_t &lRequestNum) const
bool addBasketAccountID(const OTIdentifier &basketId, const OTIdentifier &basketAccountId, const OTIdentifier &basketContractId)
Definition: Transactor.cpp:432
EXPORT bool SaveSignedNymfile(OTPseudonym &SIGNER_NYM)
EXPORT void IncrementRequestNum(OTPseudonym &SIGNER_NYM, const OTString &strServerID)
static bool __cmd_get_market_recent_trades