1#![no_std]
5#![warn(non_ascii_idents, trivial_casts, unused, unused_qualifications)]
6#![deny(unsafe_code)]
7
8pub mod utils;
9
10use serde::{Deserialize, Serialize};
11use serde_byte_array::ByteArray;
12use trussed_core::{
13 serde_extensions::{Extension, ExtensionClient, ExtensionResult},
14 types::{KeyId, Location, Message, PathBuf, UserAttribute},
15 FilesystemClient,
16};
17
18pub const CHACHA8_STREAM_NONCE_LEN: usize = 8;
19
20#[derive(Debug, Default)]
21pub struct ChunkedExtension;
22
23impl Extension for ChunkedExtension {
24 type Request = ChunkedRequest;
25 type Reply = ChunkedReply;
26}
27
28#[derive(Debug, Deserialize, Serialize, PartialEq, Eq)]
29#[allow(missing_docs, clippy::large_enum_variant)]
30pub enum ChunkedRequest {
31 StartChunkedWrite(request::StartChunkedWrite),
32 StartEncryptedChunkedWrite(request::StartEncryptedChunkedWrite),
33 StartChunkedRead(request::StartChunkedRead),
34 StartEncryptedChunkedRead(request::StartEncryptedChunkedRead),
35 ReadChunk(request::ReadChunk),
36 WriteChunk(request::WriteChunk),
37 AbortChunkedWrite(request::AbortChunkedWrite),
38 PartialReadFile(request::PartialReadFile),
39 AppendFile(request::AppendFile),
40}
41
42#[derive(Debug, Deserialize, Serialize)]
43#[allow(missing_docs)]
44pub enum ChunkedReply {
45 ReadChunk(reply::ReadChunk),
46 StartChunkedWrite(reply::StartChunkedWrite),
47 StartEncryptedChunkedWrite(reply::StartEncryptedChunkedWrite),
48 StartChunkedRead(reply::StartChunkedRead),
49 StartEncryptedChunkedRead(reply::StartEncryptedChunkedRead),
50 WriteChunk(reply::WriteChunk),
51 AbortChunkedWrite(reply::AbortChunkedWrite),
52 PartialReadFile(reply::PartialReadFile),
53 AppendFile(reply::AppendFile),
54}
55
56pub mod request {
57 use super::*;
58 use serde::{Deserialize, Serialize};
59 use serde_byte_array::ByteArray;
60 use trussed_core::types::{KeyId, Location, Message, PathBuf, UserAttribute};
61 use trussed_core::Error;
62
63 #[derive(Debug, PartialEq, Eq, Deserialize, Serialize)]
64 pub struct ReadChunk {}
65
66 impl TryFrom<ChunkedRequest> for ReadChunk {
67 type Error = Error;
68 fn try_from(request: ChunkedRequest) -> Result<Self, Self::Error> {
69 match request {
70 ChunkedRequest::ReadChunk(request) => Ok(request),
71 _ => Err(Error::InternalError),
72 }
73 }
74 }
75
76 impl From<ReadChunk> for ChunkedRequest {
77 fn from(request: ReadChunk) -> Self {
78 Self::ReadChunk(request)
79 }
80 }
81
82 #[derive(Debug, PartialEq, Eq, Deserialize, Serialize)]
83 pub struct StartChunkedWrite {
84 pub location: Location,
85 pub path: PathBuf,
86 pub user_attribute: Option<UserAttribute>,
87 }
88
89 impl TryFrom<ChunkedRequest> for StartChunkedWrite {
90 type Error = Error;
91 fn try_from(request: ChunkedRequest) -> Result<Self, Self::Error> {
92 match request {
93 ChunkedRequest::StartChunkedWrite(request) => Ok(request),
94 _ => Err(Error::InternalError),
95 }
96 }
97 }
98
99 impl From<StartChunkedWrite> for ChunkedRequest {
100 fn from(request: StartChunkedWrite) -> Self {
101 Self::StartChunkedWrite(request)
102 }
103 }
104
105 #[derive(Debug, PartialEq, Eq, Deserialize, Serialize)]
106 pub struct StartEncryptedChunkedWrite {
107 pub location: Location,
108 pub path: PathBuf,
109 pub user_attribute: Option<UserAttribute>,
110 pub key: KeyId,
111 pub nonce: Option<ByteArray<CHACHA8_STREAM_NONCE_LEN>>,
112 }
113
114 impl TryFrom<ChunkedRequest> for StartEncryptedChunkedWrite {
115 type Error = Error;
116 fn try_from(request: ChunkedRequest) -> Result<Self, Self::Error> {
117 match request {
118 ChunkedRequest::StartEncryptedChunkedWrite(request) => Ok(request),
119 _ => Err(Error::InternalError),
120 }
121 }
122 }
123
124 impl From<StartEncryptedChunkedWrite> for ChunkedRequest {
125 fn from(request: StartEncryptedChunkedWrite) -> Self {
126 Self::StartEncryptedChunkedWrite(request)
127 }
128 }
129
130 #[derive(Debug, PartialEq, Eq, Deserialize, Serialize)]
131 pub struct StartChunkedRead {
132 pub location: Location,
133 pub path: PathBuf,
134 }
135
136 impl TryFrom<ChunkedRequest> for StartChunkedRead {
137 type Error = Error;
138 fn try_from(request: ChunkedRequest) -> Result<Self, Self::Error> {
139 match request {
140 ChunkedRequest::StartChunkedRead(request) => Ok(request),
141 _ => Err(Error::InternalError),
142 }
143 }
144 }
145
146 impl From<StartChunkedRead> for ChunkedRequest {
147 fn from(request: StartChunkedRead) -> Self {
148 Self::StartChunkedRead(request)
149 }
150 }
151
152 #[derive(Debug, PartialEq, Eq, Deserialize, Serialize)]
153 pub struct StartEncryptedChunkedRead {
154 pub location: Location,
155 pub path: PathBuf,
156 pub key: KeyId,
157 }
158
159 impl TryFrom<ChunkedRequest> for StartEncryptedChunkedRead {
160 type Error = Error;
161 fn try_from(request: ChunkedRequest) -> Result<Self, Self::Error> {
162 match request {
163 ChunkedRequest::StartEncryptedChunkedRead(request) => Ok(request),
164 _ => Err(Error::InternalError),
165 }
166 }
167 }
168
169 impl From<StartEncryptedChunkedRead> for ChunkedRequest {
170 fn from(request: StartEncryptedChunkedRead) -> Self {
171 Self::StartEncryptedChunkedRead(request)
172 }
173 }
174
175 #[derive(Debug, PartialEq, Eq, Deserialize, Serialize)]
176 pub struct WriteChunk {
177 pub data: Message,
178 }
179
180 impl TryFrom<ChunkedRequest> for WriteChunk {
181 type Error = Error;
182 fn try_from(request: ChunkedRequest) -> Result<Self, Self::Error> {
183 match request {
184 ChunkedRequest::WriteChunk(request) => Ok(request),
185 _ => Err(Error::InternalError),
186 }
187 }
188 }
189
190 impl From<WriteChunk> for ChunkedRequest {
191 fn from(request: WriteChunk) -> Self {
192 Self::WriteChunk(request)
193 }
194 }
195
196 #[derive(Debug, PartialEq, Eq, Deserialize, Serialize)]
197 pub struct AbortChunkedWrite {}
198
199 impl TryFrom<ChunkedRequest> for AbortChunkedWrite {
200 type Error = Error;
201 fn try_from(request: ChunkedRequest) -> Result<Self, Self::Error> {
202 match request {
203 ChunkedRequest::AbortChunkedWrite(request) => Ok(request),
204 _ => Err(Error::InternalError),
205 }
206 }
207 }
208
209 impl From<AbortChunkedWrite> for ChunkedRequest {
210 fn from(request: AbortChunkedWrite) -> Self {
211 Self::AbortChunkedWrite(request)
212 }
213 }
214
215 #[derive(Debug, PartialEq, Eq, Deserialize, Serialize)]
216 pub struct PartialReadFile {
217 pub location: Location,
218 pub path: PathBuf,
219 pub offset: usize,
220 pub length: usize,
221 }
222
223 impl TryFrom<ChunkedRequest> for PartialReadFile {
224 type Error = Error;
225 fn try_from(request: ChunkedRequest) -> Result<Self, Self::Error> {
226 match request {
227 ChunkedRequest::PartialReadFile(request) => Ok(request),
228 _ => Err(Error::InternalError),
229 }
230 }
231 }
232
233 impl From<PartialReadFile> for ChunkedRequest {
234 fn from(request: PartialReadFile) -> Self {
235 Self::PartialReadFile(request)
236 }
237 }
238
239 #[derive(Debug, PartialEq, Eq, Deserialize, Serialize)]
240 pub struct AppendFile {
241 pub location: Location,
242 pub path: PathBuf,
243 pub data: Message,
244 }
245
246 impl TryFrom<ChunkedRequest> for AppendFile {
247 type Error = Error;
248 fn try_from(request: ChunkedRequest) -> Result<Self, Self::Error> {
249 match request {
250 ChunkedRequest::AppendFile(request) => Ok(request),
251 _ => Err(Error::InternalError),
252 }
253 }
254 }
255
256 impl From<AppendFile> for ChunkedRequest {
257 fn from(request: AppendFile) -> Self {
258 Self::AppendFile(request)
259 }
260 }
261}
262
263pub mod reply {
264 use super::*;
265 use serde::{Deserialize, Serialize};
266 use trussed_core::types::Message;
267 use trussed_core::Error;
268
269 #[derive(Debug, PartialEq, Eq, Deserialize, Serialize)]
270 pub struct ReadChunk {
271 pub data: Message,
272 pub len: usize,
273 }
274
275 impl TryFrom<ChunkedReply> for ReadChunk {
276 type Error = Error;
277 fn try_from(reply: ChunkedReply) -> Result<Self, Self::Error> {
278 match reply {
279 ChunkedReply::ReadChunk(reply) => Ok(reply),
280 _ => Err(Error::InternalError),
281 }
282 }
283 }
284
285 impl From<ReadChunk> for ChunkedReply {
286 fn from(reply: ReadChunk) -> Self {
287 Self::ReadChunk(reply)
288 }
289 }
290
291 #[derive(Debug, PartialEq, Eq, Deserialize, Serialize)]
292 pub struct StartChunkedWrite {}
293
294 impl TryFrom<ChunkedReply> for StartChunkedWrite {
295 type Error = Error;
296 fn try_from(reply: ChunkedReply) -> Result<Self, Self::Error> {
297 match reply {
298 ChunkedReply::StartChunkedWrite(reply) => Ok(reply),
299 _ => Err(Error::InternalError),
300 }
301 }
302 }
303
304 impl From<StartChunkedWrite> for ChunkedReply {
305 fn from(reply: StartChunkedWrite) -> Self {
306 Self::StartChunkedWrite(reply)
307 }
308 }
309
310 #[derive(Debug, PartialEq, Eq, Deserialize, Serialize)]
311 pub struct StartEncryptedChunkedWrite {}
312
313 impl TryFrom<ChunkedReply> for StartEncryptedChunkedWrite {
314 type Error = Error;
315 fn try_from(reply: ChunkedReply) -> Result<Self, Self::Error> {
316 match reply {
317 ChunkedReply::StartEncryptedChunkedWrite(reply) => Ok(reply),
318 _ => Err(Error::InternalError),
319 }
320 }
321 }
322
323 impl From<StartEncryptedChunkedWrite> for ChunkedReply {
324 fn from(reply: StartEncryptedChunkedWrite) -> Self {
325 Self::StartEncryptedChunkedWrite(reply)
326 }
327 }
328
329 #[derive(Debug, PartialEq, Eq, Deserialize, Serialize)]
330 pub struct StartChunkedRead {
331 pub data: Message,
332 pub len: usize,
333 }
334
335 impl TryFrom<ChunkedReply> for StartChunkedRead {
336 type Error = Error;
337 fn try_from(reply: ChunkedReply) -> Result<Self, Self::Error> {
338 match reply {
339 ChunkedReply::StartChunkedRead(reply) => Ok(reply),
340 _ => Err(Error::InternalError),
341 }
342 }
343 }
344
345 impl From<StartChunkedRead> for ChunkedReply {
346 fn from(reply: StartChunkedRead) -> Self {
347 Self::StartChunkedRead(reply)
348 }
349 }
350
351 #[derive(Debug, PartialEq, Eq, Deserialize, Serialize)]
352 pub struct StartEncryptedChunkedRead {}
353
354 impl TryFrom<ChunkedReply> for StartEncryptedChunkedRead {
355 type Error = Error;
356 fn try_from(reply: ChunkedReply) -> Result<Self, Self::Error> {
357 match reply {
358 ChunkedReply::StartEncryptedChunkedRead(reply) => Ok(reply),
359 _ => Err(Error::InternalError),
360 }
361 }
362 }
363
364 impl From<StartEncryptedChunkedRead> for ChunkedReply {
365 fn from(reply: StartEncryptedChunkedRead) -> Self {
366 Self::StartEncryptedChunkedRead(reply)
367 }
368 }
369
370 #[derive(Debug, PartialEq, Eq, Deserialize, Serialize)]
371 pub struct WriteChunk {}
372
373 impl TryFrom<ChunkedReply> for WriteChunk {
374 type Error = Error;
375 fn try_from(reply: ChunkedReply) -> Result<Self, Self::Error> {
376 match reply {
377 ChunkedReply::WriteChunk(reply) => Ok(reply),
378 _ => Err(Error::InternalError),
379 }
380 }
381 }
382
383 impl From<WriteChunk> for ChunkedReply {
384 fn from(reply: WriteChunk) -> Self {
385 Self::WriteChunk(reply)
386 }
387 }
388
389 #[derive(Debug, PartialEq, Eq, Deserialize, Serialize)]
390 pub struct AbortChunkedWrite {
391 pub aborted: bool,
392 }
393
394 impl TryFrom<ChunkedReply> for AbortChunkedWrite {
395 type Error = Error;
396 fn try_from(reply: ChunkedReply) -> Result<Self, Self::Error> {
397 match reply {
398 ChunkedReply::AbortChunkedWrite(reply) => Ok(reply),
399 _ => Err(Error::InternalError),
400 }
401 }
402 }
403
404 impl From<AbortChunkedWrite> for ChunkedReply {
405 fn from(reply: AbortChunkedWrite) -> Self {
406 Self::AbortChunkedWrite(reply)
407 }
408 }
409
410 #[derive(Debug, PartialEq, Eq, Deserialize, Serialize)]
411 pub struct PartialReadFile {
412 pub data: Message,
413 pub file_length: usize,
414 }
415
416 impl TryFrom<ChunkedReply> for PartialReadFile {
417 type Error = Error;
418 fn try_from(reply: ChunkedReply) -> Result<Self, Self::Error> {
419 match reply {
420 ChunkedReply::PartialReadFile(reply) => Ok(reply),
421 _ => Err(Error::InternalError),
422 }
423 }
424 }
425
426 impl From<PartialReadFile> for ChunkedReply {
427 fn from(reply: PartialReadFile) -> Self {
428 Self::PartialReadFile(reply)
429 }
430 }
431
432 #[derive(Debug, PartialEq, Eq, Deserialize, Serialize)]
433 pub struct AppendFile {
434 pub file_length: usize,
435 }
436
437 impl TryFrom<ChunkedReply> for AppendFile {
438 type Error = Error;
439 fn try_from(reply: ChunkedReply) -> Result<Self, Self::Error> {
440 match reply {
441 ChunkedReply::AppendFile(reply) => Ok(reply),
442 _ => Err(Error::InternalError),
443 }
444 }
445 }
446
447 impl From<AppendFile> for ChunkedReply {
448 fn from(reply: AppendFile) -> Self {
449 Self::AppendFile(reply)
450 }
451 }
452}
453
454pub type ChunkedResult<'a, R, C> = ExtensionResult<'a, ChunkedExtension, R, C>;
455
456pub trait ChunkedClient: ExtensionClient<ChunkedExtension> + FilesystemClient {
457 fn start_chunked_write(
462 &mut self,
463 location: Location,
464 path: PathBuf,
465 user_attribute: Option<UserAttribute>,
466 ) -> ChunkedResult<'_, reply::StartChunkedWrite, Self> {
467 self.extension(request::StartChunkedWrite {
468 location,
469 path,
470 user_attribute,
471 })
472 }
473
474 fn start_encrypted_chunked_write(
479 &mut self,
480 location: Location,
481 path: PathBuf,
482 key: KeyId,
483 nonce: Option<ByteArray<CHACHA8_STREAM_NONCE_LEN>>,
484 user_attribute: Option<UserAttribute>,
485 ) -> ChunkedResult<'_, reply::StartEncryptedChunkedWrite, Self> {
486 self.extension(request::StartEncryptedChunkedWrite {
487 location,
488 path,
489 key,
490 user_attribute,
491 nonce,
492 })
493 }
494
495 fn start_chunked_read(
500 &mut self,
501 location: Location,
502 path: PathBuf,
503 ) -> ChunkedResult<'_, reply::StartChunkedRead, Self> {
504 self.extension(request::StartChunkedRead { location, path })
505 }
506
507 fn start_encrypted_chunked_read(
513 &mut self,
514 location: Location,
515 path: PathBuf,
516 key: KeyId,
517 ) -> ChunkedResult<'_, reply::StartEncryptedChunkedRead, Self> {
518 self.extension(request::StartEncryptedChunkedRead {
519 location,
520 path,
521 key,
522 })
523 }
524
525 fn write_file_chunk(&mut self, data: Message) -> ChunkedResult<'_, reply::WriteChunk, Self> {
529 self.extension(request::WriteChunk { data })
530 }
531
532 fn abort_chunked_write(&mut self) -> ChunkedResult<'_, reply::AbortChunkedWrite, Self> {
534 self.extension(request::AbortChunkedWrite {})
535 }
536
537 fn read_file_chunk(&mut self) -> ChunkedResult<'_, reply::ReadChunk, Self> {
539 self.extension(request::ReadChunk {})
540 }
541
542 fn partial_read_file(
548 &mut self,
549 location: Location,
550 path: PathBuf,
551 offset: usize,
552 length: usize,
553 ) -> ChunkedResult<'_, reply::PartialReadFile, Self> {
554 self.extension(request::PartialReadFile {
555 location,
556 path,
557 offset,
558 length,
559 })
560 }
561
562 fn append_file(
564 &mut self,
565 location: Location,
566 path: PathBuf,
567 data: Message,
568 ) -> ChunkedResult<'_, reply::AppendFile, Self> {
569 self.extension(request::AppendFile {
570 location,
571 path,
572 data,
573 })
574 }
575}
576
577impl<C: ExtensionClient<ChunkedExtension> + FilesystemClient> ChunkedClient for C {}