1use async_trait::async_trait;
6
7use std::path::Path;
8
9use coven_protocol::objects::{
10 BlobSpoolProtection, BlobSpoolWrite, BlobWriteAuthority, ExactObjectRef, ObjectSlot,
11 PreparedExactObject, ProtocolObjectContext, ResolvedProviderBinding, StorageError,
12};
13
14pub const BLOB_TOMBSTONE_PREFIX: &str = "blob_tombstones/";
15
16pub fn blob_tombstone_object_id(
17 stored: &coven_protocol::blob::locator::StoredBlobRef,
18) -> coven_protocol::store_commit::ObjectHash {
19 coven_protocol::remote_object::remote_object_id(stored.object())
20}
21
22pub fn blob_tombstone_key(
23 stored: &coven_protocol::blob::locator::StoredBlobRef,
24 suffix: &str,
25) -> String {
26 format!(
27 "{BLOB_TOMBSTONE_PREFIX}{}{suffix}",
28 blob_tombstone_object_id(stored)
29 )
30}
31
32#[derive(Clone, Debug)]
33pub enum ListedBlobTombstone {
34 Opened {
35 object_id: coven_protocol::store_commit::ObjectHash,
36 plaintext: Vec<u8>,
37 },
38 InvalidKey {
39 provider_key: String,
40 },
41 InvalidBody {
42 provider_key: String,
43 source: std::sync::Arc<coven_keys::encryption::EncryptionError>,
44 },
45}
46
47#[async_trait]
48pub trait CloudSyncObjectStorage: Send + Sync {
49 fn blob_path_scheme(&self) -> crate::BlobPathScheme;
51
52 async fn probe_provider(&self) -> Result<(), StorageError>;
54
55 fn provider_requests(
60 &self,
61 ) -> Option<std::sync::Arc<dyn coven_foundation::stage_timing::ProviderRequests>>;
62
63 async fn set_member_access(
65 &self,
66 state: crate::cloud::CloudAccessState,
67 ) -> Result<crate::cloud::CloudAccessOutcome, StorageError>;
68
69 async fn read_blob_tombstone(
70 &self,
71 stored: &coven_protocol::blob::locator::StoredBlobRef,
72 ) -> Result<Option<Vec<u8>>, StorageError>;
73
74 async fn write_blob_tombstone(
75 &self,
76 stored: &coven_protocol::blob::locator::StoredBlobRef,
77 plaintext: Vec<u8>,
78 ) -> Result<(), StorageError>;
79
80 async fn list_blob_tombstones(&self) -> Result<Vec<ListedBlobTombstone>, StorageError>;
81
82 async fn blob_tombstone_exists(
83 &self,
84 stored: &coven_protocol::blob::locator::StoredBlobRef,
85 ) -> Result<bool, StorageError>;
86
87 async fn delete_blob_tombstone(
88 &self,
89 stored: &coven_protocol::blob::locator::StoredBlobRef,
90 ) -> Result<(), StorageError>;
91
92 #[cfg(any(test, feature = "test-utils"))]
93 async fn read_provider_bytes_for_test(&self, key: &str) -> Result<Vec<u8>, StorageError>;
94
95 #[cfg(any(test, feature = "test-utils"))]
96 async fn write_provider_bytes_for_test(
97 &self,
98 key: &str,
99 bytes: Vec<u8>,
100 ) -> Result<(), StorageError>;
101
102 #[cfg(any(test, feature = "test-utils"))]
103 async fn list_provider_keys_for_test(&self, prefix: &str) -> Result<Vec<String>, StorageError>;
104
105 #[cfg(any(test, feature = "test-utils"))]
106 async fn provider_key_exists_for_test(&self, key: &str) -> Result<bool, StorageError>;
107
108 async fn reserve_cross_principal_response_slot(
109 &self,
110 probe_id: coven_protocol::provider::ProviderProbeId,
111 ) -> Result<ObjectSlot, coven_protocol::provider::ProviderProbeError>;
112
113 async fn prepare_cross_principal_challenge(
114 &self,
115 publication_journal: &dyn coven_protocol::provider::DeviceJoinChallengePublicationJournal,
116 probe_id: coven_protocol::provider::ProviderProbeId,
117 store: &coven_protocol::StoreProviderBinding,
118 context: &coven_protocol::provider::CrossPrincipalChallengeContext,
119 administrator_signer: &dyn coven_keys::keys::DeviceSigningAuthority,
120 ) -> Result<
121 coven_protocol::provider::CrossPrincipalProbeChallenge,
122 coven_protocol::provider::ProviderProbeError,
123 >;
124
125 async fn settle_cross_principal_challenge(
126 &self,
127 publication_journal: &dyn coven_protocol::provider::DeviceJoinChallengePublicationJournal,
128 authorization: &coven_protocol::provider::DeviceJoinChallengePublicationAuthorization,
129 challenge: &coven_protocol::provider::CrossPrincipalProbeChallenge,
130 context: &coven_protocol::provider::CrossPrincipalChallengeContext,
131 store: &coven_protocol::StoreProviderBinding,
132 ) -> Result<
133 coven_protocol::provider::CrossPrincipalProbeChallenge,
134 coven_protocol::provider::ProviderProbeError,
135 >;
136
137 async fn create_cross_principal_response(
138 &self,
139 challenge: &coven_protocol::provider::CrossPrincipalProbeChallenge,
140 context: &coven_protocol::provider::CrossPrincipalResponseContext,
141 store: &coven_protocol::StoreProviderBinding,
142 administrator_signing_pubkey: &str,
143 peer_signer: &coven_keys::keys::UserKeypair,
144 ) -> Result<
145 coven_protocol::provider::CrossPrincipalProbeResponse,
146 coven_protocol::provider::ProviderProbeError,
147 >;
148
149 async fn complete_cross_principal_probe(
150 &self,
151 journal: &dyn coven_protocol::provider::ProviderProbeJournal,
152 challenge: &coven_protocol::provider::CrossPrincipalProbeChallenge,
153 response: &coven_protocol::provider::CrossPrincipalProbeResponse,
154 context: &coven_protocol::provider::CrossPrincipalResponseContext,
155 store: &coven_protocol::StoreProviderBinding,
156 administrator_signer: &dyn coven_keys::keys::DeviceSigningAuthority,
157 peer_signing_pubkey: &str,
158 ) -> Result<
159 coven_protocol::provider::CrossPrincipalProbeReceipt,
160 coven_protocol::provider::ProviderProbeError,
161 >;
162
163 async fn probe_exact_slots(
164 &self,
165 journal: &dyn coven_protocol::provider::ProviderProbeJournal,
166 probe_id: coven_protocol::provider::ProviderProbeId,
167 binding: &ResolvedProviderBinding,
168 ) -> Result<
169 coven_protocol::provider::ExactSlotProbeReceipt,
170 coven_protocol::provider::ProviderProbeError,
171 >;
172
173 async fn observe_exact_slot(
176 &self,
177 slot: &ObjectSlot,
178 ) -> Result<Option<ExactObjectRef>, StorageError>;
179
180 async fn delete_exact_slot_and_verify_absent(
182 &self,
183 slot: &ObjectSlot,
184 ) -> Result<(), StorageError>;
185
186 fn store_blob_key_fingerprint(
189 &self,
190 ) -> Result<Option<coven_keys::encryption::KeyFingerprint>, StorageError>;
191
192 fn create_store_key_confirmation(
194 &self,
195 creation_id: coven_protocol::store_commit::StoreCreationId,
196 ) -> Result<coven_protocol::store_commit::StoreKeyConfirmation, StorageError>;
197
198 fn verify_store_key_confirmation(
200 &self,
201 creation_id: coven_protocol::store_commit::StoreCreationId,
202 confirmation: &coven_protocol::store_commit::StoreKeyConfirmation,
203 ) -> Result<(), StorageError>;
204
205 async fn provider_binding(&self) -> Result<ResolvedProviderBinding, StorageError>;
208
209 async fn allocate_protocol_slot(
211 &self,
212 context: &ProtocolObjectContext,
213 semantic_prefix: &str,
214 extension: &str,
215 ) -> Result<ObjectSlot, StorageError>;
216
217 fn prepare_protocol_object(
219 &self,
220 context: &ProtocolObjectContext,
221 slot: ObjectSlot,
222 semantic_prefix: &str,
223 data: Vec<u8>,
224 ) -> Result<PreparedExactObject, StorageError>;
225
226 async fn open_prepared_protocol_object(
230 &self,
231 context: &ProtocolObjectContext,
232 prepared: &PreparedExactObject,
233 semantic_prefix: &str,
234 ) -> Result<Vec<u8>, StorageError>;
235
236 async fn verify_prepared_protocol_object(
239 &self,
240 context: &ProtocolObjectContext,
241 prepared: &PreparedExactObject,
242 semantic_prefix: &str,
243 expected: &[u8],
244 ) -> Result<(), StorageError> {
245 if self
246 .open_prepared_protocol_object(context, prepared, semantic_prefix)
247 .await?
248 == expected
249 {
250 return Ok(());
251 }
252 Err(StorageError::PreparedObjectMismatch(
253 prepared.reference().slot().logical_key().to_string(),
254 ))
255 }
256
257 async fn create_verified_protocol_object(
260 &self,
261 context: &ProtocolObjectContext,
262 prepared: &PreparedExactObject,
263 semantic_prefix: &str,
264 expected: &[u8],
265 ) -> Result<(), StorageError> {
266 self.verify_prepared_protocol_object(context, prepared, semantic_prefix, expected)
267 .await?;
268 self.create_protocol_object(prepared).await
269 }
270
271 async fn create_protocol_object(
277 &self,
278 prepared: &PreparedExactObject,
279 ) -> Result<(), StorageError>;
280
281 async fn create_versioned_protocol_record(
284 &self,
285 context: &ProtocolObjectContext,
286 prepared: &PreparedExactObject,
287 semantic_prefix: &str,
288 expected: &[u8],
289 ) -> Result<crate::cloud::CloudObjectVersion, StorageError>;
290
291 async fn read_protocol_object(
294 &self,
295 context: &ProtocolObjectContext,
296 object: &ExactObjectRef,
297 semantic_prefix: &str,
298 ) -> Result<Vec<u8>, StorageError>;
299
300 async fn read_protocol_object_with_progress(
303 &self,
304 context: &ProtocolObjectContext,
305 object: &ExactObjectRef,
306 semantic_prefix: &str,
307 progress: crate::cloud::DownloadProgress,
308 ) -> Result<Vec<u8>, StorageError>;
309
310 async fn read_versioned_protocol_record(
313 &self,
314 context: &ProtocolObjectContext,
315 slot: &ObjectSlot,
316 semantic_prefix: &str,
317 ) -> Result<(Vec<u8>, crate::cloud::CloudObjectVersion), StorageError>;
318
319 async fn replace_protocol_record_if_version(
322 &self,
323 context: &ProtocolObjectContext,
324 slot: &ObjectSlot,
325 semantic_prefix: &str,
326 expected: &crate::cloud::CloudObjectVersion,
327 data: Vec<u8>,
328 ) -> Result<crate::cloud::ConditionalWriteOutcome, StorageError>;
329
330 async fn list_protocol_slots(
343 &self,
344 context: &ProtocolObjectContext,
345 listing_prefix: &str,
346 ) -> Result<Vec<ObjectSlot>, StorageError>;
347
348 async fn read_protocol_slot(
351 &self,
352 context: &ProtocolObjectContext,
353 slot: &ObjectSlot,
354 semantic_prefix: &str,
355 ) -> Result<(Vec<u8>, ExactObjectRef), StorageError>;
356
357 async fn read_prepared_protocol_slot(
360 &self,
361 context: &ProtocolObjectContext,
362 slot: &ObjectSlot,
363 semantic_prefix: &str,
364 ) -> Result<(Vec<u8>, PreparedExactObject), StorageError>;
365
366 async fn delete_protocol_object(&self, object: &ExactObjectRef) -> Result<(), StorageError>;
368
369 async fn allocate_blob_slot(
371 &self,
372 locator: &coven_protocol::blob::locator::BlobLocator,
373 authority: &BlobWriteAuthority<'_>,
374 ) -> Result<ObjectSlot, StorageError>;
375
376 async fn seal_blob_to_spool(
380 &self,
381 locator: &coven_protocol::blob::locator::BlobLocator,
382 authority: &BlobWriteAuthority<'_>,
383 protection: BlobSpoolProtection,
384 plaintext_file: &Path,
385 spool: coven_foundation::local_file::AtomicStagedFile,
386 progress: crate::cloud::PreparationProgress,
387 ) -> Result<BlobSpoolWrite, StorageError>;
388
389 async fn seal_store_blob_to_spool(
391 &self,
392 locator: &coven_protocol::blob::locator::BlobLocator,
393 authority: &BlobWriteAuthority<'_>,
394 plaintext_file: &Path,
395 spool: coven_foundation::local_file::AtomicStagedFile,
396 progress: crate::cloud::PreparationProgress,
397 ) -> Result<BlobSpoolWrite, StorageError>;
398
399 async fn prepare_blob_object(
401 &self,
402 locator: &coven_protocol::blob::locator::BlobLocator,
403 authority: &BlobWriteAuthority<'_>,
404 slot: ObjectSlot,
405 stored_file: &Path,
406 ) -> Result<coven_protocol::blob::locator::StoredBlobRef, StorageError>;
407
408 async fn create_blob_object_from_file(
410 &self,
411 blob: &coven_protocol::blob::locator::StoredBlobRef,
412 authority: &BlobWriteAuthority<'_>,
413 stored_file: &Path,
414 control: &crate::cloud::UploadControl,
415 ) -> Result<(), StorageError>;
416
417 async fn verify_blob_object(
419 &self,
420 blob: &coven_protocol::blob::locator::StoredBlobRef,
421 ) -> Result<(), StorageError>;
422
423 async fn stage_verified_blob_plaintext(
427 &self,
428 blob: &coven_protocol::blob::locator::StoredBlobRef,
429 protection: BlobSpoolProtection,
430 stage: coven_foundation::local_file::AtomicStagedFile,
431 progress: crate::cloud::DownloadProgress,
432 ) -> Result<coven_foundation::local_file::AtomicStagedFile, StorageError>;
433
434 async fn stage_verified_store_blob_plaintext(
436 &self,
437 blob: &coven_protocol::blob::locator::StoredBlobRef,
438 stage: coven_foundation::local_file::AtomicStagedFile,
439 progress: crate::cloud::DownloadProgress,
440 ) -> Result<coven_foundation::local_file::AtomicStagedFile, StorageError>;
441
442 async fn open_blob_range_reader(
448 &self,
449 blob: &coven_protocol::blob::locator::StoredBlobRef,
450 protection: BlobSpoolProtection,
451 ) -> Result<crate::BlobRangeReader, StorageError>;
452
453 async fn open_store_blob_range_reader(
455 &self,
456 blob: &coven_protocol::blob::locator::StoredBlobRef,
457 ) -> Result<crate::BlobRangeReader, StorageError>;
458
459 async fn delete_blob_object(
461 &self,
462 blob: &coven_protocol::blob::locator::StoredBlobRef,
463 ) -> Result<(), StorageError>;
464}