diff --git a/README.md b/README.md index 3839daa..b322b3c 100644 --- a/README.md +++ b/README.md @@ -214,7 +214,7 @@ To start for testnet with non-default location of `config.json` file: ```bash -curl -w "\n" -X POST http://139.162.32.245:1984/get_version +curl -w "\n" -X POST http://127.0.0.1:1984/get_version ``` Example output: @@ -237,46 +237,11 @@ curl -w "\n" -X POST http://127.0.0.1:1984/login -d '{"address": "A2VTvE8bC9APs {"new_address":false,"status":"success"} ``` -#### get_address_info - -```bash -curl -w "\n" -X POST http://139.162.32.245:1984/get_address_info -d '{"address": "A2VTvE8bC9APsWFn3mQzgW8Xfcy2SP2CRUArD6ZtthNaWDuuvyhtBcZ8WDuYMRt1HhcnNQvpXVUavEiZ9waTbyBhP6RM8TV"}' -``` - -Output (only part shown): - -```json -{ - "blockchain_height": 858970, - "locked_funds": 0, - "scanned_block_height": 858970, - "scanned_height": 0, - "spent_outputs": [ - { - "amount": 13683584012406, - "key_image": "437518836c315bf989c5cc28b935280345ed672d727122f6d6c5c5ff32e98224", - "mixin": 0, - "out_index": 0, - "tx_pub_key": "99c74015a50d91d29a16f3c1e43540a0b9da858c2a09faaec167db3cc6939dbf" - }, - { - "amount": 13683584012406, - "key_image": "ac3088ce17cc608bcf86db65e9061fe4b9b02573b997944e4ebf7d8e64e4a3b4", - "mixin": 0, - "out_index": 0, - "tx_pub_key": "99c74015a50d91d29a16f3c1e43540a0b9da858c2a09faaec167db3cc6939dbf" - } - ], - "start_height": 855633, - "total_received": 13481878608141995, - "total_sent": 4699871131811773 -} -``` #### get_address_txs ```bash -curl -w "\n" -X POST http://139.162.32.245:1984/get_address_txs -d '{"address": "9viPdjLNXDaRFNtTTDg5wXg9Yg55uDC9XRLv882aPAFye1Ta6fSh25M41JoXBQj8d964JyFXuLVddEdg71cPJ8DY7WrSH3z"}' +curl -w "\n" -X POST http://127.0.0.1:1984/get_address_txs -d '{"address": "A2VTvE8bC9APsWFn3mQzgW8Xfcy2SP2CRUArD6ZtthNaWDuuvyhtBcZ8WDuYMRt1HhcnNQvpXVUavEiZ9waTbyBhP6RM8TV", "view_key": "041a241325326f9d86519b714a9b7f78b29111551757eeb6334d39c21f8b7400"}' ``` Output (only part shown): @@ -336,6 +301,43 @@ Output (only part shown): } ``` +#### get_address_info + +```bash +curl -w "\n" -X POST http://127.0.0.1:1984/get_address_info -d '{"address": "A2VTvE8bC9APsWFn3mQzgW8Xfcy2SP2CRUArD6ZtthNaWDuuvyhtBcZ8WDuYMRt1HhcnNQvpXVUavEiZ9waTbyBhP6RM8TV", "view_key": "041a241325326f9d86519b714a9b7f78b29111551757eeb6334d39c21f8b7400"}' +``` + +Output (only part shown): + +```json +{ + "blockchain_height": 858970, + "locked_funds": 0, + "scanned_block_height": 858970, + "scanned_height": 0, + "spent_outputs": [ + { + "amount": 13683584012406, + "key_image": "437518836c315bf989c5cc28b935280345ed672d727122f6d6c5c5ff32e98224", + "mixin": 0, + "out_index": 0, + "tx_pub_key": "99c74015a50d91d29a16f3c1e43540a0b9da858c2a09faaec167db3cc6939dbf" + }, + { + "amount": 13683584012406, + "key_image": "ac3088ce17cc608bcf86db65e9061fe4b9b02573b997944e4ebf7d8e64e4a3b4", + "mixin": 0, + "out_index": 0, + "tx_pub_key": "99c74015a50d91d29a16f3c1e43540a0b9da858c2a09faaec167db3cc6939dbf" + } + ], + "start_height": 855633, + "total_received": 13481878608141995, + "total_sent": 4699871131811773 +} +``` + + #### get_unspent_outs ```bash diff --git a/src/CurrentBlockchainStatus.cpp b/src/CurrentBlockchainStatus.cpp index 7b3b511..499f996 100644 --- a/src/CurrentBlockchainStatus.cpp +++ b/src/CurrentBlockchainStatus.cpp @@ -236,6 +236,19 @@ CurrentBlockchainStatus::tx_exist(const crypto::hash& tx_hash, uint64_t& tx_inde } +bool +CurrentBlockchainStatus::tx_exist(const string& tx_hash_str, uint64_t& tx_index) +{ + crypto::hash tx_hash; + + if (hex_to_pod(tx_hash_str, tx_hash)) + { + return tx_exist(tx_hash, tx_index); + } + + throw runtime_error("hex_to_pod(tx_hash_str, tx_hash) failed!"); +} + bool CurrentBlockchainStatus::tx_exist(const string& tx_hash_str) { diff --git a/src/CurrentBlockchainStatus.h b/src/CurrentBlockchainStatus.h index 7aa0c12..41d191b 100644 --- a/src/CurrentBlockchainStatus.h +++ b/src/CurrentBlockchainStatus.h @@ -106,6 +106,9 @@ struct CurrentBlockchainStatus static bool tx_exist(const crypto::hash& tx_hash, uint64_t& tx_index); + static bool + tx_exist(const string& tx_hash_str, uint64_t& tx_index); + static bool tx_exist(const string& tx_hash_str); diff --git a/src/YourMoneroRequests.cpp b/src/YourMoneroRequests.cpp index 800370c..ad95451 100644 --- a/src/YourMoneroRequests.cpp +++ b/src/YourMoneroRequests.cpp @@ -84,8 +84,8 @@ YourMoneroRequests::login(const shared_ptr session, const Bytes & body) } else { - j_response["status"] = "error"; - j_response["reason"] = "Viewkey provided is incorrect"; + j_response = json {{"status", "error"}, + {"reason", "Viewkey provided is incorrect"}}; } } else @@ -138,8 +138,8 @@ YourMoneroRequests::login(const shared_ptr session, const Bytes & body) } else { - j_response["status"] = "error"; - j_response["reason"] = "Failed created search thread for this account"; + j_response = json {{"status", "error"}, + {"reason", "Failed created search thread for this account"}}; } } // if (start_search_thread) @@ -150,12 +150,25 @@ YourMoneroRequests::login(const shared_ptr session, const Bytes & body) void YourMoneroRequests::get_address_txs(const shared_ptr< Session > session, const Bytes & body) { - json j_request = body_to_json(body); + json j_response; - string xmr_address = j_request["address"]; + map values_map{{"address" , {}}, {"view_key", {}}}; + + if (!parse_request(body, values_map, j_response)) + { + session_close(session, j_response.dump()); + return; + } + + const string& xmr_address = values_map["address"]; + const string& view_key = values_map["view_key"]; + + // make hash of the submited viewkey. we only store + // hash of viewkey in database, not acctual viewkey. + string viewkey_hash = make_hash(view_key); // initialize json response - json j_response { + j_response = json { { "total_received" , 0}, // calculated in this function { "total_received_unlocked", 0}, // calculated in this function { "scanned_height" , 0}, // not used. it is here to match mymonero @@ -165,12 +178,26 @@ YourMoneroRequests::get_address_txs(const shared_ptr< Session > session, const B { "transactions" , json::array()} }; - // a placeholder for exciting or new account data xmreg::XmrAccount acc; // select this account if its existing one - if (xmr_accounts->select(xmr_address, acc)) { + if (xmr_accounts->select(xmr_address, acc)) + { + // before fetching txs, check if provided view key + // is correct. this is simply to ensure that + // we cant fetch an account's txs using only address. + // knowlage of the viewkey is also needed. + + if (viewkey_hash != acc.viewkey_hash) + { + j_response = json {{"status", "error"}, + {"reason", "Viewkey provided is incorrect"}}; + + session_close(session, j_response.dump()); + return; + } + uint64_t total_received {0}; uint64_t total_received_unlocked {0}; @@ -306,11 +333,24 @@ YourMoneroRequests::get_address_txs(const shared_ptr< Session > session, const B void YourMoneroRequests::get_address_info(const shared_ptr< Session > session, const Bytes & body) { - json j_request = body_to_json(body); + json j_response; - string xmr_address = j_request["address"]; + map values_map{{"address" , {}}, {"view_key", {}}}; - json j_response { + if (!parse_request(body, values_map, j_response)) + { + session_close(session, j_response.dump()); + return; + } + + const string& xmr_address = values_map["address"]; + const string& view_key = values_map["view_key"]; + + // make hash of the submited viewkey. we only store + // hash of viewkey in database, not acctual viewkey. + string viewkey_hash = make_hash(view_key); + + j_response = json { {"locked_funds" , 0}, // locked xmr (e.g., younger than 10 blocks) {"total_received" , 0}, // calculated in this function {"total_sent" , 0}, // calculated in this function @@ -325,13 +365,21 @@ YourMoneroRequests::get_address_info(const shared_ptr< Session > session, const // only client has spent key }; - // a placeholder for exciting or new account data xmreg::XmrAccount acc; // select this account if its existing one if (xmr_accounts->select(xmr_address, acc)) { + if (viewkey_hash != acc.viewkey_hash) + { + j_response = json {{"status", "error"}, + {"reason", "Viewkey provided is incorrect"}}; + + session_close(session, j_response.dump()); + return; + } + uint64_t total_received {0}; // ping the search thread that we still need it. @@ -379,15 +427,20 @@ YourMoneroRequests::get_address_info(const shared_ptr< Session > session, const } total_received += out.amount; - } - } - } + + } // for (XmrOutput &out: outs) + + } // if (xmr_accounts->select_outputs_for_tx(tx.id, outs)) + + } // for (XmrTransaction tx: txs) + j_response["total_received"] = total_received; j_response["total_sent"] = total_sent; j_response["spent_outputs"] = j_spent_outputs; - } + + } // if (xmr_accounts->select_txs_for_account_spendability_check(acc.id, txs)) } // if (xmr_accounts->select(xmr_address, acc)) @@ -907,7 +960,21 @@ YourMoneroRequests::parse_request( for (const auto& kv: values_map) { + + if (j_request.count(kv.first) == 0) + { + cerr << kv.first + " value not provided" << endl; + + j_response["status"] = "error"; + j_response["reason"] = kv.first + " value not provided"; + + return false; + } + values_map[kv.first] = j_request[kv.first]; + + // assume some needed value in json is not given + j_response["reason"] = kv.first + " value not provided"; } return true;