18 auto get_state_digest = [&](
auto& ctx,
ApiVersion api_version) {
27 std::string member_id_str;
29 ctx.rpc_ctx->get_request_path_params(),
34 detail::set_gov_error(
36 HTTP_STATUS_BAD_REQUEST,
37 ccf::errors::InvalidResourceName,
45 ctx.tx.template ro<ccf::MemberAcks>(Tables::MEMBER_ACKS);
46 auto ack = acks_handle->get(member_id);
49 detail::set_gov_error(
51 HTTP_STATUS_NOT_FOUND,
52 ccf::errors::ResourceNotFound,
53 fmt::format(
"No ACK record exists for member {}.", member_id));
57 auto response_body = nlohmann::json::object();
58 response_body[
"memberId"] = member_id_str;
59 response_body[
"stateDigest"] = ack->state_digest;
60 ctx.rpc_ctx->set_response_json(response_body, HTTP_STATUS_OK);
67 "/members/state-digests/{memberId}",
74 auto update_state_digest = [&](
auto& ctx,
ApiVersion api_version) {
83 std::string member_id_str;
85 ctx.rpc_ctx->get_request_path_params(),
90 detail::set_gov_error(
92 HTTP_STATUS_BAD_REQUEST,
93 ccf::errors::InvalidResourceName,
100 const auto& cose_ident =
101 ctx.template get_caller<ccf::MemberCOSESign1AuthnIdentity>();
102 if (cose_ident.member_id != member_id)
104 detail::set_gov_error(
106 HTTP_STATUS_BAD_REQUEST,
107 ccf::errors::InvalidAuthenticationInfo,
109 "Member ID from path parameter ({}) does not match "
110 "member ID from body signature ({}).",
112 cose_ident.member_id));
120 ctx.tx.template rw<ccf::MemberAcks>(Tables::MEMBER_ACKS);
121 auto ack_opt = acks_handle->get(member_id);
122 if (ack_opt.has_value())
124 ack = ack_opt.value();
129 ctx.tx.template ro<ccf::Signatures>(Tables::SIGNATURES);
130 auto sig = sigs_handle->get();
131 if (!sig.has_value())
133 detail::set_gov_error(
135 HTTP_STATUS_INTERNAL_SERVER_ERROR,
136 ccf::errors::InternalError,
137 "Service has no signatures to ack yet - try again soon.");
143 acks_handle->put(member_id, ack);
145 auto body = nlohmann::json::object();
146 body[
"memberId"] = member_id_str;
148 ctx.rpc_ctx->set_response_json(body, HTTP_STATUS_OK);
155 "/members/state-digests/{memberId}:update",
162 auto ack_state_digest = [&](
auto& ctx,
ApiVersion api_version) {
171 std::string member_id_str;
173 ctx.rpc_ctx->get_request_path_params(),
178 detail::set_gov_error(
180 HTTP_STATUS_BAD_REQUEST,
181 ccf::errors::InvalidResourceName,
188 const auto& cose_ident =
189 ctx.template get_caller<ccf::MemberCOSESign1AuthnIdentity>();
190 if (cose_ident.member_id != member_id)
192 detail::set_gov_error(
194 HTTP_STATUS_BAD_REQUEST,
195 ccf::errors::InvalidAuthenticationInfo,
197 "Member ID from path parameter ({}) does not match "
198 "member ID from body signature ({}).",
200 cose_ident.member_id));
206 ctx.tx.template rw<ccf::MemberAcks>(Tables::MEMBER_ACKS);
207 auto ack = acks_handle->get(member_id);
208 if (!ack.has_value())
210 detail::set_gov_error(
212 HTTP_STATUS_FORBIDDEN,
213 ccf::errors::AuthorizationFailed,
214 fmt::format(
"No ACK record exists for member {}.", member_id));
219 const auto expected_digest = ack->state_digest;
220 const auto signed_body = nlohmann::json::parse(cose_ident.content);
221 const auto actual_digest =
222 signed_body[
"stateDigest"].template get<std::string>();
223 if (expected_digest != actual_digest)
225 detail::set_gov_error(
227 HTTP_STATUS_BAD_REQUEST,
228 ccf::errors::StateDigestMismatch,
230 "Submitted state digest is not valid.\n"
241 ack->signed_req = std::nullopt;
244 ack->cose_sign1_req = std::vector<uint8_t>(
245 cose_ident.envelope.begin(), cose_ident.envelope.end());
248 acks_handle->put(member_id, ack.
value());
253 bool newly_active =
false;
259 catch (
const std::logic_error& e)
261 detail::set_gov_error(
263 HTTP_STATUS_INTERNAL_SERVER_ERROR,
264 ccf::errors::InternalError,
265 fmt::format(
"Error activating member: {}", e.what()));
276 auto service_status =
278 if (!service_status.has_value())
280 detail::set_gov_error(
282 HTTP_STATUS_INTERNAL_SERVER_ERROR,
283 ccf::errors::InternalError,
284 "No service currently available.");
292 share_manager.shuffle_recovery_shares(ctx.tx);
294 catch (
const std::logic_error& e)
296 detail::set_gov_error(
298 HTTP_STATUS_INTERNAL_SERVER_ERROR,
299 ccf::errors::InternalError,
301 "Error issuing new recovery shares: {}", e.what()));
308 ctx.rpc_ctx->set_response_status(HTTP_STATUS_NO_CONTENT);
316 "/members/state-digests/{memberId}:ack",
319 {std::make_shared<MemberCOSESign1AuthnPolicy>(
"ack")})
320 .set_openapi_hidden(
true)