CCF
Loading...
Searching...
No Matches
service_state.h
Go to the documentation of this file.
1// Copyright (c) Microsoft Corporation. All rights reserved.
2// Licensed under the Apache 2.0 License.
3#pragma once
4
7
9{
11 const ccf::MemberId& member_id,
12 const ccf::MemberDetails& member_details,
13 ccf::MemberCerts::ReadOnlyHandle* member_certs_handle,
14 ccf::MemberPublicEncryptionKeys::ReadOnlyHandle* member_enc_keys_handle)
15 {
16 auto member = nlohmann::json::object();
17
18 member["memberId"] = member_id;
19 member["status"] = member_details.status;
20 member["memberData"] = member_details.member_data;
21
22 const auto cert = member_certs_handle->get(member_id);
23 if (cert.has_value())
24 {
25 member["certificate"] = cert.value().str();
26 }
27 else
28 {
29 GOV_INFO_FMT("Member {} has no certificate", member_id);
30 }
31
32 const auto enc_key = member_enc_keys_handle->get(member_id);
33 if (enc_key.has_value())
34 {
35 member["publicEncryptionKey"] = enc_key.value().str();
36 }
37
38 return member;
39 }
40
42 const ccf::UserId& user_id,
43 const ccf::crypto::Pem& user_cert,
44 ccf::UserInfo::ReadOnlyHandle* user_info_handle)
45 {
46 auto user = nlohmann::json::object();
47
48 user["userId"] = user_id;
49 user["certificate"] = user_cert.str();
50
51 const auto user_info = user_info_handle->get(user_id);
52 // For consistency with other *Data fields, we always insert this, even if
53 // it iss nullopt (JSON null)
54 user["userData"] = user_info;
55
56 return user;
57 }
58
60 const ccf::NodeId& node_id,
61 const ccf::NodeInfo& node_info,
62 ccf::NodeEndorsedCertificates::ReadOnlyHandle* node_endorsed_certs_handle)
63 {
64 auto node = nlohmann::json::object();
65
66 node["nodeId"] = node_id;
67 node["status"] = node_info.status;
68 node["nodeData"] = node_info.node_data;
69
70 const auto endorsed_cert = node_endorsed_certs_handle->get(node_id);
71 if (endorsed_cert.has_value())
72 {
73 node["certificate"] = endorsed_cert.value().str();
74 }
75 else
76 {
77 GOV_INFO_FMT("Node {} has no endorsed certificate", node_id);
78 }
79
80 node["retiredCommitted"] = node_info.retired_committed;
81
82 auto quote_info = nlohmann::json::object();
83 switch (node_info.quote_info.format)
84 {
86 {
87 quote_info["format"] = "OE_SGX_v1";
88 quote_info["quote"] =
90 quote_info["endorsements"] =
92 break;
93 }
95 {
96 quote_info["format"] = "Insecure_Virtual";
97 break;
98 }
100 {
101 quote_info["format"] = "AMD_SEV_SNP_v1";
102 if (node_info.quote_info.uvm_endorsements.has_value())
103 {
104 quote_info["uvmEndorsements"] = ccf::crypto::b64_from_raw(
105 node_info.quote_info.uvm_endorsements.value());
106 }
107 if (node_info.quote_info.endorsed_tcb.has_value())
108 {
109 quote_info["endorsedTcb"] = ccf::crypto::b64_from_raw(
110 ds::from_hex(node_info.quote_info.endorsed_tcb.value()));
111 }
112 break;
113 }
114 }
115 node["quoteInfo"] = quote_info;
116
117 auto rpc_interfaces = nlohmann::json::object();
118 for (const auto& [interface_id, net_interface] : node_info.rpc_interfaces)
119 {
120 auto rpc_interface = nlohmann::json::object();
121
122 rpc_interface["publishedAddress"] = net_interface.published_address;
123 if (net_interface.app_protocol.has_value())
124 {
125 rpc_interface["protocol"] = net_interface.app_protocol.value();
126 }
127 else
128 {
129 GOV_INFO_FMT("RPC interface {} has no protocol", interface_id);
130 }
131 rpc_interfaces[interface_id] = rpc_interface;
132 }
133
134 node["rpcInterfaces"] = rpc_interfaces;
135
136 return node;
137 }
138
140 {
141 auto get_constitution = [&](auto& ctx, ApiVersion api_version) {
142 switch (api_version)
143 {
145 case ApiVersion::v1:
146 default:
147 {
148 auto constitution_handle =
149 ctx.tx.template ro<ccf::Constitution>(ccf::Tables::CONSTITUTION);
150 auto constitution = constitution_handle->get();
151
152 if (!constitution.has_value())
153 {
154 detail::set_gov_error(
155 ctx.rpc_ctx,
156 HTTP_STATUS_NOT_FOUND,
157 ccf::errors::ResourceNotFound,
158 "Constitution not found");
159 return;
160 }
161
162 // Return raw JS constitution in body
163 ctx.rpc_ctx->set_response_status(HTTP_STATUS_OK);
164 ctx.rpc_ctx->set_response_body(std::move(constitution.value()));
165 ctx.rpc_ctx->set_response_header(
166 ccf::http::headers::CONTENT_TYPE,
167 http::headervalues::contenttype::JAVASCRIPT);
168 return;
169 }
170 }
171 };
172 registry
174 "/service/constitution",
175 HTTP_GET,
176 api_version_adapter(get_constitution),
177 no_auth_required)
178 .set_openapi_hidden(true)
179 .install();
180
181 auto get_service_info = [&](auto& ctx, ApiVersion api_version) {
182 switch (api_version)
183 {
185 case ApiVersion::v1:
186 default:
187 {
188 auto response_body = nlohmann::json::object();
189
190 auto service_info_handle =
191 ctx.tx.template ro<ccf::Service>(ccf::Tables::SERVICE);
192 auto service_info = service_info_handle->get();
193
194 if (!service_info.has_value())
195 {
196 detail::set_gov_error(
197 ctx.rpc_ctx,
198 HTTP_STATUS_NOT_FOUND,
199 ccf::errors::ResourceNotFound,
200 "Service info not yet available");
201 return;
202 }
203
204 response_body["status"] = service_info->status;
205 response_body["certificate"] = service_info->cert.str();
206 response_body["recoveryCount"] =
207 service_info->recovery_count.value_or(0);
208
209 if (service_info->current_service_create_txid.has_value())
210 {
211 response_body["creationTransactionId"] =
212 service_info->current_service_create_txid.value();
213 }
214 else
215 {
216 GOV_INFO_FMT("No recorded current_service_create_txid");
217 }
218
219 if (service_info->previous_service_identity_version.has_value())
220 {
222 service_info->previous_service_identity_version.value();
224 // Note: deliberately ignoring errors. Prefer to return single
225 // invalid field than convert entire response to error.
227 response_body["previousServiceCreationTransactionId"] =
228 ccf::TxID{.view = view, .seqno = seqno};
229 }
230
231 response_body["serviceData"] = service_info->service_data;
232
233 {
234 auto config_handle = ctx.tx.template ro<ccf::Configuration>(
235 ccf::Tables::CONFIGURATION);
236
237 auto config = config_handle->get();
238 if (config.has_value())
239 {
240 auto configuration = nlohmann::json::object();
241 configuration["recoveryThreshold"] = config->recovery_threshold;
242 configuration["maximumNodeCertificateValidityDays"] =
243 config->maximum_node_certificate_validity_days.value_or(
244 ccf::default_node_cert_validity_period_days);
245 configuration["maximumServiceCertificateValidityDays"] =
246 config->maximum_service_certificate_validity_days.value_or(
247 ccf::default_service_cert_validity_period_days);
248 configuration["recentCoseProposalsWindowSize"] =
249 config->recent_cose_proposals_window_size.value_or(
250 ccf::default_recent_cose_proposals_window_size);
251 response_body["configuration"] = configuration;
252 }
253 else
254 {
255 GOV_INFO_FMT("No service configuration available");
256 }
257 }
258
259 ctx.rpc_ctx->set_response_json(response_body, HTTP_STATUS_OK);
260 return;
261 }
262 }
263 };
264 registry
266 "/service/info",
267 HTTP_GET,
268 api_version_adapter(get_service_info),
269 no_auth_required)
270 .set_openapi_hidden(true)
271 .install();
272
273 auto get_javascript_app = [&](auto& ctx, ApiVersion api_version) {
274 switch (api_version)
275 {
277 case ApiVersion::v1:
278 default:
279 {
280 auto response_body = nlohmann::json::object();
281
282 // Describe JS endpoints
283 {
284 auto endpoints = nlohmann::json::object();
285
286 auto js_endpoints_handle =
287 ctx.tx.template ro<ccf::endpoints::EndpointsMap>(
288 ccf::endpoints::Tables::ENDPOINTS);
289 js_endpoints_handle->foreach(
290 [&endpoints](
292 const ccf::endpoints::EndpointProperties& properties) {
293 auto ib =
294 endpoints.emplace(key.uri_path, nlohmann::json::object());
295 auto& operations = *ib.first;
296
297 auto operation = nlohmann::json::object();
298
299 operation["jsModule"] = properties.js_module;
300 operation["jsFunction"] = properties.js_function;
301 operation["forwardingRequired"] =
302 properties.forwarding_required;
303
304 auto policies = nlohmann::json::array();
305 for (const auto& policy : properties.authn_policies)
306 {
307 policies.push_back(policy);
308 }
309 operation["authnPolicies"] = policies;
310
311 operation["mode"] = properties.mode;
312 operation["openApi"] = properties.openapi;
313
314 operations[key.verb.c_str()] = operation;
315
316 return true;
317 });
318
319 response_body["endpoints"] = endpoints;
320 }
321
322 ctx.rpc_ctx->set_response_json(response_body, HTTP_STATUS_OK);
323 return;
324 }
325 }
326 };
327 registry
329 "/service/javascript-app",
330 HTTP_GET,
331 api_version_adapter(get_javascript_app, ApiVersion::v1),
332 no_auth_required)
333 .set_openapi_hidden(true)
334 .install();
335
336 auto get_javascript_modules = [&](auto& ctx, ApiVersion api_version) {
337 switch (api_version)
338 {
340 case ApiVersion::v1:
341 default:
342 {
343 auto response_body = nlohmann::json::object();
344
345 {
346 auto module_list = nlohmann::json::array();
347
348 auto modules_handle =
349 ctx.tx.template ro<ccf::Modules>(ccf::Tables::MODULES);
350
351 modules_handle->foreach_key(
352 [&module_list](const std::string& module_name) {
353 auto entry = nlohmann::json::object();
354 entry["moduleName"] = module_name;
355 module_list.push_back(entry);
356 return true;
357 });
358
359 response_body["value"] = module_list;
360 }
361
362 ctx.rpc_ctx->set_response_json(response_body, HTTP_STATUS_OK);
363 return;
364 }
365 }
366 };
367 registry
369 "/service/javascript-modules",
370 HTTP_GET,
371 api_version_adapter(get_javascript_modules, ApiVersion::v1),
372 no_auth_required)
373 .set_openapi_hidden(true)
374 .install();
375
376 auto get_javascript_module_by_name =
377 [&](auto& ctx, ApiVersion api_version) {
378 switch (api_version)
379 {
381 case ApiVersion::v1:
382 default:
383 {
384 std::string module_name;
385 {
386 std::string error;
388 ctx.rpc_ctx->get_request_path_params(),
389 "moduleName",
390 module_name,
391 error))
392 {
393 detail::set_gov_error(
394 ctx.rpc_ctx,
395 HTTP_STATUS_BAD_REQUEST,
396 ccf::errors::InvalidResourceName,
397 std::move(error));
398 return;
399 }
400 }
401
402 module_name = ::http::url_decode(module_name);
403
404 auto modules_handle =
405 ctx.tx.template ro<ccf::Modules>(ccf::Tables::MODULES);
406 auto module = modules_handle->get(module_name);
407
408 if (!module.has_value())
409 {
410 detail::set_gov_error(
411 ctx.rpc_ctx,
412 HTTP_STATUS_NOT_FOUND,
413 ccf::errors::ResourceNotFound,
414 fmt::format("Module {} does not exist.", module_name));
415 return;
416 }
417
418 // Return raw JS module content in body
419 ctx.rpc_ctx->set_response_status(HTTP_STATUS_OK);
420 ctx.rpc_ctx->set_response_body(std::move(module.value()));
421 ctx.rpc_ctx->set_response_header(
422 ccf::http::headers::CONTENT_TYPE,
423 http::headervalues::contenttype::JAVASCRIPT);
424 return;
425 }
426 }
427 };
428 registry
430 "/service/javascript-modules/{moduleName}",
431 HTTP_GET,
432 api_version_adapter(get_javascript_module_by_name, ApiVersion::v1),
433 no_auth_required)
434 .set_openapi_hidden(true)
435 .install();
436
437 auto get_join_policy = [&](auto& ctx, ApiVersion api_version) {
438 switch (api_version)
439 {
441 case ApiVersion::v1:
442 default:
443 {
444 auto response_body = nlohmann::json::object();
445
446 // Describe SGX join policy
447 {
448 auto sgx_policy = nlohmann::json::object();
449
450 auto sgx_measurements = nlohmann::json::array();
451 auto code_ids_handle =
452 ctx.tx.template ro<ccf::CodeIDs>(ccf::Tables::NODE_CODE_IDS);
453 code_ids_handle->foreach(
454 [&sgx_measurements](
455 const ccf::pal::SgxAttestationMeasurement& measurement,
456 const ccf::CodeStatus& status) {
458 {
459 sgx_measurements.push_back(measurement.hex_str());
460 }
461 return true;
462 });
463 sgx_policy["measurements"] = sgx_measurements;
464
465 response_body["sgx"] = sgx_policy;
466 }
467
468 // Describe SNP join policy
469 {
470 auto snp_policy = nlohmann::json::object();
471
472 auto snp_measurements = nlohmann::json::array();
473 auto measurements_handle = ctx.tx.template ro<ccf::SnpMeasurements>(
474 ccf::Tables::NODE_SNP_MEASUREMENTS);
475 measurements_handle->foreach(
476 [&snp_measurements](
477 const pal::SnpAttestationMeasurement& measurement,
478 const ccf::CodeStatus& status) {
480 {
481 snp_measurements.push_back(measurement.hex_str());
482 }
483 return true;
484 });
485 snp_policy["measurements"] = snp_measurements;
486
487 auto snp_host_data = nlohmann::json::object();
488 auto host_data_handle =
489 ctx.tx.template ro<ccf::SnpHostDataMap>(ccf::Tables::HOST_DATA);
490 host_data_handle->foreach(
491 [&snp_host_data](
492 const HostData& host_data, const HostDataMetadata& metadata) {
493 snp_host_data[host_data.hex_str()] = metadata;
494 return true;
495 });
496 snp_policy["hostData"] = snp_host_data;
497
498 auto snp_endorsements = nlohmann::json::object();
499 auto endorsements_handle =
500 ctx.tx.template ro<ccf::SNPUVMEndorsements>(
501 ccf::Tables::NODE_SNP_UVM_ENDORSEMENTS);
502 endorsements_handle->foreach(
503 [&snp_endorsements](
504 const ccf::DID& did,
505 const ccf::FeedToEndorsementsDataMap& feed_info) {
506 snp_endorsements[did] = feed_info;
507 return true;
508 });
509 snp_policy["uvmEndorsements"] = snp_endorsements;
510
511 response_body["snp"] = snp_policy;
512 }
513
514 ctx.rpc_ctx->set_response_json(response_body, HTTP_STATUS_OK);
515 return;
516 }
517 }
518 };
519 registry
521 "/service/join-policy",
522 HTTP_GET,
523 api_version_adapter(get_join_policy),
524 no_auth_required)
525 .set_openapi_hidden(true)
526 .install();
527
528 auto get_jwk = [&](auto& ctx, ApiVersion api_version) {
529 switch (api_version)
530 {
532 case ApiVersion::v1:
533 default:
534 {
535 auto response_body = nlohmann::json::object();
536
537 // Populate issuers field
538 {
539 auto issuers = nlohmann::json::object();
540
541 auto jwt_issuers_handle =
542 ctx.tx.template ro<ccf::JwtIssuers>(ccf::Tables::JWT_ISSUERS);
543 jwt_issuers_handle->foreach(
544 [&issuers](
545 const ccf::JwtIssuer& issuer_id,
546 const ccf::JwtIssuerMetadata& metadata) {
547 auto jwt_issuer = nlohmann::json::object();
548
549 jwt_issuer["keyFilter"] = metadata.key_filter;
550 jwt_issuer["autoRefresh"] = metadata.auto_refresh;
551
552 if (metadata.key_policy.has_value())
553 {
554 jwt_issuer["keyPolicy"] = metadata.key_policy.value();
555 }
556
557 if (metadata.ca_cert_bundle_name.has_value())
558 {
559 jwt_issuer["caCertBundleName"] =
560 metadata.ca_cert_bundle_name.value();
561 }
562
563 issuers[issuer_id] = jwt_issuer;
564 return true;
565 });
566
567 response_body["issuers"] = issuers;
568 }
569
570 // Populate keys field
571 {
572 auto keys = nlohmann::json::object();
573
574 auto jwt_keys_handle =
575 ctx.tx.template ro<ccf::JwtPublicSigningKeys>(
576 ccf::Tables::JWT_PUBLIC_SIGNING_KEYS_METADATA);
577
578 jwt_keys_handle->foreach(
579 [&keys](
580 const ccf::JwtKeyId& k,
581 const std::vector<OpenIDJWKMetadata>& v) {
582 auto keys_info = nlohmann::json::array();
583 for (const auto& metadata : v)
584 {
585 auto info = nlohmann::json::object();
586
587 // cert is stored as DER - convert to PEM for API
588 const auto cert_pem =
589 ccf::crypto::cert_der_to_pem(metadata.cert);
590 info["certificate"] = cert_pem.str();
591
592 info["issuer"] = metadata.issuer;
593 info["constraint"] = metadata.constraint;
594
595 keys_info.push_back(info);
596 }
597
598 keys[k] = keys_info;
599 return true;
600 });
601
602 response_body["keys"] = keys;
603 }
604
605 // Populate caCertBundles field
606 {
607 auto cert_bundles = nlohmann::json::object();
608
609 auto cert_bundles_handle =
610 ctx.tx.template ro<ccf::CACertBundlePEMs>(
611 ccf::Tables::CA_CERT_BUNDLE_PEMS);
612 cert_bundles_handle->foreach([&cert_bundles](
613 const std::string& bundle_name,
614 const std::string& bundle_value) {
615 cert_bundles[bundle_name] = bundle_value;
616 return true;
617 });
618
619 response_body["caCertBundles"] = cert_bundles;
620 }
621
622 ctx.rpc_ctx->set_response_json(response_body, HTTP_STATUS_OK);
623 return;
624 }
625 }
626 };
627 registry
629 "/service/jwk",
630 HTTP_GET,
631 api_version_adapter(get_jwk),
632 no_auth_required)
633 .set_openapi_hidden(true)
634 .install();
635
636 auto get_members = [&](auto& ctx, ApiVersion api_version) {
637 switch (api_version)
638 {
640 case ApiVersion::v1:
641 default:
642 {
643 auto response_body = nlohmann::json::object();
644
645 {
646 auto member_list = nlohmann::json::array();
647
648 auto member_info_handle =
649 ctx.tx.template ro<ccf::MemberInfo>(ccf::Tables::MEMBER_INFO);
650 auto member_certs_handle =
651 ctx.tx.template ro<ccf::MemberCerts>(ccf::Tables::MEMBER_CERTS);
652 auto member_enc_keys_handle =
653 ctx.tx.template ro<ccf::MemberPublicEncryptionKeys>(
654 ccf::Tables::MEMBER_ENCRYPTION_PUBLIC_KEYS);
655
656 member_info_handle->foreach(
657 [&member_list, member_certs_handle, member_enc_keys_handle](
658 const ccf::MemberId& member_id,
659 const ccf::MemberDetails& member_details) {
660 member_list.push_back(produce_member_description(
661 member_id,
662 member_details,
663 member_certs_handle,
664 member_enc_keys_handle));
665 return true;
666 });
667
668 response_body["value"] = member_list;
669 }
670
671 ctx.rpc_ctx->set_response_json(response_body, HTTP_STATUS_OK);
672 return;
673 }
674 }
675 };
676 registry
678 "/service/members",
679 HTTP_GET,
680 api_version_adapter(get_members),
681 no_auth_required)
682 .set_openapi_hidden(true)
683 .install();
684
685 auto get_member_by_id = [&](auto& ctx, ApiVersion api_version) {
686 switch (api_version)
687 {
689 case ApiVersion::v1:
690 default:
691 {
692 ccf::MemberId member_id;
693 if (!detail::try_parse_member_id(ctx.rpc_ctx, member_id))
694 {
695 return;
696 }
697
698 auto member_info_handle =
699 ctx.tx.template ro<ccf::MemberInfo>(ccf::Tables::MEMBER_INFO);
700 const auto member_info = member_info_handle->get(member_id);
701 if (!member_info.has_value())
702 {
703 detail::set_gov_error(
704 ctx.rpc_ctx,
705 HTTP_STATUS_NOT_FOUND,
706 ccf::errors::ResourceNotFound,
707 fmt::format("Member {} does not exist.", member_id));
708 return;
709 }
710
711 auto member_certs_handle =
712 ctx.tx.template ro<ccf::MemberCerts>(ccf::Tables::MEMBER_CERTS);
713 auto member_enc_keys_handle =
714 ctx.tx.template ro<ccf::MemberPublicEncryptionKeys>(
715 ccf::Tables::MEMBER_ENCRYPTION_PUBLIC_KEYS);
716
717 const auto member = produce_member_description(
718 member_id,
719 member_info.value(),
720 member_certs_handle,
721 member_enc_keys_handle);
722
723 ctx.rpc_ctx->set_response_json(member, HTTP_STATUS_OK);
724 return;
725 }
726 }
727 };
728 registry
730 "/service/members/{memberId}",
731 HTTP_GET,
732 api_version_adapter(get_member_by_id),
733 no_auth_required)
734 .set_openapi_hidden(true)
735 .install();
736
737 auto get_users = [&](auto& ctx, ApiVersion api_version) {
738 switch (api_version)
739 {
741 case ApiVersion::v1:
742 default:
743 {
744 auto response_body = nlohmann::json::object();
745
746 {
747 auto user_list = nlohmann::json::array();
748
749 auto user_certs_handle =
750 ctx.tx.template ro<ccf::UserCerts>(ccf::Tables::USER_CERTS);
751 auto user_info_handle =
752 ctx.tx.template ro<ccf::UserInfo>(ccf::Tables::USER_INFO);
753
754 user_certs_handle->foreach([&user_list, user_info_handle](
755 const ccf::UserId& user_id,
756 const ccf::crypto::Pem& user_cert) {
757 user_list.push_back(
758 produce_user_description(user_id, user_cert, user_info_handle));
759 return true;
760 });
761
762 response_body["value"] = user_list;
763 }
764
765 ctx.rpc_ctx->set_response_json(response_body, HTTP_STATUS_OK);
766 return;
767 }
768 }
769 };
770 registry
772 "/service/users",
773 HTTP_GET,
774 api_version_adapter(get_users),
775 no_auth_required)
776 .set_openapi_hidden(true)
777 .install();
778
779 auto get_user_by_id = [&](auto& ctx, ApiVersion api_version) {
780 switch (api_version)
781 {
783 case ApiVersion::v1:
784 default:
785 {
786 ccf::UserId user_id;
787 if (!detail::try_parse_user_id(ctx.rpc_ctx, user_id))
788 {
789 return;
790 }
791
792 auto user_certs_handle =
793 ctx.tx.template ro<ccf::UserCerts>(ccf::Tables::USER_CERTS);
794
795 const auto user_cert = user_certs_handle->get(user_id);
796 if (!user_cert.has_value())
797 {
798 detail::set_gov_error(
799 ctx.rpc_ctx,
800 HTTP_STATUS_NOT_FOUND,
801 ccf::errors::ResourceNotFound,
802 fmt::format("User {} does not exist.", user_id));
803 return;
804 }
805
806 auto user_info_handle =
807 ctx.tx.template ro<ccf::UserInfo>(ccf::Tables::USER_INFO);
808
809 const auto user = produce_user_description(
810 user_id, user_cert.value(), user_info_handle);
811
812 ctx.rpc_ctx->set_response_json(user, HTTP_STATUS_OK);
813 return;
814 }
815 }
816 };
817 registry
819 "/service/users/{userId}",
820 HTTP_GET,
821 api_version_adapter(get_user_by_id),
822 no_auth_required)
823 .set_openapi_hidden(true)
824 .install();
825
826 auto get_nodes = [&](auto& ctx, ApiVersion api_version) {
827 switch (api_version)
828 {
830 case ApiVersion::v1:
831 default:
832 {
833 auto response_body = nlohmann::json::object();
834
835 {
836 auto node_list = nlohmann::json::array();
837
838 auto node_info_handle =
839 ctx.tx.template ro<ccf::Nodes>(ccf::Tables::NODES);
840 auto node_endorsed_certs_handle =
841 ctx.tx.template ro<ccf::NodeEndorsedCertificates>(
842 ccf::Tables::NODE_ENDORSED_CERTIFICATES);
843
844 node_info_handle->foreach(
845 [&node_list, node_endorsed_certs_handle](
846 const ccf::NodeId& node_id, const ccf::NodeInfo& node_info) {
847 node_list.push_back(produce_node_description(
848 node_id, node_info, node_endorsed_certs_handle));
849 return true;
850 });
851
852 response_body["value"] = node_list;
853 }
854
855 ctx.rpc_ctx->set_response_json(response_body, HTTP_STATUS_OK);
856 return;
857 }
858 }
859 };
860 registry
862 "/service/nodes",
863 HTTP_GET,
864 api_version_adapter(get_nodes),
865 no_auth_required)
866 .set_openapi_hidden(true)
867 .install();
868
869 auto get_node_by_id = [&](auto& ctx, ApiVersion api_version) {
870 switch (api_version)
871 {
873 case ApiVersion::v1:
874 default:
875 {
876 ccf::NodeId node_id;
877 if (!detail::try_parse_node_id(ctx.rpc_ctx, node_id))
878 {
879 return;
880 }
881
882 auto node_info_handle =
883 ctx.tx.template ro<ccf::Nodes>(ccf::Tables::NODES);
884 const auto node_info = node_info_handle->get(node_id);
885 if (!node_info.has_value())
886 {
887 detail::set_gov_error(
888 ctx.rpc_ctx,
889 HTTP_STATUS_NOT_FOUND,
890 ccf::errors::ResourceNotFound,
891 fmt::format("Node {} does not exist.", node_id));
892 return;
893 }
894
895 auto node_endorsed_certs_handle =
896 ctx.tx.template ro<ccf::NodeEndorsedCertificates>(
897 ccf::Tables::NODE_ENDORSED_CERTIFICATES);
898 const auto node = produce_node_description(
899 node_id, node_info.value(), node_endorsed_certs_handle);
900
901 ctx.rpc_ctx->set_response_json(node, HTTP_STATUS_OK);
902 return;
903 }
904 }
905 };
906 registry
908 "/service/nodes/{nodeId}",
909 HTTP_GET,
910 api_version_adapter(get_node_by_id),
911 no_auth_required)
912 .set_openapi_hidden(true)
913 .install();
914 }
915}
Definition base_endpoint_registry.h:121
ApiResult get_view_for_seqno_v1(ccf::SeqNo seqno, ccf::View &view)
Definition base_endpoint_registry.cpp:202
Definition pem.h:18
const std::string & str() const
Definition pem.h:46
Definition sha256_hash.h:16
std::string hex_str() const
Definition sha256_hash.cpp:61
virtual Endpoint make_read_only_endpoint(const std::string &method, RESTVerb verb, const ReadOnlyEndpointFunction &f, const AuthnPolicies &ap)
Definition endpoint_registry.cpp:235
#define GOV_INFO_FMT
Definition gov_logging.h:15
std::string HostDataMetadata
Definition host_data.h:10
ccf::crypto::Pem cert_der_to_pem(const std::vector< uint8_t > &der)
Definition verifier.cpp:33
std::string b64_from_raw(const uint8_t *data, size_t size)
Definition base64.cpp:39
bool get_path_param(const ccf::PathParams &params, const std::string &param_name, T &value, std::string &error)
Definition endpoint_registry.h:64
bool try_parse_user_id(const std::shared_ptr< ccf::RpcContext > &rpc_ctx, ccf::UserId &user_id)
Definition helpers.h:123
bool try_parse_member_id(const std::shared_ptr< ccf::RpcContext > &rpc_ctx, ccf::MemberId &member_id)
Definition helpers.h:63
bool try_parse_node_id(const std::shared_ptr< ccf::RpcContext > &rpc_ctx, ccf::NodeId &node_id)
Definition helpers.h:225
Definition api_version.h:11
nlohmann::json produce_user_description(const ccf::UserId &user_id, const ccf::crypto::Pem &user_cert, ccf::UserInfo::ReadOnlyHandle *user_info_handle)
Definition service_state.h:41
nlohmann::json produce_member_description(const ccf::MemberId &member_id, const ccf::MemberDetails &member_details, ccf::MemberCerts::ReadOnlyHandle *member_certs_handle, ccf::MemberPublicEncryptionKeys::ReadOnlyHandle *member_enc_keys_handle)
Definition service_state.h:10
auto api_version_adapter(Fn &&f, ApiVersion min_accepted=ApiVersion::MIN)
Definition api_version.h:101
ApiVersion
Definition api_version.h:13
nlohmann::json produce_node_description(const ccf::NodeId &node_id, const ccf::NodeInfo &node_info, ccf::NodeEndorsedCertificates::ReadOnlyHandle *node_endorsed_certs_handle)
Definition service_state.h:59
void init_service_state_handlers(ccf::BaseEndpointRegistry &registry)
Definition service_state.h:139
AttestationMeasurement< snp_attestation_measurement_size > SnpAttestationMeasurement
Definition measurement.h:107
AttestationMeasurement< sgx_attestation_measurement_size > SgxAttestationMeasurement
Definition measurement.h:97
std::string JwtIssuer
Definition jwt.h:57
@ error
Definition tls_session.h:25
view
Definition signatures.h:54
std::map< Feed, UVMEndorsementsData > FeedToEndorsementsDataMap
Definition uvm_endorsements.h:22
std::string DID
Definition uvm_endorsements.h:20
CodeStatus
Definition code_status.h:12
seqno
Definition signatures.h:54
uint64_t View
Definition tx_id.h:23
uint64_t SeqNo
Definition tx_id.h:36
std::string JwtKeyId
Definition jwt.h:58
Value & value()
Definition entity_id.h:60
Definition jwt.h:41
bool auto_refresh
Whether to auto-refresh keys from the issuer.
Definition jwt.h:49
std::optional< std::string > ca_cert_bundle_name
Optional CA bundle name used for authentication when auto-refreshing.
Definition jwt.h:47
std::optional< JwtIssuerKeyPolicy > key_policy
Optional Key Policy.
Definition jwt.h:45
JwtIssuerKeyFilter key_filter
JWT issuer key filter.
Definition jwt.h:43
Definition members.h:61
nlohmann::json member_data
Definition members.h:66
MemberStatus status
Status of the member in the consortium.
Definition members.h:63
RpcInterfaces rpc_interfaces
RPC interfaces.
Definition node_info_network.h:150
Definition node_info.h:30
bool retired_committed
Definition node_info.h:74
QuoteInfo quote_info
Node enclave quote.
Definition node_info.h:32
NodeStatus status
Node status.
Definition node_info.h:36
nlohmann::json node_data
Definition node_info.h:57
QuoteFormat format
Quote format.
Definition quote_info.h:28
std::optional< std::string > endorsed_tcb
Endorsed TCB (hex-encoded)
Definition quote_info.h:36
std::optional< std::vector< uint8_t > > uvm_endorsements
UVM endorsements (SNP-only)
Definition quote_info.h:34
std::vector< uint8_t > quote
Enclave quote.
Definition quote_info.h:30
std::vector< uint8_t > endorsements
Quote endorsements.
Definition quote_info.h:32
Definition tx_id.h:44
View view
Definition tx_id.h:45
Definition endpoint.h:20
Definition endpoint.h:161
nlohmann::json openapi
OpenAPI schema for endpoint.
Definition endpoint.h:171
std::string js_module
JavaScript module.
Definition endpoint.h:175
std::string js_function
JavaScript function name.
Definition endpoint.h:177
std::vector< nlohmann::json > authn_policies
Authentication policies.
Definition endpoint.h:169
ForwardingRequired forwarding_required
Endpoint forwarding policy.
Definition endpoint.h:165
Mode mode
Endpoint mode.
Definition endpoint.h:163
Endpoint & set_openapi_hidden(bool hidden)
Definition endpoint.cpp:8
void install()
Definition endpoint.cpp:120