Merge pull request #232 from larteyoh/backup

changes to protocol
pull/245/head
larteyoh 3 months ago committed by GitHub
commit 0004dd17cb
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -284,17 +284,6 @@ std::vector<uint8_t> neroshop::msgpack::process(const std::vector<uint8_t>& requ
std::string key = params_object["key"];
assert(params_object["value"].is_string());
std::string value = params_object["value"];
assert(params_object["verified"].is_boolean());
bool verified = params_object["verified"].get<bool>();
if(verified == false) {
code = static_cast<int>(KadResultCode::DataVerificationFailed);
response_object["error"]["code"] = code;
response_object["error"]["message"] = "Data verification failed";
response_object["tid"] = tid;
response = nlohmann::json::to_msgpack(response_object);
return response;
}
// Send put messages to the closest nodes in your routing table (IPC mode)
int put_messages_sent = node.send_put(key, value);

@ -269,15 +269,15 @@ int neroshop::Node::put(const std::string& key, const std::string& value) {
return true;
}
if(!validate(key, value)) {
return false;
}
// If node has the key but the value has been altered, verify data integrity and ownership then update the data
if (has_key(key) && get(key) != value) {
std::cout << "Updating value for key (" << key << ")\n";
std::cout << "Updating value for key (" << key << ") ...\n";
return set(key, value);
}
if(!validate(key, value)) {
return false;
}
data[key] = value;
return has_key(key); // boolean
@ -313,39 +313,37 @@ void neroshop::Node::map(const std::string& key, const std::string& value) {
}
int neroshop::Node::set(const std::string& key, const std::string& value) {
nlohmann::json json = nlohmann::json::parse(value); // Already validated so we just need to parse it without checking for errors
// Detect when key is the same but the value has changed
nlohmann::json json = nlohmann::json::parse(value); // Already validated in put() so we just need to parse it without checking for errors
// Same key but both current and new values do not match
if(has_key(key)) {
std::string current_value = find_value(key);//std::cout << "preexisting_value: " << preexisting_value << std::endl;
// Compare the preexisting value with the new value
std::string current_value = find_value(key);
if (current_value != value) {
////std::cout << "Value modification detected. Performing signature verification ...\n";//std::cout << "Value mismatch. Skipping ...\n";//return false;}
nlohmann::json current_json = nlohmann::json::parse(current_value);
// Verify signature using user's public key (required for account data and listing data)
// If a signature field is found in the value, we can verify the data by using the signed message, signing monero address, and the signature itself
if (json.contains("signature")) {
assert(json["signature"].is_string());
std::string signature = json["signature"].get<std::string>();//neroshop::base64_decode(json["signature"].get<std::string>());
std::string signature = json["signature"].get<std::string>(); // the signature may have been updated
assert(json["metadata"].is_string());
std::string metadata = json["metadata"].get<std::string>();
if(metadata != current_json["metadata"].get<std::string>()) { std::cerr << "Metadata mismatch\n"; return false; } // metadata is immutable
std::cout << "Verifying existing key's signature ...\n";
// For metadata="listing"
// For listings
if(metadata == "listing") {
std::string message = json["id"].get<std::string>(); // the listing's "id" (or "uuid") is the signed message
std::string address = json["seller_id"].get<std::string>(); // the "seller_id" is the signing address
// Create a temporary monero_wallet_full object to verify signature
std::string message = json["id"].get<std::string>(); // the id (uuid) is the signed message
std::string address = json["seller_id"].get<std::string>(); // the seller_id (monero primary address) is the signing address
if(message != current_json["id"].get<std::string>()) { std::cerr << "Listing UUID mismatch\n"; return false; } // id is immutable
if(address != current_json["seller_id"].get<std::string>()) { std::cerr << "Seller ID mismatch\n"; return false; } // seller_id is immutable
// Create a temporary monero wallet
monero::monero_wallet_config wallet_config_obj;
wallet_config_obj.m_path = "";
wallet_config_obj.m_password = "";
wallet_config_obj.m_network_type = monero_network_type::STAGENET;
std::unique_ptr<monero::monero_wallet_full> monero_wallet_obj = std::unique_ptr<monero_wallet_full>(monero_wallet_full::create_wallet (wallet_config_obj, nullptr));
// Verify the data's signature
// Verify the message
bool verified = monero_wallet_obj->verify_message(message, address, signature).m_is_good;
if(!verified) {
std::cerr << "Verification failed." << std::endl;
std::cerr << "\033[91mData verification failed.\033[0m" << std::endl;
return false; // Verification failed, return false
}
// Destroy the wallet
@ -998,11 +996,18 @@ bool neroshop::Node::validate(const std::string& key, const std::string& value)
return false; // Invalid value, return false
}
// Make sure value contains a metadata field
// Make sure value contains a valid metadata field
if(!json.contains("metadata")) {
std::cerr << "No metadata found\n";
return false;
}
assert(json["metadata"].is_string());
std::string metadata = json["metadata"].get<std::string>();
std::vector<std::string> valid_metadatas = { "user","listing","product_rating","seller_rating","order","message", };
if (std::find(valid_metadatas.begin(), valid_metadatas.end(), metadata) == valid_metadatas.end()) {
std::cerr << metadata << " is not a VALID metadata\n";
return false;
}
// Check whether data is expired so we don't store it
db::Sqlite3 * database = neroshop::get_database();
@ -1010,15 +1015,14 @@ bool neroshop::Node::validate(const std::string& key, const std::string& value)
assert(json["expiration_date"].is_string());
std::string expiration_date = json["expiration_date"].get<std::string>();
if(neroshop_timestamp::is_expired(expiration_date)) {
std::cerr << "Data has expired (exp date: " << expiration_date << ")\n";
// Notify the other nodes that this data has expired (so that once they receive a put with the expired data, it will be removed from their local hash table as soon as it goes through the validate function)
////send_put(key, value); // this should propagate the expiration information to other nodes in the DHT until the expired data is removed once and for all. Hmmm this could cause an endless loop ...
// This won't work unless all data contain a mandatory expiration date set on creation. A consensus mechanism may be necessary
// Remove the data from hash table if it was previously stored
if(has_key(key)) {
std::cout << "Data has expired. Removing data (key: " << key << ", exp:" << expiration_date << ") from hash table ...\n";
if(remove(key) == true) {
int error = database->execute_params("DELETE FROM mappings WHERE key = ?1", { key });
std::cout << "Expired data with key (" << key << ") has been removed from hash table\n";
}
}
return false;

@ -239,9 +239,9 @@ void neroshop::Client::get(const std::string& key, std::string& reply) {
}
}
void neroshop::Client::set(const std::string& key, const std::string& value, bool verified, std::string& reply) {
void neroshop::Client::set(const std::string& key, const std::string& value, std::string& reply) {
// Send set - no id or tid required for IPC client requests. The DHT server will deal with that
nlohmann::json args_obj = { {"key", key}, {"value", value}, {"verified", verified} };
nlohmann::json args_obj = { {"key", key}, {"value", value} };
nlohmann::json query_object = { {"version", std::string(NEROSHOP_DHT_VERSION)}, {"query", "set"}, {"args", args_obj}, {"tid", nullptr} };
std::vector<uint8_t> packed_data = nlohmann::json::to_msgpack(query_object);
send(packed_data);

@ -56,7 +56,7 @@ public:
// Interactions with the DHT node, which only exists on the client side via IPC server
void put(const std::string& key, const std::string& value, std::string& response);
void get(const std::string& key, std::string& response);
void set(const std::string& key, const std::string& value, bool verified, std::string& response);
void set(const std::string& key, const std::string& value, std::string& response);
void close(); // kills socket
void shutdown(); // shuts down connection (disconnects from server)
void disconnect(); // breaks connection to server then closes the client socket // combination of shutdown() and close()

@ -139,14 +139,18 @@ void neroshop::Seller::delist_item(const std::string& listing_key) {
std::string listing_id = value_obj["id"].get<std::string>();
std::string signature = value_obj["signature"].get<std::string>();
bool verified = wallet->verify_message(listing_id, signature);
if(!verified) { neroshop::print("Data verification failed."); return; }
// Might be a good idea to set the stock quantity to zero beforehand or nah?
////value_obj["quantity"] = 0;
// Finally, set the expiration date
value_obj["expiration_date"] = neroshop::timestamp::get_current_utc_timestamp();//value_obj["valid_until"] = neroshop::timestamp::get_current_utc_timestamp();
// Re-sign the listing to reflect the modification
std::string new_signature = wallet->sign_message(listing_id, monero_message_signature_type::SIGN_WITH_SPEND_KEY);
value_obj["signature"] = new_signature;
// Send set request containing the updated value with the same key as before
std::string modified_value = value_obj.dump();
std::string response;
client->set(listing_key, modified_value, verified, response);
client->set(listing_key, modified_value, response);
std::cout << "Received response (set): " << response << "\n";
}
}
@ -348,14 +352,18 @@ void neroshop::Seller::set_stock_quantity(const std::string& listing_key, int qu
std::string listing_id = value_obj["id"].get<std::string>();
std::string signature = value_obj["signature"].get<std::string>();
bool verified = wallet->verify_message(listing_id, signature);
if(!verified) { neroshop::print("Data verification failed."); return; }
// Finally, modify the quantity
value_obj["quantity"] = quantity;
// Add a last_modified or last_updated field so nodes can compare dates and choose the most recent listing
value_obj["last_updated"] = neroshop::timestamp::get_current_utc_timestamp();
// Re-sign the listing to reflect the modification
std::string new_signature = wallet->sign_message(listing_id, monero_message_signature_type::SIGN_WITH_SPEND_KEY);
value_obj["signature"] = new_signature;
// Send set request containing the updated value with the same key as before
std::string modified_value = value_obj.dump();
std::string response;
client->set(listing_key, modified_value, verified, response);
client->set(listing_key, modified_value, response);
std::cout << "Received response (set): " << response << "\n";
}
}

Loading…
Cancel
Save