// Used for adding transaction numbers back to a Nym, after deciding not to use this agreement // or failing in trying to use it. Client side. // void OTAgreement::HarvestClosingNumbers(OTPseudonym & theNym) { // since we overrode the parent, we give it a chance to harvest also. // OTCronItem::HarvestClosingNumbers(theNym); // The Nym is the original recipient. (If Compares true). // FYI, if Nym is the original sender, then the above call will handle him. // // GetTransactionNum() is burned, but we can harvest the closing // numbers from the "Closing" list, which is only for the sender's numbers. // Subclasses will have to override this function for recipients, etc. // if (theNym.CompareID(GetRecipientUserID())) { const OTString strServerID(GetServerID()); for (int i = 0; i < GetRecipientCountClosingNumbers(); i++) { if (theNym.VerifyIssuedNum(strServerID, GetRecipientClosingTransactionNoAt(i))) // we only "add it back" if it was really there in the first place. theNym.AddTransactionNum(theNym, strServerID, GetRecipientClosingTransactionNoAt(i), (i == (GetRecipientCountClosingNumbers()-1) ? true : false)); // bSave=true only on the last iteration. } } }
// You usually wouldn't want to use this, since if the transaction failed, the opening number // is already burned and gone. But there might be cases where it's not, and you want to retrieve it. // So I added this function. // void OTAgreement::HarvestOpeningNumber(OTPseudonym & theNym) { // since we overrode the parent, we give it a chance to harvest also. // IF theNym is the original sender, the opening number will be harvested // inside this call. // OTCronItem::HarvestOpeningNumber(theNym); // The Nym is the original recipient. (If Compares true). // IN CASES where GetTransactionNum() isn't already burned, we can harvest it here. // if (theNym.CompareID(GetRecipientUserID())) { // This function will only "add it back" if it was really there in the first place. // (Verifies it is on issued list first, before adding to available list.) // theNym.ClawbackTransactionNumber(GetServerID(), GetRecipientOpeningNum(), true); //bSave=true } // NOTE: if the message failed (transaction never actually ran) then the sender AND recipient // can both reclaim their opening numbers. But if the message SUCCEEDED and the transaction FAILED, // then only the recipient can claim his opening number -- the sender's is already burned. So then, // what if you mistakenly call this function and pass the sender, when that number is already burned? // There's nothing this function can do, because we have no way of telling, from inside here, // whether the message succeeded or not, and whether the transaction succeeded or not. Therefore, // ==> we MUST rely on the CALLER to know this, and to avoid calling this function in the first place, // if he's sitting on a sender with a failed transaction. }
/// See if theNym has rights to remove this item from Cron. /// bool OTAgreement::CanRemoveItemFromCron(OTPseudonym & theNym) { // You don't just go willy-nilly and remove a cron item from a market unless you check first // and make sure the Nym who requested it actually has said number (or a related closing number) // signed out to him on his last receipt... // if (true == OTCronItem::CanRemoveItemFromCron(theNym)) return true; const OTString strServerID(GetServerID()); // Usually the Nym is the originator. (Meaning GetTransactionNum() on this agreement // is still verifiable as an issued number on theNum, and belongs to him.) In that case, // the above call will discover this, and return true. // In other cases, theNym has the right to Remove the item even though theNym didn't originate it. // (Like if he is the recipient -- not the sender -- in a payment plan.) We check such things // HERE in this function (see below.) // if (false == theNym.CompareID(GetRecipientUserID())) { OTLog::Output(0, "OTAgreement::CanRemoveItemFromCron Weird: Nym tried to remove agreement (payment plan), even " "though he apparently wasn't the sender OR recipient.\n"); return false; } else if (this->GetRecipientCountClosingNumbers() < 2) { OTLog::vOutput(0, "OTAgreement::CanRemoveItemFromCron Weird: Recipient tried to remove agreement " "(or payment plan); expected 2 closing numbers to be available--that weren't. (Found %d).\n", this->GetRecipientCountClosingNumbers()); return false; } if (false == theNym.VerifyIssuedNum(strServerID, this->GetRecipientClosingNum())) { OTLog::Output(0, "OTAgreement::CanRemoveItemFromCron: Recipient Closing number didn't verify (for removal from cron).\n"); return false; } // By this point, we KNOW theNym is the sender, and we KNOW there are the proper number of transaction // numbers available to close. We also know that this cron item really was on the cron object, since // that is where it was looked up from, when this function got called! So I'm pretty sure, at this point, // to authorize removal, as long as the transaction num is still issued to theNym (this check here.) // return theNym.VerifyIssuedNum(strServerID, this->GetRecipientOpeningNum()); // Normally this will be all we need to check. The originator will have the transaction // number signed-out to him still, if he is trying to close it. BUT--in some cases, someone // who is NOT the originator can cancel. Like in a payment plan, the sender is also the depositor, // who would normally be the person cancelling the plan. But technically, the RECIPIENT should // also have the ability to cancel that payment plan. BUT: the transaction number isn't signed // out to the RECIPIENT... In THAT case, the below VerifyIssuedNum() won't work! In those cases, // expect that the special code will be in the subclasses override of this function. (OTPaymentPlan::CanRemoveItem() etc) // P.S. If you override this function, MAKE SURE to call the parent (OTCronItem::CanRemoveItem) first, // for the VerifyIssuedNum call above. Only if that fails, do you need to dig deeper... }
bool OTEnvelope::Seal(const OTPseudonym & theRecipient, const OTString & theInput) { OTString strNymID; mapOfAsymmetricKeys theKeys; theRecipient.GetIdentifier(strNymID); theKeys.insert(std::pair<std::string, OTAsymmetricKey *> (strNymID.Get(), const_cast<OTAsymmetricKey *>(&(theRecipient.GetPublicEncrKey())))); // ----------------------------- return this->Seal(theKeys, theInput); }
FOR_EACH(mapOfNyms, m_mapNyms) { OTPseudonym * pNym = (*it).second; OT_ASSERT_MSG((NULL != pNym), "NULL pseudonym pointer in OTWallet::GetNymByID."); OTIdentifier id_CurrentNym; pNym->GetIdentifier(id_CurrentNym); if (id_CurrentNym == NYM_ID) return pNym; }
// This is a good implementation. Dots all the i's, so to speak. // client-side. // The basket ONLY stores closing numbers, so this means "harvest 'em all." // void OTBasket::HarvestClosingNumbers(OTPseudonym & theNym, const OTIdentifier & theServerID, const bool bSave/*=true*/) { const OTString strServerID(theServerID); bool bNeedToSave = false; // ************************************************************************* // The SUB-CURRENCIES first... // const unsigned int nCount = static_cast<unsigned int>(this->Count()); for (unsigned int i = 0; i < nCount; i++) { BasketItem * pRequestItem = this->At(i); OT_ASSERT(NULL != pRequestItem); // -------------------------------- const long lClosingTransNo = pRequestItem->lClosingTransactionNo; // -------------------------------- // This function will only "add it back" if it was really there in the first place. // (Verifies it is on issued list first, before adding to available list.) // const bool bClawedBack = theNym.ClawbackTransactionNumber(theServerID, lClosingTransNo, false); // bSave=false if (bClawedBack) bNeedToSave = true; // else // OTLog::vError("OTBasket::HarvestClosingNumbers: Number (%ld) failed as issued. (Thus didn't bother 'adding it back'.)\n", // lClosingTransNo); } // for // ************************************************************************* // Then the BASKET currency itself... // const long lClosingTransNo = this->GetClosingNum(); // -------------------------------- // This function will only "add it back" if it was really there in the first place. // (Verifies it is on issued list first, before adding to available list.) // const bool bClawedBack = theNym.ClawbackTransactionNumber(theServerID, lClosingTransNo, false); // bSave=false if (bClawedBack) bNeedToSave = true; // ************************************************************************* // Until I put this down here, there were subtle cases where the Nym wouldn't get saved. // Therefore another vote for my "dirty instances" theory. // if (bSave && bNeedToSave) { OTPseudonym * pSignerNym = &theNym;// probably unnecessary. theNym.SaveSignedNymfile(*pSignerNym); } }
bool OTEnvelope::Seal(setOfNyms & theRecipients, const OTString & theInput) { mapOfAsymmetricKeys RecipPubKeys; // Loop through theRecipients, and add the public key of each one to a set of keys. // FOR_EACH(setOfNyms, theRecipients) { OTPseudonym * pNym = *it; OT_ASSERT_MSG(NULL != pNym, "OTEnvelope::Seal: Assert: NULL pseudonym pointer."); // ------------------------------ OTString strNymID; pNym->GetIdentifier(strNymID); RecipPubKeys.insert(std::pair<std::string, OTAsymmetricKey *> (strNymID.Get(), const_cast<OTAsymmetricKey *>(&(pNym->GetPublicEncrKey())))); }
// Normally, Asset Contracts do NOT update / rewrite their contents, since their // primary goal is for the signature to continue to verify. But when first creating // a basket contract, we have to rewrite the contents, which is done here. bool OTAssetContract::CreateBasket(OTBasket & theBasket, OTPseudonym & theSigner) { Release(); // Grab a string copy of the basket information. theBasket.SaveContractRaw(m_strBasketInfo); // ------------------------------- // Insert the server's public key as the "contract" key for this basket currency. OTString strPubKey, strKeyName("contract"); // todo stop hardcoding theSigner.GetPublicKey().GetPublicKey(strPubKey); InsertNym(strKeyName, strPubKey); // todo check the above two return values. OTASCIIArmor theBasketArmor(m_strBasketInfo); // ------------------------------- m_xmlUnsigned.Concatenate("<?xml version=\"%s\"?>\n\n", "1.0"); m_xmlUnsigned.Concatenate("<basketContract version=\"%s\">\n\n", m_strVersion.Get()); m_xmlUnsigned.Concatenate("<basketInfo>\n%s</basketInfo>\n\n", theBasketArmor.Get()); m_xmlUnsigned.Concatenate("<key name=\"%s\">\n%s</key>\n\n", strKeyName.Get(), strPubKey.Get()); m_xmlUnsigned.Concatenate("</basketContract>\n"); // This function assumes that m_xmlUnsigned is ready to be processed. // This function only processes that portion of the contract. bool bLoaded = LoadContractXML(); if (bLoaded) { OTString strTemp; SignContract(theSigner); RewriteContract(strTemp); // this trims // This is probably redundant... // std::string str_Trim(strTemp.Get()); // std::string str_Trim2 = OTString::trim(str_Trim); // strTemp.Set(str_Trim2.c_str()); // ----------------------------------- Release(); LoadContractFromString(strTemp); SaveContract(); OTIdentifier NEW_ID; CalculateContractID(NEW_ID); m_ID = NEW_ID; return true; } return false; }
// You usually wouldn't want to use this, since if the transaction failed, the opening number // is already burned and gone. But there might be cases where it's not, and you want to retrieve it. // So I added this function. // void OTAgreement::HarvestOpeningNumber(OTPseudonym & theNym) { // since we overrode the parent, we give it a chance to harvest also. // OTCronItem::HarvestOpeningNumber(theNym); // The Nym is the original sender. (If Compares true). // IN CASES where GetTransactionNum() isn't already burned, we can harvest it here. // Subclasses will have to override this function for recipients, etc. // if (theNym.CompareID(GetRecipientUserID())) { const OTString strServerID(GetServerID()); if (theNym.VerifyIssuedNum(strServerID, GetRecipientOpeningNum())) // we only "add it back" if it was really there in the first place. theNym.AddTransactionNum(theNym, strServerID, GetRecipientOpeningNum(), true); // bSave=true } }
// Verify Contract ID first, THEN Verify Owner. // Because we use the ID in this function, so make sure that it is verified before calling this. // bool OTAccount::VerifyOwner(const OTPseudonym & theCandidate) const { OTIdentifier ID_CANDIDATE; theCandidate.GetIdentifier(ID_CANDIDATE); // ID_CANDIDATE now contains the ID of the Nym we're testing. if (m_AcctUserID == ID_CANDIDATE) { return true; } return false; }
// Verify Contract ID first, THEN Verify Owner. // Because we use the ID in this function, so make sure that it is verified before calling this. bool OTAccount::VerifyOwner(OTPseudonym & theCandidate) { OTIdentifier ID_CANDIDATE; theCandidate.GetIdentifier(ID_CANDIDATE); // ID_CANDIDATE now contains the ID of the Nym we're testing. if (m_AcctUserID == ID_CANDIDATE) // There's an op== function, but no != ... So I used == since it exists. { return true; } return false; }
// Used for adding transaction numbers back to a Nym, after deciding not to use this agreement // or failing in trying to use it. Client side. // void OTAgreement::HarvestClosingNumbers(OTPseudonym & theNym) { // Since we overrode the parent, we give it a chance to harvest also. // If theNym is the sender, then his closing numbers will be harvested // inside here. But what if the transaction was a success? The numbers // will still be harvested, since they are still on the sender's issued // list, but they should not have been harvested, regardless, since the // transaction was a success and the server therefore has them marked as // "used." So clearly you cannot just blindly call this function unless // you know beforehand whether the message and transaction were a success. // OTCronItem::HarvestClosingNumbers(theNym); // The Nym is the original recipient. (If Compares true). // FYI, if Nym is the original sender, then the above call will handle him. // // GetTransactionNum() is burned, but we can harvest the closing // numbers from the "Closing" list, which is only for the sender's numbers. // Subclasses will have to override this function for recipients, etc. // if (theNym.CompareID(GetRecipientUserID())) { for (int i = 0; i < GetRecipientCountClosingNumbers(); i++) { // This function will only "add it back" if it was really there in the first place. // (Verifies it is on issued list first, before adding to available list.) // const bool bClawedBack = theNym.ClawbackTransactionNumber(GetServerID(), GetRecipientClosingTransactionNoAt(i), (i == (GetRecipientCountClosingNumbers()-1) ? true : false)); // bSave=true only on the last iteration. if (!bClawedBack) { // OTLog::vError("OTAgreement::HarvestClosingNumbers: Number (%ld) failed as issued. (Thus didn't bother 'adding it back'.)\n", // GetRecipientClosingTransactionNoAt(i)); } } } }
int main (int argc, char * const argv[]) { if (argc < 4) { printf("\n\nUsage: createmint server_id server_user_id asset_type_id \n\n" "For now, expiration dates are automatically set:\n" "-- FROM: Today, Now.\n" "-- TO: 6 months from now.\n\n" "It is recommended that you issue a new series (create a new mint) every 3 months for each\n" "asset type, so that there is a 3-month overlap. In the future, this will be configured inside\n" "the contracts themselves.\n\n" "Server ID needs to match the Server ID from notaryServer.xml\n" "Server user ID needs to match the Server User ID from notaryServer.xml\n" "Asset Type ID needs to match the Asset ID (aka Hashed Contract ID) of the currency contract.\n\n" // "The path to the data folder is necessary for initialization of the OT library.\n\n" // "(You probably want to use ~/.ot/server_data as your data folder.)\n\n" ); return 0; } // ************************************************************************** class __OTcreatemint_RAII { public: __OTcreatemint_RAII() { if(!OTLog::Init(SERVER_CONFIG_KEY,0)) { assert(false); }; // setup the logger. OTLog::vOutput(0, "\n\nWelcome to Open Transactions -- 'createmint', version %s\n", OTLog::Version()); // ------------------------------------ #ifdef _WIN32 WSADATA wsaData; WORD wVersionRequested = MAKEWORD( 2, 2 ); int err = WSAStartup( wVersionRequested, &wsaData ); /* Tell the user that we could not find a usable */ /* Winsock DLL. */ OT_ASSERT_MSG((err == 0), "WSAStartup failed!\n"); /* Confirm that the WinSock DLL supports 2.2. */ /* Note that if the DLL supports versions greater */ /* than 2.2 in addition to 2.2, it will still return */ /* 2.2 in wVersion since that is the version we */ /* requested. */ bool bWinsock = (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2); /* Tell the user that we could not find a usable */ /* WinSock DLL. */ if (!bWinsock) WSACleanup(); // do cleanup. OT_ASSERT_MSG((!bWinsock), "Could not find a usable version of Winsock.dll\n"); /* The Winsock DLL is acceptable. Proceed to use it. */ /* Add network programming using Winsock here */ /* then call WSACleanup when done using the Winsock dll */ OTLog::vOutput(0,"The Winsock 2.2 dll was found okay\n"); #endif // ------------------------------------ // SIGNALS // #if defined(OT_SIGNAL_HANDLING) // OTLog::SetupSignalHandler(); // <===== SIGNALS // // This is optional! You can always remove it using the OT_NO_SIGNAL_HANDLING // option, and plus, the internals only execute once anyway. (It keeps count.) #endif // ------------------------------------ // // OT Server Path: // { bool bSetupPathsSuccess = false; if(!OTDataFolder::Init(SERVER_CONFIG_KEY)) { OT_ASSERT(false); } else bSetupPathsSuccess = true; OT_ASSERT_MSG(bSetupPathsSuccess, "main(): Assert failed: Failed to set OT Path"); } // ----------------------------------------------------------------------- OTCrypto::It()->Init(); // (OpenSSL gets initialized here.) // ------------------------------------ } ~__OTcreatemint_RAII() { // We clean these up in reverse order from the Init function, which just seems // like the best default, in absence of any brighter ideas. // OTCrypto::It()->Cleanup(); // (OpenSSL gets cleaned up here.) // ------------------------------------ #ifdef _WIN32 WSACleanup(); // Corresponds to WSAStartup() in InitOTAPI(). #endif // ------------------------------------ } }; // -------------------------------------------- __OTcreatemint_RAII the_createmint_cleanup; // ************************************************************************** OTServer theServer; // ----------------------------------------- int nReturnVal = 0; OTString strServerID(argv[1]), strServerNymID(argv[2]), strAssetTypeID(argv[3]); OTIdentifier ASSET_TYPE_ID(strAssetTypeID), SERVER_ID(strServerID); // std::string strDataFolderPath(argv[4]), strNotaryFile("notaryServer.xml"); OTLog::vOutput(0, "\nNow loading the server nym, which will also ask you for a password, to unlock\n" "its private key. (Default password is \"%s\".)\n", KEY_PASSWORD); // Keys, etc are loaded here. ===> Assumes main path is set! <=== // theServer.Init(true); //bool bReadOnly=false by default (We don't want to overwrite anything if the ACTUAL server is running...) // NOTE: I copied some code in here from xmlrpcxx_server.cpp, including the above // call to theServer.Init(), which has the InitDefaultStorage inside of it, and // which uses OTLog::Path(), which the above new code should be setting properly // before theServer.Init() actually gets called. (So this should work....) // // bool bSuccessInitDefault = OTDB::InitDefaultStorage(OTDB_DEFAULT_STORAGE, // OTDB_DEFAULT_PACKER, strDataFolderPath, strNotaryFile); // if (!bSuccessInitDefault) // { // OTLog::vError("\n\n%s: Failed invoking OTDB::InitDefaultStorage with path: %s and main filename: %s\n\n", // __FUNCTION__, strDataFolderPath.c_str(), strNotaryFile.c_str()); // return 0; // } // ----------------------------------------- OTString strMintPath; bool bFileIsPresent = false; int nSeries = 0; for (nSeries = 0; nSeries < 10000; ++nSeries) { // struct stat st; OTString strFilename; strFilename.Format("%s%s%d", strAssetTypeID.Get(), ".", nSeries); bFileIsPresent = OTDB::Exists(OTFolders::Mint().Get(), strServerID.Get(), strFilename.Get()); // Old Code //strMintPath.Format("%s%s%s%s%s%s%s%s%d", // OTLog::Path(), // OTLog::PathSeparator(), // OTFolders::Mint().Get(), // OTLog::PathSeparator(), // strServerID.Get(), // OTLog::PathSeparator(), // strAssetTypeID.Get(), ".", nSeries); //bFileIsPresent = (stat(strMintPath.Get(), &st) == 0); if (!bFileIsPresent) break; } // if bFileIsPresent is STILL true, that means we got all the way up to 1000 and the // file was present every time. // Geez, there must be 10000 mints on this computer. At one new Mint per 3 months, // that's 4 per year, that's 2500 years already!! // if (bFileIsPresent) { OTLog::Output(0, "\n\nThis program automatically finds the next series, up to 10000. You\n" "have reached 10000. You will have to change the source code of this\n" "program in order to continue. Sorry.\n\n"); return 0; } // --------------------------------------------------------------------- // nSeries now contains the number we need to use for the next series. // and strMintPath now contains the correct file path. OTMint * pMint = new OTMint(strServerID, strServerNymID, strAssetTypeID); OT_ASSERT(NULL != pMint); OTString strSeries; strSeries.Format("%s%d", ".", nSeries); if (pMint->LoadMint(strSeries.Get())) { OTLog::Output(0, "\n\nSorry, that mint already exists. Delete it first if you wish to re-create it.\n\n"); } else { OTLog::vOutput(0, "\n\nMint file does not (yet) exist for series %d and asset type:\n%s\n Creating......\n\n", nSeries, strAssetTypeID.Get()); // TODO: read the denominations out of the asset contract itself, instead of hardcoding them here. // Calculate FROM as Today, Now, // then calculate TO as 6 months from now, // and EXPIRATION as 3 months from now. // // TODO: Let these numbers be configured either in server operator contract, or issuer contract. // In the meantime, 3 and 6 months are good enough. OTPseudonym theNym; theNym.SetIdentifier(strServerNymID); // 1 hour == 3600 Seconds // 1 day == 86400 Seconds // 30 days == 2592000 Seconds // 3 months == 7776000 Seconds // 6 months == 15552000 Seconds // This part requires the server operator to enter his passphrase. // Which is why the server can't just fire it off automatically and // make a mint available to the client. The client has to wait a day or // until the operator is able to run this script and type the passphrase. if (theNym.Loadx509CertAndPrivateKey()) { const time_t CURRENT_TIME = time(NULL), VALID_TO = CURRENT_TIME + 15552000, // Tokens generated by this mint are valid from today until 6 months from today MINT_EXPIRATION = CURRENT_TIME + 7776000; // The mint itself will expire in 3 months from today, and be replaced with a new one. pMint->GenerateNewMint(nSeries, CURRENT_TIME, VALID_TO, MINT_EXPIRATION, ASSET_TYPE_ID, SERVER_ID, // penny, nickel, dime, quarter, $1, $5, $10, $20, $100, $1000 theNym, 1, 5, 10, 25, 100, 500, 1000, 2000, 10000, 100000); // should be: 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768, 65536 // --------------------------------------- // OTString strFilename;// strPUBLICFilename; // strFilename. Format("%s%s%s", strServerID.Get(), OTLog::PathSeparator(), strAssetTypeID.Get()); // strPUBLICFilename. Format("%s%s%s%sPUBLIC",strServerID.Get(), OTLog::PathSeparator(), strAssetTypeID.Get(), "."); if (!OTDataFolder::IsInitialized()) { OT_ASSERT(false); }; OTString strServerFolder(""), strMintFolder(""); if (!OTPaths::AppendFolder(strMintFolder, OTDataFolder::Get(),OTFolders::Mint())) { OT_ASSERT(false); }; // mint/ if (!OTPaths::AppendFolder(strServerFolder, strMintFolder, strServerID.Get())) { OT_ASSERT(false); }; // mint/serverID bool bFolderCreated; if (OTPaths::BuildFolderPath(strServerFolder,bFolderCreated)) { // ------------------------------------------------------------------- // This causes the next serialization to save the private, not just public, keys. pMint->SetSavePrivateKeys(); // <== PRIVATE MINT VERSION. pMint->SignContract(theNym); pMint->SaveContract(); pMint->SaveMint(); // save the private mint file as: path/mints/server_id/Asset_TypeID (overwriting the last "current mint"...) pMint->SaveMint(strSeries.Get()); // save the private mint file as: path/mints/server_id/Asset_TypeID.nSeries (These accumulate.) // When the server needs to reference the "current" private keys, then it just loads the // mint without specifying the series number. Since this file is overwritten with each new // mint, it is thus always the latest one. (Similarly, the latest public is always asset_id.PUBLIC) // On the other hand, if I need to load the keys for a specific series, (since more than one may be // redeemable, even if only the latest one is being issued) then they are all also saved by series // number, which is not overwritten with each new mint, but accumulates. // That is why above, you see me save the mint twice in two different files, and below you see // it being saved with the .PUBLIC appending to the filename. // pMint->SaveContract(OTFolders::Mint().Get(), strFilename.Get()); // save the mint file. // ------------------------------------------------------------------- // Now I sign it again, to get the private keys out of there. pMint->ReleaseSignatures(); pMint->SignContract(theNym); pMint->SaveContract(); pMint->SaveMint(".PUBLIC"); // save the public mint file. // pMint->SaveContract(OTFolders::Mint().Get(), strPUBLICFilename.Get()); // save the public mint file. nReturnVal = 1; OTLog::Output(0, "\nDone.\n\n"); } else OTLog::Output(0, "\n\nError calling OTLog::ConfirmOrCreateFolder() for path/mints/server_id\n\n"); } else OTLog::Output(0, "\n\nError calling theNym.Loadx509CertAndPrivateKey()\n\n"); } // Mint file doesn't exist yet (therefore the above block creates it...) return nReturnVal; }
// The mint has a different key pair for each denomination. // Pass the actual denomination such as 5, 10, 20, 50, 100... bool OTMint_Lucre::AddDenomination(OTPseudonym & theNotary, int64_t lDenomination, int32_t nPrimeLength/*=1024*/) { OT_ASSERT(NULL != m_pKeyPublic); bool bReturnValue = false; // Let's make sure it doesn't already exist OTASCIIArmor theArmor; if (GetPublic(theArmor, lDenomination)) { // it already exists. OTLog::Error("Error: Denomination public already exists in OTMint::AddDenomination\n"); return false; } if (GetPrivate(theArmor, lDenomination)) { // it already exists. OTLog::Error("Error: Denomination private already exists in OTMint::AddDenomination\n"); return false; } // OTLog::Error("%s <size of bank prime in bits> <bank data file> <bank public data file>\n", if ((nPrimeLength/8) < (MIN_COIN_LENGTH+DIGEST_LENGTH)) { OTLog::vError("Prime must be at least %d bits\n", (MIN_COIN_LENGTH+DIGEST_LENGTH)*8); return false; } if (nPrimeLength%8) { OTLog::Error("Prime length must be a multiple of 8\n"); return false; } #ifdef _WIN32 SetMonitor("openssl.dump"); #else SetMonitor(stderr); #endif OpenSSL_BIO bio = BIO_new(BIO_s_mem()); OpenSSL_BIO bioPublic = BIO_new(BIO_s_mem()); // Generate the mint private key information Bank bank(nPrimeLength/8); bank.WriteBIO(bio); // Generate the mint public key information PublicBank pbank(bank); pbank.WriteBIO(bioPublic); // Copy from BIO back to a normal OTString or Ascii-Armor char privateBankBuffer[4096], publicBankBuffer[4096]; // todo stop hardcoding these string lengths int32_t privatebankLen = BIO_read(bio, privateBankBuffer, 4000); // cutting it a little short on purpose, with the buffer. int32_t publicbankLen = BIO_read(bioPublic, publicBankBuffer, 4000); // Just makes me feel more comfortable for some reason. if (privatebankLen && publicbankLen) { // With this, we have the Lucre public and private bank info converted to OTStrings OTString strPublicBank; strPublicBank.Set(publicBankBuffer, publicbankLen); OTString strPrivateBank; strPrivateBank.Set(privateBankBuffer, privatebankLen); OTASCIIArmor * pPublic = new OTASCIIArmor(); OTASCIIArmor * pPrivate = new OTASCIIArmor(); OT_ASSERT(NULL != pPublic); OT_ASSERT(NULL != pPrivate); // Set the public bank info onto pPublic pPublic->SetString(strPublicBank, true); // linebreaks = true // Seal the private bank info up into an encrypted Envelope // and set it onto pPrivate OTEnvelope theEnvelope; theEnvelope.Seal(theNotary, strPrivateBank); // Todo check the return values on these two functions theEnvelope.GetAsciiArmoredData(*pPrivate); // Add the new key pair to the maps, using denomination as the key m_mapPublic[lDenomination] = pPublic; m_mapPrivate[lDenomination] = pPrivate; // Grab the Server Nym ID and save it with this Mint theNotary.GetIdentifier(m_ServerNymID); // --------------------------- // Grab the Server's public key and save it with this Mint // const OTAsymmetricKey & theNotaryPubKey = theNotary.GetPublicSignKey(); delete m_pKeyPublic; m_pKeyPublic = theNotaryPubKey.ClonePubKey(); // --------------------------- m_nDenominationCount++; // --------------------------- // Success! bReturnValue = true; OTLog::vOutput(1, "Successfully added denomination: %lld\n", lDenomination); } return bReturnValue; }
OTString::OTString(OTPseudonym & theValue) { Initialize(); theValue.SavePseudonym(*this); }
int main (int argc, char * const argv[]) { if (argc < 3) { printf("Usage: createmint server_user_id asset_type_id\n\n" "For now, expiration dates are automatically set:\n" "FROM: Today, Now.\n" "TO: 6 months from now.\n\n" "It is recommended that you issue a new series (create a new mint) every 3 months for each\n" "asset type, so that there is a 3-month overlap. In the future, this will be configured inside\n" "the contracts themselves.\n\n" "Server user ID needs to match the Server User ID from notaryServer.xml\n" "Asset Type ID needs to match the Asset ID (aka Hashed Contract ID) of the currency contract.\n\n"); exit(1); } SSL_library_init(); SSL_load_error_strings(); OTString strServerID(argv[1]), strAssetTypeID(argv[2]); OTIdentifier ASSET_TYPE_ID(strAssetTypeID); OTString strMintPath; bool bFileIsPresent = false; int nSeries = 0; for (nSeries = 0; nSeries < 1000; nSeries++) { struct stat st; strMintPath.Format("%s%smints%s%s.%d", OTLog::Path(), OTLog::PathSeparator(), OTLog::PathSeparator(), strAssetTypeID.Get(), nSeries); bFileIsPresent = (stat(strMintPath.Get(), &st) == 0); if (!bFileIsPresent) break; } // if bFileIsPresent is STILL true, that means we got all the way up to 1000 and the // file was present every time. // Geez, there must be 1000 mints on this computer. At one new Mint per 3 months, // that's 4 per year, that's 250 years already!! if (bFileIsPresent) { fprintf(stdout, "This program automatically finds the next series, up to 1000. You\n" "have reached 1000. You will have to change the source code of this\n" "program in order to continue. Sorry.\n"); exit(1); } // nSeries now contains the number we need to use for the next series. // and strMintPath now contains the correct file path. OTMint * pMint = new OTMint(strAssetTypeID, strMintPath, strAssetTypeID); if (pMint && pMint->LoadContract()) { printf("The mint already exists. Delete it first if you wish to re-create it.\n"); } else { fprintf(stderr, "Mint file does not yet exist, for series %d and asset type:\n%s\nCreating......\n", nSeries, strAssetTypeID.Get()); if (pMint) { // TODO: read the denominations out of the asset contract itself, instead of hardcoding them here. // Calculate FROM as Today, Now, // then calculate TO as 6 months from now, // and EXPIRATION as 3 months from now. // // TODO: Let these numbers be configured either in server operator contract, or issuer contract. // In the meantime, 3 and 6 months are good enough. OTPseudonym theNym; theNym.SetIdentifier(strServerID); // 1 hour == 3600 Seconds // 1 day == 86400 Seconds // 30 days == 2592000 Seconds // 3 months == 7776000 Seconds // 6 months == 15552000 Seconds // This part requires the server operator to enter his passphrase. // Which is why the server can't just fire it off automatically and // make a mint available to the client. The client has to wait a day or // until the operator is able to run this script and type the passphrase. if (theNym.Loadx509CertAndPrivateKey()) { const time_t CURRENT_TIME = time(NULL), VALID_TO = CURRENT_TIME + 15552000, // Tokens generated by this mint are valid from today until 6 months from today MINT_EXPIRATION = CURRENT_TIME + 7776000; // The mint itself will expire in 3 months from today, and be replaced with a new one. pMint->GenerateNewMint(nSeries, CURRENT_TIME, VALID_TO, MINT_EXPIRATION, // penny, nickel, dime, quarter, $1, $5, $10, $20, $100, $1000 ASSET_TYPE_ID, theNym, 1, 5, 10, 25, 100, 500, 1000, 2000, 10000, 100000); // should be: 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768, 65536 pMint->SetSavePrivateKeys(); // This causes the next serialization to save the private, not just public, keys. pMint->SignContract(theNym); pMint->SaveContract(strMintPath.Get()); // save the mint file. // Now I sign it again, to get the private keys out of there. pMint->ReleaseSignatures(); pMint->SignContract(theNym); strMintPath.Format("%s%smints%s%s.PUBLIC", OTLog::Path(), OTLog::PathSeparator(), OTLog::PathSeparator(), strAssetTypeID.Get()); pMint->SaveContract(strMintPath.Get()); printf("Done.\n"); } else { printf("Error calling theNym.Loadx509CertAndPrivateKey()\n"); } } else { fprintf(stdout, "Error allocating memory for new OTMint.\n"); } } return 0; }
OTString::OTString(OTPseudonym & theValue) : m_lLength(0), m_lPosition(0), m_strBuffer(NULL) { // Initialize(); theValue.SavePseudonym(*this); }
int main (int argc, char * const argv[]) { if (argc < 5) { printf("\n\nUsage: createmint server_id server_user_id asset_type_id full_path_to_data_folder\n\n" "For now, expiration dates are automatically set:\n" "-- FROM: Today, Now.\n" "-- TO: 6 months from now.\n\n" "It is recommended that you issue a new series (create a new mint) every 3 months for each\n" "asset type, so that there is a 3-month overlap. In the future, this will be configured inside\n" "the contracts themselves.\n\n" "Server ID needs to match the Server ID from notaryServer.xml\n" "Server user ID needs to match the Server User ID from notaryServer.xml\n" "Asset Type ID needs to match the Asset ID (aka Hashed Contract ID) of the currency contract.\n" "The path to the data folder is necessary for initialization of the OT library.\n\n"); exit(1); } SSL_library_init(); SSL_load_error_strings(); // ----------------------------------------- OTString strServerID(argv[1]), strServerNymID(argv[2]), strAssetTypeID(argv[3]); OTIdentifier ASSET_TYPE_ID(strAssetTypeID), SERVER_ID(strServerID); std::string strDataFolderPath(argv[4]), strWalletFile("wallet.xml"); bool bSuccessInitDefault = OTDB::InitDefaultStorage(OTDB_DEFAULT_STORAGE, OTDB_DEFAULT_PACKER, strDataFolderPath, strWalletFile); // ----------------------------------------- OTString strMintPath; bool bFileIsPresent = false; int nSeries = 0; for (nSeries = 0; nSeries < 1000; nSeries++) { struct stat st; strMintPath.Format("%s%s%s%s%s%s%s%s%d", OTLog::Path(), OTLog::PathSeparator(), OTLog::MintFolder(), OTLog::PathSeparator(), strServerID.Get(), OTLog::PathSeparator(), strAssetTypeID.Get(), ".", nSeries); bFileIsPresent = (stat(strMintPath.Get(), &st) == 0); if (!bFileIsPresent) break; } // if bFileIsPresent is STILL true, that means we got all the way up to 1000 and the // file was present every time. // Geez, there must be 1000 mints on this computer. At one new Mint per 3 months, // that's 4 per year, that's 250 years already!! if (bFileIsPresent) { OTLog::Output(0, "This program automatically finds the next series, up to 1000. You\n" "have reached 1000. You will have to change the source code of this\n" "program in order to continue. Sorry.\n"); exit(1); } // nSeries now contains the number we need to use for the next series. // and strMintPath now contains the correct file path. OTMint * pMint = new OTMint(strServerID, strServerNymID, strAssetTypeID); OTString strSeries; strSeries.Format("%s%d", ".", nSeries); // if ((NULL != pMint) && pMint->LoadMint(strSeries.Get())) { OTLog::Output(0, "The mint already exists. Delete it first if you wish to re-create it.\n"); } else { OTLog::vOutput(0, "Mint file does not (yet) exist for series %d and asset type:\n%s\n Creating......\n", nSeries, strAssetTypeID.Get()); if (pMint) { // TODO: read the denominations out of the asset contract itself, instead of hardcoding them here. // Calculate FROM as Today, Now, // then calculate TO as 6 months from now, // and EXPIRATION as 3 months from now. // // TODO: Let these numbers be configured either in server operator contract, or issuer contract. // In the meantime, 3 and 6 months are good enough. OTPseudonym theNym; theNym.SetIdentifier(strServerNymID); // 1 hour == 3600 Seconds // 1 day == 86400 Seconds // 30 days == 2592000 Seconds // 3 months == 7776000 Seconds // 6 months == 15552000 Seconds // This part requires the server operator to enter his passphrase. // Which is why the server can't just fire it off automatically and // make a mint available to the client. The client has to wait a day or // until the operator is able to run this script and type the passphrase. if (theNym.Loadx509CertAndPrivateKey()) { const time_t CURRENT_TIME = time(NULL), VALID_TO = CURRENT_TIME + 15552000, // Tokens generated by this mint are valid from today until 6 months from today MINT_EXPIRATION = CURRENT_TIME + 7776000; // The mint itself will expire in 3 months from today, and be replaced with a new one. pMint->GenerateNewMint(nSeries, CURRENT_TIME, VALID_TO, MINT_EXPIRATION, ASSET_TYPE_ID, SERVER_ID, // penny, nickel, dime, quarter, $1, $5, $10, $20, $100, $1000 theNym, 1, 5, 10, 25, 100, 500, 1000, 2000, 10000, 100000); // should be: 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768, 65536 // --------------------------------------- // OTString strFilename;// strPUBLICFilename; // strFilename. Format("%s%s%s", strServerID.Get(), OTLog::PathSeparator(), strAssetTypeID.Get()); // strPUBLICFilename. Format("%s%s%s%sPUBLIC",strServerID.Get(), OTLog::PathSeparator(), strAssetTypeID.Get(), "."); OTString strServerFolder; strServerFolder.Format("%s%s%s", OTLog::MintFolder(), OTLog::PathSeparator(), strServerID.Get()); if (OTLog::ConfirmOrCreateFolder(OTLog::MintFolder()) && OTLog::ConfirmOrCreateFolder(strServerFolder.Get())) { // ------------------------------------------------------------------- // This causes the next serialization to save the private, not just public, keys. pMint->SetSavePrivateKeys(); // <== PRIVATE MINT VERSION. pMint->SignContract(theNym); pMint->SaveContract(); pMint->SaveMint(); // save the private mint file as: path/mints/server_id/Asset_TypeID (overwriting the last "current mint"...) pMint->SaveMint(strSeries.Get()); // save the private mint file as: path/mints/server_id/Asset_TypeID.nSeries (These accumulate.) // When the server needs to reference the "current" private keys, then it just loads the // mint without specifying the series number. Since this file is overwritten with each new // mint, it is thus always the latest one. (Similarly, the latest public is always asset_id.PUBLIC) // On the other hand, if I need to load the keys for a specific series, (since more than one may be // redeemable, even if only the latest one is being issued) then they are all also saved by series // number, which is not overwritten with each new mint, but accumulates. // That is why above, you see me save the mint twice in two different files, and below you see // it being saved with the .PUBLIC appending to the filename. // pMint->SaveContract(OTLog::MintFolder(), strFilename.Get()); // save the mint file. // ------------------------------------------------------------------- // Now I sign it again, to get the private keys out of there. pMint->ReleaseSignatures(); pMint->SignContract(theNym); pMint->SaveContract(); pMint->SaveMint(".PUBLIC"); // save the public mint file. // pMint->SaveContract(OTLog::MintFolder(), strPUBLICFilename.Get()); // save the public mint file. OTLog::Output(0, "Done.\n"); } else OTLog::Output(0, "Error calling OTLog::ConfirmOrCreateFolder() for path/mints/server_id\n"); } else OTLog::Output(0, "Error calling theNym.Loadx509CertAndPrivateKey()\n"); } else { OTLog::Output(0, "Error allocating memory for new OTMint.\n"); } } return 0; }
// This is called by OTCronItem::HookRemovalFromCron // (After calling this method, HookRemovalFromCron then calls onRemovalFromCron.) // void OTAgreement::onFinalReceipt(OTCronItem & theOrigCronItem, const long & lNewTransactionNumber, OTPseudonym & theOriginator, OTPseudonym * pRemover) { OTCron * pCron = GetCron(); OT_ASSERT(NULL != pCron); OTPseudonym * pServerNym = pCron->GetServerNym(); OT_ASSERT(NULL != pServerNym); // ------------------------------------------------- // The finalReceipt Item's ATTACHMENT contains the UPDATED Cron Item. // (With the SERVER's signature on it!) // OTString strUpdatedCronItem(*this); OTString * pstrAttachment=&strUpdatedCronItem; const OTString strOrigCronItem(theOrigCronItem); // ----------------------------------------------------------------- OTPseudonym theRecipientNym; // Don't use this... use the pointer just below. // The Nym who is actively requesting to remove a cron item will be passed in as pRemover. // However, sometimes there is no Nym... perhaps it just expired and pRemover is NULL. // The originating Nym (if different than remover) is loaded up. Otherwise the originator // pointer just pointers to *pRemover. // OTPseudonym * pRecipient = NULL; if (pServerNym->CompareID(this->GetRecipientUserID())) { pRecipient = pServerNym; // Just in case the recipient Nym is also the server Nym. } // ******************************************************* // // If pRemover is NOT NULL, and he has the Recipient's ID... // then set the pointer accordingly. // else if ((NULL != pRemover) && (true == pRemover->CompareID(this->GetRecipientUserID()))) { pRecipient = pRemover; // <======== now both pointers are set (to same Nym). DONE! } // -------------------------------------------------------------------------------------------------- if (NULL == pRecipient) { // GetSenderUserID() should be the same on THIS (updated version of the same cron item) // but for whatever reason, I'm checking the userID on the original version. Sue me. // const OTIdentifier NYM_ID(this->GetRecipientUserID()); theRecipientNym.SetIdentifier(NYM_ID); if (false == theRecipientNym.LoadPublicKey()) { OTString strNymID(NYM_ID); OTLog::vError("OTAgreement::onFinalReceipt: Failure loading Recipient's public key:\n%s\n", strNymID.Get()); } else if (theRecipientNym.VerifyPseudonym() && theRecipientNym.LoadSignedNymfile(*pServerNym)) // ServerNym here is merely the signer on this file. { pRecipient = &theRecipientNym; // <===== } else { OTString strNymID(NYM_ID); OTLog::vError("OTAgreement::onFinalReceipt: Failure verifying Recipient's public key or loading signed nymfile: %s\n", strNymID.Get()); } } // ------------------------------- // First, we are closing the transaction number ITSELF, of this cron item, // as an active issued number on the originating nym. (Changing it to CLOSED.) // // Second, we're verifying the CLOSING number, and using it as the closing number // on the FINAL RECEIPT (with that receipt being "InReferenceTo" this->GetTransactionNum()) // const long lRecipientOpeningNumber = this->GetRecipientOpeningNum(); const long lRecipientClosingNumber = this->GetRecipientClosingNum(); // ----------------------------------------------------------------------------------- const long lSenderOpeningNumber = theOrigCronItem.GetTransactionNum(); const long lSenderClosingNumber = (theOrigCronItem.GetCountClosingNumbers() > 0) ? theOrigCronItem.GetClosingTransactionNoAt(0) : 0; // index 0 is closing number for sender, since GetTransactionNum() is his opening #. // ---------------------------------- const OTString strServerID(GetServerID()); // ----------------------------------------------------------------- // if ((lSenderOpeningNumber > 0) && theOriginator.VerifyIssuedNum(strServerID, lSenderOpeningNumber)) { // The Nym (server side) stores a list of all opening and closing cron #s. // So when the number is released from the Nym, we also take it off that list. // std::set<long> & theIDSet = theOriginator.GetSetOpenCronItems(); theIDSet.erase(lSenderOpeningNumber); // the RemoveIssued call means the original transaction# (to find this cron item on cron) is now CLOSED. // But the Transaction itself is still OPEN. How? Because the CLOSING number is still signed out. // The closing number is also USED, since the NotarizePaymentPlan or NotarizeMarketOffer call, but it // remains ISSUED, until the final receipt itself is accepted during a process inbox. // theOriginator.RemoveIssuedNum(*pServerNym, strServerID, lSenderOpeningNumber, false); //bSave=false theOriginator.SaveSignedNymfile(*pServerNym); // ------------------------------------ OTPseudonym * pActualNym = NULL; // use this. DON'T use theActualNym. OTPseudonym theActualNym; // unused unless it's really not already loaded. (use pActualNym.) const OTIdentifier ACTUAL_NYM_ID = GetSenderUserID(); if ( (NULL != pServerNym) && pServerNym->CompareID(ACTUAL_NYM_ID) ) pActualNym = pServerNym; else if (theOriginator.CompareID(ACTUAL_NYM_ID)) pActualNym = &theOriginator; else if ( (NULL != pRemover) && pRemover->CompareID(ACTUAL_NYM_ID) ) pActualNym = pRemover; // -------------------------- else // We couldn't find the Nym among those already loaded--so we have to load { // it ourselves (so we can update its NymboxHash value.) theActualNym.SetIdentifier(ACTUAL_NYM_ID); if (false == theActualNym.LoadPublicKey()) // Note: this step may be unnecessary since we are only updating his Nymfile, not his key. { OTString strNymID(ACTUAL_NYM_ID); OTLog::vError("OTAgreement::onFinalReceipt: Failure loading public key for Nym: %s. " "(To update his NymboxHash.) \n", strNymID.Get()); } else if (theActualNym.VerifyPseudonym() && // this line may be unnecessary. theActualNym.LoadSignedNymfile(*pServerNym)) // ServerNym here is not theActualNym's identity, but merely the signer on this file. { OTLog::Output(0, "OTAgreement::onFinalReceipt: Loading actual Nym, since he wasn't already loaded. " "(To update his NymboxHash.)\n"); pActualNym = &theActualNym; // <===== } else { OTString strNymID(ACTUAL_NYM_ID); OTLog::vError("OTAgreement::onFinalReceipt: Failure loading or verifying Actual Nym public key: %s. " "(To update his NymboxHash.)\n", strNymID.Get()); } } // ------------- if (false == this->DropFinalReceiptToNymbox(GetSenderUserID(), lNewTransactionNumber, strOrigCronItem, NULL, pstrAttachment, pActualNym)) { OTLog::Error("OTAgreement::onFinalReceipt: Failure dropping sender final receipt into nymbox.\n"); } } else { OTLog::Error("OTAgreement::onFinalReceipt: Failure verifying sender's opening number.\n"); } // ----------------------------------------------------------------- if ((lSenderClosingNumber > 0) && theOriginator.VerifyIssuedNum(strServerID, lSenderClosingNumber) ) // --------------------------------------------------------------- { // In this case, I'm passing NULL for pstrNote, since there is no note. // (Additional information would normally be stored in the note.) if (false == this->DropFinalReceiptToInbox(GetSenderUserID(), GetSenderAcctID(), lNewTransactionNumber, lSenderClosingNumber, // The closing transaction number to put on the receipt. strOrigCronItem, NULL, pstrAttachment)) OTLog::Error("OTAgreement::onFinalReceipt: Failure dropping receipt into sender's inbox.\n"); // This part below doesn't happen until theOriginator ACCEPTS the final receipt (when processing his inbox.) // // theOriginator.RemoveIssuedNum(strServerID, lSenderClosingNumber, true); //bSave=false } else { OTLog::Error("OTAgreement::onFinalReceipt: Failed verifying lSenderClosingNumber=theOrigCronItem.GetClosingTransactionNoAt(0)>0 && " "theOriginator.VerifyTransactionNum(lSenderClosingNumber)\n"); } // ----------------------------------------------------------------- // if ((NULL != pRecipient) && (lRecipientOpeningNumber > 0) && pRecipient->VerifyIssuedNum(strServerID, lRecipientOpeningNumber) ) { // The Nym (server side) stores a list of all opening and closing cron #s. // So when the number is released from the Nym, we also take it off that list. // std::set<long> & theIDSet = pRecipient->GetSetOpenCronItems(); theIDSet.erase(lRecipientOpeningNumber); // the RemoveIssued call means the original transaction# (to find this cron item on cron) is now CLOSED. // But the Transaction itself is still OPEN. How? Because the CLOSING number is still signed out. // The closing number is also USED, since the NotarizePaymentPlan or NotarizeMarketOffer call, but it // remains ISSUED, until the final receipt itself is accepted during a process inbox. // pRecipient->RemoveIssuedNum(*pServerNym, strServerID, lRecipientOpeningNumber, false); //bSave=false // pRecipient->SaveSignedNymfile(*pServerNym); // Moved lower. // ----------------------------------------------------- if (false == this->DropFinalReceiptToNymbox(GetRecipientUserID(), lNewTransactionNumber, strOrigCronItem, NULL, pstrAttachment, pRecipient)) // NymboxHash is updated here in pRecipient. { OTLog::Error("OTAgreement::onFinalReceipt: Failure dropping recipient final receipt into nymbox.\n"); } // ----------------------------------------------------- // Saving both the Removed Issued Number, as well as the new NymboxHash. // NOTE: Todo: if the NymboxHash WAS updated (as it should have been) then // it was probably saved at that time. Below is therefore a redundant save. // Need to fix by making certain objects savable and dirty, and then let them // autosave before destruction, IF they are dirty. // pRecipient->SaveSignedNymfile(*pServerNym); } else { OTLog::Error("OTAgreement::onFinalReceipt: Failed verifying " "lRecipientClosingNumber=this->GetRecipientClosingTransactionNoAt(1)>0 && " "pRecipient->VerifyTransactionNum(lRecipientClosingNumber) && VerifyIssuedNum(lRecipientOpeningNumber)\n"); } // ----------------------------------------------------------------- if ((NULL != pRecipient) && (lRecipientClosingNumber > 0) && pRecipient->VerifyIssuedNum(strServerID, lRecipientClosingNumber) ) { if (false == this->DropFinalReceiptToInbox(GetRecipientUserID(), GetRecipientAcctID(), lNewTransactionNumber, lRecipientClosingNumber, // The closing transaction number to put on the receipt. strOrigCronItem, NULL, pstrAttachment)) OTLog::Error("OTAgreement::onFinalReceipt: Failure dropping receipt into recipient's inbox.\n"); // This part below doesn't happen until pRecipient ACCEPTs the final receipt (when processing his inbox.) // // pRecipient->RemoveIssuedNum(strServerID, lRecipientClosingNumber, true); //bSave=false } else { OTLog::Error("OTAgreement::onFinalReceipt: Failed verifying " "lRecipientClosingNumber=this->GetRecipientClosingTransactionNoAt(1)>0 && " "pRecipient->VerifyTransactionNum(lRecipientClosingNumber) && VerifyIssuedNum(lRecipientOpeningNumber)\n"); } // QUESTION: Won't there be Cron Items that have no asset account at all? // In which case, there'd be no need to drop a final receipt, but I don't think // that's the case, since you have to use a transaction number to get onto cron // in the first place. // ----------------------------------------------------------------- }
// 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; }
// ---------------------------------------------------- // INTERNAL NYM: For adding a PASSPHRASE to a PURSE. // // What if you DON'T want to encrypt the purse to your Nym?? // What if you just want to use a passphrase instead? // That's what these functions are for. OT just generates // a dummy Nym and stores it INSIDE THE PURSE. You set the // passphrase for the dummy nym, and thereafter your // experience is one of a password-protected purse. (But // in reality, there is a dummy nym inside that purse.) // bool OTPurse::GenerateInternalNym(int nBits/*=1024*/) { // ------------------------------------------- if (this->IsUsingATempNym() || (NULL != this->GetInternalNym())) { OTLog::Output(0, "OTPurse::GenerateInternalNym: Failed: internal Nym already exists.\n"); return false; } // ------------------------------------------- if (!this->IsEmpty()) { OTLog::Output(0, "OTPurse::GenerateInternalNym: Failed: The purse must be EMPTY before you create a new dummy Nym, internal to that purse. (For the purposes of adding a passphrase to the purse, normally.)\n"); return false; } // ------------------------------------------- switch (nBits) { case 1024: // todo hardcoding. case 2048: case 4096: case 8192: break; default: OTLog::vError("OTPurse::GenerateInternalNym: Failure: nBits must be one of: " "1024, 2048, 4096, 8192. (%d was passed...)\n", nBits); return false; } // ------------------------------------------- OTPseudonym * pNym = new OTPseudonym; OT_ASSERT_MSG(NULL != pNym, "OTPurse::GenerateInternalNym: Assert: NULL != new OTPseudonym \n"); // BELOW THIS point, pNym must either be deleted, or saved. (Or it will leak.) // -------------------------------------------- if (false == pNym->GenerateNym(nBits, false)) // bCreateFile=true by default, but it's FALSE here. { OTLog::vOutput(0, "OTPurse::GenerateInternalNym: Failed while calling pNym->GenerateNym(%d, false).\n", nBits); delete pNym; pNym = NULL; return false; } // --------------------------------------------------- const bool bSetIdentifier = pNym->SetIdentifierByPubkey(); OT_ASSERT_MSG(bSetIdentifier, "OTPurse::GenerateInternalNym: Assert: pNym->SetIdentifierByPubkey() \n"); // By this point, the Nym has been successfully generated, and he even has an ID! // Let's attach him to the purse so we don't have to keep worrying about a leak. // m_pTempNym = pNym; // ---------------------------- // Let's make sure the new Nym's ID is also this purse's UserID... // pNym->GetIdentifier(m_UserID); m_bUsingTempNym = true; m_bIsNymIDIncluded = true; return true; }
// RSA / AES bool OTEnvelope::Seal(const OTPseudonym & theRecipient, const OTString & theContents) { return Seal(theRecipient.GetPublicKey(), theContents); }
/// Only if it is an inbox, a ledger will loop through the transactions /// and produce the XML output for the report that's necessary during /// a balance agreement. (Any balance agreement for an account must /// include the list of transactions the nym has issued for use, as /// well as a listing of the transactions in the inbox for that account. /// This function does that last part :) /// /// returns a new balance statement item containing the inbox report /// CALLER IS RESPONSIBLE TO DELETE. OTItem * OTLedger::GenerateBalanceStatement(const long lAdjustment, const OTTransaction & theOwner, OTPseudonym & theNym, const OTAccount & theAccount, OTLedger & theOutbox) { if (OTLedger::inbox != GetType()) { OTLog::Error("OTLedger::GenerateBalanceStatement: Wrong ledger type.\n"); return NULL; } // ------------------------------------------------------ const OTIdentifier theNymID(theNym); if ( (theAccount.GetPurportedAccountID() != GetPurportedAccountID()) || (theAccount.GetPurportedServerID() != GetPurportedServerID()) || (theAccount.GetUserID() != GetUserID()) ) { OTLog::Error("Wrong Account passed in to OTLedger::GenerateBalanceStatement.\n"); return NULL; } if ( (theOutbox.GetPurportedAccountID() != GetPurportedAccountID()) || (theOutbox.GetPurportedServerID() != GetPurportedServerID()) || (theOutbox.GetUserID() != GetUserID()) ) { OTLog::Error("Wrong Outbox passed in to OTLedger::GenerateBalanceStatement.\n"); return NULL; } if ( (theNymID != GetUserID())) { OTLog::Error("Wrong Nym passed in to OTLedger::GenerateBalanceStatement.\n"); return NULL; } // --------------------------------------------------------- // theOwner is the withdrawal, or deposit, or whatever, that wants to change // the account balance, and thus that needs a new balance agreement signed. // OTItem * pBalanceItem = OTItem::CreateItemFromTransaction(theOwner, OTItem::balanceStatement); // <=== balanceStatement type, with user ID, server ID, account ID, transaction ID. // The above has an ASSERT, so this this will never actually happen. if (NULL == pBalanceItem) return NULL; // --------------------------------------------------------- // COPY THE ISSUED TRANSACTION NUMBERS FROM THE NYM to the MESSAGE NYM. OTPseudonym theMessageNym; theMessageNym.HarvestIssuedNumbers(this->GetPurportedServerID(), theNym /*unused in this case, not saving to disk*/, theNym, false); // bSave = false; // ------------------------------------- switch (theOwner.GetType()) { // These five options will remove the transaction number from the issued list, SUCCESS OR FAIL. // Server will expect the number to be missing from the list, in the case of these. // Therefore I remove it here in order to generate a proper balance agreement, acceptable to the server. case OTTransaction::processInbox: case OTTransaction::deposit: case OTTransaction::withdrawal: case OTTransaction::cancelCronItem: case OTTransaction::exchangeBasket: theMessageNym.RemoveIssuedNum(theOwner.GetRealServerID(), theOwner.GetTransactionNum()); // a transaction number is being used, and REMOVED from my list of responsibility, theMessageNym.RemoveTransactionNum(theOwner.GetRealServerID(), theOwner.GetTransactionNum()); // a transaction number is being used, and REMOVED from my list of available numbers. break; case OTTransaction::transfer: case OTTransaction::marketOffer: case OTTransaction::paymentPlan: // Nothing removed here since the transaction is still in play. (Assuming success.) // If the server replies with rejection for any of these three, then I can remove // the transaction number from my list of issued/signed for. But if success, then I // am responsible for the transaction number until I sign off on closing it. // Since the Balance Statement ANTICIPATES SUCCESS, NOT FAILURE, it assumes the number // to be "in play" here, and thus DOES NOT remove it (vs the cases above, which do.) break; default: // Error OTLog::vError("OTLedger::GenerateBalanceStatement: wrong owner transaction type: %s\n", theOwner.GetTypeString()); break; } OTString strMessageNym(theMessageNym); // Okay now we have the transaction numbers in this MessageNym string. pBalanceItem->SetAttachment(strMessageNym); // <======== This is where the server will read the transaction numbers from (A nym in item.m_ascAttachment) // --------------------------------------------------------- long lCurrentBalance = theAccount.GetBalance(); pBalanceItem->SetAmount(lCurrentBalance + lAdjustment); // <==== Here's the new (predicted) balance for after the withdrawal is complete. (item.GetAmount) // --------------------------------------------------------- // loop through the INBOX transactions, and produce a sub-item onto pBalanceItem for each, which will // be a report on each transaction in this inbox, therefore added to the balance item. // (So the balance item contains a complete report on the receipts in this inbox.) OTTransaction * pTransaction = NULL; OTLog::Output(2, "About to loop through the inbox items and produce a report for each one...\n"); for (mapOfTransactions::iterator ii = m_mapTransactions.begin(); ii != m_mapTransactions.end(); ++ii) { pTransaction = (*ii).second; OT_ASSERT(NULL != pTransaction); OTLog::Output(2, "Producing a report...\n"); // it only reports receipts where we don't yet have balance agreement. // pTransaction->ProduceInboxReportItem(*pBalanceItem, const_cast<OTTransaction &>(theOwner)); pTransaction->ProduceInboxReportItem(*pBalanceItem); // <======= This function adds a receipt sub-item to pBalanceItem, where appropriate for INBOX items. // self note: I added the const_cast because the function needs to loop through it, even though it doesn't really change it // (doesn't violate the const, just needs to perform a loop and the const screws with the loop.) } // --------------------------------------------------------- theOutbox.ProduceOutboxReport(*pBalanceItem); // <======= This function adds receipt sub-items to pBalanceItem, where appropriate for the OUTBOX items. // --------------------------------------------------------- pBalanceItem->SignContract(theNym); // <=== Sign, save, and return. OTTransactionType needs to weasel in a "date signed" variable. pBalanceItem->SaveContract(); return pBalanceItem; }
// THIS FUNCTION IS CALLED BY THE CUSTOMER // // (Transaction number and closing number are retrieved from Nym at this time.) bool OTAgreement::Confirm(OTPseudonym & MERCHANT_NYM, OTPseudonym & PAYER_NYM) { // ---------------------------------------------------------------------------- OTIdentifier id_MERCHANT_NYM, id_PAYER_NYM; MERCHANT_NYM.GetIdentifier(id_MERCHANT_NYM); PAYER_NYM.GetIdentifier(id_PAYER_NYM); if (GetRecipientUserID() == GetSenderUserID()) { OTLog::Output(0, "OTAgreement::Confirm: Error: Sender and recipient have the same Nym ID (not allowed.)\n"); return false; } else if (GetRecipientUserID() != id_MERCHANT_NYM) { OTLog::Output(0, "OTAgreement::Confirm: Merchant has wrong NymID (should be same as RecipientUserID.)\n"); return false; } else if (GetSenderUserID() != id_PAYER_NYM) { OTLog::Output(0, "OTAgreement::Confirm: Payer has wrong NymID (should be same as SenderUserID.)\n"); return false; } else if (PAYER_NYM.GetTransactionNumCount(GetServerID()) < 2) // Need opening and closing numbers (that's 2)... { OTLog::Output(0, "OTAgreement::Confirm: Failure. You need at least 2 transaction numbers available to do this.\n"); return false; } else if (GetRecipientCountClosingNumbers() < 2) { OTLog::Output(0, "OTAgreement::Confirm: Failure. (The merchant was supposed to attach 2 transaction numbers.)\n"); return false; } // ---------------------------------------------------------------------------- // This is the single reason why MERCHANT_NYM was even passed in here! // Supposedly merchant has already signed. Let's verify this!! // if (false == this->VerifySignature(MERCHANT_NYM)) { OTLog::Output(0, "OTAgreement::Confirm: Merchant's signature failed to verify.\n"); return false; } // ---------------------------------------------------------------------------- // Now that we KNOW the merchant signed it... SAVE MERCHANT's COPY. // Let's save a copy of the one the merchant signed, before changing it and re-signing it, // (to add my own transaction numbers...) // OTString strTemp; this->SaveContractRaw(strTemp); this->SetMerchantSignedCopy(strTemp); // ******************************************************************* // The payer has to submit TWO transaction numbers in order to activate this agreement... // OTString strServerID(GetServerID()); long lTransactionNumber=0, lClosingTransactionNo=0; if (false == PAYER_NYM.GetNextTransactionNum(PAYER_NYM, strServerID, lTransactionNumber)) { OTLog::Error("OTAgreement::Confirm: Error: Strangely unable to get a transaction number.\n"); return false; } else if (false == PAYER_NYM.GetNextTransactionNum(PAYER_NYM, strServerID, lClosingTransactionNo)) { OTLog::Error("OTAgreement::Confirm: Error: Strangely unable to get a closing transaction number.\n"); PAYER_NYM.AddTransactionNum(PAYER_NYM, strServerID, lTransactionNumber, true); // bSave=true // (Since the first one was successful, we just put it back before returning.) return false; } // At this point we now HAVE 2 transaction numbers (for payer / sender)... // We can't return without USING THEM or PUTTING THEM BACK. // // --------------------------------------------------------- this->SetTransactionNum(lTransactionNumber); // Set the Transaction Number this->AddClosingTransactionNo(lClosingTransactionNo); // and the Closing Number (both for sender)... // ------------------------------------------- // CREATION DATE was set in the Merchant's proposal, and it's RESET here in the Confirm. // This way, (since we still have the original proposal) we can see BOTH times. // time_t CURRENT_TIME = time(NULL); // Set the Creation Date. SetCreationDate(CURRENT_TIME); // ------------------------------------------- OTLog::Output(4, "OTAgreement::Confirm(): Success!\n"); return true; }
// THIS FUNCTION IS CALLED BY THE MERCHANT // // (lMerchantTransactionNumber, lMerchantClosingNumber are set internally in this call, from MERCHANT_NYM.) bool OTAgreement::SetProposal(OTPseudonym & MERCHANT_NYM, const OTString & strConsideration, const time_t VALID_FROM/*=0*/, const time_t VALID_TO/*=0*/) { // ---------------------------------------------------------------------------- OTIdentifier id_MERCHANT_NYM; MERCHANT_NYM.GetIdentifier(id_MERCHANT_NYM); if (GetRecipientUserID() != id_MERCHANT_NYM) { OTLog::Output(0, "OTAgreement::SetProposal: Merchant has wrong NymID (should be same as RecipientUserID.)\n"); return false; } else if (GetRecipientUserID() == GetSenderUserID()) { OTLog::Output(0, "OTAgreement::SetProposal: Error: Sender and recipient have the same Nym ID (not allowed.)\n"); return false; } else if (MERCHANT_NYM.GetTransactionNumCount(GetServerID()) < 2) // Need opening and closing numbers (that's 2)... { OTLog::Output(0, "OTAgreement::SetProposal: Failure. You need at least 2 transaction numbers available to do this.\n"); return false; } // ------------------------------------------- // Set the CREATION DATE // const time_t CURRENT_TIME = time(NULL); // Set the Creation Date. SetCreationDate(CURRENT_TIME); // ----------------------------------------- // Putting this above here so I don't have to put the transaction numbers back if this fails: // ------------------------------------------- // VALID_FROM // // The default "valid from" time is NOW. if (0 >= VALID_FROM) // if it's 0 or less, set to current time. SetValidFrom(CURRENT_TIME); else // Otherwise use whatever was passed in. SetValidFrom(VALID_FROM); // ------------------------------------------- // VALID_TO // // The default "valid to" time is 0 (which means no expiration date / cancel anytime.) if (0 == VALID_TO) // VALID_TO is 0 { SetValidTo(VALID_TO); // Keep it at zero then, so it won't expire. } else if (0 < VALID_TO) // VALID_TO is ABOVE zero... { if (VALID_TO < VALID_FROM) // If Valid-To date is EARLIER than Valid-From date... { long lValidTo = VALID_TO, lValidFrom = VALID_FROM; OTLog::vError("OTAgreement::SetProposal: VALID_TO (%ld) is earlier than VALID_FROM (%ld)\n", lValidTo, lValidFrom); return false; } SetValidTo(VALID_TO); // Set it to whatever it is, since it is now validated as higher than Valid-From. } else // VALID_TO is a NEGATIVE number... Error. { long lValidTo = VALID_TO; OTLog::vError("Negative value for valid_to in SetAgreement: %ld\n", lValidTo); return false; } // ---------------------------------------------------------------------------- // Since we'll be needing 2 transaction numbers to do this, let's grab 'em... // OTString strServerID(GetServerID()); long lTransactionNumber=0, lClosingTransactionNo=0; if (MERCHANT_NYM.GetTransactionNumCount(GetServerID()) < 2) // Need opening and closing numbers (that's 2)... { OTLog::Output(0, "OTAgreement::SetProposal: Failure. You need at least 2 transaction numbers available to do this.\n"); return false; } else if (false == MERCHANT_NYM.GetNextTransactionNum(MERCHANT_NYM, strServerID, lTransactionNumber)) { OTLog::Error("OTAgreement::SetProposal: Error: Strangely unable to get a transaction number.\n"); return false; } else if (false == MERCHANT_NYM.GetNextTransactionNum(MERCHANT_NYM, strServerID, lClosingTransactionNo)) { OTLog::Error("OTAgreement::SetProposal: Error: Strangely unable to get a closing transaction number.\n"); MERCHANT_NYM.AddTransactionNum(MERCHANT_NYM, strServerID, lTransactionNumber, true); // bSave=true // (Since the first one was successful, we just put it back before returning.) return false; } // At this point we now have 2 transaction numbers... // We can't return without either USING THEM, or PUTTING THEM BACK. // // --------------------------------------------------------- // Set the Transaction Number and the Closing transaction number... (for merchant / recipient.) // this->AddRecipientClosingTransactionNo(lTransactionNumber); this->AddRecipientClosingTransactionNo(lClosingTransactionNo); // (They just both go onto this same list.) // ------------------------------------------- // Set the Consideration memo... m_strConsideration.Set(strConsideration); // ------------------------------------------- OTLog::Output(4, "Successfully performed OTPaymentPlan::SetProposal()\n"); return true; }
// 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; }
bool OTEnvelope::Open(const OTPseudonym & theRecipient, OTString & theContents) { bool retval = false; EVP_CIPHER_CTX ctx; unsigned char buffer[4096]; unsigned char buffer_out[4096 + EVP_MAX_IV_LENGTH]; unsigned char iv[EVP_MAX_IV_LENGTH]; size_t len = 0; int len_out = 0; unsigned char * ek = NULL; int eklen = 0; uint32_t eklen_n = 0; memset(buffer, 0, 4096); memset(buffer_out, 0, 4096 + EVP_MAX_IV_LENGTH); memset(iv, 0, EVP_MAX_IV_LENGTH); OTAsymmetricKey & privateKey = (OTAsymmetricKey &)theRecipient.GetPrivateKey(); EVP_PKEY * pkey = (EVP_PKEY *)privateKey.GetKey(); if (NULL == pkey) { OTLog::Error("Null private key in OTEnvelope::Open\n"); return false; } EVP_CIPHER_CTX_init(&ctx); ek = (unsigned char*)malloc(EVP_PKEY_size(pkey)); // I assume this is for the AES key OT_ASSERT(NULL != ek); memset(ek, 0, EVP_PKEY_size(pkey)); eklen = EVP_PKEY_size(pkey); //int EVP_OpenInit(EVP_CIPHER_CTX *ctx, //EVP_CIPHER *type, //unsigned char *ek, //int ekl, //unsigned char *iv, //EVP_PKEY *priv); //EVP_OpenInit() initializes a cipher context ctx for decryption with cipher type. It decrypts the encrypted // symmetric key of length ekl bytes passed in the ek parameter using the private key priv. The IV is supplied // in the iv parameter. theContents.Release(); // This is where we'll put the decrypted data. m_dataContents.reset(); // reset the fread position on this object. int nReadLength = 0; int nReadKey = 0; int nReadIV = 0; // First we read the encrypted key size. if (0 == (nReadLength = m_dataContents.OTfread((char*)&eklen_n, sizeof(eklen_n)))) { OTLog::Error("Error reading encrypted key size in OTEnvelope::Open\n"); free(ek); ek = NULL; return false; } // convert it from network to host endian. eklen = ntohl(eklen_n); // Next we read the encrypted key itself. if (0 == (nReadKey = m_dataContents.OTfread((char*)ek, eklen))) { OTLog::Error("Error reading encrypted key size in OTEnvelope::Open\n"); free(ek); ek = NULL; return false; } // Next we read the initialization vector. if (0 == (nReadIV = m_dataContents.OTfread((char*)iv, EVP_CIPHER_iv_length(EVP_aes_128_cbc())))) { OTLog::Error("Error reading initialization vector in OTEnvelope::Open\n"); free(ek); ek = NULL; return false; } OTData ciphertext((const void*)((unsigned char *)m_dataContents.GetPointer() + nReadLength + nReadKey + nReadIV), m_dataContents.GetSize() - nReadLength - nReadKey - nReadIV); // Now we process ciphertext and write the decrypted data to plaintext. OTData plaintext; if (!EVP_OpenInit(&ctx, EVP_aes_128_cbc(), ek, eklen, iv, pkey)) { OTLog::Error("EVP_OpenInit: failed.\n"); free(ek); ek = NULL; return false; } while ((len = ciphertext.OTfread((char*)buffer, sizeof(buffer))) > 0) { if (!EVP_OpenUpdate(&ctx, buffer_out, &len_out, buffer, len)) { OTLog::Error("EVP_OpenUpdate: failed.\n"); free(ek); ek = NULL; return false; } OTData dataOpenUpdate(buffer_out, len_out); plaintext += dataOpenUpdate; } if (!EVP_OpenFinal(&ctx, buffer_out, &len_out)) { OTLog::Error("EVP_OpenFinal: failed.\n"); free(ek); ek = NULL; return false; } OTData dataOpenFinal(buffer_out, len_out); plaintext += dataOpenFinal; // Make sure it's null terminated int nIndex = plaintext.GetSize()-1; ((unsigned char*)plaintext.GetPointer())[nIndex] = 0; // Set it into theContents (to return the plaintext to the caller) theContents.Set((const char *)plaintext.GetPointer()); retval = true; free(ek); ek = NULL; return retval; }