trussed_manage/
lib.rs

1// Copyright (C) Nitrokey GmbH
2// SPDX-License-Identifier: Apache-2.0 or MIT
3
4#![no_std]
5#![warn(non_ascii_idents, trivial_casts, unused, unused_qualifications)]
6#![deny(unsafe_code)]
7
8use littlefs2_core::{path, Path, PathBuf};
9use serde::{Deserialize, Serialize};
10use trussed_core::{
11    serde_extensions::{Extension, ExtensionClient, ExtensionResult},
12    Error,
13};
14
15pub struct ManageExtension;
16
17/// Factory reset the entire device
18///
19/// This will reset all filesystems
20#[derive(Debug, Deserialize, Serialize, Copy, Clone)]
21pub struct FactoryResetDeviceRequest;
22
23/// Factory reset a specific application
24///
25/// This will reset all data for a specific client
26#[derive(Debug, Deserialize, Serialize, Clone)]
27pub struct FactoryResetClientRequest {
28    pub client: PathBuf,
29}
30
31#[allow(clippy::large_enum_variant)]
32#[derive(Debug, Deserialize, Serialize, Clone)]
33pub enum ManageRequest {
34    FactoryResetDevice(FactoryResetDeviceRequest),
35    FactoryResetClient(FactoryResetClientRequest),
36}
37
38impl From<FactoryResetClientRequest> for ManageRequest {
39    fn from(value: FactoryResetClientRequest) -> Self {
40        Self::FactoryResetClient(value)
41    }
42}
43
44impl TryFrom<ManageRequest> for FactoryResetClientRequest {
45    type Error = Error;
46    fn try_from(value: ManageRequest) -> Result<Self, Self::Error> {
47        match value {
48            ManageRequest::FactoryResetClient(v) => Ok(v),
49            _ => Err(Error::InternalError),
50        }
51    }
52}
53
54impl From<FactoryResetDeviceRequest> for ManageRequest {
55    fn from(value: FactoryResetDeviceRequest) -> Self {
56        Self::FactoryResetDevice(value)
57    }
58}
59
60impl TryFrom<ManageRequest> for FactoryResetDeviceRequest {
61    type Error = Error;
62    fn try_from(value: ManageRequest) -> Result<Self, Self::Error> {
63        match value {
64            ManageRequest::FactoryResetDevice(v) => Ok(v),
65            _ => Err(Error::InternalError),
66        }
67    }
68}
69
70/// Factory reset the entire device
71///
72/// This will reset all filesystems
73#[derive(Debug, Deserialize, Serialize, Copy, Clone)]
74pub struct FactoryResetDeviceReply;
75
76/// Factory reset a specific application
77///
78/// This will reset all data for a specific client
79#[derive(Debug, Deserialize, Serialize, Clone)]
80pub struct FactoryResetClientReply;
81
82#[derive(Debug, Deserialize, Serialize, Clone)]
83pub enum ManageReply {
84    FactoryResetDevice(FactoryResetDeviceReply),
85    FactoryResetClient(FactoryResetClientReply),
86}
87
88impl From<FactoryResetClientReply> for ManageReply {
89    fn from(value: FactoryResetClientReply) -> Self {
90        Self::FactoryResetClient(value)
91    }
92}
93
94impl TryFrom<ManageReply> for FactoryResetClientReply {
95    type Error = Error;
96    fn try_from(value: ManageReply) -> Result<Self, Self::Error> {
97        match value {
98            ManageReply::FactoryResetClient(v) => Ok(v),
99            _ => Err(Error::InternalError),
100        }
101    }
102}
103
104impl From<FactoryResetDeviceReply> for ManageReply {
105    fn from(value: FactoryResetDeviceReply) -> Self {
106        Self::FactoryResetDevice(value)
107    }
108}
109
110impl TryFrom<ManageReply> for FactoryResetDeviceReply {
111    type Error = Error;
112    fn try_from(value: ManageReply) -> Result<Self, Self::Error> {
113        match value {
114            ManageReply::FactoryResetDevice(v) => Ok(v),
115            _ => Err(Error::InternalError),
116        }
117    }
118}
119
120impl Extension for ManageExtension {
121    type Request = ManageRequest;
122    type Reply = ManageReply;
123}
124
125pub type ManageResult<'a, R, C> = ExtensionResult<'a, ManageExtension, R, C>;
126
127pub trait ManageClient: ExtensionClient<ManageExtension> {
128    /// Factory reset the entire device
129    ///
130    /// This will reset all filesystems
131    fn factory_reset_device(&mut self) -> ManageResult<'_, FactoryResetDeviceReply, Self> {
132        self.extension(FactoryResetDeviceRequest)
133    }
134
135    /// Factory reset the entire client
136    ///
137    fn factory_reset_client(
138        &mut self,
139        client: &Path,
140    ) -> ManageResult<'_, FactoryResetClientReply, Self> {
141        self.extension(FactoryResetClientRequest {
142            client: client.into(),
143        })
144    }
145}
146
147impl<C: ExtensionClient<ManageExtension>> ManageClient for C {}
148
149/// Empty file written to mark that a file system should be reformatted
150///
151/// When booting, if this file is written to a filesystem, it means that the previous
152/// power cycle was caused by a factory reset and the storage should be reformatted
153pub const FACTORY_RESET_MARKER_FILE: &Path = path!("/factory-reset-must-reformat");