diff --git a/examples/hpclient/file-client.js b/examples/hpclient/file-client.js index 0d85a9ee..64f6858e 100644 --- a/examples/hpclient/file-client.js +++ b/examples/hpclient/file-client.js @@ -54,14 +54,14 @@ function main() { let inp_container = { nonce: (new Date()).getTime().toString(), input: inp.toString('hex'), - max_ledger_seqno: 9999999 + max_lcl_seqno: 9999999 } let inp_container_bytes = JSON.stringify(inp_container); let sig_bytes = sodium.crypto_sign_detached(inp_container_bytes, keys.privateKey); let signed_inp_container = { type: "contract_input", - content: inp_container_bytes.toString('hex'), + input_container: inp_container_bytes.toString('hex'), sig: Buffer.from(sig_bytes).toString('hex') } @@ -80,7 +80,7 @@ function main() { // sign the challenge and send back the response var sigbytes = sodium.crypto_sign_detached(m.challenge, keys.privateKey); var response = { - type: 'challenge_resp', + type: 'handshake_response', challenge: m.challenge, sig: Buffer.from(sigbytes).toString('hex'), pubkey: pkhex @@ -128,13 +128,13 @@ function main() { return } - if (m.type == 'public_challenge') { + if (m.type == 'handshake_challenge') { handle_public_challange(m); } else if (m.type == 'contract_output') { console.log("Contract says: " + Buffer.from(m.content, 'hex').toString()); } - else if (m.type == 'request_status_result') { + else if (m.type == 'contract_input_status') { if (m.status != "accepted") console.log("Input status: " + m.status); } diff --git a/examples/hpclient/malicious-client.js b/examples/hpclient/malicious-client.js deleted file mode 100644 index 2c81e665..00000000 --- a/examples/hpclient/malicious-client.js +++ /dev/null @@ -1,116 +0,0 @@ -// -// HotPocket client example code adopted from: -// https://github.com/codetsunami/hotpocket/blob/master/hp_client.js -// - -const fs = require('fs') -const ws_api = require('ws'); -const sodium = require('libsodium-wrappers') -const readline = require('readline') - -// sodium has a trigger when it's ready, we will wait and execute from there -sodium.ready.then(main).catch((e) => { console.log(e) }) - - -function main() { - - if (process.argv.length != 6) { - console.log("Incorrect format"); - console.log("node client.js "); - process.exit(); - } - - var args = process.argv.slice(2); - var keys = sodium.crypto_sign_keypair() - - - // check for client keys - if (!fs.existsSync('.hp_client_keys')) { - keys.privateKey = sodium.to_hex(keys.privateKey) - keys.publicKey = sodium.to_hex(keys.publicKey) - fs.writeFileSync('.hp_client_keys', JSON.stringify(keys)) - } else { - keys = JSON.parse(fs.readFileSync('.hp_client_keys')) - keys.privateKey = Uint8Array.from(Buffer.from(keys.privateKey, 'hex')) - keys.publicKey = Uint8Array.from(Buffer.from(keys.publicKey, 'hex')) - } - - - var server = 'wss://localhost:8080' - - if (process.argv.length == 3) server = 'wss://localhost:' + args[0] - - if (process.argv.length == 4) server = 'wss://' + args[0] + ':' + args[1] - - var ws = new ws_api(server, { - rejectUnauthorized: false - }) - - /* anatomy of a public challenge - { - version: '0.1', - type: 'public_challenge', - challenge: '' - } - */ - - - // if the console ctrl + c's us we should close ws gracefully - process.once('SIGINT', function (code) { - console.log('SIGINT received...'); - ws.close() - }); - - ws.on('message', (m) => { - console.log("-----Received raw message-----") - console.log(m.toString()) - console.log("------------------------------") - - try { - m = JSON.parse(m) - } catch (e) { - return - } - - if (m.type != 'public_challenge') return - - console.log("Received challenge message") - console.log(m) - - let pkhex = 'ed' + Buffer.from(keys.publicKey).toString('hex'); - console.log('My public key is: ' + pkhex); - - // sign the challenge and send back the response - var sigbytes = sodium.crypto_sign_detached(m.challenge, keys.privateKey); - var response = { - type: 'challenge_resp', - challenge: m.challenge, - sig: Buffer.from(sigbytes).toString('hex'), - pubkey: pkhex - } - - console.log('Sending challenge response.'); - ws.send(JSON.stringify(response)); - - setInterval(() => { - var message = generateRandomMessage(args[2]); - console.log("Message :" + message); - ws.send(message); - }, args[3]); - - }); - - ws.on('close', () => { - console.log('Server disconnected.'); - }); -} - -function generateRandomMessage(length) { - var result = ''; - var characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; - var charactersLength = characters.length; - for (var i = 0; i < length; i++) { - result += characters.charAt(Math.floor(Math.random() * charactersLength)); - } - return result; -} diff --git a/examples/hpclient/text-client.js b/examples/hpclient/text-client.js index f070e349..c6c48877 100644 --- a/examples/hpclient/text-client.js +++ b/examples/hpclient/text-client.js @@ -58,14 +58,14 @@ function main() { let inp_container = { nonce: (new Date()).getTime().toString(), input: Buffer.from(inp).toString('hex'), - max_ledger_seqno: 9999999 + max_lcl_seqno: 9999999 } let inp_container_bytes = JSON.stringify(inp_container); let sig_bytes = sodium.crypto_sign_detached(inp_container_bytes, keys.privateKey); let signed_inp_container = { type: "contract_input", - content: inp_container_bytes.toString('hex'), + input_container: inp_container_bytes.toString('hex'), sig: Buffer.from(sig_bytes).toString('hex') } @@ -97,7 +97,7 @@ function main() { // sign the challenge and send back the response var sigbytes = sodium.crypto_sign_detached(m.challenge, keys.privateKey); var response = { - type: 'challenge_resp', + type: 'handshake_response', challenge: m.challenge, sig: Buffer.from(sigbytes).toString('hex'), pubkey: pkhex @@ -144,13 +144,13 @@ function main() { return } - if (m.type == 'public_challenge') { + if (m.type == 'handshake_challenge') { handle_public_challange(m); } else if (m.type == 'contract_output' || m.type == 'contract_read_response') { console.log(Buffer.from(m.content, 'hex').toString()); } - else if (m.type == 'request_status_result') { + else if (m.type == 'contract_input_status') { if (m.status != "accepted") console.log("Input status: " + m.status); } diff --git a/src/cons/cons.cpp b/src/cons/cons.cpp index 0bf20e3e..2d32f81e 100644 --- a/src/cons/cons.cpp +++ b/src/cons/cons.cpp @@ -380,11 +380,11 @@ namespace cons { std::string nonce; std::string input; - uint64_t maxledgerseqno; - jusrmsg::extract_input_container(nonce, input, maxledgerseqno, umsg.content); + uint64_t max_lcl_seqno; + jusrmsg::extract_input_container(input, nonce, max_lcl_seqno, umsg.content); // Ignore the input if our ledger has passed the input TTL. - if (maxledgerseqno > ctx.led_seq_no) + if (max_lcl_seqno > ctx.led_seq_no) { if (!appbill_balance_exceeded) { @@ -399,7 +399,7 @@ namespace cons { ctx.candidate_user_inputs.try_emplace( hash, - candidate_user_input(pubkey, std::move(input), maxledgerseqno)); + candidate_user_input(pubkey, std::move(input), max_lcl_seqno)); } else { @@ -435,11 +435,10 @@ namespace cons // Send the request status result if this user is connected to us. if (session != NULL) { - usr::send_request_status_result(*session, - reject_reason == NULL ? jusrmsg::STATUS_ACCEPTED : jusrmsg::STATUS_REJECTED, - reject_reason == NULL ? "" : reject_reason, - jusrmsg::MSGTYPE_CONTRACT_INPUT, - jusrmsg::origin_data_for_contract_input(umsg.sig)); + usr::send_input_status(*session, + reject_reason == NULL ? jusrmsg::STATUS_ACCEPTED : jusrmsg::STATUS_REJECTED, + reject_reason == NULL ? "" : reject_reason, + umsg.sig); } } } diff --git a/src/jsonschema/usrmsg_helpers.cpp b/src/jsonschema/usrmsg_helpers.cpp index 38a37a4b..068e5885 100644 --- a/src/jsonschema/usrmsg_helpers.cpp +++ b/src/jsonschema/usrmsg_helpers.cpp @@ -7,10 +7,6 @@ namespace jsonschema::usrmsg { - - // User JSON message schema version - constexpr const char *SCHEMA_VERSION = "0.1"; - // Separators constexpr const char *SEP_COMMA = "\",\""; constexpr const char *SEP_COLON = "\":\""; @@ -18,19 +14,19 @@ namespace jsonschema::usrmsg constexpr const char *SEP_COLON_NOQUOTE = "\":"; // Message field names - const char *const FLD_VERSION = "version"; constexpr const char *FLD_TYPE = "type"; constexpr const char *FLD_CHALLENGE = "challenge"; constexpr const char *FLD_SIG = "sig"; constexpr const char *FLD_PUBKEY = "pubkey"; constexpr const char *FLD_INPUT = "input"; - constexpr const char *FLD_MAX_LED_SEQ = "max_ledger_seqno"; + constexpr const char *FLD_INPUT_CONTAINER = "input_container"; + constexpr const char *FLD_INPUT_SIG = "input_sig"; + constexpr const char *FLD_MAX_LCL_SEQ = "max_lcl_seqno"; constexpr const char *FLD_CONTENT = "content"; constexpr const char *FLD_NONCE = "nonce"; constexpr const char *FLD_LCL = "lcl"; constexpr const char *FLD_LCL_SEQ = "lcl_seqno"; constexpr const char *FLD_STATUS = "status"; - constexpr const char *FLD_ORIGIN = "origin"; constexpr const char *FLD_REASON = "reason"; // Length of user random challenge bytes. @@ -44,8 +40,7 @@ namespace jsonschema::usrmsg * @param msg String reference to copy the generated json message string into. * Message format: * { - * "version": "", - * "type": "public_challenge", + * "type": "handshake_challenge", * "challenge": "" * } * @param challengehex String reference to copy the generated hex challenge string into. @@ -69,13 +64,9 @@ namespace jsonschema::usrmsg // so allocating 128bytes for heap padding. msg.reserve(128); msg.append("{\"") - .append(FLD_VERSION) - .append(SEP_COLON) - .append(SCHEMA_VERSION) - .append(SEP_COMMA) .append(FLD_TYPE) .append(SEP_COLON) - .append(MSGTYPE_CHALLENGE) + .append(MSGTYPE_HANDSHAKE_CHALLENGE) .append(SEP_COMMA) .append(FLD_CHALLENGE) .append(SEP_COLON) @@ -88,7 +79,7 @@ namespace jsonschema::usrmsg * @param msg String reference to copy the generated json message string into. * Message format: * { - * "type": "stat_resp", + * "type": "stat_response", * "lcl": "", * "lcl_seqno": * } @@ -99,7 +90,7 @@ namespace jsonschema::usrmsg msg.append("{\"") .append(FLD_TYPE) .append(SEP_COLON) - .append(MSGTYPE_STAT_RESP) + .append(MSGTYPE_STAT_RESPONSE) .append(SEP_COMMA) .append(FLD_LCL) .append(SEP_COLON) @@ -112,30 +103,29 @@ namespace jsonschema::usrmsg } /** - * Constructs a request result message. + * Constructs a contract input status message. * @param msg String reference to copy the generated json message string into. * Message format: * { - * "type": "request_status_result", + * "type": "contract_input_status", * "status": "", - * "reason": "", - * "origin": { - * "type": "", - * ... - * } + * "reason": "", + * "input_sig": "" * } * @param is_accepted Whether the original message was accepted or not. * @param reason Rejected reason. Empty if accepted. - * @param origin_type Original message type which generated this result. - * @param origin_extra_data Extra field data string to be injected into origin. + * @param input_sig Binary signature of the original input message which generated this result. */ - void create_request_status_result(std::string &msg, std::string_view status, std::string_view reason, std::string_view origin_type, std::string_view origin_extra_data) + void create_contract_input_status(std::string &msg, std::string_view status, std::string_view reason, std::string_view input_sig) { + std::string sighex; + util::bin2hex(sighex, reinterpret_cast(input_sig.data()), input_sig.length()); + msg.reserve(128); msg.append("{\"") .append(FLD_TYPE) .append(SEP_COLON) - .append(MSGTYPE_REQUEST_STATUS_RESULT) + .append(MSGTYPE_CONTRACT_INPUT_STATUS) .append(SEP_COMMA) .append(FLD_STATUS) .append(SEP_COLON) @@ -145,36 +135,12 @@ namespace jsonschema::usrmsg .append(SEP_COLON) .append(reason) .append(SEP_COMMA) - .append(FLD_ORIGIN) - .append("\":{\"") - .append(FLD_TYPE) - .append(SEP_COLON) - .append(origin_type) - .append("\"") - .append(origin_extra_data) - .append("}}"); - } - - /** - * Returns concatenated string for contract input origin data fields to be included in request result. - * @param sig Binary singature of the original contract input. - */ - std::string origin_data_for_contract_input(std::string_view sig) - { - std::string sighex; - util::bin2hex(sighex, reinterpret_cast(sig.data()), sig.length()); - - std::string extra_data; - extra_data.append(",\"") - .append(FLD_SIG) + .append(FLD_INPUT_SIG) .append(SEP_COLON) .append(sighex) - .append("\""); - - return extra_data; + .append("\"}"); } - /** * Constructs a contract read response message. * @param msg String reference to copy the generated json message string into. @@ -268,7 +234,7 @@ namespace jsonschema::usrmsg return -1; // Validate msg type. - if (d[FLD_TYPE] != MSGTYPE_CHALLENGE_RESP) + if (d[FLD_TYPE] != MSGTYPE_HANDSHAKE_RESPONSE) { LOG_DBG << "User challenge response type invalid. 'challenge_response' expected."; return -1; @@ -357,27 +323,27 @@ namespace jsonschema::usrmsg /** * Extracts a signed input container message sent by user. * - * @param extracted_content The content extracted from the message. + * @param extracted_input_container The input container extracted from the message. * @param extracted_sig The binary signature extracted from the message. * @param d The json document holding the input container. * Accepted signed input container format: * { * "type": "contract_input", - * "content": "", + * "input_container": "", * "sig": "" * } * @return 0 on successful extraction. -1 for failure. */ int extract_signed_input_container( - std::string &extracted_content, std::string &extracted_sig, const rapidjson::Document &d) + std::string &extracted_input_container, std::string &extracted_sig, const rapidjson::Document &d) { - if (!d.HasMember(FLD_CONTENT) || !d.HasMember(FLD_SIG)) + if (!d.HasMember(FLD_INPUT_CONTAINER) || !d.HasMember(FLD_SIG)) { LOG_DBG << "User signed input required fields missing."; return -1; } - if (!d[FLD_CONTENT].IsString() || !d[FLD_SIG].IsString()) + if (!d[FLD_INPUT_CONTAINER].IsString() || !d[FLD_SIG].IsString()) { LOG_DBG << "User signed input invalid field values."; return -1; @@ -386,32 +352,32 @@ namespace jsonschema::usrmsg // We do not verify the signature of the content here since we need to let each node // (including self) to verify that individually after we broadcast the NUP proposal. - const std::string content(d[FLD_CONTENT].GetString(), d[FLD_CONTENT].GetStringLength()); + const std::string input_container(d[FLD_INPUT_CONTAINER].GetString(), d[FLD_INPUT_CONTAINER].GetStringLength()); const std::string_view sighex(d[FLD_SIG].GetString(), d[FLD_SIG].GetStringLength()); std::string sig; sig.resize(crypto_sign_ed25519_BYTES); util::hex2bin(reinterpret_cast(sig.data()), sig.length(), sighex); - extracted_content = std::move(content); + extracted_input_container = std::move(input_container); extracted_sig = std::move(sig); return 0; } /** * Extract the individual components of a given input container json. - * @param nonce The extracted nonce. * @param input The extracted input. - * @param max_ledger_seqno Themaxledgerseqno extracted max ledger sequence no. + * @param nonce The extracted nonce. + * @param max_lcl_seqno The extracted max ledger sequence no. * @param contentjson The json string containing the input container message. * { - * "nonce": "", * "input": "", - * "max_ledger_seqno": + * "nonce": "", + * "max_lcl_seqno": * } * @return 0 on succesful extraction. -1 on failure. */ - int extract_input_container(std::string &nonce, std::string &input, uint64_t &max_ledger_seqno, std::string_view contentjson) + int extract_input_container(std::string &input, std::string &nonce, uint64_t &max_lcl_seqno, std::string_view contentjson) { rapidjson::Document d; d.Parse(contentjson.data()); @@ -421,13 +387,13 @@ namespace jsonschema::usrmsg return -1; } - if (!d.HasMember(FLD_NONCE) || !d.HasMember(FLD_INPUT) || !d.HasMember(FLD_MAX_LED_SEQ)) + if (!d.HasMember(FLD_NONCE) || !d.HasMember(FLD_INPUT) || !d.HasMember(FLD_MAX_LCL_SEQ)) { LOG_DBG << "User input container required fields missing."; return -1; } - if (!d[FLD_NONCE].IsString() || !d[FLD_INPUT].IsString() || !d[FLD_MAX_LED_SEQ].IsUint64()) + if (!d[FLD_NONCE].IsString() || !d[FLD_INPUT].IsString() || !d[FLD_MAX_LCL_SEQ].IsUint64()) { LOG_DBG << "User input container invalid field values."; return -1; @@ -448,7 +414,7 @@ namespace jsonschema::usrmsg } nonce = d[FLD_NONCE].GetString(); - max_ledger_seqno = d[FLD_MAX_LED_SEQ].GetUint64(); + max_lcl_seqno = d[FLD_MAX_LCL_SEQ].GetUint64(); return 0; } diff --git a/src/jsonschema/usrmsg_helpers.hpp b/src/jsonschema/usrmsg_helpers.hpp index 782cb946..4eda1b63 100644 --- a/src/jsonschema/usrmsg_helpers.hpp +++ b/src/jsonschema/usrmsg_helpers.hpp @@ -10,15 +10,15 @@ namespace jsonschema::usrmsg extern const char* const FLD_TYPE; // Message types -constexpr const char* MSGTYPE_CHALLENGE = "public_challenge"; -constexpr const char* MSGTYPE_CHALLENGE_RESP = "challenge_resp"; +constexpr const char* MSGTYPE_HANDSHAKE_CHALLENGE = "handshake_challenge"; +constexpr const char* MSGTYPE_HANDSHAKE_RESPONSE = "handshake_response"; constexpr const char* MSGTYPE_CONTRACT_READ_REQUEST = "contract_read_request"; constexpr const char* MSGTYPE_CONTRACT_READ_RESPONSE = "contract_read_response"; constexpr const char* MSGTYPE_CONTRACT_INPUT = "contract_input"; +constexpr const char* MSGTYPE_CONTRACT_INPUT_STATUS = "contract_input_status"; constexpr const char* MSGTYPE_CONTRACT_OUTPUT = "contract_output"; constexpr const char* MSGTYPE_STAT = "stat"; -constexpr const char* MSGTYPE_STAT_RESP = "stat_resp"; -constexpr const char* MSGTYPE_REQUEST_STATUS_RESULT = "request_status_result"; +constexpr const char* MSGTYPE_STAT_RESPONSE = "stat_response"; constexpr const char* MSGTYPE_UNKNOWN = "unknown"; constexpr const char *STATUS_ACCEPTED = "accepted"; @@ -34,9 +34,7 @@ void create_user_challenge(std::string &msg, std::string &challengehex); void create_status_response(std::string &msg); -void create_request_status_result(std::string &msg, std::string_view status, std::string_view reason, std::string_view origin_type, std::string_view origin_extra_data); - -std::string origin_data_for_contract_input(std::string_view sig); +void create_contract_input_status(std::string &msg, std::string_view status, std::string_view reason, std::string_view input_sig); void create_contract_read_response_container(std::string &msg, std::string_view content); @@ -46,9 +44,9 @@ int verify_user_challenge_response(std::string &extracted_pubkeyhex, std::string int extract_read_request(std::string &extracted_content, const rapidjson::Document &d); -int extract_signed_input_container(std::string &extracted_content, std::string &extracted_sig, const rapidjson::Document &d); +int extract_signed_input_container(std::string &extracted_input_container, std::string &extracted_sig, const rapidjson::Document &d); -int extract_input_container(std::string &nonce, std::string &input, uint64_t &max_ledger_seqno, std::string_view contentjson); +int extract_input_container(std::string &input, std::string &nonce, uint64_t &max_lcl_seqno, std::string_view contentjson); int parse_user_message(rapidjson::Document &d, std::string_view message); diff --git a/src/usr/usr.cpp b/src/usr/usr.cpp index 281631ce..d930555d 100644 --- a/src/usr/usr.cpp +++ b/src/usr/usr.cpp @@ -147,7 +147,7 @@ namespace usr } else { - send_request_status_result(user.session, jusrmsg::STATUS_REJECTED, jusrmsg::REASON_BAD_MSG_FORMAT, msg_type, ""); + send_input_status(user.session, jusrmsg::STATUS_REJECTED, jusrmsg::REASON_BAD_MSG_FORMAT, ""); return -1; } } @@ -155,21 +155,21 @@ namespace usr { // Message is a contract input message. - std::string contentjson; + std::string input_container_json; std::string sig; - if (jusrmsg::extract_signed_input_container(contentjson, sig, d) == 0) + if (jusrmsg::extract_signed_input_container(input_container_json, sig, d) == 0) { std::lock_guard lock(ctx.users_mutex); //Add to the submitted input list. user.submitted_inputs.push_back(user_submitted_message( - std::move(contentjson), + std::move(input_container_json), std::move(sig))); return 0; } else { - send_request_status_result(user.session, jusrmsg::STATUS_REJECTED, jusrmsg::REASON_BAD_SIG, msg_type, jusrmsg::origin_data_for_contract_input(sig)); + send_input_status(user.session, jusrmsg::STATUS_REJECTED, jusrmsg::REASON_BAD_SIG, sig); return -1; } } @@ -183,25 +183,25 @@ namespace usr else { LOG_DBG << "Invalid user message type: " << msg_type; - send_request_status_result(user.session, jusrmsg::STATUS_REJECTED, jusrmsg::REASON_INVALID_MSG_TYPE, msg_type, ""); + send_input_status(user.session, jusrmsg::STATUS_REJECTED, jusrmsg::REASON_INVALID_MSG_TYPE, ""); return -1; } } else { // Bad message. - send_request_status_result(user.session, jusrmsg::STATUS_REJECTED, jusrmsg::REASON_BAD_MSG_FORMAT, msg_type, ""); + send_input_status(user.session, jusrmsg::STATUS_REJECTED, jusrmsg::REASON_BAD_MSG_FORMAT, ""); return -1; } } /** - * Send the specified status result via the provided session. + * Send the specified contract input status result via the provided session. */ - void send_request_status_result(const comm::comm_session &session, std::string_view status, std::string_view reason, std::string_view origin_type, std::string_view origin_extra_data) + void send_input_status(const comm::comm_session &session, std::string_view status, std::string_view reason, std::string_view input_sig) { std::string msg; - jusrmsg::create_request_status_result(msg, status, reason, origin_type, origin_extra_data); + jusrmsg::create_contract_input_status(msg, status, reason, input_sig); session.send(msg); } diff --git a/src/usr/usr.hpp b/src/usr/usr.hpp index b7e0ec00..2cce892f 100644 --- a/src/usr/usr.hpp +++ b/src/usr/usr.hpp @@ -72,7 +72,7 @@ namespace usr int handle_user_message(connected_user &user, std::string_view message); - void send_request_status_result(const comm::comm_session &session, std::string_view status, std::string_view reason, std::string_view origin_type, std::string_view origin_extra_data); + void send_input_status(const comm::comm_session &session, std::string_view status, std::string_view reason, std::string_view input_sig); int add_user(const comm::comm_session &session, const std::string &pubkey);