예제 #1
0
/**
 * Queries the server to determine if a username is available.
 */
tABC_CC ABC_LoginServerAvailable(const Lobby &lobby,
                                 tABC_Error *pError)
{

    tABC_CC cc = ABC_CC_Ok;

    HttpReply reply;
    std::string url = ABC_SERVER_ROOT "/" ABC_SERVER_ACCOUNT_AVAILABLE;
    ServerReplyJson replyJson;
    std::string get;
    AccountAvailableJson json;

    // create the json
    ABC_CHECK_NEW(json.authIdSet(base64Encode(lobby.authId())));
    ABC_CHECK_NEW(json.encode(get));

    // send the command
    ABC_CHECK_NEW(AirbitzRequest().post(reply, url, get));

    // decode the result
    ABC_CHECK_NEW(replyJson.decode(reply.body));
    ABC_CHECK_NEW(replyJson.ok());

exit:
    return cc;
}
예제 #2
0
static
tABC_CC ABC_WalletServerRepoPost(const Lobby &lobby,
                                 DataSlice LP1,
                                 const std::string &szWalletAcctKey,
                                 const char *szPath,
                                 tABC_Error *pError)
{
    tABC_CC cc = ABC_CC_Ok;

    const auto url = ABC_SERVER_ROOT "/" + std::string(szPath);
    HttpReply reply;
    ServerReplyJson replyJson;

    JsonPtr json(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.c_str()));

    // send the command
    ABC_CHECK_NEW(AirbitzRequest().post(reply, url, json.encode()));

    ABC_CHECK_NEW(replyJson.decode(reply.body));
    ABC_CHECK_NEW(replyJson.ok());

exit:
    return cc;
}
예제 #3
0
/**
 * 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;
}
예제 #4
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;
}
예제 #5
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;
}
예제 #6
0
static
tABC_CC ABC_LoginPasswordDisk(std::shared_ptr<Login> &result,
                              std::shared_ptr<Lobby> lobby,
                              tABC_U08Buf LP,
                              tABC_Error *pError)
{
    tABC_CC cc = ABC_CC_Ok;

    std::unique_ptr<Login> login;
    tABC_CarePackage    *pCarePackage   = NULL;
    tABC_LoginPackage   *pLoginPackage  = NULL;
    AutoU08Buf          LP2;
    AutoU08Buf          MK;

    // Load the packages:
    ABC_CHECK_RET(ABC_LoginDirLoadPackages(lobby->dir(), &pCarePackage, &pLoginPackage, pError));

    // Decrypt MK:
    ABC_CHECK_RET(ABC_CryptoScryptSNRP(LP, pCarePackage->pSNRP2, &LP2, pError));
    ABC_CHECK_RET(ABC_CryptoDecryptJSONObject(pLoginPackage->EMK_LP2, LP2, &MK, pError));

    // Decrypt SyncKey:
    login.reset(new Login(lobby, static_cast<U08Buf>(MK)));
    ABC_CHECK_NEW(login->init(pLoginPackage), pError);
    result.reset(login.release());

exit:
    ABC_CarePackageFree(pCarePackage);
    ABC_LoginPackageFree(pLoginPackage);

    return cc;
}
예제 #7
0
/**
 * Modifies a previously created receive request.
 * Note: the previous details will be free'ed so if the user is using the previous details for this request
 * they should not assume they will be valid after this call.
 *
 * @param szRequestID   ID of this request
 * @param pDetails      Pointer to transaction details
 * @param pError        A pointer to the location to store the error if there is one
 */
tABC_CC ABC_TxModifyReceiveRequest(Wallet &self,
                                   const char *szRequestID,
                                   tABC_TxDetails *pDetails,
                                   tABC_Error *pError)
{
    tABC_CC cc = ABC_CC_Ok;
    AutoCoreLock lock(gCoreMutex);

    Address address;
    ABC_CHECK_NEW(self.addresses.get(address, szRequestID));
    address.metadata = pDetails;
    ABC_CHECK_NEW(self.addresses.save(address));

exit:
    return cc;
}
예제 #8
0
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;
}
예제 #9
0
tABC_CC ABC_BridgeWatcherConnect(Wallet &self, tABC_Error *pError)
{
    tABC_CC cc = ABC_CC_Ok;
    tABC_GeneralInfo *ppInfo = NULL;
    const char *szServer = FALLBACK_OBELISK;

    Watcher *watcher = nullptr;
    ABC_CHECK_NEW(watcherFind(watcher, self));

    // Pick a server:
    if (isTestnet())
    {
        szServer = TESTNET_OBELISK;
    }
    else if (ABC_CC_Ok == ABC_GeneralGetInfo(&ppInfo, pError) &&
        0 < ppInfo->countObeliskServers)
    {
        ++gLastObelisk;
        if (ppInfo->countObeliskServers <= gLastObelisk)
            gLastObelisk = 0;
        szServer = ppInfo->aszObeliskServers[gLastObelisk];
    }

    // Connect:
    ABC_DebugLog("Wallet %s connecting to %s", self.id().c_str(), szServer);
    watcher->connect(szServer);

exit:
    ABC_GeneralFreeInfo(ppInfo);
    return cc;
}
예제 #10
0
tABC_CC ABC_BridgePrioritizeAddress(Wallet &self,
                                    const char *szAddress,
                                    tABC_Error *pError)
{
    tABC_CC cc = ABC_CC_Ok;
    bc::payment_address addr;

    Watcher *watcher = nullptr;
    ABC_CHECK_NEW(watcherFind(watcher, self));

    if (szAddress)
    {
        if (!addr.set_encoded(szAddress))
        {
            cc = ABC_CC_Error;
            ABC_DebugLog("Invalid szAddress %s\n", szAddress);
            goto exit;
        }
    }

    watcher->prioritize_address(addr);

exit:
    return cc;
}
예제 #11
0
/**
 * Filters a transaction list, removing any that aren't found in the
 * watcher database.
 * @param aTransactions The array to filter. This will be modified in-place.
 * @param pCount        The array length. This will be updated upon return.
 */
tABC_CC ABC_BridgeFilterTransactions(Wallet &self,
                                     tABC_TxInfo **aTransactions,
                                     unsigned int *pCount,
                                     tABC_Error *pError)
{
    tABC_CC cc = ABC_CC_Ok;
    tABC_TxInfo *const *end = aTransactions + *pCount;
    tABC_TxInfo *const *si = aTransactions;
    tABC_TxInfo **di = aTransactions;

    Watcher *watcher = nullptr;
    ABC_CHECK_NEW(watcherFind(watcher, self));

    while (si < end)
    {
        tABC_TxInfo *pTx = *si++;

        int height;
        bc::hash_digest txid;
        if (!bc::decode_hash(txid, pTx->szMalleableTxId))
            ABC_RET_ERROR(ABC_CC_ParseError, "Bad txid");
        if (watcher->get_tx_height(txid, height))
        {
            *di++ = pTx;
        }
        else
        {
            ABC_TxFreeTransaction(pTx);
        }
    }
    *pCount = di - aTransactions;

exit:
    return cc;
}
예제 #12
0
/**
 * Marks the address as unusable and returns its metadata.
 *
 * @param ppDetails     Metadata extracted from the address database
 * @param paAddress     Addresses that will be updated
 * @param addressCount  Number of address in paAddress
 */
tABC_CC ABC_TxTrashAddresses(Wallet &self,
                             tABC_TxDetails **ppDetails,
                             tABC_TxOutput **paAddresses,
                             unsigned int addressCount,
                             tABC_Error *pError)
{
    tABC_CC cc = ABC_CC_Ok;

    *ppDetails = nullptr;
    for (unsigned i = 0; i < addressCount; ++i)
    {
        if (paAddresses[i]->input)
            continue;

        Address address;
        if (self.addresses.get(address, paAddresses[i]->szAddress))
        {
            // Update the transaction:
            if (address.recyclable)
            {
                address.recyclable = false;
                ABC_CHECK_NEW(self.addresses.save(address));
            }

            // Return our details:
            ABC_TxDetailsFree(*ppDetails);
            *ppDetails = address.metadata.toDetails();
        }
    }

exit:
    return cc;
}
예제 #13
0
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;
}
예제 #14
0
/**
 * 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;
}
예제 #15
0
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;
}
예제 #16
0
tABC_CC ABC_BridgeWatcherLoop(Wallet &self,
                              tABC_BitCoin_Event_Callback fAsyncCallback,
                              void *pData,
                              tABC_Error *pError)
{
    tABC_CC cc = ABC_CC_Ok;
    Watcher::block_height_callback heightCallback;
    Watcher::tx_callback txCallback;
    Watcher::tx_sent_callback sendCallback;
    Watcher::quiet_callback on_quiet;
    Watcher::fail_callback failCallback;

    WatcherInfo *watcherInfo = nullptr;
    ABC_CHECK_NEW(watcherFind(watcherInfo, self));
    watcherInfo->fAsyncCallback = fAsyncCallback;
    watcherInfo->pData = pData;

    txCallback = [watcherInfo, fAsyncCallback, pData] (const libbitcoin::transaction_type& tx)
    {
        ABC_BridgeTxCallback(watcherInfo, tx, fAsyncCallback, pData);
    };
    watcherInfo->watcher.set_tx_callback(txCallback);

    heightCallback = [watcherInfo, fAsyncCallback, pData](const size_t height)
    {
        if (fAsyncCallback)
        {
            tABC_AsyncBitCoinInfo info;
            info.eventType = ABC_AsyncEventType_BlockHeightChange;
            info.pData = pData;
            info.szDescription = "Block height change";
            fAsyncCallback(&info);
        }
        watcherSave(watcherInfo->wallet); // Failure is not fatal
    };
    watcherInfo->watcher.set_height_callback(heightCallback);

    on_quiet = [watcherInfo]()
    {
        ABC_BridgeQuietCallback(watcherInfo);
    };
    watcherInfo->watcher.set_quiet_callback(on_quiet);

    failCallback = [watcherInfo]()
    {
        tABC_Error error;
        ABC_BridgeWatcherConnect(watcherInfo->wallet, &error);
    };
    watcherInfo->watcher.set_fail_callback(failCallback);

    watcherInfo->watcher.loop();

exit:
    return cc;
}
예제 #17
0
/**
 * 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;
}
예제 #18
0
/**
 * Sets the recycle status on an address as specified
 *
 * @param szAddress     ID of the address
 * @param pError        A pointer to the location to store the error if there is one
 */
static
tABC_CC ABC_TxSetAddressRecycle(Wallet &self,
                                const char *szAddress,
                                bool bRecyclable,
                                tABC_Error *pError)
{
    tABC_CC cc = ABC_CC_Ok;
    AutoCoreLock lock(gCoreMutex);

    Address address;
    ABC_CHECK_NEW(self.addresses.get(address, szAddress));
    if (address.recyclable != bRecyclable)
    {
        address.recyclable = bRecyclable;
        ABC_CHECK_NEW(self.addresses.save(address));
    }

exit:
    return cc;
}
예제 #19
0
/**
 * Creates a receive request.
 *
 * @param szUserName    UserName for the account associated with this request
 * @param pDetails      Pointer to transaction details
 * @param pszRequestID  Pointer to store allocated ID for this request
 * @param pError        A pointer to the location to store the error if there is one
 */
tABC_CC ABC_TxCreateReceiveRequest(Wallet &self,
                                   tABC_TxDetails *pDetails,
                                   char **pszRequestID,
                                   bool bTransfer,
                                   tABC_Error *pError)
{
    tABC_CC cc = ABC_CC_Ok;

    Address address;
    ABC_CHECK_NEW(self.addresses.getNew(address));
    address.time = time(nullptr);
    address.metadata = pDetails;
    ABC_CHECK_NEW(self.addresses.save(address));

    // set the id for the caller
    *pszRequestID = stringCopy(address.address);

exit:
    return cc;
}
예제 #20
0
tABC_CC ABC_BridgeWatcherDisconnect(Wallet &self, tABC_Error *pError)
{
    tABC_CC cc = ABC_CC_Ok;

    Watcher *watcher = nullptr;
    ABC_CHECK_NEW(watcherFind(watcher, self));

    watcher->disconnect();

exit:
    return cc;
}
예제 #21
0
/**
 * Gets the bit coin public address for a specified request
 *
 * @param szRequestID       ID of request
 * @param pszAddress        Location to store allocated address string (caller must free)
 * @param pError            A pointer to the location to store the error if there is one
 */
tABC_CC ABC_TxGetRequestAddress(Wallet &self,
                                const char *szRequestID,
                                char **pszAddress,
                                tABC_Error *pError)
{
    tABC_CC cc = ABC_CC_Ok;

    Address address;
    ABC_CHECK_NEW(self.addresses.get(address, szRequestID));
    *pszAddress = stringCopy(address.address);

exit:
    return cc;
}
예제 #22
0
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;
}
예제 #23
0
tABC_CC
ABC_BridgeTxBlockHeight(Wallet &self, unsigned int *height, tABC_Error *pError)
{
    tABC_CC cc = ABC_CC_Ok;

    Watcher *watcher = nullptr;
    ABC_CHECK_NEW(watcherFind(watcher, self));

    *height = watcher->get_last_block_height();
    if (*height == 0)
    {
        cc = ABC_CC_Synchronizing;
    }
exit:
    return cc;
}
예제 #24
0
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;
}
예제 #25
0
static
tABC_CC ABC_LoginPasswordServer(std::shared_ptr<Login> &result,
                                std::shared_ptr<Lobby> lobby,
                                tABC_U08Buf LP,
                                tABC_Error *pError)
{
    tABC_CC cc = ABC_CC_Ok;

    std::unique_ptr<Login> login;
    tABC_CarePackage    *pCarePackage   = NULL;
    tABC_LoginPackage   *pLoginPackage  = NULL;
    tABC_U08Buf         LRA1            = ABC_BUF_NULL; // Do not free
    AutoU08Buf          LP1;
    AutoU08Buf          LP2;
    AutoU08Buf          MK;

    // Get the CarePackage:
    ABC_CHECK_RET(ABC_LoginServerGetCarePackage(toU08Buf(lobby->authId()), &pCarePackage, pError));

    // Get the LoginPackage:
    ABC_CHECK_RET(ABC_CryptoScryptSNRP(LP, pCarePackage->pSNRP1, &LP1, pError));
    ABC_CHECK_RET(ABC_LoginServerGetLoginPackage(toU08Buf(lobby->authId()), LP1, LRA1, &pLoginPackage, pError));

    // Decrypt MK:
    ABC_CHECK_RET(ABC_CryptoScryptSNRP(LP, pCarePackage->pSNRP2, &LP2, pError));
    ABC_CHECK_RET(ABC_CryptoDecryptJSONObject(pLoginPackage->EMK_LP2, LP2, &MK, pError));

    // Decrypt SyncKey:
    login.reset(new Login(lobby, static_cast<U08Buf>(MK)));
    ABC_CHECK_NEW(login->init(pLoginPackage), pError);

    // Set up the on-disk login:
    ABC_CHECK_RET(ABC_LoginDirSavePackages(lobby->dir(), pCarePackage, pLoginPackage, pError));

    // Assign the result:
    result.reset(login.release());

exit:
    ABC_CarePackageFree(pCarePackage);
    ABC_LoginPackageFree(pLoginPackage);

    return cc;
}
예제 #26
0
tABC_CC
ABC_BridgeTxHeight(Wallet &self, const char *szTxId, unsigned int *height, tABC_Error *pError)
{
    tABC_CC cc = ABC_CC_Ok;
    int height_;
    bc::hash_digest txid;

    Watcher *watcher = nullptr;
    ABC_CHECK_NEW(watcherFind(watcher, self));

    if (!bc::decode_hash(txid, szTxId))
        ABC_RET_ERROR(ABC_CC_ParseError, "Bad txid");
    if (!watcher->get_tx_height(txid, height_))
    {
        cc = ABC_CC_Synchronizing;
    }
    *height = height_;
exit:
    return cc;
}
예제 #27
0
tABC_CC ABC_BridgeWatchAddr(Wallet &self,
                            const char *pubAddress,
                            tABC_Error *pError)
{
    tABC_CC cc = ABC_CC_Ok;

    ABC_DebugLog("Watching %s for %s", pubAddress, self.id().c_str());
    bc::payment_address addr;

    WatcherInfo *watcherInfo = nullptr;
    ABC_CHECK_NEW(watcherFind(watcherInfo, self));

    if (!addr.set_encoded(pubAddress))
    {
        cc = ABC_CC_Error;
        ABC_DebugLog("Invalid pubAddress %s\n", pubAddress);
        goto exit;
    }
    watcherInfo->addresses.insert(pubAddress);
    watcherInfo->watcher.watch_address(addr);

exit:
    return cc;
}
예제 #28
0
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;
}
예제 #29
0
tABC_CC ABC_BridgeTxDetailsSplit(Wallet &self, const char *szTxID,
                                 tABC_TxOutput ***paInputs, unsigned int *pInCount,
                                 tABC_TxOutput ***paOutputs, unsigned int *pOutCount,
                                 int64_t *pAmount, int64_t *pFees,
                                 tABC_Error *pError)
{
    tABC_CC cc = ABC_CC_Ok;
    tABC_TxOutput **paInArr = NULL;
    tABC_TxOutput **paOutArr = NULL;
    bc::transaction_type tx;
    unsigned int idx = 0, iCount = 0, oCount = 0;
    int64_t fees = 0;
    int64_t totalInSatoshi = 0, totalOutSatoshi = 0, totalMeSatoshi = 0, totalMeInSatoshi = 0;

    WatcherInfo *watcherInfo = nullptr;
    ABC_CHECK_NEW(watcherFind(watcherInfo, self));

    bc::hash_digest txid;
    if (!bc::decode_hash(txid, szTxID))
        ABC_RET_ERROR(ABC_CC_ParseError, "Bad txid");

    tx = watcherInfo->watcher.find_tx(txid);

    idx = 0;
    iCount = tx.inputs.size();
    paInArr = (tABC_TxOutput **) malloc(sizeof(tABC_TxOutput *) * iCount);
    for (auto i : tx.inputs)
    {
        bc::payment_address addr;
        bc::extract(addr, i.script);
        auto prev = i.previous_output;

        // Create output
        tABC_TxOutput *out = (tABC_TxOutput *) malloc(sizeof(tABC_TxOutput));
        out->input = true;
        out->szTxId = stringCopy(bc::encode_hash(prev.hash));
        out->szAddress = stringCopy(addr.encoded());

        auto tx = watcherInfo->watcher.find_tx(prev.hash);
        if (prev.index < tx.outputs.size())
        {
            out->value = tx.outputs[prev.index].value;
            totalInSatoshi += tx.outputs[prev.index].value;
            auto row = watcherInfo->addresses.find(addr.encoded());
            if  (row != watcherInfo->addresses.end())
                totalMeInSatoshi += tx.outputs[prev.index].value;
        } else {
            out->value = 0;
        }
        paInArr[idx] = out;
        idx++;
    }

    idx = 0;
    oCount = tx.outputs.size();
    paOutArr = (tABC_TxOutput **) malloc(sizeof(tABC_TxOutput *) * oCount);
    for (auto o : tx.outputs)
    {
        bc::payment_address addr;
        bc::extract(addr, o.script);
        // Create output
        tABC_TxOutput *out = (tABC_TxOutput *) malloc(sizeof(tABC_TxOutput));
        out->input = false;
        out->value = o.value;
        out->szAddress = stringCopy(addr.encoded());
        out->szTxId = stringCopy(szTxID);

        // Do we own this address?
        auto row = watcherInfo->addresses.find(addr.encoded());
        if  (row != watcherInfo->addresses.end())
        {
            totalMeSatoshi += o.value;
        }
        totalOutSatoshi += o.value;
        paOutArr[idx] = out;
        idx++;
    }
    fees = totalInSatoshi - totalOutSatoshi;
    totalMeSatoshi -= totalMeInSatoshi;

    *paInputs = paInArr;
    *pInCount = iCount;
    *paOutputs = paOutArr;
    *pOutCount = oCount;
    *pAmount = totalMeSatoshi;
    *pFees = fees;
    paInArr = NULL;
    paOutArr = NULL;
exit:
    ABC_TxFreeOutputs(paInArr, iCount);
    ABC_TxFreeOutputs(paOutArr, oCount);
    return cc;
}
예제 #30
0
/**
 * 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;
}