/** * Gets the specified field from a json string */ tABC_CC ABC_UtilGetIntValueFromJSONString(const char *szJSON, const char *szFieldName, int *pValue, tABC_Error *pError) { tABC_CC cc = ABC_CC_Ok; json_t *pJSON_Root = NULL; json_t *pJSON_Value = NULL; ABC_CHECK_NULL(szJSON); ABC_CHECK_NULL(szFieldName); ABC_CHECK_NULL(pValue); // decode the object json_error_t error; pJSON_Root = json_loads(szJSON, 0, &error); ABC_CHECK_ASSERT(pJSON_Root != NULL, ABC_CC_JSONError, "Error parsing JSON"); ABC_CHECK_ASSERT(json_is_object(pJSON_Root), ABC_CC_JSONError, "Error parsing JSON"); // get the field pJSON_Value = json_object_get(pJSON_Root, szFieldName); ABC_CHECK_ASSERT((pJSON_Value && json_is_number(pJSON_Value)), ABC_CC_JSONError, "Error parsing JSON int value"); *pValue = (int) json_integer_value(pJSON_Value); exit: if (pJSON_Root) json_decref(pJSON_Root); return cc; }
tABC_CC ABC_LoginServerOtpStatus(const Lobby &lobby, tABC_U08Buf LP1, bool *on, long *timeout, tABC_Error *pError) { tABC_CC cc = ABC_CC_Ok; json_t *pJSON_Value = NULL; JsonPtr reply; std::string url = ABC_SERVER_ROOT "/otp/status"; ABC_CHECK_RET(ABC_LoginServerOtpRequest(url.c_str(), lobby, LP1, &reply, pError)); pJSON_Value = json_object_get(reply.get(), ABC_SERVER_JSON_OTP_ON); ABC_CHECK_ASSERT((pJSON_Value && json_is_boolean(pJSON_Value)), ABC_CC_JSONError, "Error otp/on JSON"); *on = json_is_true(pJSON_Value); if (*on) { pJSON_Value = json_object_get(reply.get(), ABC_SERVER_JSON_OTP_TIMEOUT); ABC_CHECK_ASSERT((pJSON_Value && json_is_integer(pJSON_Value)), ABC_CC_JSONError, "Error otp/timeout JSON"); *timeout = json_integer_value(pJSON_Value); } exit: return cc; }
/** * Gets the specified field from a json string * the user is responsible for free'ing the value */ tABC_CC ABC_UtilGetStringValueFromJSONString(const char *szJSON, const char *szFieldName, char **pszValue, tABC_Error *pError) { tABC_CC cc = ABC_CC_Ok; json_t *pJSON_Root = NULL; json_t *pJSON_Value = NULL; ABC_CHECK_NULL(szJSON); ABC_CHECK_NULL(szFieldName); ABC_CHECK_NULL(pszValue); // decode the object json_error_t error; pJSON_Root = json_loads(szJSON, 0, &error); ABC_CHECK_ASSERT(pJSON_Root != NULL, ABC_CC_JSONError, "Error parsing JSON"); ABC_CHECK_ASSERT(json_is_object(pJSON_Root), ABC_CC_JSONError, "Error parsing JSON"); // get the field pJSON_Value = json_object_get(pJSON_Root, szFieldName); ABC_CHECK_ASSERT((pJSON_Value && json_is_string(pJSON_Value)), ABC_CC_JSONError, "Error parsing JSON string value"); ABC_STRDUP(*pszValue, json_string_value(pJSON_Value)); exit: if (pJSON_Root) json_decref(pJSON_Root); return cc; }
tABC_CC ABC_BridgeSweepKey(Wallet &self, tABC_U08Buf key, bool compressed, tABC_Sweep_Done_Callback fCallback, void *pData, tABC_Error *pError) { tABC_CC cc = ABC_CC_Ok; bc::ec_secret ec_key; bc::ec_point ec_addr; bc::payment_address address; PendingSweep sweep; WatcherInfo *watcherInfo = nullptr; ABC_CHECK_NEW(watcherFind(watcherInfo, self)); // Decode key and address: ABC_CHECK_ASSERT(key.size() == ec_key.size(), ABC_CC_Error, "Bad key size"); std::copy(key.begin(), key.end(), ec_key.data()); ec_addr = bc::secret_to_public_key(ec_key, compressed); address.set(pubkeyVersion(), bc::bitcoin_short_hash(ec_addr)); // Start the sweep: sweep.address = address; sweep.key = abcd::wif_key{ec_key, compressed}; sweep.done = false; sweep.fCallback = fCallback; sweep.pData = pData; watcherInfo->sweeping.push_back(sweep); watcherInfo->watcher.watch_address(address); exit: 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; }
/** * Gets the specified field from a json string * the user is responsible for free'ing the array */ tABC_CC ABC_UtilGetArrayValuesFromJSONString(const char *szJSON, const char *szFieldName, char ***aszValues, unsigned int *pCount, tABC_Error *pError) { tABC_CC cc = ABC_CC_Ok; json_t *pJSON_Root = NULL; json_t *pJSON_Value = NULL; char **pArrayStrings = NULL; ABC_CHECK_NULL(szJSON); ABC_CHECK_NULL(szFieldName); ABC_CHECK_NULL(aszValues); *aszValues = NULL; ABC_CHECK_NULL(pCount); *pCount = 0; // decode the object json_error_t error; pJSON_Root = json_loads(szJSON, 0, &error); ABC_CHECK_ASSERT(pJSON_Root != NULL, ABC_CC_JSONError, "Error parsing JSON"); ABC_CHECK_ASSERT(json_is_object(pJSON_Root), ABC_CC_JSONError, "Error parsing JSON"); // get the field pJSON_Value = json_object_get(pJSON_Root, szFieldName); ABC_CHECK_ASSERT((pJSON_Value && json_is_array(pJSON_Value)), ABC_CC_JSONError, "Error parsing JSON array value"); // get the number of elements in the array *pCount = (int) json_array_size(pJSON_Value); if (*pCount > 0) { ABC_ARRAY_NEW(pArrayStrings, *pCount, char*); for (unsigned i = 0; i < *pCount; i++) { json_t *pJSON_Elem = json_array_get(pJSON_Value, i); ABC_CHECK_ASSERT((pJSON_Elem && json_is_string(pJSON_Elem)), ABC_CC_JSONError, "Error parsing JSON string value"); ABC_STRDUP(pArrayStrings[i], json_string_value(pJSON_Elem)); } *aszValues = pArrayStrings; pArrayStrings = NULL; }
/** * Loads a CarePackage object from a string. */ tABC_CC ABC_CarePackageDecode(tABC_CarePackage **ppSelf, char *szCarePackage, tABC_Error *pError) { tABC_CC cc = ABC_CC_Ok; tABC_CarePackage *pSelf = NULL; json_t *pJSON_Root = NULL; json_t *pJSON_SNRP2 = NULL; json_t *pJSON_SNRP3 = NULL; json_t *pJSON_SNRP4 = NULL; int e; // Allocate self: ABC_NEW(pSelf, tABC_CarePackage); // Parse the JSON: json_error_t error; pJSON_Root = json_loads(szCarePackage, 0, &error); ABC_CHECK_ASSERT(pJSON_Root != NULL, ABC_CC_JSONError, "Error parsing CarePackage JSON"); ABC_CHECK_ASSERT(json_is_object(pJSON_Root), ABC_CC_JSONError, "Error parsing CarePackage JSON"); // Unpack the contents: e = json_unpack(pJSON_Root, "{s:o, s:o, s:o, s?o}", JSON_ACCT_SNRP2_FIELD, &pJSON_SNRP2, JSON_ACCT_SNRP3_FIELD, &pJSON_SNRP3, JSON_ACCT_SNRP4_FIELD, &pJSON_SNRP4, JSON_ACCT_ERQ_FIELD, &pSelf->ERQ); ABC_CHECK_SYS(!e, "Error parsing CarePackage JSON"); // Decode SNRP's: ABC_CHECK_RET(ABC_CryptoCreateSNRPForServer(&pSelf->pSNRP1, pError)); ABC_CHECK_RET(ABC_CryptoDecodeJSONObjectSNRP(pJSON_SNRP2, &pSelf->pSNRP2, pError)); ABC_CHECK_RET(ABC_CryptoDecodeJSONObjectSNRP(pJSON_SNRP3, &pSelf->pSNRP3, pError)); ABC_CHECK_RET(ABC_CryptoDecodeJSONObjectSNRP(pJSON_SNRP4, &pSelf->pSNRP4, pError)); // Save everything: if (pSelf->ERQ) json_incref(pSelf->ERQ); *ppSelf = pSelf; pSelf = NULL; exit: if (pSelf) ABC_CarePackageFree(pSelf); if (pJSON_Root) json_decref(pJSON_Root); 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; }
/** * Loads a LoginPackage object from a string. */ tABC_CC ABC_LoginPackageDecode(tABC_LoginPackage **ppSelf, char *szLoginPackage, tABC_Error *pError) { tABC_CC cc = ABC_CC_Ok; tABC_LoginPackage *pSelf = NULL; json_t *pJSON_Root = NULL; int e; // Allocate self: ABC_NEW(pSelf, tABC_LoginPackage); // Parse the JSON: json_error_t error; pJSON_Root = json_loads(szLoginPackage, 0, &error); ABC_CHECK_ASSERT(pJSON_Root != NULL, ABC_CC_JSONError, "Error parsing LoginPackage JSON"); ABC_CHECK_ASSERT(json_is_object(pJSON_Root), ABC_CC_JSONError, "Error parsing LoginPackage JSON"); // Unpack the contents: e = json_unpack(pJSON_Root, "{s?o, s?o, s:o, s?o, s?o}", JSON_ACCT_EMK_LP2_FIELD, &pSelf->EMK_LP2, JSON_ACCT_EMK_LRA3_FIELD, &pSelf->EMK_LRA3, JSON_ACCT_ESYNCKEY_FIELD, &pSelf->ESyncKey, JSON_ACCT_ELP1_FIELD, &pSelf->ELP1, JSON_ACCT_ELRA1_FIELD, &pSelf->ELRA1); ABC_CHECK_SYS(!e, "Error parsing LoginPackage JSON"); // Save everything: if (pSelf->EMK_LP2) json_incref(pSelf->EMK_LP2); if (pSelf->EMK_LRA3) json_incref(pSelf->EMK_LRA3); if (pSelf->ESyncKey) json_incref(pSelf->ESyncKey); if (pSelf->ELP1) json_incref(pSelf->ELP1); if (pSelf->ELRA1) json_incref(pSelf->ELRA1); *ppSelf = pSelf; pSelf = NULL; exit: if (pSelf) ABC_LoginPackageFree(pSelf); if (pJSON_Root) json_decref(pJSON_Root); return cc; }
/** * Load the general info. * * This function will load the general info which includes information on * Obelisk Servers, AirBitz fees and miners fees. */ tABC_CC ABC_GeneralGetInfo(tABC_GeneralInfo **ppInfo, tABC_Error *pError) { tABC_CC cc = ABC_CC_Ok; json_t *pJSON_Root = NULL; json_t *pJSON_Value = NULL; char *szInfoFilename = NULL; tABC_GeneralInfo *pInfo = NULL; json_t *pJSON_MinersFeesArray = NULL; json_t *pJSON_AirBitzFees = NULL; json_t *pJSON_ObeliskArray = NULL; json_t *pJSON_SyncArray = NULL; bool bExists = false; ABC_CHECK_NULL(ppInfo); // get the info filename ABC_CHECK_RET(ABC_GeneralGetInfoFilename(&szInfoFilename, pError)); // check to see if we have the file ABC_CHECK_RET(ABC_FileIOFileExists(szInfoFilename, &bExists, pError)); if (false == bExists) { // pull it down from the server ABC_CHECK_RET(ABC_GeneralUpdateInfo(pError)); } // load the json ABC_CHECK_RET(ABC_FileIOReadFileObject(szInfoFilename, &pJSON_Root, true, pError)); // allocate the struct ABC_NEW(pInfo, tABC_GeneralInfo); // get the miners fees array pJSON_MinersFeesArray = json_object_get(pJSON_Root, JSON_INFO_MINERS_FEES_FIELD); ABC_CHECK_ASSERT((pJSON_MinersFeesArray && json_is_array(pJSON_MinersFeesArray)), ABC_CC_JSONError, "Error parsing JSON array value"); // get the number of elements in the array pInfo->countMinersFees = (unsigned int) json_array_size(pJSON_MinersFeesArray); if (pInfo->countMinersFees > 0) { ABC_ARRAY_NEW(pInfo->aMinersFees, pInfo->countMinersFees, tABC_GeneralMinerFee*); }
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; }
/** * 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; }
/** * Loads the settings for a specific account using the given key * If no settings file exists for the given user, defaults are created * * @param login Access to the account sync dir * @param ppSettings Location to store ptr to allocated settings (caller must free) * @param pError A pointer to the location to store the error if there is one */ tABC_CC ABC_AccountSettingsLoad(const Login &login, tABC_AccountSettings **ppSettings, tABC_Error *pError) { tABC_CC cc = ABC_CC_Ok; AutoCoreLock lock(gCoreMutex); tABC_AccountSettings *pSettings = NULL; json_t *pJSON_Root = NULL; json_t *pJSON_Value = NULL; bool bExists = false; auto filename = login.syncDir() + ACCOUNT_SETTINGS_FILENAME; ABC_CHECK_NULL(ppSettings); ABC_CHECK_RET(ABC_FileIOFileExists(filename.c_str(), &bExists, pError)); if (true == bExists) { // load and decrypted the file into a json object ABC_CHECK_RET(ABC_CryptoDecryptJSONFileObject(filename.c_str(), toU08Buf(login.dataKey()), &pJSON_Root, pError)); //ABC_DebugLog("Loaded settings JSON:\n%s\n", json_dumps(pJSON_Root, JSON_INDENT(4) | JSON_PRESERVE_ORDER)); // allocate the new settings object ABC_NEW(pSettings, tABC_AccountSettings); pSettings->szFirstName = NULL; pSettings->szLastName = NULL; pSettings->szNickname = NULL; // get the first name pJSON_Value = json_object_get(pJSON_Root, JSON_ACCT_FIRST_NAME_FIELD); if (pJSON_Value) { ABC_CHECK_ASSERT(json_is_string(pJSON_Value), ABC_CC_JSONError, "Error parsing JSON string value"); ABC_STRDUP(pSettings->szFirstName, json_string_value(pJSON_Value)); } // get the last name pJSON_Value = json_object_get(pJSON_Root, JSON_ACCT_LAST_NAME_FIELD); if (pJSON_Value) { ABC_CHECK_ASSERT(json_is_string(pJSON_Value), ABC_CC_JSONError, "Error parsing JSON string value"); ABC_STRDUP(pSettings->szLastName, json_string_value(pJSON_Value)); } // get the nickname pJSON_Value = json_object_get(pJSON_Root, JSON_ACCT_NICKNAME_FIELD); if (pJSON_Value) { ABC_CHECK_ASSERT(json_is_string(pJSON_Value), ABC_CC_JSONError, "Error parsing JSON string value"); ABC_STRDUP(pSettings->szNickname, json_string_value(pJSON_Value)); } pJSON_Value = json_object_get(pJSON_Root, JSON_ACCT_PIN_FIELD); if (pJSON_Value) { ABC_CHECK_ASSERT(json_is_string(pJSON_Value), ABC_CC_JSONError, "Error parsing JSON string value"); ABC_STRDUP(pSettings->szPIN, json_string_value(pJSON_Value)); } // get name on payments option pJSON_Value = json_object_get(pJSON_Root, JSON_ACCT_NAME_ON_PAYMENTS_FIELD); ABC_CHECK_ASSERT((pJSON_Value && json_is_boolean(pJSON_Value)), ABC_CC_JSONError, "Error parsing JSON boolean value"); pSettings->bNameOnPayments = json_is_true(pJSON_Value) ? true : false; // get minutes auto logout pJSON_Value = json_object_get(pJSON_Root, JSON_ACCT_MINUTES_AUTO_LOGOUT_FIELD); ABC_CHECK_ASSERT((pJSON_Value && json_is_integer(pJSON_Value)), ABC_CC_JSONError, "Error parsing JSON integer value"); pSettings->minutesAutoLogout = (int) json_integer_value(pJSON_Value); pJSON_Value = json_object_get(pJSON_Root, JSON_ACCT_RECOVERY_REMINDER_COUNT); if (pJSON_Value) { ABC_CHECK_ASSERT((pJSON_Value && json_is_integer(pJSON_Value)), ABC_CC_JSONError, "Error parsing JSON integer value"); pSettings->recoveryReminderCount = (int) json_integer_value(pJSON_Value); } else { pSettings->recoveryReminderCount = 0; } // get language pJSON_Value = json_object_get(pJSON_Root, JSON_ACCT_LANGUAGE_FIELD); ABC_CHECK_ASSERT((pJSON_Value && json_is_string(pJSON_Value)), ABC_CC_JSONError, "Error parsing JSON string value"); ABC_STRDUP(pSettings->szLanguage, json_string_value(pJSON_Value)); // get currency num pJSON_Value = json_object_get(pJSON_Root, JSON_ACCT_NUM_CURRENCY_FIELD); ABC_CHECK_ASSERT((pJSON_Value && json_is_integer(pJSON_Value)), ABC_CC_JSONError, "Error parsing JSON integer value"); pSettings->currencyNum = (int) json_integer_value(pJSON_Value); // get advanced features pJSON_Value = json_object_get(pJSON_Root, JSON_ACCT_ADVANCED_FEATURES_FIELD); ABC_CHECK_ASSERT((pJSON_Value && json_is_boolean(pJSON_Value)), ABC_CC_JSONError, "Error parsing JSON boolean value"); pSettings->bAdvancedFeatures = json_is_true(pJSON_Value) ? true : false; pJSON_Value = json_object_get(pJSON_Root, JSON_ACCT_DAILY_SPEND_LIMIT_ENABLED); if (pJSON_Value) { ABC_CHECK_ASSERT((pJSON_Value && json_is_boolean(pJSON_Value)), ABC_CC_JSONError, "Error parsing JSON boolean value"); pSettings->bDailySpendLimit = json_is_true(pJSON_Value) ? true : false; } else { pSettings->bDailySpendLimit = false; } pJSON_Value = json_object_get(pJSON_Root, JSON_ACCT_DAILY_SPEND_LIMIT_SATOSHIS); if (pJSON_Value) { ABC_CHECK_ASSERT((pJSON_Value && json_is_integer(pJSON_Value)), ABC_CC_JSONError, "Error parsing JSON daily spend satoshi value"); pSettings->dailySpendLimitSatoshis = (int64_t) json_integer_value(pJSON_Value); } else { pSettings->dailySpendLimitSatoshis = 0; } pJSON_Value = json_object_get(pJSON_Root, JSON_ACCT_SPEND_REQUIRE_PIN_ENABLED); if (pJSON_Value) { ABC_CHECK_ASSERT((pJSON_Value && json_is_boolean(pJSON_Value)), ABC_CC_JSONError, "Error parsing JSON boolean value"); pSettings->bSpendRequirePin = json_is_true(pJSON_Value) ? true : false; } else { // Default to PIN required pSettings->bSpendRequirePin = true; } pJSON_Value = json_object_get(pJSON_Root, JSON_ACCT_DISABLE_PIN_LOGIN); if (pJSON_Value) { ABC_CHECK_ASSERT((pJSON_Value && json_is_boolean(pJSON_Value)), ABC_CC_JSONError, "Error parsing JSON boolean value"); pSettings->bDisablePINLogin = json_is_true(pJSON_Value) ? true : false; } else { // Default to PIN login allowed pSettings->bDisablePINLogin = false; } pJSON_Value = json_object_get(pJSON_Root, JSON_ACCT_PIN_LOGIN_COUNT); if (pJSON_Value) { ABC_CHECK_ASSERT((pJSON_Value && json_is_integer(pJSON_Value)), ABC_CC_JSONError, "Error parsing JSON pin login count"); pSettings->pinLoginCount = json_integer_value(pJSON_Value); } else { // Default to PIN login allowed pSettings->pinLoginCount = 0; } pJSON_Value = json_object_get(pJSON_Root, JSON_ACCT_SPEND_REQUIRE_PIN_SATOSHIS); if (pJSON_Value) { ABC_CHECK_ASSERT((pJSON_Value && json_is_integer(pJSON_Value)), ABC_CC_JSONError, "Error parsing JSON daily spend satoshi value"); pSettings->spendRequirePinSatoshis = (int64_t) json_integer_value(pJSON_Value); } else { // Default PIN requirement to 50mb pSettings->spendRequirePinSatoshis = DEF_REQUIRE_PIN_SATOSHIS; } // get the denomination object json_t *pJSON_Denom = json_object_get(pJSON_Root, JSON_ACCT_BITCOIN_DENOMINATION_FIELD); ABC_CHECK_ASSERT((pJSON_Denom && json_is_object(pJSON_Denom)), ABC_CC_JSONError, "Error parsing JSON object value"); // get denomination satoshi display size (e.g., 100,000 would be milli-bit coin) pJSON_Value = json_object_get(pJSON_Denom, JSON_ACCT_SATOSHI_FIELD); ABC_CHECK_ASSERT((pJSON_Value && json_is_integer(pJSON_Value)), ABC_CC_JSONError, "Error parsing JSON integer value"); pSettings->bitcoinDenomination.satoshi = json_integer_value(pJSON_Value); // get denomination type pJSON_Value = json_object_get(pJSON_Denom, JSON_ACCT_LABEL_TYPE); ABC_CHECK_ASSERT((pJSON_Value && json_is_integer(pJSON_Value)), ABC_CC_JSONError, "Error parsing JSON integer value"); pSettings->bitcoinDenomination.denominationType = json_integer_value(pJSON_Value); // get the exchange rates array json_t *pJSON_Sources = json_object_get(pJSON_Root, JSON_ACCT_EX_RATE_SOURCES_FIELD); ABC_CHECK_ASSERT((pJSON_Sources && json_is_array(pJSON_Sources)), ABC_CC_JSONError, "Error parsing JSON array value"); // get the number of elements in the array pSettings->exchangeRateSources.numSources = (int) json_array_size(pJSON_Sources); if (pSettings->exchangeRateSources.numSources > 0) { ABC_ARRAY_NEW(pSettings->exchangeRateSources.aSources, pSettings->exchangeRateSources.numSources, tABC_ExchangeRateSource*); }
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; }