Skip to main content

objectstore_service/
resumable.rs

1//! Types supporting authenticated Resumable Upload Session tokens.
2//!
3//! Storage backends represent their opaque upload state as a [`BackendToken`]. At the service
4//! boundary, `SessionToken` combines that state with service-specific fields, and
5//! [`crate::encryption::Cipher`] protects the serialized token before it is returned to the server.
6//!
7//! ```text
8//! Storage backend       | objectstore-service                         | objectstore-server             |
9//! BackendToken <------->| SessionToken ---------- Cipher ------------>| EncryptedSessionToken          |
10//! opaque backend state  | { ObjectId, BackendToken }                  | b64url encoded opaque envelope |
11//! ```
12
13use serde::{Deserialize, Deserializer, Serialize, Serializer, de};
14
15use crate::id::ObjectId;
16
17pub use objectstore_types::resumable::{
18    SessionToken as EncryptedSessionToken, UploadOffset, UploadProgress,
19};
20
21/// Opaque session state encoded and decoded by a storage backend.
22pub type BackendToken = String;
23
24/// Structured token encrypted at the service boundary.
25#[derive(Deserialize, Serialize)]
26pub(crate) struct SessionToken {
27    #[serde(
28        serialize_with = "serialize_object_id",
29        deserialize_with = "deserialize_object_id"
30    )]
31    pub(crate) object_id: ObjectId,
32    pub(crate) backend_token: BackendToken,
33}
34
35fn serialize_object_id<S>(id: &ObjectId, serializer: S) -> std::result::Result<S::Ok, S::Error>
36where
37    S: Serializer,
38{
39    serializer.collect_str(&id.as_storage_path())
40}
41
42fn deserialize_object_id<'de, D>(deserializer: D) -> std::result::Result<ObjectId, D::Error>
43where
44    D: Deserializer<'de>,
45{
46    let path = String::deserialize(deserializer)?;
47    ObjectId::from_storage_path(&path)
48        .ok_or_else(|| de::Error::custom("invalid object storage path"))
49}