/** * Sets the currency number of a wallet */ static tABC_CC ABC_WalletSetCurrencyNum(tABC_WalletID self, int currencyNum, tABC_Error *pError) { tABC_CC cc = ABC_CC_Ok; tWalletData *pData = NULL; char *szFilename = NULL; char *szJSON = NULL; // load the wallet data into the cache ABC_CHECK_RET(ABC_WalletCacheData(self, &pData, pError)); // set the currency number pData->currencyNum = currencyNum; // create the json for the currency number ABC_CHECK_RET(ABC_UtilCreateIntJSONString(currencyNum, JSON_WALLET_CURRENCY_NUM_FIELD, &szJSON, pError)); //printf("currency num:\n%s\n", szJSON); // write the name out to the file ABC_STR_NEW(szFilename, ABC_FILEIO_MAX_PATH_LENGTH); sprintf(szFilename, "%s/%s", pData->szWalletSyncDir, WALLET_CURRENCY_FILENAME); tABC_U08Buf Data; ABC_BUF_SET_PTR(Data, (unsigned char *)szJSON, strlen(szJSON) + 1); ABC_CHECK_RET(ABC_CryptoEncryptJSONFile(Data, pData->MK, ABC_CryptoType_AES256, szFilename, pError)); exit: ABC_FREE_STR(szFilename); ABC_FREE_STR(szJSON); return cc; }
/** * Sets the name of a wallet */ tABC_CC ABC_WalletSetName(tABC_WalletID self, const char *szName, tABC_Error *pError) { tABC_CC cc = ABC_CC_Ok; tWalletData *pData = NULL; char *szFilename = NULL; char *szJSON = NULL; // load the wallet data into the cache ABC_CHECK_RET(ABC_WalletCacheData(self, &pData, pError)); // set the new name ABC_FREE_STR(pData->szName); ABC_STRDUP(pData->szName, szName); // create the json for the wallet name ABC_CHECK_RET(ABC_UtilCreateValueJSONString(szName, JSON_WALLET_NAME_FIELD, &szJSON, pError)); //printf("name:\n%s\n", szJSON); // write the name out to the file ABC_STR_NEW(szFilename, ABC_FILEIO_MAX_PATH_LENGTH); sprintf(szFilename, "%s/%s", pData->szWalletSyncDir, WALLET_NAME_FILENAME); tABC_U08Buf Data; ABC_BUF_SET_PTR(Data, (unsigned char *)szJSON, strlen(szJSON) + 1); ABC_CHECK_RET(ABC_CryptoEncryptJSONFile(Data, pData->MK, ABC_CryptoType_AES256, szFilename, pError)); exit: ABC_FREE_STR(szFilename); ABC_FREE_STR(szJSON); return cc; }
/** * Sync the wallet's data */ tABC_CC ABC_WalletSyncData(tABC_WalletID self, int *pDirty, tABC_Error *pError) { tABC_CC cc = ABC_CC_Ok; ABC_SET_ERR_CODE(pError, ABC_CC_Ok); tABC_GeneralInfo *pInfo = NULL; char *szDirectory = NULL; char *szSyncDirectory = NULL; tWalletData *pData = NULL; bool bExists = false; bool bNew = false; // Fetch general info ABC_CHECK_RET(ABC_GeneralGetInfo(&pInfo, pError)); // create the wallet root directory if necessary ABC_CHECK_RET(ABC_WalletCreateRootDir(pError)); // create the wallet directory - <Wallet_UUID1> <- All data in this directory encrypted with MK_<Wallet_UUID1> ABC_CHECK_RET(ABC_WalletGetDirName(&szDirectory, self.szUUID, pError)); ABC_CHECK_RET(ABC_FileIOFileExists(szDirectory, &bExists, pError)); if (!bExists) { ABC_CHECK_RET(ABC_FileIOCreateDir(szDirectory, pError)); } // create the wallet sync dir under the main dir ABC_CHECK_RET(ABC_WalletGetSyncDirName(&szSyncDirectory, self.szUUID, pError)); ABC_CHECK_RET(ABC_FileIOFileExists(szSyncDirectory, &bExists, pError)); if (!bExists) { ABC_CHECK_RET(ABC_FileIOCreateDir(szSyncDirectory, pError)); // Init repo ABC_CHECK_RET(ABC_SyncMakeRepo(szSyncDirectory, pError)); bNew = true; } // load the wallet data into the cache ABC_CHECK_RET(ABC_WalletCacheData(self, &pData, pError)); ABC_CHECK_ASSERT(NULL != pData->szWalletAcctKey, ABC_CC_Error, "Expected to find RepoAcctKey in key cache"); // Sync ABC_CHECK_RET(ABC_SyncRepo(pData->szWalletSyncDir, pData->szWalletAcctKey, pDirty, pError)); if (*pDirty || bNew) { *pDirty = 1; ABC_CHECK_RET(ABC_WalletClearCache(pError)); } exit: ABC_FREE_STR(szSyncDirectory); ABC_FREE_STR(szDirectory); ABC_GeneralFreeInfo(pInfo); return cc; }
void ABC_TxDetailsFree(tABC_TxDetails *pDetails) { if (pDetails) { ABC_FREE_STR(pDetails->szName); ABC_FREE_STR(pDetails->szCategory); ABC_FREE_STR(pDetails->szNotes); ABC_CLEAR_FREE(pDetails, sizeof(tABC_TxDetails)); } }
/** * Activate an account on the server. * * @param LP1 Password hash for the account */ tABC_CC ABC_LoginServerActivate(const Lobby &lobby, tABC_U08Buf LP1, tABC_Error *pError) { tABC_CC cc = ABC_CC_Ok; HttpReply reply; std::string url = ABC_SERVER_ROOT "/" ABC_SERVER_ACCOUNT_ACTIVATE; ServerReplyJson replyJson; char *szPost = NULL; json_t *pJSON_Root = NULL; // create the post data pJSON_Root = json_pack("{ssss}", ABC_SERVER_JSON_L1_FIELD, base64Encode(lobby.authId()).c_str(), ABC_SERVER_JSON_LP1_FIELD, base64Encode(LP1).c_str()); szPost = ABC_UtilStringFromJSONObject(pJSON_Root, JSON_COMPACT); // send the command ABC_CHECK_NEW(AirbitzRequest().post(reply, url, szPost)); // decode the result ABC_CHECK_NEW(replyJson.decode(reply.body)); ABC_CHECK_NEW(replyJson.ok()); exit: ABC_FREE_STR(szPost); if (pJSON_Root) json_decref(pJSON_Root); return cc; }
/** * Frees the strings inside a tABC_WalletID struct. * * This is normally not necessary, except in cases where ABC_WalletIDCopy * has been used. */ void ABC_WalletIDFree(tABC_WalletID in) { char *szUUID = (char *)in.szUUID; ABC_SyncFreeKeys(in.pKeys); ABC_FREE_STR(szUUID); }
int main(int argc, char *argv[]) { tABC_CC cc; tABC_Error error; unsigned char seed[] = {1, 2, 3}; tABC_SyncKeys *pKeys = NULL; tABC_U08Buf data; char *szSeed; if (argc != 5) { fprintf(stderr, "usage: %s <dir> <user> <pass> <wallet-name>\n", argv[0]); return 1; } MAIN_CHECK(ABC_Initialize(argv[1], CA_CERT, seed, sizeof(seed), &error)); MAIN_CHECK(ABC_LoginShimGetSyncKeys(argv[2], argv[3], &pKeys, &error)); MAIN_CHECK(ABC_WalletGetBitcoinPrivateSeed(ABC_WalletID(pKeys, argv[4]), &data, &error)); MAIN_CHECK(ABC_CryptoHexEncode(data, &szSeed, &error)); printf("%s\n", szSeed); ABC_SyncFreeKeys(pKeys); ABC_BUF_FREE(data); ABC_FREE_STR(szSeed); return 0; }
/** * Changes the password for an account on the server. * * This function sends information to the server to change the password for an account. * Either the old LP1 or LRA1 can be used for authentication. * * @param oldLP1 Old password hash for the account (if this is empty, LRA1 is used instead) * @param LRA1 LRA1 for the account (used if oldP1 is empty) */ tABC_CC ABC_LoginServerChangePassword(const Lobby &lobby, tABC_U08Buf oldLP1, tABC_U08Buf newLP1, tABC_U08Buf newLRA1, const CarePackage &carePackage, const LoginPackage &loginPackage, tABC_Error *pError) { tABC_CC cc = ABC_CC_Ok; HttpReply reply; std::string url = ABC_SERVER_ROOT "/" ABC_SERVER_CHANGE_PASSWORD_PATH; ServerReplyJson replyJson; char *szPost = NULL; std::string carePackageStr; std::string loginPackageStr; json_t *pJSON_OldLRA1 = NULL; json_t *pJSON_NewLRA1 = NULL; json_t *pJSON_Root = NULL; ABC_CHECK_NULL_BUF(oldLP1); ABC_CHECK_NULL_BUF(newLP1); ABC_CHECK_NEW(carePackage.encode(carePackageStr)); ABC_CHECK_NEW(loginPackage.encode(loginPackageStr)); // Encode those: pJSON_Root = json_pack("{ss, ss, ss, ss, ss}", ABC_SERVER_JSON_L1_FIELD, base64Encode(lobby.authId()).c_str(), ABC_SERVER_JSON_LP1_FIELD, base64Encode(oldLP1).c_str(), ABC_SERVER_JSON_NEW_LP1_FIELD, base64Encode(newLP1).c_str(), ABC_SERVER_JSON_CARE_PACKAGE_FIELD, carePackageStr.c_str(), ABC_SERVER_JSON_LOGIN_PACKAGE_FIELD, loginPackageStr.c_str()); // set up the recovery, if any: if (newLRA1.size()) { pJSON_NewLRA1 = json_string(base64Encode(newLRA1).c_str()); json_object_set(pJSON_Root, ABC_SERVER_JSON_NEW_LRA1_FIELD, pJSON_NewLRA1); } // create the post data szPost = ABC_UtilStringFromJSONObject(pJSON_Root, JSON_COMPACT); // send the command ABC_CHECK_NEW(AirbitzRequest().post(reply, url, szPost)); ABC_CHECK_NEW(replyJson.decode(reply.body)); ABC_CHECK_NEW(replyJson.ok()); exit: ABC_FREE_STR(szPost); if (pJSON_OldLRA1) json_decref(pJSON_OldLRA1); if (pJSON_NewLRA1) json_decref(pJSON_NewLRA1); if (pJSON_Root) json_decref(pJSON_Root); return cc; }
/** * Frees the general info struct. */ void ABC_GeneralFreeInfo(tABC_GeneralInfo *pInfo) { if (pInfo) { if ((pInfo->aMinersFees != NULL) && (pInfo->countMinersFees > 0)) { for (unsigned i = 0; i < pInfo->countMinersFees; i++) { ABC_CLEAR_FREE(pInfo->aMinersFees[i], sizeof(tABC_GeneralMinerFee)); } ABC_CLEAR_FREE(pInfo->aMinersFees, sizeof(tABC_GeneralMinerFee *) * pInfo->countMinersFees); } if (pInfo->pAirBitzFee) { ABC_FREE_STR(pInfo->pAirBitzFee->szAddresss); ABC_CLEAR_FREE(pInfo->pAirBitzFee, sizeof(tABC_GeneralMinerFee)); } if ((pInfo->aszObeliskServers != NULL) && (pInfo->countObeliskServers > 0)) { for (unsigned i = 0; i < pInfo->countObeliskServers; i++) { ABC_FREE_STR(pInfo->aszObeliskServers[i]); } ABC_CLEAR_FREE(pInfo->aszObeliskServers, sizeof(char *) * pInfo->countObeliskServers); } if ((pInfo->aszSyncServers != NULL) && (pInfo->countSyncServers > 0)) { for (unsigned i = 0; i < pInfo->countSyncServers; i++) { ABC_FREE_STR(pInfo->aszSyncServers[i]); } ABC_CLEAR_FREE(pInfo->aszSyncServers, sizeof(char *) * pInfo->countSyncServers); } ABC_CLEAR_FREE(pInfo, sizeof(tABC_GeneralInfo)); } }
int main(int argc, char *argv[]) { tABC_CC cc; tABC_Error error; unsigned char seed[] = {1, 2, 3}; tABC_SyncKeys *pKeys = NULL; tABC_AccountWalletInfo info; tABC_U08Buf data = ABC_BUF_NULL; char *szContents = NULL; char *szEncrypted = NULL; if (argc != 6) { fprintf(stderr, "usage: %s <dir> <user> <pass> <uuid> <filepath>\n", argv[0]); return 1; } MAIN_CHECK(ABC_Initialize(argv[1], CA_CERT, seed, sizeof(seed), &error)); MAIN_CHECK(ABC_LoginShimGetSyncKeys(argv[2], argv[3], &pKeys, &error)); MAIN_CHECK(ABC_AccountWalletLoad(pKeys, argv[4], &info, &error)); szContents = Slurp(argv[5]); if (szContents) { ABC_BUF_SET_PTR(data, (unsigned char *) szContents, strlen(szContents)); MAIN_CHECK(ABC_CryptoEncryptJSONString( data, info.MK, ABC_CryptoType_AES256, &szEncrypted, &error)); printf("%s\n", szEncrypted); } ABC_SyncFreeKeys(pKeys); ABC_AccountWalletInfoFree(&info); ABC_FREE_STR(szContents); ABC_FREE_STR(szEncrypted); return 0; }
/** * Uploads the pin package. * * @param LP1 Login + Password hash * @param DID Device Id * @param LPIN1 Hashed pin * @param szPinPackage Pin package * @param szAli auto-logout interval */ tABC_CC ABC_LoginServerUpdatePinPackage(const Lobby &lobby, tABC_U08Buf LP1, tABC_U08Buf DID, tABC_U08Buf LPIN1, const std::string &pinPackage, time_t ali, tABC_Error *pError) { tABC_CC cc = ABC_CC_Ok; HttpReply reply; std::string url = ABC_SERVER_ROOT "/" ABC_SERVER_PIN_PACK_UPDATE_PATH; ServerReplyJson replyJson; char *szPost = NULL; json_t *pJSON_Root = NULL; char szALI[DATETIME_LENGTH]; ABC_CHECK_NULL_BUF(LP1); ABC_CHECK_NULL_BUF(DID); ABC_CHECK_NULL_BUF(LPIN1); // format the ali strftime(szALI, DATETIME_LENGTH, "%Y-%m-%dT%H:%M:%S", gmtime(&ali)); // Encode those: pJSON_Root = json_pack("{ss, ss, ss, ss, ss, ss}", ABC_SERVER_JSON_L1_FIELD, base64Encode(lobby.authId()).c_str(), ABC_SERVER_JSON_LP1_FIELD, base64Encode(LP1).c_str(), ABC_SERVER_JSON_DID_FIELD, base64Encode(DID).c_str(), ABC_SERVER_JSON_LPIN1_FIELD, base64Encode(LPIN1).c_str(), JSON_ACCT_PIN_PACKAGE, pinPackage.c_str(), ABC_SERVER_JSON_ALI_FIELD, szALI); // create the post data szPost = ABC_UtilStringFromJSONObject(pJSON_Root, JSON_COMPACT); // send the command ABC_CHECK_NEW(AirbitzRequest().post(reply, url, szPost)); ABC_CHECK_NEW(replyJson.decode(reply.body)); ABC_CHECK_NEW(replyJson.ok()); exit: ABC_FREE_STR(szPost); if (pJSON_Root) json_decref(pJSON_Root); return cc; }
tABC_CC ABC_LoginServerGetPinPackage(tABC_U08Buf DID, tABC_U08Buf LPIN1, char **szPinPackage, tABC_Error *pError) { tABC_CC cc = ABC_CC_Ok; HttpReply reply; std::string url = ABC_SERVER_ROOT "/" ABC_SERVER_PIN_PACK_GET_PATH; ServerReplyJson replyJson; json_t *pJSON_Value = NULL; json_t *pJSON_Root = NULL; char *szPost = NULL; ABC_CHECK_NULL_BUF(DID); ABC_CHECK_NULL_BUF(LPIN1); pJSON_Root = json_pack("{ss, ss}", ABC_SERVER_JSON_DID_FIELD, base64Encode(DID).c_str(), ABC_SERVER_JSON_LPIN1_FIELD, base64Encode(LPIN1).c_str()); szPost = ABC_UtilStringFromJSONObject(pJSON_Root, JSON_COMPACT); // send the command ABC_CHECK_NEW(AirbitzRequest().post(reply, url, szPost)); // Check the result ABC_CHECK_NEW(replyJson.decode(reply.body)); ABC_CHECK_NEW(replyJson.ok()); // get the results field pJSON_Value = replyJson.results().get(); ABC_CHECK_ASSERT((pJSON_Value && json_is_object(pJSON_Value)), ABC_CC_JSONError, "Error parsing server JSON pin package results"); // get the pin_package field pJSON_Value = json_object_get(pJSON_Value, JSON_ACCT_PIN_PACKAGE); ABC_CHECK_ASSERT((pJSON_Value && json_is_string(pJSON_Value)), ABC_CC_JSONError, "Error pin package JSON results"); // copy the value ABC_STRDUP(*szPinPackage, json_string_value(pJSON_Value)); exit: if (pJSON_Root) json_decref(pJSON_Root); ABC_FREE_STR(szPost); return cc; }
tABC_CC ABC_LoginServerGetCarePackage(const Lobby &lobby, CarePackage &result, tABC_Error *pError) { tABC_CC cc = ABC_CC_Ok; std::string url = ABC_SERVER_ROOT "/" ABC_SERVER_GET_CARE_PACKAGE_PATH; char *szCarePackage = NULL; ABC_CHECK_RET(ABC_LoginServerGetString(lobby, U08Buf(), U08Buf(), url.c_str(), JSON_ACCT_CARE_PACKAGE, &szCarePackage, pError)); ABC_CHECK_NEW(result.decode(szCarePackage)); exit: ABC_FREE_STR(szCarePackage); return cc; }
/** * Creates an account on the server. * * This function sends information to the server to create an account. * If the account was created, ABC_CC_Ok is returned. * If the account already exists, ABC_CC_AccountAlreadyExists is returned. * * @param LP1 Password hash for the account */ tABC_CC ABC_LoginServerCreate(const Lobby &lobby, tABC_U08Buf LP1, const CarePackage &carePackage, const LoginPackage &loginPackage, const char *szRepoAcctKey, tABC_Error *pError) { tABC_CC cc = ABC_CC_Ok; HttpReply reply; std::string url = ABC_SERVER_ROOT "/" ABC_SERVER_ACCOUNT_CREATE_PATH; ServerReplyJson replyJson; char *szPost = NULL; std::string carePackageStr; std::string loginPackageStr; json_t *pJSON_Root = NULL; ABC_CHECK_NULL_BUF(LP1); ABC_CHECK_NEW(carePackage.encode(carePackageStr)); ABC_CHECK_NEW(loginPackage.encode(loginPackageStr)); // create the post data pJSON_Root = json_pack("{ssssssssss}", ABC_SERVER_JSON_L1_FIELD, base64Encode(lobby.authId()).c_str(), ABC_SERVER_JSON_LP1_FIELD, base64Encode(LP1).c_str(), ABC_SERVER_JSON_CARE_PACKAGE_FIELD, carePackageStr.c_str(), ABC_SERVER_JSON_LOGIN_PACKAGE_FIELD, loginPackageStr.c_str(), ABC_SERVER_JSON_REPO_FIELD, szRepoAcctKey); szPost = ABC_UtilStringFromJSONObject(pJSON_Root, JSON_COMPACT); // send the command ABC_CHECK_NEW(AirbitzRequest().post(reply, url, szPost)); // decode the result ABC_CHECK_NEW(replyJson.decode(reply.body)); ABC_CHECK_NEW(replyJson.ok()); exit: ABC_FREE_STR(szPost); if (pJSON_Root) json_decref(pJSON_Root); return cc; }
tABC_CC ABC_LoginServerOtpRequest(const char *szUrl, const Lobby &lobby, tABC_U08Buf LP1, JsonPtr *results, tABC_Error *pError) { tABC_CC cc = ABC_CC_Ok; HttpReply reply; ServerReplyJson replyJson; char *szPost = NULL; json_t *pJSON_Root = NULL; // create the post data pJSON_Root = json_pack("{ss}", ABC_SERVER_JSON_L1_FIELD, base64Encode(lobby.authId()).c_str()); // If there is a LP1 provided if (LP1.data()) { json_object_set_new(pJSON_Root, ABC_SERVER_JSON_LP1_FIELD, json_string(base64Encode(LP1).c_str())); } { auto key = lobby.otpKey(); if (key) json_object_set_new(pJSON_Root, ABC_SERVER_JSON_OTP_FIELD, json_string(key->totp().c_str())); } json_object_set_new(pJSON_Root, ABC_SERVER_JSON_OTP_RESET_AUTH, json_string(gOtpResetAuth.c_str())); szPost = ABC_UtilStringFromJSONObject(pJSON_Root, JSON_COMPACT); // send the command ABC_CHECK_NEW(AirbitzRequest().post(reply, szUrl, szPost)); ABC_CHECK_NEW(replyJson.decode(reply.body)); ABC_CHECK_NEW(replyJson.ok()); if (results) *results = replyJson.results(); exit: ABC_FREE_STR(szPost); if (pJSON_Root) json_decref(pJSON_Root); return cc; }
/** * Enables 2 Factor authentication * * @param LP1 Password hash for the account * @param timeout Amount of time needed for a reset to complete */ tABC_CC ABC_LoginServerOtpEnable(const Lobby &lobby, tABC_U08Buf LP1, const char *szOtpSecret, const long timeout, tABC_Error *pError) { tABC_CC cc = ABC_CC_Ok; HttpReply reply; std::string url = ABC_SERVER_ROOT "/otp/on"; ServerReplyJson replyJson; char *szPost = NULL; json_t *pJSON_Root = NULL; ABC_CHECK_NULL_BUF(LP1); // create the post data pJSON_Root = json_pack("{sssssssi}", ABC_SERVER_JSON_L1_FIELD, base64Encode(lobby.authId()).c_str(), ABC_SERVER_JSON_LP1_FIELD, base64Encode(LP1).c_str(), ABC_SERVER_JSON_OTP_SECRET_FIELD, szOtpSecret, ABC_SERVER_JSON_OTP_TIMEOUT, timeout); { auto key = lobby.otpKey(); if (key) json_object_set_new(pJSON_Root, ABC_SERVER_JSON_OTP_FIELD, json_string(key->totp().c_str())); } szPost = ABC_UtilStringFromJSONObject(pJSON_Root, JSON_COMPACT); // send the command ABC_CHECK_NEW(AirbitzRequest().post(reply, url, szPost)); ABC_CHECK_NEW(replyJson.decode(reply.body)); ABC_CHECK_NEW(replyJson.ok()); exit: ABC_FREE_STR(szPost); if (pJSON_Root) json_decref(pJSON_Root); return cc; }
static tABC_CC ABC_WalletServerRepoPost(const Lobby &lobby, tABC_U08Buf LP1, const char *szWalletAcctKey, const char *szPath, tABC_Error *pError) { tABC_CC cc = ABC_CC_Ok; HttpReply reply; std::string url = ABC_SERVER_ROOT "/" + std::string(szPath); ServerReplyJson replyJson; char *szPost = NULL; json_t *pJSON_Root = NULL; ABC_CHECK_NULL_BUF(LP1); // create the post data pJSON_Root = json_pack("{ssssss}", ABC_SERVER_JSON_L1_FIELD, base64Encode(lobby.authId()).c_str(), ABC_SERVER_JSON_LP1_FIELD, base64Encode(LP1).c_str(), ABC_SERVER_JSON_REPO_WALLET_FIELD, szWalletAcctKey); szPost = ABC_UtilStringFromJSONObject(pJSON_Root, JSON_COMPACT); // send the command ABC_CHECK_NEW(AirbitzRequest().post(reply, url, szPost)); ABC_CHECK_NEW(replyJson.decode(reply.body)); ABC_CHECK_NEW(replyJson.ok()); exit: ABC_FREE_STR(szPost); if (pJSON_Root) json_decref(pJSON_Root); return cc; }
static tABC_CC ABC_BridgeDoSweep(WatcherInfo *watcherInfo, PendingSweep& sweep, tABC_Error *pError) { tABC_CC cc = ABC_CC_Ok; char *szID = NULL; char *szAddress = NULL; uint64_t funds = 0; abcd::unsigned_transaction utx; bc::transaction_output_type output; abcd::key_table keys; std::string malTxId, txId; // Find utxos for this address: auto utxos = watcherInfo->watcher.get_utxos(sweep.address); // Bail out if there are no funds to sweep: if (!utxos.size()) { // Tell the GUI if there were funds in the past: if (watcherInfo->watcher.db().has_history(sweep.address)) { if (sweep.fCallback) { sweep.fCallback(ABC_CC_Ok, NULL, 0); } else { if (watcherInfo->fAsyncCallback) { tABC_AsyncBitCoinInfo info; info.eventType = ABC_AsyncEventType_IncomingSweep; info.sweepSatoshi = 0; info.szTxID = NULL; watcherInfo->fAsyncCallback(&info); } } sweep.done = true; } return ABC_CC_Ok; } // There are some utxos, so send them to ourselves: tABC_TxDetails details; memset(&details, 0, sizeof(tABC_TxDetails)); details.amountSatoshi = 0; details.amountCurrency = 0; details.amountFeesAirbitzSatoshi = 0; details.amountFeesMinersSatoshi = 0; details.szName = const_cast<char*>(""); details.szCategory = const_cast<char*>(""); details.szNotes = const_cast<char*>(""); details.attributes = 0x2; // Create a new receive request: ABC_CHECK_RET(ABC_TxCreateReceiveRequest(watcherInfo->wallet, &details, &szID, false, pError)); ABC_CHECK_RET(ABC_TxGetRequestAddress(watcherInfo->wallet, szID, &szAddress, pError)); // Build a transaction: utx.tx.version = 1; utx.tx.locktime = 0; for (auto &utxo : utxos) { bc::transaction_input_type input; input.sequence = 0xffffffff; input.previous_output = utxo.point; funds += utxo.value; utx.tx.inputs.push_back(input); } if (10000 < funds) funds -= 10000; // Ugh, hard-coded mining fee ABC_CHECK_ASSERT(!outputIsDust(funds), ABC_CC_InsufficientFunds, "Not enough funds"); output.value = funds; ABC_CHECK_NEW(outputScriptForAddress(output.script, szAddress)); utx.tx.outputs.push_back(output); // Now sign that: keys[sweep.address] = sweep.key; ABC_CHECK_SYS(abcd::gather_challenges(utx, watcherInfo->watcher), "gather_challenges"); ABC_CHECK_SYS(abcd::sign_tx(utx, keys), "sign_tx"); // Send: { bc::data_chunk raw_tx(satoshi_raw_size(utx.tx)); bc::satoshi_save(utx.tx, raw_tx.begin()); ABC_CHECK_NEW(broadcastTx(raw_tx)); } // Save the transaction in the database: malTxId = bc::encode_hash(bc::hash_transaction(utx.tx)); txId = ABC_BridgeNonMalleableTxId(utx.tx); ABC_CHECK_RET(ABC_TxSweepSaveTransaction(watcherInfo->wallet, txId.c_str(), malTxId.c_str(), funds, &details, pError)); // Done: if (sweep.fCallback) { sweep.fCallback(ABC_CC_Ok, txId.c_str(), output.value); } else { if (watcherInfo->fAsyncCallback) { tABC_AsyncBitCoinInfo info; info.eventType = ABC_AsyncEventType_IncomingSweep; info.sweepSatoshi = output.value; info.szTxID = stringCopy(txId); watcherInfo->fAsyncCallback(&info); ABC_FREE_STR(info.szTxID); } } sweep.done = true; watcherInfo->watcher.send_tx(utx.tx); exit: ABC_FREE_STR(szID); ABC_FREE_STR(szAddress); return cc; }
/** * Creates the wallet with the given info. * * @param pszUUID Pointer to hold allocated pointer to UUID string */ tABC_CC ABC_WalletCreate(tABC_SyncKeys *pKeys, tABC_U08Buf L1, tABC_U08Buf LP1, const char *szUserName, const char *szWalletName, int currencyNum, unsigned int attributes, char **pszUUID, tABC_Error *pError) { tABC_CC cc = ABC_CC_Ok; char *szFilename = NULL; char *szJSON = NULL; char *szUUID = NULL; char *szWalletDir = NULL; json_t *pJSON_Data = NULL; json_t *pJSON_Wallets = NULL; tABC_U08Buf WalletAcctKey = ABC_BUF_NULL; tWalletData *pData = NULL; ABC_CHECK_NULL(pszUUID); // create a new wallet data struct ABC_NEW(pData, tWalletData); pData->archived = 0; // create wallet guid ABC_CHECK_RET(ABC_CryptoGenUUIDString(&szUUID, pError)); ABC_STRDUP(pData->szUUID, szUUID); ABC_STRDUP(*pszUUID, szUUID); // generate the master key for this wallet - MK_<Wallet_GUID1> ABC_CHECK_RET(ABC_CryptoCreateRandomData(WALLET_KEY_LENGTH, &pData->MK, pError)); // create and set the bitcoin private seed for this wallet ABC_CHECK_RET(ABC_CryptoCreateRandomData(WALLET_BITCOIN_PRIVATE_SEED_LENGTH, &pData->BitcoinPrivateSeed, pError)); // Create Wallet Repo key ABC_CHECK_RET(ABC_CryptoCreateRandomData(SYNC_KEY_LENGTH, &WalletAcctKey, pError)); ABC_CHECK_RET(ABC_CryptoHexEncode(WalletAcctKey, &(pData->szWalletAcctKey), pError)); // create the wallet root directory if necessary ABC_CHECK_RET(ABC_WalletCreateRootDir(pError)); // create the wallet directory - <Wallet_UUID1> <- All data in this directory encrypted with MK_<Wallet_UUID1> ABC_CHECK_RET(ABC_WalletGetDirName(&(pData->szWalletDir), pData->szUUID, pError)); ABC_CHECK_RET(ABC_FileIOCreateDir(pData->szWalletDir, pError)); ABC_STRDUP(szWalletDir, pData->szWalletDir); // create the wallet sync dir under the main dir ABC_CHECK_RET(ABC_WalletGetSyncDirName(&(pData->szWalletSyncDir), pData->szUUID, pError)); ABC_CHECK_RET(ABC_FileIOCreateDir(pData->szWalletSyncDir, pError)); // we now have a new wallet so go ahead and cache its data ABC_CHECK_RET(ABC_WalletAddToCache(pData, pError)); // all the functions below assume the wallet is in the cache or can be loaded into the cache // set the wallet name ABC_CHECK_RET(ABC_WalletSetName(ABC_WalletID(pKeys, szUUID), szWalletName, pError)); // set the currency ABC_CHECK_RET(ABC_WalletSetCurrencyNum(ABC_WalletID(pKeys, szUUID), currencyNum, pError)); // Request remote wallet repo ABC_CHECK_RET(ABC_WalletServerRepoPost(L1, LP1, pData->szWalletAcctKey, ABC_SERVER_WALLET_CREATE_PATH, pError)); // set this account for the wallet's first account ABC_CHECK_RET(ABC_WalletAddAccount(ABC_WalletID(pKeys, szUUID), szUserName, pError)); // TODO: should probably add the creation date to optimize wallet export (assuming it is even used) // Init the git repo and sync it int dirty; ABC_CHECK_RET(ABC_SyncMakeRepo(pData->szWalletSyncDir, pError)); ABC_CHECK_RET(ABC_SyncRepo(pData->szWalletSyncDir, pData->szWalletAcctKey, &dirty, pError)); // Actiate the remote wallet ABC_CHECK_RET(ABC_WalletServerRepoPost(L1, LP1, pData->szWalletAcctKey, ABC_SERVER_WALLET_ACTIVATE_PATH, pError)); // If everything worked, add the wallet to the account: tABC_AccountWalletInfo info; // No need to free this info.szUUID = szUUID; info.MK = pData->MK; info.BitcoinSeed = pData->BitcoinPrivateSeed; info.SyncKey = WalletAcctKey; info.archived = 0; ABC_CHECK_RET(ABC_AccountWalletList(pKeys, NULL, &info.sortIndex, pError)); ABC_CHECK_RET(ABC_AccountWalletSave(pKeys, &info, pError)); // Now the wallet is written to disk, generate some addresses ABC_CHECK_RET(ABC_TxCreateInitialAddresses(ABC_WalletID(pKeys, pData->szUUID), pError)); // After wallet is created, sync the account, ignoring any errors tABC_Error Error; ABC_CHECK_RET(ABC_SyncRepo(pKeys->szSyncDir, pKeys->szSyncKey, &dirty, &Error)); pData = NULL; // so we don't free what we just added to the cache exit: if (cc != ABC_CC_Ok) { if (szUUID) { ABC_WalletRemoveFromCache(szUUID, NULL); } if (szWalletDir) { ABC_FileIODeleteRecursive(szWalletDir, NULL); } } ABC_FREE_STR(szWalletDir); ABC_FREE_STR(szFilename); ABC_FREE_STR(szJSON); ABC_FREE_STR(szUUID); if (pJSON_Data) json_decref(pJSON_Data); if (pJSON_Wallets) json_decref(pJSON_Wallets); if (pData) ABC_WalletFreeData(pData); return cc; }
/** * Generate the QR code for a previously created receive request. * * @param szRequestID ID of this request * @param pszURI Pointer to string to store URI(optional) * @param paData Pointer to store array of data bytes (0x0 white, 0x1 black) * @param pWidth Pointer to store width of image (image will be square) * @param pError A pointer to the location to store the error if there is one */ tABC_CC ABC_TxGenerateRequestQRCode(Wallet &self, const char *szRequestID, char **pszURI, unsigned char **paData, unsigned int *pWidth, tABC_Error *pError) { tABC_CC cc = ABC_CC_Ok; AutoCoreLock lock(gCoreMutex); QRcode *qr = NULL; unsigned char *aData = NULL; unsigned int length = 0; char *szURI = NULL; // load the request/address Address address; ABC_CHECK_NEW(self.addresses.get(address, szRequestID)); // Get the URL string for this info tABC_BitcoinURIInfo infoURI; memset(&infoURI, 0, sizeof(tABC_BitcoinURIInfo)); infoURI.amountSatoshi = address.metadata.amountSatoshi; infoURI.szAddress = address.address.c_str(); // Set the label if there is one ABC_CHECK_RET(ABC_TxBuildFromLabel(self, &(infoURI.szLabel), pError)); // if there is a note if (!address.metadata.notes.empty()) { infoURI.szMessage = address.metadata.notes.c_str(); } ABC_CHECK_RET(ABC_BridgeEncodeBitcoinURI(&szURI, &infoURI, pError)); // encode our string ABC_DebugLog("Encoding: %s", szURI); qr = QRcode_encodeString(szURI, 0, QR_ECLEVEL_L, QR_MODE_8, 1); ABC_CHECK_ASSERT(qr != NULL, ABC_CC_Error, "Unable to create QR code"); length = qr->width * qr->width; ABC_ARRAY_NEW(aData, length, unsigned char); for (unsigned i = 0; i < length; i++) { aData[i] = qr->data[i] & 0x1; } *pWidth = qr->width; *paData = aData; aData = NULL; if (pszURI != NULL) { *pszURI = stringCopy(szURI); } exit: ABC_FREE_STR(szURI); QRcode_free(qr); ABC_CLEAR_FREE(aData, length); return cc; }
tABC_CC ABC_LoginServerOtpPending(std::list<DataChunk> users, std::list<bool> &isPending, tABC_Error *pError) { tABC_CC cc = ABC_CC_Ok; HttpReply reply; std::string url = ABC_SERVER_ROOT "/otp/pending/check"; ServerReplyJson replyJson; JsonArray arrayJson; json_t *pJSON_Root = NULL; char *szPost = NULL; std::map<std::string, bool> userMap; std::list<std::string> usersEncoded; std::string param; for (const auto &u : users) { std::string username = base64Encode(u); param += (username + ","); userMap[username] = false; usersEncoded.push_back(username); } // create the post data pJSON_Root = json_pack("{ss}", "l1s", param.c_str()); szPost = ABC_UtilStringFromJSONObject(pJSON_Root, JSON_COMPACT); // send the command ABC_CHECK_NEW(AirbitzRequest().post(reply, url, szPost)); ABC_CHECK_NEW(replyJson.decode(reply.body)); ABC_CHECK_NEW(replyJson.ok()); arrayJson = replyJson.results(); if (arrayJson) { size_t rows = arrayJson.size(); for (size_t i = 0; i < rows; i++) { json_t *pJSON_Row = arrayJson[i].get(); ABC_CHECK_ASSERT((pJSON_Row && json_is_object(pJSON_Row)), ABC_CC_JSONError, "Error parsing JSON array element object"); json_t *pJSON_Value = json_object_get(pJSON_Row, "login"); ABC_CHECK_ASSERT((pJSON_Value && json_is_string(pJSON_Value)), ABC_CC_JSONError, "Error otp/pending/login JSON"); std::string username(json_string_value(pJSON_Value)); pJSON_Value = json_object_get(pJSON_Row, ABC_SERVER_JSON_OTP_PENDING); ABC_CHECK_ASSERT((pJSON_Value && json_is_boolean(pJSON_Value)), ABC_CC_JSONError, "Error otp/pending/pending JSON"); if (json_is_true(pJSON_Value)) { userMap[username] = json_is_true(pJSON_Value);; } } } isPending.clear(); for (auto &username: usersEncoded) { isPending.push_back(userMap[username]); } exit: ABC_FREE_STR(szPost); if (pJSON_Root) json_decref(pJSON_Root); return cc; }
/** * Helper function for getting CarePackage or LoginPackage. */ static tABC_CC ABC_LoginServerGetString(const Lobby &lobby, tABC_U08Buf LP1, tABC_U08Buf LRA1, const char *szURL, const char *szField, char **szResponse, tABC_Error *pError) { tABC_CC cc = ABC_CC_Ok; HttpReply reply; ServerReplyJson replyJson; json_t *pJSON_Value = NULL; json_t *pJSON_Root = NULL; char *szPost = NULL; // create the post data with or without LP1 if (LP1.data() == NULL && LRA1.data() == NULL) { pJSON_Root = json_pack("{ss}", ABC_SERVER_JSON_L1_FIELD, base64Encode(lobby.authId()).c_str()); } else { if (LP1.data() == NULL) { pJSON_Root = json_pack("{ssss}", ABC_SERVER_JSON_L1_FIELD, base64Encode(lobby.authId()).c_str(), ABC_SERVER_JSON_LRA1_FIELD, base64Encode(LRA1).c_str()); } else { pJSON_Root = json_pack("{ssss}", ABC_SERVER_JSON_L1_FIELD, base64Encode(lobby.authId()).c_str(), ABC_SERVER_JSON_LP1_FIELD, base64Encode(LP1).c_str()); } } { auto key = lobby.otpKey(); if (key) json_object_set_new(pJSON_Root, ABC_SERVER_JSON_OTP_FIELD, json_string(key->totp().c_str())); } szPost = ABC_UtilStringFromJSONObject(pJSON_Root, JSON_COMPACT); // send the command ABC_CHECK_NEW(AirbitzRequest().post(reply, szURL, szPost)); // Check the results, and store json if successful ABC_CHECK_NEW(replyJson.decode(reply.body)); ABC_CHECK_NEW(replyJson.ok()); // get the care package pJSON_Value = replyJson.results().get(); ABC_CHECK_ASSERT((pJSON_Value && json_is_object(pJSON_Value)), ABC_CC_JSONError, "Error parsing server JSON care package results"); pJSON_Value = json_object_get(pJSON_Value, szField); ABC_CHECK_ASSERT((pJSON_Value && json_is_string(pJSON_Value)), ABC_CC_JSONError, "Error care package JSON results"); ABC_STRDUP(*szResponse, json_string_value(pJSON_Value)); exit: if (pJSON_Root) json_decref(pJSON_Root); ABC_FREE_STR(szPost); return cc; }