From 3b1718de549d0841c14e0ce4057421ebc58cf135 Mon Sep 17 00:00:00 2001 From: David Estes Date: Thu, 27 Jun 2024 10:52:08 -0600 Subject: [PATCH] feat: add `payload` option to return signed payload without signature information --- api-server/README.md | 2 +- api-server/api/openapi.yaml | 4 +++- api-server/docs/default_api.md | 2 +- api/ceramic.yaml | 5 +++-- api/src/server.rs | 4 +++- event/src/unvalidated/signed/mod.rs | 12 ++++++++++++ service/src/event/store.rs | 17 +++++++++++++++++ 7 files changed, 40 insertions(+), 6 deletions(-) diff --git a/api-server/README.md b/api-server/README.md index 1f8055c46..33340dfa2 100644 --- a/api-server/README.md +++ b/api-server/README.md @@ -15,7 +15,7 @@ To see how to make this your own, look here: [README]((https://openapi-generator.tech)) - API version: 0.25.0 -- Build date: 2024-06-26T12:41:21.980959-06:00[America/Denver] +- Build date: 2024-06-27T10:50:10.100652-06:00[America/Denver] diff --git a/api-server/api/openapi.yaml b/api-server/api/openapi.yaml index fe6841116..1cb806ba3 100644 --- a/api-server/api/openapi.yaml +++ b/api-server/api/openapi.yaml @@ -325,7 +325,8 @@ paths: - description: | Whether to include the event data (carfile) in the response. In the future, only the payload or other options may be supported: * `none` - Empty, only the event ID is returned - * `full` - The entire envelope carfile (including the envelope and payload) + * `payload` - Only the signed event payload data as a carfile. Unsigned and time events are unchanged. + * `full` - The entire envelope carfile (including the envelope, capability and payload when applicable) explode: true in: query name: includeData @@ -333,6 +334,7 @@ paths: schema: enum: - none + - payload - full type: string style: form diff --git a/api-server/docs/default_api.md b/api-server/docs/default_api.md index 3ed469c43..1f73d069c 100644 --- a/api-server/docs/default_api.md +++ b/api-server/docs/default_api.md @@ -168,7 +168,7 @@ Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- **resume_at** | **String**| token that designates the point to resume from, that is find keys added after this point | **limit** | **i32**| The maximum number of events to return, default is 100. The max with data is 10000. | - **include_data** | **String**| Whether to include the event data (carfile) in the response. In the future, only the payload or other options may be supported: * `none` - Empty, only the event ID is returned * `full` - The entire envelope carfile (including the envelope and payload) | + **include_data** | **String**| Whether to include the event data (carfile) in the response. In the future, only the payload or other options may be supported: * `none` - Empty, only the event ID is returned * `payload` - Only the signed event payload data as a carfile. Unsigned and time events are unchanged. * `full` - The entire envelope carfile (including the envelope, capability and payload when applicable) | ### Return type diff --git a/api/ceramic.yaml b/api/ceramic.yaml index 99b4d6bd8..9af6b2d6e 100644 --- a/api/ceramic.yaml +++ b/api/ceramic.yaml @@ -302,12 +302,13 @@ paths: required: false schema: type: string - enum: [none, full] + enum: [none, payload, full] description: > Whether to include the event data (carfile) in the response. In the future, only the payload or other options may be supported: * `none` - Empty, only the event ID is returned - * `full` - The entire envelope carfile (including the envelope and payload) + * `payload` - Only the signed event payload data as a carfile. Unsigned and time events are unchanged. + * `full` - The entire envelope carfile (including the envelope, capability and payload when applicable) responses: "200": description: success diff --git a/api/src/server.rs b/api/src/server.rs index 69cee5f93..82972ade1 100644 --- a/api/src/server.rs +++ b/api/src/server.rs @@ -208,6 +208,7 @@ impl EventDataResult { #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum IncludeEventData { None, + Payload, Full, } @@ -216,6 +217,7 @@ impl TryFrom for IncludeEventData { fn try_from(value: String) -> Result { match value.as_str() { "none" => Ok(Self::None), + "payload" => Ok(Self::Payload), "full" => Ok(Self::Full), _ => Err(format!("Invalid value: {}.", value)), } @@ -441,7 +443,7 @@ where Err(e) => { return Ok(FeedEventsGetResponse::BadRequest( models::BadRequestResponse::new(format!( - "{} must be one of 'none' or 'full'", + "{} must be one of 'none', 'payload', or 'full'", e )), )) diff --git a/event/src/unvalidated/signed/mod.rs b/event/src/unvalidated/signed/mod.rs index 1c1e5c7e7..b99e98c90 100644 --- a/event/src/unvalidated/signed/mod.rs +++ b/event/src/unvalidated/signed/mod.rs @@ -138,6 +138,18 @@ impl Event { Ok(car) } + /// Encodes the signed event payload into a CAR file without the envelope or capability. + pub async fn encode_payload_car(&self) -> anyhow::Result> { + let payload_bytes = self.encode_payload()?; + let mut car = Vec::new(); + let roots: Vec = vec![self.payload_cid]; + let mut writer = CarWriter::new(CarHeader::V1(roots.into()), &mut car); + writer.write(self.payload_cid, payload_bytes).await?; + writer.finish().await?; + + Ok(car) + } + /// Accessor for the envelope and payload. pub fn into_parts(self) -> (Envelope, Payload) { (self.envelope, self.payload) diff --git a/service/src/event/store.rs b/service/src/event/store.rs index 3c3b12fc2..1c580b027 100644 --- a/service/src/event/store.rs +++ b/service/src/event/store.rs @@ -166,6 +166,23 @@ impl ceramic_api::EventStore for CeramicEventService { .collect(); (hw, res) } + ceramic_api::IncludeEventData::Payload => { + let (hw, data) = + CeramicOneEvent::new_events_since_value_with_data(&self.pool, highwater, limit) + .await?; + let mut res = Vec::with_capacity(data.len()); + for (cid, event) in data { + let encoded = match event { + ceramic_event::unvalidated::Event::Time(t) => t.encode_car().await?, + ceramic_event::unvalidated::Event::Signed(s) => { + s.encode_payload_car().await? + } + ceramic_event::unvalidated::Event::Unsigned(u) => u.encode_car().await?, + }; + res.push(ceramic_api::EventDataResult::new(cid, Some(encoded))); + } + (hw, res) + } ceramic_api::IncludeEventData::Full => { let (hw, data) = CeramicOneEvent::new_events_since_value_with_data(&self.pool, highwater, limit)