bool OTToken::RecordTokenAsSpent(OTString & theCleartextToken) { OTString strAssetID(GetAssetID()); // ---------------------------------------------------------------------------- // Calculate the filename (a hash of the Lucre cleartext token ID) OTIdentifier theTokenHash; theTokenHash.CalculateDigest(theCleartextToken); // Grab the new hash into a string (for use as a filename) OTString strTokenHash(theTokenHash); OTString strAssetFolder; strAssetFolder.Format("%s.%d", strAssetID.Get(), GetSeries()); // -------------------------------------------------------------------- // See if the spent token file ALREADY EXISTS... bool bTokenIsPresent = OTDB::Exists(OTLog::SpentFolder(), strAssetFolder.Get(), strTokenHash.Get()); // If so, we're trying to record a token that was already recorded... if (bTokenIsPresent) { OTLog::vError("OTToken::RecordTokenAsSpent: Trying to record token as spent," " but it was already recorded: %s%s%s%s%s\n", OTLog::SpentFolder(), OTLog::PathSeparator(), strAssetFolder.Get(), OTLog::PathSeparator(), strTokenHash.Get()); return false; } // ---------------------------------------------------------------------- // FINISHED: // We actually save the token itself into the file, which is named based // on a hash of the Lucre data. // The success of that operation is also now the success of this one. OTString strToken; SaveContract(strToken); bool bSaved = OTDB::StorePlainString(strToken.Get(), OTLog::SpentFolder(), strAssetFolder.Get(), strTokenHash.Get()); if (!bSaved) { OTLog::vError("OTToken::RecordTokenAsSpent: Error saving file: %s%s%s%s%s\n", OTLog::SpentFolder(), OTLog::PathSeparator(), strAssetFolder.Get(), OTLog::PathSeparator(), strTokenHash.Get()); } return bSaved; }
// Most contracts calculate their ID by hashing the Raw File (signatures and all). // The Basket only hashes the unsigned contents, and only with the account IDs removed. // This way, the basket will produce a consistent ID across multiple different servers. void OTBasket::CalculateContractID(OTIdentifier & newID) { const OTString strContents(m_xmlUnsigned); // Produce a version of the file without account IDs (which are different from server to server.) // m_bHideAccountID = true; UpdateContents(); // <========= newID.CalculateDigest(m_xmlUnsigned); // Put it back the way it was. m_bHideAccountID = false; // UpdateContents(); // No need to do this, we already had this string before (above). m_xmlUnsigned = strContents; // Here we just set it back again. }
// Note: ALL failures will return true, even if the token has NOT already been // spent, and the failure was actually due to a directory creation error. Why, // you might ask? Because no matter WHAT is causing the failure, any return of // false is a signal that the token is SAFE TO ACCEPT AS TENDER. If there was a // temporary file system error, someone could suddenly deposit the same token // over and over again and this method would return "false" (Token is "not already // spent.") // // We simply cannot risk that, so false is not returned unless execution reaches // the very bottom of this method. Every other error acts as if the token is // no good, for security reasons. If the token really IS good, the user can submit // it again later and it will work. // bool OTToken::IsTokenAlreadySpent(OTString & theCleartextToken) { OTString strAssetID(GetAssetID()); // ---------------------------------------------------------------------------- // Calculate the filename (a hash of the Lucre cleartext token ID) OTIdentifier theTokenHash; theTokenHash.CalculateDigest(theCleartextToken); // Grab the new hash into a string (for use as a filename) OTString strTokenHash(theTokenHash); // ---------------------------------------------------------------------------- OTString strAssetFolder; strAssetFolder.Format("%s.%d", strAssetID.Get(), GetSeries()); bool bTokenIsPresent = OTDB::Exists(OTLog::SpentFolder(), strAssetFolder.Get(), strTokenHash.Get()); // -------------------------------------------------------------------- if (bTokenIsPresent) { OTLog::vOutput(0, "\nOTToken::IsTokenAlreadySpent: Token was already spent: %s%s%s%s%s\n", OTLog::SpentFolder(), OTLog::PathSeparator(), strAssetFolder.Get(), OTLog::PathSeparator(), strTokenHash.Get()); return true; // all errors must return true in this function. // But this is not an error. Token really WAS already } // spent, and this true is for real. The others are just // for security reasons because of this one. // This is the ideal case: the token was NOT already spent, it was good, // so we can return false and the depositor can be credited appropriately. // IsTokenAlreadySpent? NO-it was NOT already spent. You can only POSSIBLY // get a false out of this method if you actually reached the bottom (here.) return false; }
// This method implements the SAMY hash bool OTIdentifier::CalculateDigest(const OTData & dataInput) { //#ifndef ANDROID // SHA256 on Android; no whirlpool until OpenSSL 1.0.0 is added. OTIdentifier idSecondHash; if (idSecondHash.CalculateDigest(dataInput, HashAlgorithm2) && CalculateDigest(dataInput, HashAlgorithm1)) { // At this point, we have successfully generated the WHRLPOOL hash in // idSecondHash, and we've successfully generated the SHA-256 hash in // this object. // Next we XOR them together for the final product. return XOR(idSecondHash); } //#else // ANDROID // if (CalculateDigest(dataInput, HashAlgorithm1)) // SHA256 only until I add the new OpenSSL 1.0 for Android // { // return true; // } //#endif // ANDROID return false; }
// This method implements the SAMY hash bool OTIdentifier::CalculateDigest(const OTString & strInput) { #ifndef ANDROID // If NOT Android... OTIdentifier idSecondHash; if (idSecondHash.CalculateDigest(strInput, HashAlgorithm2) && CalculateDigest(strInput, HashAlgorithm1)) { // At this point, we have successfully generated the WHRLPOOL hash in // idSecondHash, and we've successfully generated the SHA-256 hash in // this object. // Next we XOR them together for the final product. return XOR(idSecondHash); } #else // SHA256 on Android; no whirlpool until OpenSSL 1.0.0 is added. if (CalculateDigest(strInput, HashAlgorithm1)) { return true; } #endif // ANDROID return false; }
// The above method uses this one internally... bool OTAccount::GenerateNewAccount(const OTPseudonym & theServer, const OTMessage & theMessage, const OTAccount::AccountType eAcctType/*=OTAccount::simple*/) { // First we generate a secure random number into a binary object. OTPayload thePayload; thePayload.SetPayloadSize(100); if (!RAND_bytes((unsigned char*)thePayload.GetPayloadPointer(), 100)) { OTLog::Error("The PRNG is not seeded!\n"); // abort( ); return false; } // Next we calculate that binary object into a message digest (an OTIdentifier). OTIdentifier newID; if (!newID.CalculateDigest(thePayload)) { OTLog::Error("Error generating new account ID.\n"); return false; } // Next we get that digest (which is a binary hash number) // and extract a human-readable standard string format of that hash, // into an OTString. OTString strID(newID); SetRealAccountID(newID); // Set the account number based on what we just generated. SetPurportedAccountID(newID); // Might as well set them both. (Safe here to do so, for once.) m_strName.Set(strID); // So it's not blank. The user can always change it. // Next we create the full path filename for the account using the ID. m_strFilename.Format("%s%s%s%s%s", OTLog::Path(), OTLog::PathSeparator(), OTLog::AccountFolder(), OTLog::PathSeparator(), strID.Get()); // Then we try to load it, in order to make sure that it doesn't already exist. if (LoadContractRawFile()) { OTLog::Error("Error generating new account ID, account already exists.\n"); return false; } // Set up the various important starting values of the account. m_AcctType = eAcctType; // account type defaults to OTAccount::simple. But there are also issuer accts... // for basket accounts, the server is the user. if (OTAccount::basket == eAcctType) { theServer.GetIdentifier(m_AcctUserID); } else { m_AcctUserID.SetString(theMessage.m_strNymID); } m_AcctAssetTypeID.SetString(theMessage.m_strAssetID); OTString TEMPstr(m_AcctAssetTypeID); OTLog::vOutput(3, "Creating new account, type:\n%s\nChanged to ID then back to string:\n%s\n", theMessage.m_strAssetID.Get(), TEMPstr.Get()); OTIdentifier SERVER_ID(theMessage.m_strServerID); SetRealServerID(SERVER_ID); // todo this assumes the serverID on the message is correct. It's vetted, but still... SetPurportedServerID(SERVER_ID); const time_t tDate = time(NULL); // Today, now. m_BalanceDate.Format("%d", tDate); m_BalanceAmount.Set("0"); // Sign the Account (so we know that we did)... Otherwise someone could put a fake // account file on the server if the code wasn't designed to verify the signature on the // account. SignContract(theServer); SaveContract(); // Save the Account to storage (based on its ID.) SaveAccount(); // Don't know why I had this here. Putting SaveAccount() instead. // OTString strFilename(m_strFilename); // SaveContract(strFilename.Get()); // Saves the account to a specific filename // No need to create the inbox and outbox ledgers...they will be created automatically // if they do not exist when they are needed. return true; }
int main (int argc, char **argv) { OTLog::vOutput(0, "\n\nWelcome to Open Transactions... Test Client -- version %s\n" "(transport build: OTMessage -> TCP -> SSL)\n" "IF YOU PREFER TO USE ZMQ (message based), then rebuild from main folder like this:\n" "cd ..; make clean; make\n\n", OTLog::Version()); OT_API::InitOTAPI(); // ----------------------------------------------------------------------- // The beginnings of an INI file!! OTString strPath; { CSimpleIniA ini; // We're assuming this file is on the path. SI_Error rc = ini.LoadFile("./.ot_ini"); // todo: stop hardcoding. if (rc >=0) { const char * pVal = ini.GetValue("paths", "client_path", SERVER_PATH_DEFAULT); // todo stop hardcoding. if (NULL != pVal) strPath.Set(pVal); else strPath.Set(SERVER_PATH_DEFAULT); } else { strPath.Set(SERVER_PATH_DEFAULT); } } // ----------------------------------------------------------------------- OTString strCAFile, strKeyFile, strSSLPassword; if (argc < 2) { OTLog::vOutput(0, "\n==> USAGE: %s <SSL-password> <absolute_path_to_data_folder>\n\n" #if defined (FELLOW_TRAVELER) "(Password defaults to '%s' if left blank.)\n" "(Folder defaults to '%s' if left blank.)\n" #else "(The test password is always 'test'.\n'cd data_folder' then 'pwd' to see the absolute path.)\n" #endif "\n\n", argv[0] #if defined (FELLOW_TRAVELER) , KEY_PASSWORD, strPath.Get() #endif ); #if defined (FELLOW_TRAVELER) strSSLPassword.Set(KEY_PASSWORD); OTString strClientPath(strPath.Get()); g_OT_API.Init(strClientPath); // SSL gets initialized in here, before any keys are loaded. #else exit(1); #endif } else if (argc < 3) { OTLog::vOutput(0, "\n==> USAGE: %s <SSL-password> <absolute_path_to_data_folder>\n\n" #if defined (FELLOW_TRAVELER) "(Folder defaults to '%s' if left blank.)\n" #endif "\n\n", argv[0] #if defined (FELLOW_TRAVELER) , strPath.Get() #endif ); #if defined (FELLOW_TRAVELER) strSSLPassword.Set(argv[1]); OTString strClientPath(strPath.Get()); g_OT_API.Init(strClientPath); // SSL gets initialized in here, before any keys are loaded. #else exit(1); #endif } else { strSSLPassword.Set(argv[1]); OTString strClientPath(argv[2]); g_OT_API.Init(strClientPath); // SSL gets initialized in here, before any keys are loaded. } OTLog::vOutput::(0, "Using as path to data folder: %s\n", OTLog::Path()); strCAFile. Format("%s%s%s", OTLog::Path(), OTLog::PathSeparator(), CA_FILE); strKeyFile.Format("%s%s%s", OTLog::Path(), OTLog::PathSeparator(), KEY_FILE); // ------------------------------------------------------------------------------ // // Basically, loop: // // 1) Present a prompt, and get a user string of input. Wait for that. // // 2) Process it out as an OTMessage to the server. It goes down the pipe. // // 3) Sleep for 1 second. // // 4) Awake and check for messages to be read in response from the server. // Loop. As long as there are any responses there, then process and handle // them all. // Then continue back up to the prompt at step (1). char buf[200] = ""; int retVal = 0; int nExpectResponse = 0; OTLog::Output(0, "You may wish to 'load' then 'connect' then 'stat'.\n"); OTLog::vOutput(4, "Starting client loop. u_header size in C code is %d.\n", OT_CMD_HEADER_SIZE); for(;;) { buf[0] = 0; // Making it fresh again. nExpectResponse = 0; // 1) Present a prompt, and get a user string of input. Wait for that. OTLog::Output(0, "\nWallet> "); if (NULL == fgets(buf, sizeof(buf)-10, stdin)) // Leaving myself 10 extra bytes at the end for safety's sake. break; OTLog::Output(0, ".\n..\n...\n....\n.....\n......\n.......\n........\n.........\n..........\n" "...........\n............\n.............\n"); // so we can process the user input std::string strLine = buf; // 1.5 The one command that doesn't involve a message to the server (so far) // is the command to load the wallet from disk (which we do before we can // do anything else.) That and maybe the message to CONNECT to the server. // Load wallet.xml if (strLine.compare(0,4,"load") == 0) { OTLog::Output(0, "User has instructed to load wallet.xml...\n"); g_OT_API.GetWallet()->LoadWallet("wallet.xml"); // g_OT_API.GetWallet()->SaveWallet("NEWwallet.xml"); // todo remove this test code. continue; } else if (strLine.compare(0,5,"clear") == 0) { if (NULL == g_pTemporaryNym) { OTLog::Output(0, "No Nym yet available. Try 'load'.\n"); continue; } g_pTemporaryNym->RemoveAllNumbers(); g_pTemporaryNym->SaveSignedNymfile(*g_pTemporaryNym); OTLog::Output(0, "Successfully removed all issued and transaction numbers. Saving nym...\n"); continue; } else if (strLine.compare(0,7,"payment") == 0) { if (NULL == g_pTemporaryNym) { OTLog::Output(0, "No Nym yet available to sign the payment plan with. Try 'load'.\n"); continue; } OTLog::Output(0, "Enter your Asset Account ID that the payments will come from: "); OTString strTemp; strTemp.OTfgets(std::cin); const OTIdentifier ACCOUNT_ID(strTemp), USER_ID(*g_pTemporaryNym); OTAccount * pAccount = g_OT_API.GetWallet()->GetAccount(ACCOUNT_ID); if (NULL == pAccount) { OTLog::Output(0, "That account isn't loaded right now. Try 'load'.\n"); continue; } // To write a payment plan, like a cheque, we need to burn one of our transaction numbers. (Presumably // the wallet is also storing a couple of these, since they are needed to perform any transaction.) // // I don't have to contact the server to write a payment plan -- as long as I already have a transaction // number I can use to write it. Otherwise I'd have to ask the server to send me one first. OTString strServerID(pAccount->GetRealServerID()); long lTransactionNumber=0; if (false == g_pTemporaryNym->GetNextTransactionNum(*g_pTemporaryNym, strServerID, lTransactionNumber)) { OTLog::Output(0, "Payment Plans are written offline, but you still need a transaction number\n" "(and you have none, currently.) Try using 'n' to request another transaction number.\n"); continue; } // ----------------------------------------------------------------------- OTString str_RECIPIENT_USER_ID, str_RECIPIENT_ACCT_ID, strConsideration; // Get the Recipient Nym ID OTLog::Output(0, "Enter the Recipient's User ID (NymID): "); str_RECIPIENT_USER_ID.OTfgets(std::cin); // THEN GET AN ACCOUNT ID in that same asset type OTLog::Output(0, "Enter the Recipient's ACCOUNT ID (of the same asset type as your account): "); str_RECIPIENT_ACCT_ID.OTfgets(std::cin); OTLog::Output(0, "Enter a memo describing consideration for the payment plan: "); strConsideration.OTfgets(std::cin); const OTIdentifier RECIPIENT_USER_ID(str_RECIPIENT_USER_ID), RECIPIENT_ACCT_ID(str_RECIPIENT_ACCT_ID); OTPaymentPlan thePlan(pAccount->GetRealServerID(), pAccount->GetAssetTypeID(), pAccount->GetRealAccountID(), pAccount->GetUserID(), RECIPIENT_ACCT_ID, RECIPIENT_USER_ID); // ----------------------------------------------------------------------- // Valid date range (in seconds) OTLog::Output(0, " 6 minutes == 360 Seconds\n" "10 minutes == 600 Seconds\n" "1 hour == 3600 Seconds\n" "1 day == 86400 Seconds\n" "30 days == 2592000 Seconds\n" "3 months == 7776000 Seconds\n" "6 months == 15552000 Seconds\n\n" ); long lExpirationInSeconds = 86400; OTLog::vOutput(0, "How many seconds before payment plan expires? (defaults to 1 day: %ld): ", lExpirationInSeconds); strTemp.Release(); strTemp.OTfgets(std::cin); if (strTemp.GetLength() > 1) lExpirationInSeconds = atol(strTemp.Get()); // ----------------------------------------------------------------------- time_t VALID_FROM = time(NULL); // This time is set to TODAY NOW OTLog::vOutput(0, "Payment plan becomes valid for processing STARTING date\n" "(defaults to now, in seconds) [%ld]: ", VALID_FROM); strTemp.Release(); strTemp.OTfgets(std::cin); if (strTemp.GetLength() > 2) VALID_FROM = atol(strTemp.Get()); const time_t VALID_TO = VALID_FROM + lExpirationInSeconds; // now + 86400 // ----------------------------------------------------------------------- bool bSuccessSetAgreement = thePlan.SetAgreement(lTransactionNumber, strConsideration, VALID_FROM, VALID_TO); if (!bSuccessSetAgreement) { OTLog::Output(0, "Failed trying to set the agreement!\n"); // IF FAILED, ADD TRANSACTION NUMBER BACK TO LIST OF AVAILABLE NUMBERS. g_pTemporaryNym->AddTransactionNum(*g_pTemporaryNym, strServerID, lTransactionNumber, true); // bSave=true continue; } bool bSuccessSetInitialPayment = true; // the default, in case user chooses not to even have this payment. bool bSuccessSetPaymentPlan = true; // the default, in case user chooses not to have a payment plan // ----------------------------------------------------------------------- OTLog::Output(0, "What is the Initial Payment Amount, if any? [0]: "); strTemp.Release(); strTemp.OTfgets(std::cin); long lInitialPayment = atol(strTemp.Get()); if (lInitialPayment > 0) { time_t PAYMENT_DELAY = 60; // 60 seconds. OTLog::vOutput(0, "From the Start Date forward, how long until the Initial Payment should charge?\n" "(defaults to one minute, in seconds) [%d]: ", PAYMENT_DELAY); strTemp.Release(); strTemp.OTfgets(std::cin); if ((strTemp.GetLength() > 1) && atol(strTemp.Get())>0) PAYMENT_DELAY = atol(strTemp.Get()); // ----------------------------------------------------------------------- bSuccessSetInitialPayment = thePlan.SetInitialPayment(lInitialPayment, PAYMENT_DELAY); } if (!bSuccessSetInitialPayment) { OTLog::Output(0, "Failed trying to set the initial payment!\n"); // IF FAILED, ADD TRANSACTION NUMBER BACK TO LIST OF AVAILABLE NUMBERS. g_pTemporaryNym->AddTransactionNum(*g_pTemporaryNym, strServerID, lTransactionNumber, true); // bSave=true continue; } // ----------------------------------------------------------------------- OTLog::Output(0, "What is the regular payment amount, if any? [0]: "); strTemp.Release(); strTemp.OTfgets(std::cin); long lRegularPayment = atol(strTemp.Get()); if (lRegularPayment > 0) // If there are regular payments. { // ----------------------------------------------------------------------- time_t PAYMENT_DELAY = 120; // 120 seconds. OTLog::vOutput(0, "From the Start Date forward, how long until the Regular Payments start?\n" "(defaults to two minutes, in seconds) [%d]: ", PAYMENT_DELAY); strTemp.Release(); strTemp.OTfgets(std::cin); if ((strTemp.GetLength() > 1) && atol(strTemp.Get())>0) PAYMENT_DELAY = atol(strTemp.Get()); // ----------------------------------------------------------------------- time_t PAYMENT_PERIOD = 30; // 30 seconds. OTLog::vOutput(0, "Once payments begin, how much time should elapse between each payment?\n" "(defaults to thirty seconds) [%d]: ", PAYMENT_PERIOD); strTemp.Release(); strTemp.OTfgets(std::cin); if ((strTemp.GetLength() > 1) && atol(strTemp.Get())>0) PAYMENT_PERIOD = atol(strTemp.Get()); // ----------------------------------------------------------------------- time_t PLAN_LENGTH = 0; // 0 seconds (for no max length). OTLog::vOutput(0, "From start date, do you want the plan to expire after a certain maximum time?\n" "(defaults to 0 for no) [%d]: ", PLAN_LENGTH); strTemp.Release(); strTemp.OTfgets(std::cin); if (strTemp.GetLength() > 1) PLAN_LENGTH = atol(strTemp.Get()); // ----------------------------------------------------------------------- OTLog::Output(0, "Should there be some maximum number of payments? (Zero for no maximum.) [0]: "); strTemp.Release(); strTemp.OTfgets(std::cin); int nMaxPayments = atoi(strTemp.Get()); bSuccessSetPaymentPlan = thePlan.SetPaymentPlan(lRegularPayment, PAYMENT_DELAY, PAYMENT_PERIOD, PLAN_LENGTH, nMaxPayments); } if (!bSuccessSetPaymentPlan) { OTLog::Output(0, "Failed trying to set the payment plan!\n"); // IF FAILED, ADD TRANSACTION NUMBER BACK TO LIST OF AVAILABLE NUMBERS. g_pTemporaryNym->AddTransactionNum(*g_pTemporaryNym, strServerID, lTransactionNumber, true); // bSave=true continue; } thePlan.SignContract(*g_pTemporaryNym); thePlan.SaveContract(); OTString strPlan(thePlan); OTLog::vOutput(0, "\n\n(Make sure Both Parties sign the payment plan before submitting to server):\n\n\n%s\n", strPlan.Get()); continue; } else if (strLine.compare(0,6,"cheque") == 0) { if (NULL == g_pTemporaryNym) { OTLog::Output(0, "No Nym yet available to sign the cheque with. Try 'load'.\n"); continue; } OTLog::Output(0, "Enter the ID for your Asset Account that the cheque will be drawn on: "); OTString strTemp; strTemp.OTfgets(std::cin); const OTIdentifier ACCOUNT_ID(strTemp), USER_ID(*g_pTemporaryNym); OTAccount * pAccount = g_OT_API.GetWallet()->GetAccount(ACCOUNT_ID); if (NULL == pAccount) { OTLog::Output(0, "That account isn't loaded right now. Try 'load'.\n"); continue; } // To write a cheque, we need to burn one of our transaction numbers. (Presumably the wallet // is also storing a couple of these, since they are needed to perform any transaction.) // // I don't have to contact the server to write a cheque -- as long as I already have a transaction // number I can use to write it. Otherwise I'd have to ask the server to send me one first. OTString strServerID(pAccount->GetRealServerID()); long lTransactionNumber=0; if (false == g_pTemporaryNym->GetNextTransactionNum(*g_pTemporaryNym, strServerID, lTransactionNumber)) { OTLog::Output(0, "Cheques are written offline, but you still need a transaction number\n" "(and you have none, currently.) Try using 'n' to request another transaction number.\n"); continue; } OTCheque theCheque(pAccount->GetRealServerID(), pAccount->GetAssetTypeID()); // Recipient OTLog::Output(0, "Enter a User ID for the recipient of this cheque (defaults to blank): "); OTString strRecipientUserID; strRecipientUserID.OTfgets(std::cin); const OTIdentifier RECIPIENT_USER_ID(strRecipientUserID.Get()); // Amount OTLog::Output(0, "Enter an amount: "); strTemp.Release(); strTemp.OTfgets(std::cin); const long lAmount = atol(strTemp.Get()); // ----------------------------------------------------------------------- // Memo OTLog::Output(0, "Enter a memo for your check: "); OTString strChequeMemo; strChequeMemo.OTfgets(std::cin); // ----------------------------------------------------------------------- // Valid date range (in seconds) OTLog::Output(0, " 6 minutes == 360 Seconds\n" "10 minutes == 600 Seconds\n" "1 hour == 3600 Seconds\n" "1 day == 86400 Seconds\n" "30 days == 2592000 Seconds\n" "3 months == 7776000 Seconds\n" "6 months == 15552000 Seconds\n\n" ); long lExpirationInSeconds = 3600; OTLog::vOutput(0, "How many seconds before cheque expires? (defaults to 1 hour: %ld): ", lExpirationInSeconds); strTemp.Release(); strTemp.OTfgets(std::cin); if (strTemp.GetLength() > 1) lExpirationInSeconds = atol(strTemp.Get()); // ----------------------------------------------------------------------- time_t VALID_FROM = time(NULL); // This time is set to TODAY NOW OTLog::vOutput(0, "Cheque may be cashed STARTING date (defaults to now, in seconds) [%ld]: ", VALID_FROM); strTemp.Release(); strTemp.OTfgets(std::cin); if (strTemp.GetLength() > 2) VALID_FROM = atol(strTemp.Get()); const time_t VALID_TO = VALID_FROM + lExpirationInSeconds; // now + 3600 // ----------------------------------------------------------------------- bool bIssueCheque = theCheque.IssueCheque(lAmount, lTransactionNumber, VALID_FROM, VALID_TO, ACCOUNT_ID, USER_ID, strChequeMemo, (strRecipientUserID.GetLength() > 2) ? &(RECIPIENT_USER_ID) : NULL); if (bIssueCheque) { theCheque.SignContract(*g_pTemporaryNym); theCheque.SaveContract(); OTString strCheque(theCheque); OTLog::vOutput(0, "\n\nOUTPUT:\n\n\n%s\n", strCheque.Get()); } else { OTLog::Output(0, "Failed trying to issue the cheque!\n"); // IF FAILED, ADD TRANSACTION NUMBER BACK TO LIST OF AVAILABLE NUMBERS. g_pTemporaryNym->AddTransactionNum(*g_pTemporaryNym, strServerID, lTransactionNumber, true); // bSave=true } continue; } else if (strLine.compare(0,7,"decrypt") == 0) { if (NULL == g_pTemporaryNym) { OTLog::Output(0, "No Nym yet available to decrypt with.\n"); continue; } OTLog::Output(0, "Enter text to be decrypted:\n> "); OTASCIIArmor theArmoredText; char decode_buffer[200]; // Safe since we only read sizeof - 1 do { decode_buffer[0] = 0; if (NULL != fgets(decode_buffer, sizeof(decode_buffer)-1, stdin)) { theArmoredText.Concatenate("%s\n", decode_buffer); OTLog::Output(0, "> "); } else { break; } } while (strlen(decode_buffer)>1); OTEnvelope theEnvelope(theArmoredText); OTString strDecodedText; theEnvelope.Open(*g_pTemporaryNym, strDecodedText); OTLog::vOutput(0, "\n\nDECRYPTED TEXT:\n\n%s\n\n", strDecodedText.Get()); continue; } else if (strLine.compare(0,6,"decode") == 0) { OTLog::Output(0, "Enter text to be decoded:\n> "); OTASCIIArmor theArmoredText; char decode_buffer[200]; // Safe since we only read sizeof - 1. do { decode_buffer[0] = 0; if (NULL != fgets(decode_buffer, sizeof(decode_buffer)-1, stdin)) { theArmoredText.Concatenate("%s\n", decode_buffer); OTLog::Output(0, "> "); } else { break; } } while (strlen(decode_buffer)>1); OTString strDecodedText(theArmoredText); OTLog::vOutput(0, "\n\nDECODED TEXT:\n\n%s\n\n", strDecodedText.Get()); continue; } else if (strLine.compare(0,6,"encode") == 0) { OTLog::Output(0, "Enter text to be ascii-encoded (terminate with ~ on a new line):\n> "); OTString strDecodedText; char decode_buffer[200]; // Safe since we only read sizeof - 1. do { decode_buffer[0] = 0; if ((NULL != fgets(decode_buffer, sizeof(decode_buffer)-1, stdin)) && (decode_buffer[0] != '~')) { strDecodedText.Concatenate("%s", decode_buffer); OTLog::Output(0, "> "); } else { break; } } while (decode_buffer[0] != '~'); OTASCIIArmor theArmoredText(strDecodedText); OTLog::vOutput(0, "\n\nENCODED TEXT:\n\n%s\n\n", theArmoredText.Get()); continue; } else if (strLine.compare(0,4,"hash") == 0) { OTLog::Output(0, "Enter text to be hashed (terminate with ~ on a new line):\n> "); OTString strDecodedText; char decode_buffer[200]; // Safe since we only read sizeof - 1. do { decode_buffer[0] = 0; if ((NULL != fgets(decode_buffer, sizeof(decode_buffer)-1, stdin)) && (decode_buffer[0] != '~')) { strDecodedText.Concatenate("%s\n", decode_buffer); OTLog::Output(0, "> "); } else { break; } } while (decode_buffer[0] != '~'); OTIdentifier theIdentifier; theIdentifier.CalculateDigest(strDecodedText); OTString strHash(theIdentifier); OTLog::vOutput(0, "\n\nMESSAGE DIGEST:\n\n%s\n\n", strHash.Get()); continue; } else if (strLine.compare(0,4,"stat") == 0) { OTLog::Output(0, "User has instructed to display wallet contents...\n"); OTString strStat; g_OT_API.GetWallet()->DisplayStatistics(strStat); OTLog::vOutput(0, "%s\n", strStat.Get()); continue; } else if (strLine.compare(0,4,"help") == 0) { OTLog::Output(0, "User has instructed to display the help file...\n"); system("more ../docs/CLIENT-COMMANDS.txt"); continue; } else if (strLine.compare(0,4,"quit") == 0) { OTLog::Output(0, "User has instructed to exit the wallet...\n"); break; } // 1.6 Connect to the first server in the wallet. (assuming it loaded a server contract.) else if (strLine.compare(0,7,"connect") == 0) { OTLog::Output(0, "User has instructed to connect to the first server available in the wallet.\n"); if (NULL == g_pTemporaryNym) { OTLog::Output(0, "No Nym yet available to connect with. Try 'load'.\n"); continue; } // Wallet, after loading, should contain a list of server // contracts. Let's pull the hostname and port out of // the first contract, and connect to that server. bool bConnected = g_OT_API.GetClient()->ConnectToTheFirstServerOnList(*g_pTemporaryNym, strCAFile, strKeyFile, strSSLPassword); if (bConnected) OTLog::Output(0, "Success. (Connected to the first notary server on your wallet's list.)\n"); else { OTLog::Output(0, "Either the wallet is not loaded, or there was an error connecting to server.\n"); } continue; } if (!g_OT_API.GetClient()->IsConnected()) { OTLog::Output(0, "(You are not connected to a notary server--you cannot send commands.)\n"); continue; } // 2) Process it out as an OTMessage to the server. It goes down the pipe. g_OT_API.GetClient()->ProcessMessageOut(buf, &nExpectResponse); // 3) Sleep for 1 second. #ifdef _WIN32 OT_Sleep(1000); #else sleep (1); #endif bool bFoundMessage = false; // 4) While there are messages to be read in response from the server, // then process and handle them all. do { OTMessage * pMsg = new OTMessage; OT_ASSERT(NULL != pMsg); // If this returns true, that means a Message was // received and processed into an OTMessage object (theMsg) bFoundMessage = g_OT_API.GetClient()->ProcessInBuffer(*pMsg); if (true == bFoundMessage) { // OTString strReply; // theMsg.SaveContract(strReply); // OTLog::vOutput(0, "\n\n**********************************************\n" // "Successfully in-processed server response.\n\n%s\n", strReply.Get()); g_OT_API.GetClient()->ProcessServerReply(*pMsg); // the Client takes ownership and will handle cleanup. } else { delete pMsg; pMsg = NULL; } } while (true == bFoundMessage); } // for OTLog::Output(0, "Finished running client.\n"); #ifdef _WIN32 WSACleanup(); #endif return retVal; }
// The above method uses this one internally... bool OTAccount::GenerateNewAccount(const OTPseudonym & theServer, const OTMessage & theMessage, const OTAccount::AccountType eAcctType/*=OTAccount::simple*/, int64_t lStashTransNum/*=0*/) { const char *szFunc = "OTAccount::GenerateNewAccount"; // ----------------------------------------------- // First we generate a secure random number into a binary object... // OTPayload thePayload; if (false == thePayload.Randomize(100)) // todo hardcoding. Plus: is 100 bytes of random a little much here? { OTLog::vError("%s: Failed trying to acquire random numbers.\n", szFunc); return false; } // -------------------------------------------------- // // Next we calculate that binary object into a message digest (an OTIdentifier). // OTIdentifier newID; if (!newID.CalculateDigest(thePayload)) { OTLog::vError("%s: Error generating new account ID.\n", szFunc); return false; } // -------------------------------------------------- // // Next we get that digest (which is a binary hash number) // and extract a human-readable standard string format of that hash, // into an OTString. // OTString strID(newID); SetRealAccountID(newID); // Set the account number based on what we just generated. SetPurportedAccountID(newID); // Might as well set them both. (Safe here to do so, for once.) m_strName.Set(strID); // So it's not blank. The user can always change it. // Next we create the full path filename for the account using the ID. // m_strFoldername = OTFolders::Account().Get(); m_strFilename = strID.Get(); // Then we try to load it, in order to make sure that it doesn't already exist. // -------------------------------------------------------------------- if (OTDB::Exists(m_strFoldername.Get(), m_strFilename.Get())) { OTLog::vError("%s: Account already exists: %s\n", szFunc, m_strFilename.Get()); return false; } // -------------------------------------------------------------------- // Set up the various important starting values of the account. m_AcctType = eAcctType; // account type defaults to OTAccount::simple. But there are also issuer accts... // -------------------------------------------------------------------- if (IsInternalServerAcct()) // basket, basketsub, mint, voucher, and stash accounts are all "owned" by the server. { theServer.GetIdentifier(m_AcctUserID); } else { m_AcctUserID.SetString(theMessage.m_strNymID); } // -------------------------------------------------------------------- m_AcctAssetTypeID.SetString(theMessage.m_strAssetID); OTLog::vOutput(3, "%s: Creating new account, type:\n%s\n", szFunc, theMessage.m_strAssetID.Get()); OTIdentifier SERVER_ID(theMessage.m_strServerID); SetRealServerID(SERVER_ID); // todo this assumes the serverID on the message is correct. It's vetted, but still... SetPurportedServerID(SERVER_ID); const time64_t tDate = OTTimeGetCurrentTime(); // Today, now. m_BalanceDate.Format("%d", tDate); m_BalanceAmount.Set("0"); // -------------------------------------------------------------------- if (IsStashAcct()) { OT_ASSERT_MSG(lStashTransNum > 0, "You created a stash account, but with a zero-or-negative transaction number for its cron item."); m_lStashTransNum = lStashTransNum; } // -------------------------------------------------------------------- // Sign the Account (so we know that we did)... Otherwise someone could put a fake // account file on the server if the code wasn't designed to verify the signature on the // account. SignContract(theServer); SaveContract(); // Save the Account to storage (based on its ID.) SaveAccount(); // Don't know why I had this here. Putting SaveAccount() instead. // OTString strFilename(m_strFilename); // SaveContract(strFilename.Get()); // Saves the account to a specific filename // No need to create the inbox and outbox ledgers...they will be created automatically // if they do not exist when they are needed. return true; }