| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768 |
- using Invercargill;
- using Invercargill.DataStructures;
- using InvercargillJson;
- using Inversion;
- using Astralis;
- namespace Statum {
- /**
- * `POST /_statum/slots` — refreshes snapshots whose `transmit_after` window
- * has elapsed, and is also the target of a `transmit(retry)` directive.
- *
- * The client POSTs a JSON array of Statum frames it holds. For each frame
- * this endpoint verifies the signature: on success it
- * {@link StateService.restore_slot}s the slot into the cache, re-signs it
- * (issuing a fresh `as_at`/`transmit_after`), and returns a `set` directive
- * so the client refreshes its local snapshot; on failure it returns an
- * `invalidate` for that frame's signature so the client drops the slot whose
- * frame the server could not trust.
- */
- public class SlotPostEndpoint : Object, Endpoint {
- private StateService state_service = inject<StateService>();
- private Cryptography.SigningProvider signing_provider = inject<Cryptography.SigningProvider>();
- public async HttpResult handle_request(HttpContext http_context, RouteContext route_context) throws GLib.Error {
- var body = yield http_context.request.request_body.read_all();
- var body_str = body.to_raw_string();
- var directives = new Series<Model.DirectiveDto>();
- var invalid_signatures = new Series<string>();
- if (body_str.strip().length > 0) {
- var body_element = new JsonElement.from_string(body_str);
- var array = body_element.as<JsonArray>();
- foreach (var item in array) {
- var frame = Model.FrameDto.get_mapper().materialise(item.as<JsonObject>());
- try {
- signing_provider.verify_frame(frame);
- } catch (GLib.Error e) {
- // Signature did not verify: tell the client to drop the
- // slot holding this frame, identified by signature.
- if (frame.signature != null && frame.signature.length > 0) {
- invalid_signatures.add(frame.signature);
- }
- continue;
- }
- var content_element = new JsonElement.from_string(frame.content);
- var content_object = content_element.as<JsonObject>();
- var snapshot = Model.SnapshotDto.get_mapper().materialise(content_object);
- state_service.restore_slot(frame);
- var refreshed = state_service.sign_slot(snapshot.slot.key);
- if (refreshed != null) {
- directives.add(new Model.SetDirectiveDto.with_frame((!)refreshed));
- }
- }
- }
- return StatumDirectives.to_result(directives, invalid_signatures);
- }
- }
- }
|