19 auto get_state_digest = [&](
auto& ctx,
ApiVersion api_version) {
28 std::string member_id_str;
30 ctx.rpc_ctx->get_request_path_params(),
35 detail::set_gov_error(
37 HTTP_STATUS_BAD_REQUEST,
38 ccf::errors::InvalidResourceName,
46 ctx.tx.template ro<ccf::MemberAcks>(Tables::MEMBER_ACKS);
47 auto ack = acks_handle->get(member_id);
50 detail::set_gov_error(
52 HTTP_STATUS_NOT_FOUND,
53 ccf::errors::ResourceNotFound,
54 fmt::format(
"No ACK record exists for member {}.", member_id));
58 auto response_body = nlohmann::json::object();
59 response_body[
"memberId"] = member_id_str;
60 response_body[
"stateDigest"] = ack->state_digest;
61 ctx.rpc_ctx->set_response_json(response_body, HTTP_STATUS_OK);
68 "/members/state-digests/{memberId}",
75 auto update_state_digest = [&](
auto& ctx,
ApiVersion api_version) {
84 std::string member_id_str;
86 ctx.rpc_ctx->get_request_path_params(),
91 detail::set_gov_error(
93 HTTP_STATUS_BAD_REQUEST,
94 ccf::errors::InvalidResourceName,
101 const auto& cose_ident =
102 ctx.template get_caller<ccf::MemberCOSESign1AuthnIdentity>();
103 if (cose_ident.member_id != member_id)
105 detail::set_gov_error(
107 HTTP_STATUS_BAD_REQUEST,
108 ccf::errors::InvalidAuthenticationInfo,
110 "Member ID from path parameter ({}) does not match "
111 "member ID from body signature ({}).",
113 cose_ident.member_id));
121 ctx.tx.template rw<ccf::MemberAcks>(Tables::MEMBER_ACKS);
122 auto ack_opt = acks_handle->get(member_id);
123 if (ack_opt.has_value())
125 ack = ack_opt.value();
129 auto tree_handle = ctx.tx.template ro<ccf::SerialisedMerkleTree>(
130 Tables::SERIALISED_MERKLE_TREE);
131 auto tree = tree_handle->get();
132 if (!tree.has_value())
134 detail::set_gov_error(
136 HTTP_STATUS_INTERNAL_SERVER_ERROR,
137 ccf::errors::InternalError,
138 "Service has no signatures to ack yet - try again soon.");
145 acks_handle->put(member_id, ack);
147 auto body = nlohmann::json::object();
148 body[
"memberId"] = member_id_str;
150 ctx.rpc_ctx->set_response_json(body, HTTP_STATUS_OK);
157 "/members/state-digests/{memberId}:update",
164 auto ack_state_digest = [&](
auto& ctx,
ApiVersion api_version) {
173 std::string member_id_str;
175 ctx.rpc_ctx->get_request_path_params(),
180 detail::set_gov_error(
182 HTTP_STATUS_BAD_REQUEST,
183 ccf::errors::InvalidResourceName,
190 const auto& cose_ident =
191 ctx.template get_caller<ccf::MemberCOSESign1AuthnIdentity>();
192 if (cose_ident.member_id != member_id)
194 detail::set_gov_error(
196 HTTP_STATUS_BAD_REQUEST,
197 ccf::errors::InvalidAuthenticationInfo,
199 "Member ID from path parameter ({}) does not match "
200 "member ID from body signature ({}).",
202 cose_ident.member_id));
208 ctx.tx.template rw<ccf::MemberAcks>(Tables::MEMBER_ACKS);
209 auto ack = acks_handle->get(member_id);
210 if (!ack.has_value())
212 detail::set_gov_error(
214 HTTP_STATUS_FORBIDDEN,
215 ccf::errors::AuthorizationFailed,
216 fmt::format(
"No ACK record exists for member {}.", member_id));
221 const auto expected_digest = ack->state_digest;
222 const auto signed_body = nlohmann::json::parse(cose_ident.content);
223 const auto actual_digest =
224 signed_body[
"stateDigest"].template get<std::string>();
225 if (expected_digest != actual_digest)
227 detail::set_gov_error(
229 HTTP_STATUS_BAD_REQUEST,
230 ccf::errors::StateDigestMismatch,
232 "Submitted state digest is not valid.\n"
243 ack->signed_req = std::nullopt;
246 ack->cose_sign1_req = std::vector<uint8_t>(
247 cose_ident.envelope.begin(), cose_ident.envelope.end());
250 acks_handle->put(member_id, ack.
value());
255 bool newly_active =
false;
261 catch (
const std::logic_error& e)
263 detail::set_gov_error(
265 HTTP_STATUS_INTERNAL_SERVER_ERROR,
266 ccf::errors::InternalError,
267 fmt::format(
"Error activating member: {}", e.what()));
278 auto service_status =
280 if (!service_status.has_value())
282 detail::set_gov_error(
284 HTTP_STATUS_INTERNAL_SERVER_ERROR,
285 ccf::errors::InternalError,
286 "No service currently available.");
294 share_manager.shuffle_recovery_shares(ctx.tx);
296 catch (
const std::logic_error& e)
298 detail::set_gov_error(
300 HTTP_STATUS_INTERNAL_SERVER_ERROR,
301 ccf::errors::InternalError,
303 "Error issuing new recovery shares: {}", e.what()));
310 ctx.rpc_ctx->set_response_status(HTTP_STATUS_NO_CONTENT);
318 "/members/state-digests/{memberId}:ack",
321 {std::make_shared<MemberCOSESign1AuthnPolicy>(
"ack")})
322 .set_openapi_hidden(
true)
ccf::crypto::Sha256Hash get_root() const
Definition history.h:462