diff --git a/README.md b/README.md index 480cde60..d796015d 100644 --- a/README.md +++ b/README.md @@ -10,8 +10,7 @@ A C++ version of hotpocket designed for production envrionments, original protot ## Libraries * Crypto - Libsodium https://github.com/jedisct1/libsodium * Websockets - Server: [Websocketd (forked)](https://github.com/codetsunami/websocketd) | Client: [Websocat](https://github.com/vi/websocat) | Pipe: [netcat (OpenBSD)](https://man.openbsd.org/nc.1) -* RapidJSON - http://rapidjson.org -* jsoncons (for BSON) - https://github.com/danielaparker/jsoncons +* jsoncons (for JSON and BSON) - https://github.com/danielaparker/jsoncons * P2P Protocol - https://google.github.io/flatbuffers * Fuse filesystem - https://github.com/libfuse/libfuse * Boost - https://www.boost.org @@ -49,11 +48,6 @@ Following Instructions are based on Boost [getting started](https://www.boost.or 3. Run `./bootstrap.sh` 4. Run `sudo ./b2 install` (This will compile and install boost libraries into your `/usr/local/lib`) -#### Install RapidJSON -1. Download and extract RapidJSON 1.1 source from [here](https://github.com/Tencent/rapidjson/archive/v1.1.0.tar.gz). -2. Navigate to the extracted directory. -3. Run `sudo cp -r include/rapidjson /usr/local/include/` - #### Install jsoncons 1. Download and extract jsoncons v0.153.3 source from [here](https://github.com/danielaparker/jsoncons/archive/v0.153.3.zip). 2. Navigate to the extracted directory. diff --git a/examples/nodejs_client/hp-client-lib.js b/examples/nodejs_client/hp-client-lib.js index 70c5c3da..2a4f8222 100644 --- a/examples/nodejs_client/hp-client-lib.js +++ b/examples/nodejs_client/hp-client-lib.js @@ -59,7 +59,8 @@ function HotPocketClient(server, protocol, keys) { // Use JSON if we are still in handshake phase. m = handshakeResolver ? JSON.parse(msg) : msgHelper.deserializeMessage(msg); } catch (e) { - console.log("Exception deserializing: " + received_msg); + console.log("Exception deserializing: "); + console.log(msg) return; } diff --git a/src/conf.cpp b/src/conf.cpp index c41da3ce..03c34324 100644 --- a/src/conf.cpp +++ b/src/conf.cpp @@ -9,613 +9,536 @@ namespace conf { -// Global contract context struct exposed to the application. -contract_ctx ctx; + // Global contract context struct exposed to the application. + contract_ctx ctx; -// Global configuration struct exposed to the application. -contract_config cfg; + // Global configuration struct exposed to the application. + contract_config cfg; -const static char *MODE_OBSERVER = "observer"; -const static char *MODE_PROPOSER = "proposer"; + const static char *MODE_OBSERVER = "observer"; + const static char *MODE_PROPOSER = "proposer"; -/** - * Loads and initializes the contract config for execution. Must be called once during application startup. - * @return 0 for success. -1 for failure. - */ -int init() -{ - // The validations/loading needs to be in this order. - // 1. Validate contract directories - // 2. Read and load the contract config into memory - // 3. Validate the loaded config values - - if (validate_contract_dir_paths() != 0 || load_config() != 0 || validate_config() != 0) - return -1; - - // Append self peer to peer list. - const std::string portstr = std::to_string(cfg.peerport); - - cfg.peers.emplace(std::make_pair(SELF_HOST, cfg.peerport)); - - // Append self pubkey to unl list. - cfg.unl.emplace(cfg.pubkey); - - return 0; -} - -/** - * Generates and saves new signing keys in the contract config. - */ -int rekey() -{ - // Load the contract config and re-save with the newly generated keys. - - if (load_config() != 0) - return -1; - - crypto::generate_signing_keys(cfg.pubkey, cfg.seckey); - binpair_to_hex(); - - if (save_config() != 0) - return -1; - - std::cout << "New signing keys generated at " << ctx.config_file << std::endl; - - return 0; -} - -/** - * Creates a new contract directory with the default contract config. - * By the time this gets called, the 'ctx' struct must be populated. - * This function makes use of the paths populated in the ctx. - */ -int create_contract() -{ - if (boost::filesystem::exists(ctx.contract_dir)) + /** + * Loads and initializes the contract config for execution. Must be called once during application startup. + * @return 0 for success. -1 for failure. + */ + int init() { - std::cout << "Contract dir already exists. Cannot create contract at the same location.\n"; - return -1; + // The validations/loading needs to be in this order. + // 1. Validate contract directories + // 2. Read and load the contract config into memory + // 3. Validate the loaded config values + + if (validate_contract_dir_paths() != 0 || load_config() != 0 || validate_config() != 0) + return -1; + + // Append self peer to peer list. + const std::string portstr = std::to_string(cfg.peerport); + + cfg.peers.emplace(std::make_pair(SELF_HOST, cfg.peerport)); + + // Append self pubkey to unl list. + cfg.unl.emplace(cfg.pubkey); + + return 0; } - boost::filesystem::create_directories(ctx.config_dir); - boost::filesystem::create_directories(ctx.hist_dir); - boost::filesystem::create_directories(ctx.state_rw_dir); - boost::filesystem::create_directories(ctx.state_read_req_dir); + /** + * Generates and saves new signing keys in the contract config. + */ + int rekey() + { + // Load the contract config and re-save with the newly generated keys. + if (load_config() != 0) + return -1; - //Create config file with default settings. + crypto::generate_signing_keys(cfg.pubkey, cfg.seckey); + binpair_to_hex(); - //We populate the in-memory struct with default settings and then save it to the file. + if (save_config() != 0) + return -1; - crypto::generate_signing_keys(cfg.pubkey, cfg.seckey); - binpair_to_hex(); + std::cout << "New signing keys generated at " << ctx.config_file << std::endl; - cfg.startup_mode = OPERATING_MODE::PROPOSER; - cfg.peerport = 22860; - cfg.roundtime = 1000; - cfg.pubport = 8080; + return 0; + } + + /** + * Creates a new contract directory with the default contract config. + * By the time this gets called, the 'ctx' struct must be populated. + * This function makes use of the paths populated in the ctx. + */ + int create_contract() + { + if (boost::filesystem::exists(ctx.contract_dir)) + { + std::cout << "Contract dir already exists. Cannot create contract at the same location.\n"; + return -1; + } + + boost::filesystem::create_directories(ctx.config_dir); + boost::filesystem::create_directories(ctx.hist_dir); + boost::filesystem::create_directories(ctx.state_rw_dir); + boost::filesystem::create_directories(ctx.state_read_req_dir); + + //Create config file with default settings. + + //We populate the in-memory struct with default settings and then save it to the file. + + crypto::generate_signing_keys(cfg.pubkey, cfg.seckey); + binpair_to_hex(); + + cfg.startup_mode = OPERATING_MODE::PROPOSER; + cfg.peerport = 22860; + cfg.roundtime = 1000; + cfg.pubport = 8080; #ifndef NDEBUG - cfg.loglevel = "debug"; + cfg.loglevel = "debug"; #else - cfg.loglevel = "warn"; + cfg.loglevel = "warn"; #endif - cfg.loggers.emplace("console"); + cfg.loggers.emplace("console"); - cfg.binary = ""; + cfg.binary = ""; - //Save the default settings into the config file. - if (save_config() != 0) - return -1; + //Save the default settings into the config file. + if (save_config() != 0) + return -1; - std::cout << "Contract directory created at " << ctx.contract_dir << std::endl; + std::cout << "Contract directory created at " << ctx.contract_dir << std::endl; - return 0; -} - -/** - * Updates the contract context with directory paths based on provided base directory. - * This is called after parsing HP command line arg in order to populate the ctx. - */ -void set_contract_dir_paths(std::string exepath, std::string basedir) -{ - if (exepath.empty()) - { - // this code branch will never execute the way main is currently coded, but it might change in future - std::cerr << "Executable path must be specified\n"; - exit(1); + return 0; } - if (basedir.empty()) + /** + * Updates the contract context with directory paths based on provided base directory. + * This is called after parsing HP command line arg in order to populate the ctx. + */ + void set_contract_dir_paths(std::string exepath, std::string basedir) { - // this code branch will never execute the way main is currently coded, but it might change in future - std::cerr << "a contract directory must be specified\n"; - exit(1); - } - - // resolving the path through realpath will remove any trailing slash if present - basedir = util::realpath(basedir); - - ctx.exe_dir = boost::filesystem::path(util::realpath(exepath)).parent_path().string(); - ctx.websocketd_exe_path = ctx.exe_dir + "/" + "websocketd"; - ctx.websocat_exe_path = ctx.exe_dir + "/" + "websocat"; - ctx.hpfs_exe_path = ctx.exe_dir + "/" + "hpfs"; - - ctx.contract_dir = basedir; - ctx.config_dir = basedir + "/cfg"; - ctx.config_file = ctx.config_dir + "/hp.cfg"; - ctx.tls_key_file = ctx.config_dir + "/tlskey.pem"; - ctx.tls_cert_file = ctx.config_dir + "/tlscert.pem"; - ctx.hist_dir = basedir + "/hist"; - ctx.state_dir = basedir + "/state"; - ctx.state_rw_dir = ctx.state_dir + "/rw"; - ctx.state_read_req_dir = ctx.state_dir + "/rr"; - ctx.log_dir = basedir + "/log"; -} - -/** - * Reads the config file on disk and populates the in-memory 'cfg' struct. - * - * @return 0 for successful loading of config. -1 for failure. - */ -int load_config() -{ - // Read the file into json document object. - - std::ifstream ifs(ctx.config_file); - rapidjson::IStreamWrapper isw(ifs); - - rapidjson::Document d; - if (d.ParseStream(isw).HasParseError()) - { - std::cout << "Invalid config file format. Parser error at position " << d.GetErrorOffset() << std::endl; - return -1; - } - else if (is_schema_valid(d) != 0) - { - std::cout << "Invalid config file format.\n"; - return -1; - } - ifs.close(); - - // Check whether the contract version is specified. - std::string_view cfgversion = util::getsv(d["version"]); - if (cfgversion.empty()) - { - std::cout << "Contract config version missing.\n"; - return -1; - } - - // Check whether this contract complies with the min version requirement. - int verresult = util::version_compare(std::string(cfgversion), std::string(util::MIN_CONTRACT_VERSION)); - if (verresult == -1) - { - std::cout << "Contract version too old. Minimum " - << util::MIN_CONTRACT_VERSION << " required. " - << cfgversion << " found.\n"; - return -1; - } - else if (verresult == -2) - { - std::cout << "Malformed version string.\n"; - return -1; - } - - // Load up the values into the struct. - - if (d["mode"] == MODE_OBSERVER) - cfg.startup_mode = OPERATING_MODE::OBSERVER; - else if (d["mode"] == MODE_PROPOSER) - cfg.startup_mode = OPERATING_MODE::PROPOSER; - else - { - std::cout << "Invalid mode. 'observer' or 'proposer' expected.\n"; - return -1; - } - cfg.current_mode = cfg.startup_mode; - - cfg.pubkeyhex = d["pubkeyhex"].GetString(); - cfg.seckeyhex = d["seckeyhex"].GetString(); - - cfg.binary = d["binary"].GetString(); - cfg.binargs = d["binargs"].GetString(); - cfg.appbill = d["appbill"].GetString(); - cfg.appbillargs = d["appbillargs"].GetString(); - - // Populate runtime contract execution args. - if (!cfg.binargs.empty()) - boost::split(cfg.runtime_binexec_args, cfg.binargs, boost::is_any_of(" ")); - cfg.runtime_binexec_args.insert(cfg.runtime_binexec_args.begin(), (cfg.binary[0] == '/' ? cfg.binary : util::realpath(ctx.contract_dir + "/bin/" + cfg.binary))); - - // Populate runtime app bill args. - if (!cfg.appbillargs.empty()) - boost::split(cfg.runtime_appbill_args, cfg.appbillargs, boost::is_any_of(" ")); - - cfg.runtime_appbill_args.insert(cfg.runtime_appbill_args.begin(), (cfg.appbill[0] == '/' ? cfg.appbill : util::realpath(ctx.contract_dir + "/bin/" + cfg.appbill))); - - // Uncomment for docker-based execution. - // std::string volumearg; - // volumearg.append("type=bind,source=").append(ctx.state_dir).append(",target=/state"); - // const char *dockerargs[] = {"/usr/bin/docker", "run", "--rm", "-i", "--mount", volumearg.data(), cfg.binary.data()}; - // cfg.runtime_binexec_args.insert(cfg.runtime_binexec_args.begin(), std::begin(dockerargs), std::end(dockerargs)); - - // Storing peers in unordered map keyed by the concatenated address:port and also saving address and port - // seperately to retrieve easily when handling peer connections. - std::vector splitted_peers; - cfg.peers.clear(); - for (auto &v : d["peers"].GetArray()) - { - const char *ipport_concat = v.GetString(); - // Split the address:port text into two - boost::split(splitted_peers, ipport_concat, boost::is_any_of(":")); - if (splitted_peers.size() == 2) + if (exepath.empty()) { - // Push the peer address and the port to peers set - cfg.peers.emplace(std::make_pair(splitted_peers.front(), std::stoi(splitted_peers.back()))); - splitted_peers.clear(); + // this code branch will never execute the way main is currently coded, but it might change in future + std::cerr << "Executable path must be specified\n"; + exit(1); } + + if (basedir.empty()) + { + // this code branch will never execute the way main is currently coded, but it might change in future + std::cerr << "a contract directory must be specified\n"; + exit(1); + } + + // resolving the path through realpath will remove any trailing slash if present + basedir = util::realpath(basedir); + + ctx.exe_dir = boost::filesystem::path(util::realpath(exepath)).parent_path().string(); + ctx.websocketd_exe_path = ctx.exe_dir + "/" + "websocketd"; + ctx.websocat_exe_path = ctx.exe_dir + "/" + "websocat"; + ctx.hpfs_exe_path = ctx.exe_dir + "/" + "hpfs"; + + ctx.contract_dir = basedir; + ctx.config_dir = basedir + "/cfg"; + ctx.config_file = ctx.config_dir + "/hp.cfg"; + ctx.tls_key_file = ctx.config_dir + "/tlskey.pem"; + ctx.tls_cert_file = ctx.config_dir + "/tlscert.pem"; + ctx.hist_dir = basedir + "/hist"; + ctx.state_dir = basedir + "/state"; + ctx.state_rw_dir = ctx.state_dir + "/rw"; + ctx.state_read_req_dir = ctx.state_dir + "/rr"; + ctx.log_dir = basedir + "/log"; } - cfg.unl.clear(); - for (auto &nodepk : d["unl"].GetArray()) + /** + * Reads the config file on disk and populates the in-memory 'cfg' struct. + * + * @return 0 for successful loading of config. -1 for failure. + */ + int load_config() { - // Convert the public key hex of each node to binary and store it. - std::string bin_pubkey; - bin_pubkey.resize(crypto::PFXD_PUBKEY_BYTES); - if (util::hex2bin( - reinterpret_cast(bin_pubkey.data()), - bin_pubkey.length(), - nodepk.GetString()) != 0) + // Read the file into json document object. + + std::ifstream ifs(ctx.config_file); + jsoncons::json d; + try { - std::cerr << "Error decoding unl list.\n"; + d = jsoncons::json::parse(ifs, jsoncons::strict_json_parsing()); + } + catch (const std::exception &e) + { + std::cout << "Invalid config file format. " << e.what() << '\n'; return -1; } - cfg.unl.emplace(bin_pubkey); + ifs.close(); + + // Check whether the contract version is specified. + std::string_view cfgversion = d["version"].as(); + if (cfgversion.empty()) + { + std::cout << "Contract config version missing.\n"; + return -1; + } + + // Check whether this contract complies with the min version requirement. + int verresult = util::version_compare(std::string(cfgversion), std::string(util::MIN_CONTRACT_VERSION)); + if (verresult == -1) + { + std::cout << "Contract version too old. Minimum " + << util::MIN_CONTRACT_VERSION << " required. " + << cfgversion << " found.\n"; + return -1; + } + else if (verresult == -2) + { + std::cout << "Malformed version string.\n"; + return -1; + } + + // Load up the values into the struct. + + if (d["mode"] == MODE_OBSERVER) + cfg.startup_mode = OPERATING_MODE::OBSERVER; + else if (d["mode"] == MODE_PROPOSER) + cfg.startup_mode = OPERATING_MODE::PROPOSER; + else + { + std::cout << "Invalid mode. 'observer' or 'proposer' expected.\n"; + return -1; + } + cfg.current_mode = cfg.startup_mode; + + cfg.pubkeyhex = d["pubkeyhex"].as(); + cfg.seckeyhex = d["seckeyhex"].as(); + + cfg.binary = d["binary"].as(); + cfg.binargs = d["binargs"].as(); + cfg.appbill = d["appbill"].as(); + cfg.appbillargs = d["appbillargs"].as(); + + // Populate runtime contract execution args. + if (!cfg.binargs.empty()) + boost::split(cfg.runtime_binexec_args, cfg.binargs, boost::is_any_of(" ")); + cfg.runtime_binexec_args.insert(cfg.runtime_binexec_args.begin(), (cfg.binary[0] == '/' ? cfg.binary : util::realpath(ctx.contract_dir + "/bin/" + cfg.binary))); + + // Populate runtime app bill args. + if (!cfg.appbillargs.empty()) + boost::split(cfg.runtime_appbill_args, cfg.appbillargs, boost::is_any_of(" ")); + + cfg.runtime_appbill_args.insert(cfg.runtime_appbill_args.begin(), (cfg.appbill[0] == '/' ? cfg.appbill : util::realpath(ctx.contract_dir + "/bin/" + cfg.appbill))); + + // Uncomment for docker-based execution. + // std::string volumearg; + // volumearg.append("type=bind,source=").append(ctx.state_dir).append(",target=/state"); + // const char *dockerargs[] = {"/usr/bin/docker", "run", "--rm", "-i", "--mount", volumearg.data(), cfg.binary.data()}; + // cfg.runtime_binexec_args.insert(cfg.runtime_binexec_args.begin(), std::begin(dockerargs), std::end(dockerargs)); + + // Storing peers in unordered map keyed by the concatenated address:port and also saving address and port + // seperately to retrieve easily when handling peer connections. + std::vector splitted_peers; + cfg.peers.clear(); + for (auto &v : d["peers"].array_range()) + { + const char *ipport_concat = v.as(); + // Split the address:port text into two + boost::split(splitted_peers, ipport_concat, boost::is_any_of(":")); + if (splitted_peers.size() == 2) + { + // Push the peer address and the port to peers set + cfg.peers.emplace(std::make_pair(splitted_peers.front(), std::stoi(splitted_peers.back()))); + splitted_peers.clear(); + } + } + + cfg.unl.clear(); + for (auto &nodepk : d["unl"].array_range()) + { + // Convert the public key hex of each node to binary and store it. + std::string bin_pubkey; + bin_pubkey.resize(crypto::PFXD_PUBKEY_BYTES); + if (util::hex2bin( + reinterpret_cast(bin_pubkey.data()), + bin_pubkey.length(), + nodepk.as()) != 0) + { + std::cerr << "Error decoding unl list.\n"; + return -1; + } + cfg.unl.emplace(bin_pubkey); + } + + cfg.peerport = d["peerport"].as(); + cfg.pubport = d["pubport"].as(); + cfg.roundtime = d["roundtime"].as(); + + cfg.pubmaxsize = d["pubmaxsize"].as(); + cfg.pubmaxcpm = d["pubmaxcpm"].as(); + cfg.pubmaxbadmpm = d["pubmaxbadmpm"].as(); + cfg.pubmaxcons = d["pubmaxcons"].as(); + + cfg.peermaxsize = d["peermaxsize"].as(); + cfg.peermaxcpm = d["peermaxcpm"].as(); + cfg.peermaxdupmpm = d["peermaxdupmpm"].as(); + cfg.peermaxbadmpm = d["peermaxbadmpm"].as(); + cfg.peermaxbadsigpm = d["peermaxbadsigpm"].as(); + cfg.peermaxcons = d["peermaxcons"].as(); + + cfg.loglevel = d["loglevel"].as(); + cfg.loggers.clear(); + for (auto &v : d["loggers"].array_range()) + cfg.loggers.emplace(v.as()); + + // Convert the hex keys to binary and keep for later use. + if (hexpair_to_bin() != 0) + return -1; + + return 0; + } + /** + * Saves the current values of the 'cfg' struct into the config file. + * + * @return 0 for successful save. -1 for failure. + */ + int save_config() + { + // Popualte json document with 'cfg' values. + // ojson is used instead of json to preserve insertion order + jsoncons::ojson d; + d.insert_or_assign("version", util::HP_VERSION); + d.insert_or_assign("mode", cfg.startup_mode == OPERATING_MODE::OBSERVER ? MODE_OBSERVER : MODE_PROPOSER); + + d.insert_or_assign("pubkeyhex", cfg.pubkeyhex.data()); + d.insert_or_assign("seckeyhex", cfg.seckeyhex.data()); + d.insert_or_assign("binary", cfg.binary.data()); + d.insert_or_assign("binargs", cfg.binargs.data()); + d.insert_or_assign("appbill", cfg.appbill.data()); + d.insert_or_assign("appbillargs", cfg.appbillargs.data()); + + jsoncons::ojson peers(jsoncons::json_array_arg); + for (const auto &ipport_pair : cfg.peers) + { + const std::string concat_str = std::string(ipport_pair.first).append(":").append(std::to_string(ipport_pair.second)); + peers.push_back(concat_str); + } + d.insert_or_assign("peers", peers); + + jsoncons::ojson unl(jsoncons::json_array_arg); + for (const auto &nodepk : cfg.unl) + { + std::string hex_pubkey; + util::bin2hex( + hex_pubkey, + reinterpret_cast(nodepk.data()), + nodepk.length()); + unl.push_back(hex_pubkey); + } + d.insert_or_assign("unl", unl); + + d.insert_or_assign("peerport", cfg.peerport); + d.insert_or_assign("pubport", cfg.pubport); + d.insert_or_assign("roundtime", cfg.roundtime); + + d.insert_or_assign("pubmaxsize", cfg.pubmaxsize); + d.insert_or_assign("pubmaxcpm", cfg.pubmaxcpm); + d.insert_or_assign("pubmaxbadmpm", cfg.pubmaxbadmpm); + d.insert_or_assign("pubmaxcons", cfg.pubmaxcons); + + d.insert_or_assign("peermaxsize", cfg.peermaxsize); + d.insert_or_assign("peermaxcpm", cfg.peermaxcpm); + d.insert_or_assign("peermaxdupmpm", cfg.peermaxdupmpm); + d.insert_or_assign("peermaxbadmpm", cfg.peermaxbadmpm); + d.insert_or_assign("peermaxbadsigpm", cfg.peermaxbadsigpm); + d.insert_or_assign("peermaxcons", cfg.peermaxcons); + + d.insert_or_assign("loglevel", cfg.loglevel.data()); + + jsoncons::ojson loggers(jsoncons::json_array_arg); + for (std::string_view logger : cfg.loggers) + { + loggers.push_back(logger.data()); + } + d.insert_or_assign("loggers", loggers); + + // Write the json doc to file. + + std::ofstream ofs(ctx.config_file); + try + { + ofs << jsoncons::pretty_print(d); + } + catch (const std::exception &e) + { + std::cout << "Writing to config file failed. " << ctx.config_file << std::endl; + return -1; + } + ofs.close(); + + return 0; } - cfg.peerport = d["peerport"].GetInt(); - cfg.pubport = d["pubport"].GetInt(); - cfg.roundtime = d["roundtime"].GetInt(); - - cfg.pubmaxsize = d["pubmaxsize"].GetUint64(); - cfg.pubmaxcpm = d["pubmaxcpm"].GetUint64(); - cfg.pubmaxbadmpm = d["pubmaxbadmpm"].GetUint64(); - cfg.pubmaxcons = d["pubmaxcons"].GetUint(); - - cfg.peermaxsize = d["peermaxsize"].GetUint64(); - cfg.peermaxcpm = d["peermaxcpm"].GetUint64(); - cfg.peermaxdupmpm = d["peermaxdupmpm"].GetUint64(); - cfg.peermaxbadmpm = d["peermaxbadmpm"].GetUint64(); - cfg.peermaxbadsigpm = d["peermaxbadsigpm"].GetUint64(); - cfg.peermaxcons = d["peermaxcons"].GetUint(); - - cfg.loglevel = d["loglevel"].GetString(); - cfg.loggers.clear(); - for (auto &v : d["loggers"].GetArray()) - cfg.loggers.emplace(v.GetString()); - - // Convert the hex keys to binary and keep for later use. - if (hexpair_to_bin() != 0) - return -1; - - return 0; -} -/** - * Saves the current values of the 'cfg' struct into the config file. - * - * @return 0 for successful save. -1 for failure. - */ -int save_config() -{ - // Popualte json document with 'cfg' values. - - rapidjson::Document d; - d.SetObject(); - rapidjson::Document::AllocatorType &allocator = d.GetAllocator(); - d.AddMember("version", rapidjson::StringRef(util::HP_VERSION), allocator); - d.AddMember("mode", rapidjson::StringRef(cfg.startup_mode == OPERATING_MODE::OBSERVER ? MODE_OBSERVER : MODE_PROPOSER), - allocator); - - d.AddMember("pubkeyhex", rapidjson::StringRef(cfg.pubkeyhex.data()), allocator); - d.AddMember("seckeyhex", rapidjson::StringRef(cfg.seckeyhex.data()), allocator); - d.AddMember("binary", rapidjson::StringRef(cfg.binary.data()), allocator); - d.AddMember("binargs", rapidjson::StringRef(cfg.binargs.data()), allocator); - d.AddMember("appbill", rapidjson::StringRef(cfg.appbill.data()), allocator); - d.AddMember("appbillargs", rapidjson::StringRef(cfg.appbillargs.data()), allocator); - - rapidjson::Value peers(rapidjson::kArrayType); - for (const auto &ipport_pair : cfg.peers) + /** + * Decode current binary keys in 'cfg' and populate the it with hex keys. + * + * @return Always returns 0. + */ + int binpair_to_hex() { - rapidjson::Value v; - const std::string concat_str = std::string(ipport_pair.first).append(":").append(std::to_string(ipport_pair.second)); - v.SetString(rapidjson::StringRef(concat_str.data()), allocator); - peers.PushBack(v, allocator); - } - d.AddMember("peers", peers, allocator); - - rapidjson::Value unl(rapidjson::kArrayType); - for (const auto &nodepk : cfg.unl) - { - rapidjson::Value v; - std::string hex_pubkey; util::bin2hex( - hex_pubkey, - reinterpret_cast(nodepk.data()), - nodepk.length()); + cfg.pubkeyhex, + reinterpret_cast(cfg.pubkey.data()), + cfg.pubkey.length()); - v.SetString(rapidjson::StringRef(hex_pubkey.data()), allocator); - unl.PushBack(v, allocator); - } - d.AddMember("unl", unl, allocator); + util::bin2hex( + cfg.seckeyhex, + reinterpret_cast(cfg.seckey.data()), + cfg.seckey.length()); - d.AddMember("peerport", cfg.peerport, allocator); - d.AddMember("pubport", cfg.pubport, allocator); - d.AddMember("roundtime", cfg.roundtime, allocator); - - d.AddMember("pubmaxsize", cfg.pubmaxsize, allocator); - d.AddMember("pubmaxcpm", cfg.pubmaxcpm, allocator); - d.AddMember("pubmaxbadmpm", cfg.pubmaxbadmpm, allocator); - d.AddMember("pubmaxcons", cfg.pubmaxcons, allocator); - - d.AddMember("peermaxsize", cfg.peermaxsize, allocator); - d.AddMember("peermaxcpm", cfg.peermaxcpm, allocator); - d.AddMember("peermaxdupmpm", cfg.peermaxdupmpm, allocator); - d.AddMember("peermaxbadmpm", cfg.peermaxbadmpm, allocator); - d.AddMember("peermaxbadsigpm", cfg.peermaxbadsigpm, allocator); - d.AddMember("peermaxcons", cfg.peermaxcons, allocator); - - d.AddMember("loglevel", rapidjson::StringRef(cfg.loglevel.data()), allocator); - rapidjson::Value loggers(rapidjson::kArrayType); - for (std::string_view logger : cfg.loggers) - { - rapidjson::Value v; - v.SetString(rapidjson::StringRef(logger.data()), allocator); - loggers.PushBack(v, allocator); - } - d.AddMember("loggers", loggers, allocator); - - // Write the json doc to file. - - std::ofstream ofs(ctx.config_file); - rapidjson::OStreamWrapper osw(ofs); - - rapidjson::PrettyWriter writer(osw); - if (!d.Accept(writer)) - { - std::cout << "Writing to config file failed. " << ctx.config_file << std::endl; - return -1; - } - ofs.close(); - - return 0; -} - -/** - * Decode current binary keys in 'cfg' and populate the it with hex keys. - * - * @return Always returns 0. - */ -int binpair_to_hex() -{ - util::bin2hex( - cfg.pubkeyhex, - reinterpret_cast(cfg.pubkey.data()), - cfg.pubkey.length()); - - util::bin2hex( - cfg.seckeyhex, - reinterpret_cast(cfg.seckey.data()), - cfg.seckey.length()); - - return 0; -} - -/** - * Decode current hex keys in 'cfg' and populate the it with binary keys. - * - * @return 0 for successful conversion. -1 for failure. - */ -int hexpair_to_bin() -{ - cfg.pubkey.resize(crypto::PFXD_PUBKEY_BYTES); - if (util::hex2bin( - reinterpret_cast(cfg.pubkey.data()), - cfg.pubkey.length(), - cfg.pubkeyhex) != 0) - { - std::cout << "Error decoding hex public key.\n"; - return -1; + return 0; } - cfg.seckey.resize(crypto::PFXD_SECKEY_BYTES); - if (util::hex2bin( - reinterpret_cast(cfg.seckey.data()), - cfg.seckey.length(), - cfg.seckeyhex) != 0) + /** + * Decode current hex keys in 'cfg' and populate the it with binary keys. + * + * @return 0 for successful conversion. -1 for failure. + */ + int hexpair_to_bin() { - std::cout << "Error decoding hex secret key.\n"; - return -1; - } - - return 0; -} - -/** - * Validates the 'cfg' struct for invalid values. - * - * @return 0 for successful validation. -1 for failure. - */ -int validate_config() -{ - // Check for non-empty signing keys. - // We also check for key pair validity as well in the below code. - if (cfg.pubkeyhex.empty() || cfg.seckeyhex.empty()) - { - std::cout << "Signing keys missing. Run with 'rekey' to generate new keys.\n"; - return -1; - } - - // Other required fields. - - bool fields_missing = false; - - fields_missing |= cfg.binary.empty() && std::cout << "Missing cfg field: binary\n"; - fields_missing |= cfg.peerport == 0 && std::cout << "Missing cfg field: peerport\n"; - fields_missing |= cfg.roundtime == 0 && std::cout << "Missing cfg field: roundtime\n"; - fields_missing |= cfg.pubport == 0 && std::cout << "Missing cfg field: pubport\n"; - fields_missing |= cfg.loglevel.empty() && std::cout << "Missing cfg field: loglevel\n"; - fields_missing |= cfg.loggers.empty() && std::cout << "Missing cfg field: loggers\n"; - - if (fields_missing) - { - std::cout << "Required configuration fields missing at " << ctx.config_file << std::endl; - return -1; - } - - // Log settings - const std::unordered_set valid_loglevels({"debug", "info", "warn", "error"}); - if (valid_loglevels.count(cfg.loglevel) != 1) - { - std::cout << "Invalid loglevel configured. Valid values: debug|info|warn|error\n"; - return -1; - } - - const std::unordered_set valid_loggers({"console", "file"}); - for (const std::string &logger : cfg.loggers) - { - if (valid_loggers.count(logger) != 1) + cfg.pubkey.resize(crypto::PFXD_PUBKEY_BYTES); + if (util::hex2bin( + reinterpret_cast(cfg.pubkey.data()), + cfg.pubkey.length(), + cfg.pubkeyhex) != 0) { - std::cout << "Invalid logger. Valid values: console|file\n"; + std::cout << "Error decoding hex public key.\n"; return -1; } - } - //Sign and verify a sample message to ensure we have a matching signing key pair. - const std::string msg = "hotpocket"; - const std::string sighex = crypto::sign_hex(msg, cfg.seckeyhex); - if (crypto::verify_hex(msg, sighex, cfg.pubkeyhex) != 0) - { - std::cout << "Invalid signing keys. Run with 'rekey' to generate new keys.\n"; - return -1; - } - - return 0; -} - -/** - * Checks for the existence of all contract sub directories. - * - * @return 0 for successful validation. -1 for failure. - */ -int validate_contract_dir_paths() -{ - const std::string paths[6] = { - ctx.contract_dir, - ctx.config_file, - ctx.hist_dir, - ctx.state_dir, - ctx.tls_key_file, - ctx.tls_cert_file}; - - for (const std::string &path : paths) - { - if (!boost::filesystem::exists(path)) + cfg.seckey.resize(crypto::PFXD_SECKEY_BYTES); + if (util::hex2bin( + reinterpret_cast(cfg.seckey.data()), + cfg.seckey.length(), + cfg.seckeyhex) != 0) { - if (path == ctx.tls_key_file || path == ctx.tls_cert_file) - { - std::cout << path << " does not exist. Please provide self-signed certificates. Can generate using command\n" - << "openssl req -newkey rsa:2048 -new -nodes -x509 -days 3650 -keyout tlskey.pem -out tlscert.pem\n" - << "and add it to " + ctx.config_dir << std::endl; - } - else - { - std::cout << path << " does not exist.\n"; - } - + std::cout << "Error decoding hex secret key.\n"; return -1; } + + return 0; } - return 0; -} + /** + * Validates the 'cfg' struct for invalid values. + * + * @return 0 for successful validation. -1 for failure. + */ + int validate_config() + { + // Check for non-empty signing keys. + // We also check for key pair validity as well in the below code. + if (cfg.pubkeyhex.empty() || cfg.seckeyhex.empty()) + { + std::cout << "Signing keys missing. Run with 'rekey' to generate new keys.\n"; + return -1; + } -/** - * Validates the config json document schema. - * - * @return 0 for successful validation. -1 for failure. - */ -int is_schema_valid(const rapidjson::Document &d) -{ - const char *cfg_schema = - "{" - "\"type\": \"object\"," - "\"required\": [ \"mode\", \"version\", \"pubkeyhex\", \"seckeyhex\", \"binary\", \"binargs\", \"appbill\", \"appbillargs\"" - ", \"peers\", \"unl\", \"pubport\", \"peerport\", \"roundtime\"" - ", \"pubmaxsize\", \"pubmaxcpm\", \"pubmaxbadmpm\", \"pubmaxcons\"" - ", \"peermaxsize\", \"peermaxcpm\", \"peermaxdupmpm\", \"peermaxbadmpm\", \"peermaxbadsigpm\", \"peermaxcons\"" - ", \"loglevel\", \"loggers\" ]," - "\"properties\": {" - "\"mode\": { \"type\": \"string\" }," - "\"version\": { \"type\": \"string\" }," - "\"pubkeyhex\": { \"type\": \"string\" }," - "\"seckeyhex\": { \"type\": \"string\" }," - "\"binary\": { \"type\": \"string\" }," - "\"binargs\": { \"type\": \"string\" }," - "\"appbill\": { \"type\": \"string\" }," - "\"appbillargs\": { \"type\": \"string\" }," - "\"peers\": {" - "\"type\": \"array\"," - "\"items\": { \"type\": \"string\" }" - "}," - "\"unl\": {" - "\"type\": \"array\"," - "\"items\": { \"type\": \"string\" }" - "}," - "\"peerport\": { \"type\": \"integer\" }," - "\"roundtime\": { \"type\": \"integer\" }," - "\"pubport\": { \"type\": \"integer\" }," + // Other required fields. - "\"pubmaxsize\": { \"type\": \"integer\" }," - "\"pubmaxcpm\": { \"type\": \"integer\" }," - "\"pubmaxbadmpm\": { \"type\": \"integer\" }," + bool fields_missing = false; - "\"peermaxsize\": { \"type\": \"integer\" }," - "\"peermaxcpm\": { \"type\": \"integer\" }," - "\"peermaxdupmpm\": { \"type\": \"integer\" }," - "\"peermaxbadmpm\": { \"type\": \"integer\" }," - "\"peermaxbadsigpm\": { \"type\": \"integer\" }," + fields_missing |= cfg.binary.empty() && std::cout << "Missing cfg field: binary\n"; + fields_missing |= cfg.peerport == 0 && std::cout << "Missing cfg field: peerport\n"; + fields_missing |= cfg.roundtime == 0 && std::cout << "Missing cfg field: roundtime\n"; + fields_missing |= cfg.pubport == 0 && std::cout << "Missing cfg field: pubport\n"; + fields_missing |= cfg.loglevel.empty() && std::cout << "Missing cfg field: loglevel\n"; + fields_missing |= cfg.loggers.empty() && std::cout << "Missing cfg field: loggers\n"; - "\"loglevel\": { \"type\": \"string\" }," - "\"loggers\": {" - "\"type\": \"array\"," - "\"items\": { \"type\": \"string\" }" - "}" - "}" - "}"; + if (fields_missing) + { + std::cout << "Required configuration fields missing at " << ctx.config_file << std::endl; + return -1; + } - rapidjson::Document sd; - sd.Parse(cfg_schema); - rapidjson::SchemaDocument schema(sd); + // Log settings + const std::unordered_set valid_loglevels({"debug", "info", "warn", "error"}); + if (valid_loglevels.count(cfg.loglevel) != 1) + { + std::cout << "Invalid loglevel configured. Valid values: debug|info|warn|error\n"; + return -1; + } - rapidjson::SchemaValidator validator(schema); - if (!d.Accept(validator)) - return -1; + const std::unordered_set valid_loggers({"console", "file"}); + for (const std::string &logger : cfg.loggers) + { + if (valid_loggers.count(logger) != 1) + { + std::cout << "Invalid logger. Valid values: console|file\n"; + return -1; + } + } - return 0; -} + //Sign and verify a sample message to ensure we have a matching signing key pair. + const std::string msg = "hotpocket"; + const std::string sighex = crypto::sign_hex(msg, cfg.seckeyhex); + if (crypto::verify_hex(msg, sighex, cfg.pubkeyhex) != 0) + { + std::cout << "Invalid signing keys. Run with 'rekey' to generate new keys.\n"; + return -1; + } -void change_operating_mode(const OPERATING_MODE mode) -{ - // Do not allow to change the mode if the node was started as an observer. - if (cfg.startup_mode == OPERATING_MODE::OBSERVER || cfg.current_mode == mode) - return; + return 0; + } - cfg.current_mode = mode; + /** + * Checks for the existence of all contract sub directories. + * + * @return 0 for successful validation. -1 for failure. + */ + int validate_contract_dir_paths() + { + const std::string paths[6] = { + ctx.contract_dir, + ctx.config_file, + ctx.hist_dir, + ctx.state_dir, + ctx.tls_key_file, + ctx.tls_cert_file}; - if (mode == OPERATING_MODE::OBSERVER) - LOG_INFO << "Switched to OBSERVER mode."; - else - LOG_INFO << "Switched back to PROPOSER mode."; -} + for (const std::string &path : paths) + { + if (!boost::filesystem::exists(path)) + { + if (path == ctx.tls_key_file || path == ctx.tls_cert_file) + { + std::cout << path << " does not exist. Please provide self-signed certificates. Can generate using command\n" + << "openssl req -newkey rsa:2048 -new -nodes -x509 -days 3650 -keyout tlskey.pem -out tlscert.pem\n" + << "and add it to " + ctx.config_dir << std::endl; + } + else + { + std::cout << path << " does not exist.\n"; + } + + return -1; + } + } + + return 0; + } + + void change_operating_mode(const OPERATING_MODE mode) + { + // Do not allow to change the mode if the node was started as an observer. + if (cfg.startup_mode == OPERATING_MODE::OBSERVER || cfg.current_mode == mode) + return; + + cfg.current_mode = mode; + + if (mode == OPERATING_MODE::OBSERVER) + LOG_INFO << "Switched to OBSERVER mode."; + else + LOG_INFO << "Switched back to PROPOSER mode."; + } } // namespace conf diff --git a/src/conf.hpp b/src/conf.hpp index 43e26128..ca9dada5 100644 --- a/src/conf.hpp +++ b/src/conf.hpp @@ -111,8 +111,6 @@ namespace conf int validate_contract_dir_paths(); - int is_schema_valid(const rapidjson::Document &d); - int binpair_to_hex(); int hexpair_to_bin(); diff --git a/src/msg/json/usrmsg_json.cpp b/src/msg/json/usrmsg_json.cpp index f983b9a2..1c4e48a2 100644 --- a/src/msg/json/usrmsg_json.cpp +++ b/src/msg/json/usrmsg_json.cpp @@ -46,7 +46,7 @@ namespace msg::usrmsg::json util::bin2hex(challengehex, challenge_bytes, msg::usrmsg::CHALLENGE_LEN); // Construct the challenge msg json. - // We do not use RapidJson here in favour of performance because this is a simple json message. + // We do not use jasoncons library here in favour of performance because this is a simple json message. // Since we know the rough size of the challenge message we reserve adequate amount for the holder. // Only Hot Pocket version number is variable length. Therefore message size is roughly 90 bytes @@ -221,7 +221,7 @@ namespace msg::usrmsg::json int verify_user_handshake_response(std::string &extracted_pubkeyhex, std::string &extracted_protocol, std::string_view response, std::string_view original_challenge) { - rapidjson::Document d; + jsoncons::json d; if (parse_user_message(d, response) != 0) return -1; @@ -233,35 +233,35 @@ namespace msg::usrmsg::json } // Compare the response handshake string with the original issued challenge. - if (!d.HasMember(msg::usrmsg::FLD_CHALLENGE) || d[msg::usrmsg::FLD_CHALLENGE] != original_challenge.data()) + if (!d.contains(msg::usrmsg::FLD_CHALLENGE) || d[msg::usrmsg::FLD_CHALLENGE] != original_challenge.data()) { LOG_DBG << "User handshake response 'challenge' invalid."; return -1; } // Check for the 'sig' field existence. - if (!d.HasMember(msg::usrmsg::FLD_SIG) || !d[msg::usrmsg::FLD_SIG].IsString()) + if (!d.contains(msg::usrmsg::FLD_SIG) || !d[msg::usrmsg::FLD_SIG].is()) { LOG_DBG << "User handshake response 'challenge signature' invalid."; return -1; } // Check for the 'pubkey' field existence. - if (!d.HasMember(msg::usrmsg::FLD_PUBKEY) || !d[msg::usrmsg::FLD_PUBKEY].IsString()) + if (!d.contains(msg::usrmsg::FLD_PUBKEY) || !d[msg::usrmsg::FLD_PUBKEY].is()) { LOG_DBG << "User handshake response 'public key' invalid."; return -1; } // Check for protocol field existence and valid value. - if (!d.HasMember(msg::usrmsg::FLD_PROTOCOL) || !d[msg::usrmsg::FLD_PROTOCOL].IsString()) + if (!d.contains(msg::usrmsg::FLD_PROTOCOL) || !d[msg::usrmsg::FLD_PROTOCOL].is()) { LOG_DBG << "User handshake response 'protocol' invalid."; return -1; } - std::string_view protocolsv = util::getsv(d[msg::usrmsg::FLD_PROTOCOL]); + std::string_view protocolsv = d[msg::usrmsg::FLD_PROTOCOL].as(); if (protocolsv != "json" && protocolsv != "bson") { LOG_DBG << "User handshake response 'protocol' type invalid."; @@ -269,10 +269,10 @@ namespace msg::usrmsg::json } // Verify the challenge signature. We do this last due to signature verification cost. - std::string_view pubkeysv = util::getsv(d[msg::usrmsg::FLD_PUBKEY]); + std::string_view pubkeysv = d[msg::usrmsg::FLD_PUBKEY].as(); if (crypto::verify_hex( original_challenge, - util::getsv(d[msg::usrmsg::FLD_SIG]), + d[msg::usrmsg::FLD_SIG].as(), pubkeysv) != 0) { LOG_DBG << "User challenge response signature verification failed."; @@ -287,7 +287,7 @@ namespace msg::usrmsg::json /** * Parses a json message sent by a user. - * @param d RapidJson document to which the parsed json should be loaded. + * @param d Jsoncons document to which the parsed json should be loaded. * @param message The message to parse. * Accepted message format: * { @@ -296,20 +296,20 @@ namespace msg::usrmsg::json * } * @return 0 on successful parsing. -1 for failure. */ - int parse_user_message(rapidjson::Document &d, std::string_view message) + int parse_user_message(jsoncons::json &d, std::string_view message) { - // We load response raw bytes into json document. - // Because we project the response message directly from the binary socket buffer in a zero-copy manner, the response - // string is not null terminated. 'kParseStopWhenDoneFlag' avoids rapidjson error in this case. - d.Parse(message.data()); - if (d.HasParseError()) + try + { + d = jsoncons::json::parse(message, jsoncons::strict_json_parsing()); + } + catch(const std::exception& e) { LOG_DBG << "User json message parsing failed."; return -1; } // Check existence of msg type field. - if (!d.HasMember(msg::usrmsg::FLD_TYPE) || !d[msg::usrmsg::FLD_TYPE].IsString()) + if (!d.contains(msg::usrmsg::FLD_TYPE) || !d[msg::usrmsg::FLD_TYPE].is()) { LOG_DBG << "User json message 'type' missing or invalid."; return -1; @@ -321,9 +321,9 @@ namespace msg::usrmsg::json /** * Extracts the message 'type' value from the json document. */ - int extract_type(std::string &extracted_type, const rapidjson::Document &d) + int extract_type(std::string &extracted_type, const jsoncons::json &d) { - extracted_type = d[msg::usrmsg::FLD_TYPE].GetString(); + extracted_type = d[msg::usrmsg::FLD_TYPE].as(); return 0; } @@ -339,21 +339,21 @@ namespace msg::usrmsg::json * } * @return 0 on successful extraction. -1 for failure. */ - int extract_read_request(std::string &extracted_content, const rapidjson::Document &d) + int extract_read_request(std::string &extracted_content, const jsoncons::json &d) { - if (!d.HasMember(msg::usrmsg::FLD_CONTENT)) + if (!d.contains(msg::usrmsg::FLD_CONTENT)) { LOG_DBG << "Read request required fields missing."; return -1; } - if (!d[msg::usrmsg::FLD_CONTENT].IsString()) + if (!d[msg::usrmsg::FLD_CONTENT].is()) { LOG_DBG << "Read request invalid field values."; return -1; } - std::string_view contenthex(d[msg::usrmsg::FLD_CONTENT].GetString(), d[msg::usrmsg::FLD_CONTENT].GetStringLength()); + std::string_view contenthex = d[msg::usrmsg::FLD_CONTENT].as(); std::string content; content.resize(contenthex.length() / 2); @@ -385,15 +385,15 @@ namespace msg::usrmsg::json * @return 0 on successful extraction. -1 for failure. */ int extract_signed_input_container( - std::string &extracted_input_container, std::string &extracted_sig, const rapidjson::Document &d) + std::string &extracted_input_container, std::string &extracted_sig, const jsoncons::json &d) { - if (!d.HasMember(msg::usrmsg::FLD_INPUT_CONTAINER) || !d.HasMember(msg::usrmsg::FLD_SIG)) + if (!d.contains(msg::usrmsg::FLD_INPUT_CONTAINER) || !d.contains(msg::usrmsg::FLD_SIG)) { LOG_DBG << "User signed input required fields missing."; return -1; } - if (!d[msg::usrmsg::FLD_INPUT_CONTAINER].IsString() || !d[msg::usrmsg::FLD_SIG].IsString()) + if (!d[msg::usrmsg::FLD_INPUT_CONTAINER].is() || !d[msg::usrmsg::FLD_SIG].is()) { LOG_DBG << "User signed input invalid field values."; return -1; @@ -402,12 +402,12 @@ namespace msg::usrmsg::json // 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_view input_container_hex(d[msg::usrmsg::FLD_INPUT_CONTAINER].GetString(), d[msg::usrmsg::FLD_INPUT_CONTAINER].GetStringLength()); + const std::string_view input_container_hex = d[msg::usrmsg::FLD_INPUT_CONTAINER].as(); std::string input_container; input_container.resize(input_container_hex.size() / 2); util::hex2bin(reinterpret_cast(input_container.data()), input_container.length(), input_container_hex); - const std::string_view sig_hex(d[msg::usrmsg::FLD_SIG].GetString(), d[msg::usrmsg::FLD_SIG].GetStringLength()); + const std::string_view sig_hex = d[msg::usrmsg::FLD_SIG].as(); std::string sig; sig.resize(crypto_sign_ed25519_BYTES); util::hex2bin(reinterpret_cast(sig.data()), sig.length(), sig_hex); @@ -432,28 +432,30 @@ namespace msg::usrmsg::json */ 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()); - if (d.HasParseError()) + jsoncons::json d; + try + { + d = jsoncons::json::parse(contentjson, jsoncons::strict_json_parsing()); + } + catch(const std::exception& e) { LOG_DBG << "User input container json parsing failed."; return -1; } - if (!d.HasMember(msg::usrmsg::FLD_INPUT) || !d.HasMember(msg::usrmsg::FLD_NONCE) || !d.HasMember(msg::usrmsg::FLD_MAX_LCL_SEQ)) + if (!d.contains(msg::usrmsg::FLD_INPUT) || !d.contains(msg::usrmsg::FLD_NONCE) || !d.contains(msg::usrmsg::FLD_MAX_LCL_SEQ)) { LOG_DBG << "User input container required fields missing."; return -1; } - if (!d[msg::usrmsg::FLD_INPUT].IsString() || !d[msg::usrmsg::FLD_NONCE].IsString() || !d[msg::usrmsg::FLD_MAX_LCL_SEQ].IsUint64()) + if (!d[msg::usrmsg::FLD_INPUT].is() || !d[msg::usrmsg::FLD_NONCE].is() || !d[msg::usrmsg::FLD_MAX_LCL_SEQ].is()) { LOG_DBG << "User input container invalid field values."; return -1; } - const rapidjson::Value &inputval = d[msg::usrmsg::FLD_INPUT]; - std::string_view inputhex(inputval.GetString(), inputval.GetStringLength()); + std::string_view inputhex = d[msg::usrmsg::FLD_INPUT].as(); // Convert hex input to binary. input.resize(inputhex.length() / 2); @@ -466,8 +468,8 @@ namespace msg::usrmsg::json return -1; } - nonce = d[msg::usrmsg::FLD_NONCE].GetString(); - max_lcl_seqno = d[msg::usrmsg::FLD_MAX_LCL_SEQ].GetUint64(); + nonce = d[msg::usrmsg::FLD_NONCE].as(); + max_lcl_seqno = d[msg::usrmsg::FLD_MAX_LCL_SEQ].as(); return 0; } diff --git a/src/msg/json/usrmsg_json.hpp b/src/msg/json/usrmsg_json.hpp index b7b2d656..02ef312a 100644 --- a/src/msg/json/usrmsg_json.hpp +++ b/src/msg/json/usrmsg_json.hpp @@ -20,14 +20,14 @@ namespace msg::usrmsg::json int verify_user_handshake_response(std::string &extracted_pubkeyhex, std::string &extracted_protocol, std::string_view response, std::string_view original_challenge); - int parse_user_message(rapidjson::Document &d, std::string_view message); + int parse_user_message(jsoncons::json &d, std::string_view message); - int extract_type(std::string &extracted_type, const rapidjson::Document &d); + int extract_type(std::string &extracted_type, const jsoncons::json &d); - int extract_read_request(std::string &extracted_content, const rapidjson::Document &d); + int extract_read_request(std::string &extracted_content, const jsoncons::json &d); int extract_signed_input_container(std::string &extracted_input_container, std::string &extracted_sig, - const rapidjson::Document &d); + const jsoncons::json &d); int extract_input_container(std::string &input, std::string &nonce, uint64_t &max_lcl_seqno, std::string_view contentjson); diff --git a/src/msg/usrmsg_parser.hpp b/src/msg/usrmsg_parser.hpp index 901a1d4a..4a67c453 100644 --- a/src/msg/usrmsg_parser.hpp +++ b/src/msg/usrmsg_parser.hpp @@ -12,7 +12,7 @@ namespace msg::usrmsg class usrmsg_parser { const util::PROTOCOL protocol; - rapidjson::Document jsonDoc; + jsoncons::json jsonDoc; jsoncons::ojson bsonDoc; public: diff --git a/src/pchheader.hpp b/src/pchheader.hpp index 9c652085..3df578e8 100644 --- a/src/pchheader.hpp +++ b/src/pchheader.hpp @@ -39,11 +39,6 @@ #include #include #include -#include -#include -#include -#include -#include #include #include #include diff --git a/src/util.cpp b/src/util.cpp index 895927f5..67091e0f 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -187,16 +187,6 @@ namespace util return 0; } - /** - * Returns a std::string_view pointing to the rapidjson Value which is assumed - * to be a string. We use this function because rapidjson does not have built-in string_view - * support. Passing a non-string 'v' is not supported. - */ - std::string_view getsv(const rapidjson::Value &v) - { - return std::string_view(v.GetString(), v.GetStringLength()); - } - // Provide a safe std::string overload for realpath std::string realpath(std::string path) { diff --git a/src/util.hpp b/src/util.hpp index 27978a86..65cbf5f4 100644 --- a/src/util.hpp +++ b/src/util.hpp @@ -86,8 +86,6 @@ namespace util int version_compare(const std::string &x, const std::string &y); - std::string_view getsv(const rapidjson::Value &v); - std::string realpath(std::string path); void mask_signal();