166 auto get_constitution = [&](
auto& ctx,
ApiVersion api_version) {
173 auto constitution_handle =
174 ctx.tx.template ro<ccf::Constitution>(ccf::Tables::CONSTITUTION);
175 auto constitution = constitution_handle->get();
177 if (!constitution.has_value())
179 detail::set_gov_error(
181 HTTP_STATUS_NOT_FOUND,
182 ccf::errors::ResourceNotFound,
183 "Constitution not found");
188 ctx.rpc_ctx->set_response_status(HTTP_STATUS_OK);
189 ctx.rpc_ctx->set_response_body(std::move(constitution.value()));
190 ctx.rpc_ctx->set_response_header(
191 ccf::http::headers::CONTENT_TYPE,
192 http::headervalues::contenttype::JAVASCRIPT);
199 "/service/constitution",
206 auto get_service_info = [&](
auto& ctx,
ApiVersion api_version) {
213 auto response_body = nlohmann::json::object();
215 auto service_info_handle =
216 ctx.tx.template ro<ccf::Service>(ccf::Tables::SERVICE);
217 auto service_info = service_info_handle->get();
219 if (!service_info.has_value())
221 detail::set_gov_error(
223 HTTP_STATUS_NOT_FOUND,
224 ccf::errors::ResourceNotFound,
225 "Service info not yet available");
229 response_body[
"status"] = service_info->status;
230 response_body[
"certificate"] = service_info->cert.str();
231 response_body[
"recoveryCount"] =
232 service_info->recovery_count.value_or(0);
234 if (service_info->current_service_create_txid.has_value())
236 response_body[
"creationTransactionId"] =
237 service_info->current_service_create_txid.value();
241 GOV_INFO_FMT(
"No recorded current_service_create_txid");
244 if (service_info->previous_service_identity_version.has_value())
247 service_info->previous_service_identity_version.value();
252 response_body[
"previousServiceCreationTransactionId"] =
256 response_body[
"serviceData"] = service_info->service_data;
259 auto config_handle = ctx.tx.template ro<ccf::Configuration>(
260 ccf::Tables::CONFIGURATION);
262 auto config = config_handle->get();
263 if (config.has_value())
265 auto configuration = nlohmann::json::object();
266 configuration[
"recoveryThreshold"] = config->recovery_threshold;
267 configuration[
"maximumNodeCertificateValidityDays"] =
268 config->maximum_node_certificate_validity_days.value_or(
269 ccf::default_node_cert_validity_period_days);
270 configuration[
"maximumServiceCertificateValidityDays"] =
271 config->maximum_service_certificate_validity_days.value_or(
272 ccf::default_service_cert_validity_period_days);
273 configuration[
"recentCoseProposalsWindowSize"] =
274 config->recent_cose_proposals_window_size.value_or(
275 ccf::default_recent_cose_proposals_window_size);
276 response_body[
"configuration"] = configuration;
284 ctx.rpc_ctx->set_response_json(response_body, HTTP_STATUS_OK);
298 auto get_javascript_app = [&](
auto& ctx,
ApiVersion api_version) {
305 auto response_body = nlohmann::json::object();
309 auto endpoints = nlohmann::json::object();
311 bool original_case =
false;
313 const auto parsed_query =
314 ccf::http::parse_query(ctx.rpc_ctx->get_request_query());
315 std::string error_reason;
316 const auto case_opt = ccf::http::get_query_value_opt<std::string>(
317 parsed_query,
"case", error_reason);
319 if (case_opt.has_value())
321 if (case_opt.value() !=
"original")
323 ctx.rpc_ctx->set_error(
324 HTTP_STATUS_BAD_REQUEST,
325 ccf::errors::InvalidQueryParameterValue,
326 "Accepted values for the 'case' query parameter are: "
331 original_case =
true;
335 auto js_endpoints_handle =
336 ctx.tx.template ro<ccf::endpoints::EndpointsMap>(
337 ccf::endpoints::Tables::ENDPOINTS);
341 std::vector<uint8_t>>;
342 auto raw_js_endpoints_handle = ctx.tx.template ro<RawEndpointsMap>(
343 ccf::endpoints::Tables::ENDPOINTS);
345 js_endpoints_handle->foreach(
346 [&endpoints, &raw_js_endpoints_handle, original_case](
350 endpoints.emplace(key.uri_path, nlohmann::json::object());
351 auto& operations = *ib.first;
353 auto operation = nlohmann::json::object();
357 const auto raw_value_opt = raw_js_endpoints_handle->get(key);
358 if (!raw_value_opt.has_value())
360 throw std::runtime_error(
361 "Table inconsistency: Cannot access key via raw handle?");
363 const auto& raw_value = raw_value_opt.value();
365 nlohmann::json::parse(raw_value.begin(), raw_value.end());
369 operation[
"jsModule"] = properties.
js_module;
371 operation[
"forwardingRequired"] =
373 operation[
"redirectionStrategy"] =
376 auto policies = nlohmann::json::array();
379 policies.push_back(policy);
381 operation[
"authnPolicies"] = policies;
383 operation[
"mode"] = properties.
mode;
384 operation[
"openApi"] = properties.
openapi;
387 operations[key.verb.c_str()] = operation;
392 response_body[
"endpoints"] = endpoints;
395 ctx.rpc_ctx->set_response_json(response_body, HTTP_STATUS_OK);
402 "/service/javascript-app",
406 .add_query_parameter<std::string>(
"case")
410 auto get_javascript_modules = [&](
auto& ctx,
ApiVersion api_version) {
417 auto response_body = nlohmann::json::object();
420 auto module_list = nlohmann::json::array();
422 auto modules_handle =
423 ctx.tx.template ro<ccf::Modules>(ccf::Tables::MODULES);
425 modules_handle->foreach_key(
426 [&module_list](
const std::string& module_name) {
427 auto entry = nlohmann::json::object();
428 entry[
"moduleName"] = module_name;
429 module_list.push_back(entry);
433 response_body[
"value"] = module_list;
436 ctx.rpc_ctx->set_response_json(response_body, HTTP_STATUS_OK);
443 "/service/javascript-modules",
447 .set_openapi_hidden(
true)
450 auto get_javascript_module_by_name =
458 std::string module_name;
462 ctx.rpc_ctx->get_request_path_params(),
467 detail::set_gov_error(
469 HTTP_STATUS_BAD_REQUEST,
470 ccf::errors::InvalidResourceName,
476 module_name = ::http::url_decode(module_name);
478 auto modules_handle =
479 ctx.tx.template ro<ccf::Modules>(ccf::Tables::MODULES);
480 auto module = modules_handle->get(module_name);
482 if (!module.has_value())
484 detail::set_gov_error(
486 HTTP_STATUS_NOT_FOUND,
487 ccf::errors::ResourceNotFound,
488 fmt::format(
"Module {} does not exist.", module_name));
493 ctx.rpc_ctx->set_response_status(HTTP_STATUS_OK);
494 ctx.rpc_ctx->set_response_body(std::move(module.value()));
495 ctx.rpc_ctx->set_response_header(
496 ccf::http::headers::CONTENT_TYPE,
497 http::headervalues::contenttype::JAVASCRIPT);
504 "/service/javascript-modules/{moduleName}",
511 auto get_join_policy = [&](
auto& ctx,
ApiVersion api_version) {
518 auto response_body = nlohmann::json::object();
522 auto sgx_policy = nlohmann::json::object();
524 auto sgx_measurements = nlohmann::json::array();
525 auto code_ids_handle =
526 ctx.tx.template ro<ccf::CodeIDs>(ccf::Tables::NODE_CODE_IDS);
527 code_ids_handle->foreach(
533 sgx_measurements.push_back(measurement.
hex_str());
537 sgx_policy[
"measurements"] = sgx_measurements;
539 response_body[
"sgx"] = sgx_policy;
544 auto virtual_policy = nlohmann::json::object();
546 auto virtual_measurements = nlohmann::json::array();
547 auto measurements_handle =
548 ctx.tx.template ro<ccf::VirtualMeasurements>(
549 ccf::Tables::NODE_VIRTUAL_MEASUREMENTS);
550 measurements_handle->foreach(
551 [&virtual_measurements](
556 virtual_measurements.push_back(measurement);
560 virtual_policy[
"measurements"] = virtual_measurements;
562 auto virtual_host_data = nlohmann::json::array();
563 auto host_data_handle = ctx.tx.template ro<ccf::VirtualHostDataMap>(
564 ccf::Tables::VIRTUAL_HOST_DATA);
565 host_data_handle->foreach(
566 [&virtual_host_data](
const HostData& host_data) {
567 virtual_host_data.push_back(host_data.
hex_str());
570 virtual_policy[
"hostData"] = virtual_host_data;
572 response_body[
"virtual"] = virtual_policy;
577 auto snp_policy = nlohmann::json::object();
579 auto snp_measurements = nlohmann::json::array();
580 auto measurements_handle = ctx.tx.template ro<ccf::SnpMeasurements>(
581 ccf::Tables::NODE_SNP_MEASUREMENTS);
582 measurements_handle->foreach(
588 snp_measurements.push_back(measurement.
hex_str());
592 snp_policy[
"measurements"] = snp_measurements;
594 auto snp_host_data = nlohmann::json::object();
595 auto host_data_handle =
596 ctx.tx.template ro<ccf::SnpHostDataMap>(ccf::Tables::HOST_DATA);
597 host_data_handle->foreach(
600 snp_host_data[host_data.
hex_str()] = metadata;
603 snp_policy[
"hostData"] = snp_host_data;
605 auto snp_endorsements = nlohmann::json::object();
606 auto endorsements_handle =
607 ctx.tx.template ro<ccf::SNPUVMEndorsements>(
608 ccf::Tables::NODE_SNP_UVM_ENDORSEMENTS);
609 endorsements_handle->foreach(
613 snp_endorsements[did] = feed_info;
616 snp_policy[
"uvmEndorsements"] = snp_endorsements;
618 auto snp_tcb_versions = nlohmann::json::object();
619 auto tcb_versions_handle =
620 ctx.tx.template ro<ccf::SnpTcbVersionMap>(
621 ccf::Tables::SNP_TCB_VERSIONS);
623 tcb_versions_handle->foreach(
625 const std::string& cpuid,
627 snp_tcb_versions[cpuid] = tcb_policy;
630 snp_policy[
"tcbVersions"] = snp_tcb_versions;
632 response_body[
"snp"] = snp_policy;
635 ctx.rpc_ctx->set_response_json(response_body, HTTP_STATUS_OK);
642 "/service/join-policy",
649 auto get_jwk = [&](
auto& ctx,
ApiVersion api_version) {
656 auto response_body = nlohmann::json::object();
660 auto issuers = nlohmann::json::object();
662 auto jwt_issuers_handle =
663 ctx.tx.template ro<ccf::JwtIssuers>(ccf::Tables::JWT_ISSUERS);
664 jwt_issuers_handle->foreach(
668 auto jwt_issuer = nlohmann::json::object();
674 jwt_issuer[
"caCertBundleName"] =
678 issuers[issuer_id] = jwt_issuer;
682 response_body[
"issuers"] = issuers;
687 auto keys = nlohmann::json::object();
689 auto jwt_keys_handle =
690 ctx.tx.template ro<ccf::JwtPublicSigningKeysMetadata>(
691 ccf::Tables::JWT_PUBLIC_SIGNING_KEYS_METADATA);
693 jwt_keys_handle->foreach(
696 const std::vector<OpenIDJWKMetadata>& v) {
697 auto keys_info = nlohmann::json::array();
698 for (
const auto& metadata : v)
700 auto info = nlohmann::json::object();
706 info[
"issuer"] = metadata.issuer;
707 info[
"constraint"] = metadata.constraint;
709 keys_info.push_back(info);
716 response_body[
"keys"] = keys;
721 auto cert_bundles = nlohmann::json::object();
723 auto cert_bundles_handle =
724 ctx.tx.template ro<ccf::CACertBundlePEMs>(
725 ccf::Tables::CA_CERT_BUNDLE_PEMS);
726 cert_bundles_handle->foreach([&cert_bundles](
727 const std::string& bundle_name,
728 const std::string& bundle_value) {
729 cert_bundles[bundle_name] = bundle_value;
733 response_body[
"caCertBundles"] = cert_bundles;
736 ctx.rpc_ctx->set_response_json(response_body, HTTP_STATUS_OK);
750 auto get_members = [&](
auto& ctx,
ApiVersion api_version) {
757 auto response_body = nlohmann::json::object();
760 auto member_list = nlohmann::json::array();
762 auto member_info_handle =
763 ctx.tx.template ro<ccf::MemberInfo>(ccf::Tables::MEMBER_INFO);
764 auto member_certs_handle =
765 ctx.tx.template ro<ccf::MemberCerts>(ccf::Tables::MEMBER_CERTS);
766 auto member_enc_keys_handle =
767 ctx.tx.template ro<ccf::MemberPublicEncryptionKeys>(
768 ccf::Tables::MEMBER_ENCRYPTION_PUBLIC_KEYS);
770 member_info_handle->foreach(
771 [&member_list, member_certs_handle, member_enc_keys_handle](
778 member_enc_keys_handle));
782 response_body[
"value"] = member_list;
785 ctx.rpc_ctx->set_response_json(response_body, HTTP_STATUS_OK);
799 auto get_member_by_id = [&](
auto& ctx,
ApiVersion api_version) {
812 auto member_info_handle =
813 ctx.tx.template ro<ccf::MemberInfo>(ccf::Tables::MEMBER_INFO);
814 const auto member_info = member_info_handle->get(member_id);
815 if (!member_info.has_value())
817 detail::set_gov_error(
819 HTTP_STATUS_NOT_FOUND,
820 ccf::errors::ResourceNotFound,
821 fmt::format(
"Member {} does not exist.", member_id));
825 auto member_certs_handle =
826 ctx.tx.template ro<ccf::MemberCerts>(ccf::Tables::MEMBER_CERTS);
827 auto member_enc_keys_handle =
828 ctx.tx.template ro<ccf::MemberPublicEncryptionKeys>(
829 ccf::Tables::MEMBER_ENCRYPTION_PUBLIC_KEYS);
835 member_enc_keys_handle);
837 ctx.rpc_ctx->set_response_json(member, HTTP_STATUS_OK);
844 "/service/members/{memberId}",
851 auto get_users = [&](
auto& ctx,
ApiVersion api_version) {
858 auto response_body = nlohmann::json::object();
861 auto user_list = nlohmann::json::array();
863 auto user_certs_handle =
864 ctx.tx.template ro<ccf::UserCerts>(ccf::Tables::USER_CERTS);
865 auto user_info_handle =
866 ctx.tx.template ro<ccf::UserInfo>(ccf::Tables::USER_INFO);
868 user_certs_handle->foreach([&user_list, user_info_handle](
876 response_body[
"value"] = user_list;
879 ctx.rpc_ctx->set_response_json(response_body, HTTP_STATUS_OK);
893 auto get_user_by_id = [&](
auto& ctx,
ApiVersion api_version) {
906 auto user_certs_handle =
907 ctx.tx.template ro<ccf::UserCerts>(ccf::Tables::USER_CERTS);
909 const auto user_cert = user_certs_handle->get(user_id);
910 if (!user_cert.has_value())
912 detail::set_gov_error(
914 HTTP_STATUS_NOT_FOUND,
915 ccf::errors::ResourceNotFound,
916 fmt::format(
"User {} does not exist.", user_id));
920 auto user_info_handle =
921 ctx.tx.template ro<ccf::UserInfo>(ccf::Tables::USER_INFO);
924 user_id, user_cert.
value(), user_info_handle);
926 ctx.rpc_ctx->set_response_json(user, HTTP_STATUS_OK);
933 "/service/users/{userId}",
940 auto get_nodes = [&](
auto& ctx,
ApiVersion api_version) {
947 auto response_body = nlohmann::json::object();
950 auto node_list = nlohmann::json::array();
952 auto node_info_handle =
953 ctx.tx.template ro<ccf::Nodes>(ccf::Tables::NODES);
954 auto node_endorsed_certs_handle =
955 ctx.tx.template ro<ccf::NodeEndorsedCertificates>(
956 ccf::Tables::NODE_ENDORSED_CERTIFICATES);
958 node_info_handle->foreach(
959 [&node_list, node_endorsed_certs_handle](
962 node_id, node_info, node_endorsed_certs_handle));
966 response_body[
"value"] = node_list;
969 ctx.rpc_ctx->set_response_json(response_body, HTTP_STATUS_OK);
983 auto get_node_by_id = [&](
auto& ctx,
ApiVersion api_version) {
996 auto node_info_handle =
997 ctx.tx.template ro<ccf::Nodes>(ccf::Tables::NODES);
998 const auto node_info = node_info_handle->get(node_id);
999 if (!node_info.has_value())
1001 detail::set_gov_error(
1003 HTTP_STATUS_NOT_FOUND,
1004 ccf::errors::ResourceNotFound,
1005 fmt::format(
"Node {} does not exist.", node_id));
1009 auto node_endorsed_certs_handle =
1010 ctx.tx.template ro<ccf::NodeEndorsedCertificates>(
1011 ccf::Tables::NODE_ENDORSED_CERTIFICATES);
1013 node_id, node_info.
value(), node_endorsed_certs_handle);
1015 ctx.rpc_ctx->set_response_json(node, HTTP_STATUS_OK);
1022 "/service/nodes/{nodeId}",