1use num_traits::{FromPrimitive, ToPrimitive};
5use server::{AsScalar, FromScalar, WithAppId};
6use xous::{AppId, PID};
7
8use crate::error::{AppManagerError, LaunchError};
9
10#[derive(Debug, server::Message)]
11#[response(Result<PID, AppManagerError>)]
12pub struct LaunchAppBlocking(pub AppId);
13
14#[derive(Debug, server::Message)]
15#[response(Result<(), AppManagerError>)]
16pub struct RefreshInstalledApps;
17
18#[derive(Debug, server::Message)]
22#[response(Result<(), AppManagerError>)]
23pub struct RefreshInstalledApp(pub AppId);
24
25impl AsScalar<3> for AppManagerError {
26 fn as_scalar(&self) -> [u32; 3] { [self.to_u32().unwrap(), 0, 0] }
27}
28
29impl FromScalar<3> for AppManagerError {
30 fn from_scalar([e, ..]: [u32; 3]) -> Self {
31 AppManagerError::from_u32(e).unwrap_or(AppManagerError::InternalError)
32 }
33}
34
35#[derive(Debug, Clone, server::Message, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
36#[event(AppEvent)]
37pub struct SubscribeAppEvents;
38
39#[derive(Debug, Clone, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
40pub enum AppEvent {
41 AppLaunching {
42 #[rkyv(with = WithAppId)]
43 app_id: AppId,
44 launched_by: PID,
45 },
46
47 AppLaunched {
48 #[rkyv(with = WithAppId)]
49 app_id: AppId,
50 pid: PID,
51 launched_by: PID,
52 },
53
54 AppCrashed {
55 #[rkyv(with = WithAppId)]
56 app_id: AppId,
57 pid: PID,
58 launched_by: PID,
59 exit_code: u32,
60 panic_message: Option<String>,
61 },
62
63 LaunchError {
64 #[rkyv(with = WithAppId)]
65 app_id: AppId,
66 error: LaunchError,
67 launched_by: PID,
68 },
69
70 AppRemoving {
71 #[rkyv(with = WithAppId)]
72 app_id: AppId,
73 },
74
75 AppRemovalFailed {
76 #[rkyv(with = WithAppId)]
77 app_id: AppId,
78 result: RemoveInstalledAppResult,
79 },
80
81 AppSetChanged {
87 #[rkyv(with = rkyv::with::Map<WithAppId>)]
88 installed: Vec<AppId>,
89 #[rkyv(with = rkyv::with::Map<WithAppId>)]
90 removed: Vec<AppId>,
91 },
92
93 AllowedPublishersChanged,
94}
95
96#[derive(Debug, server::Message)]
97pub struct LaunchApp(pub AppId);
98
99#[derive(Debug, server::Message)]
100pub struct RemoveApp(pub AppId);
101
102#[derive(Debug, Clone, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
103pub struct AppQrMatchRules {
104 #[rkyv(with = WithAppId)]
105 pub id: AppId,
106 pub rules_json: Vec<u8>,
107}
108
109#[derive(Debug, Clone, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
112pub struct InstalledAppPermissionSubgroup {
113 pub key: String,
114 pub label: String,
115 pub approved: bool,
116}
117
118#[derive(Debug, Clone, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
121pub struct InstalledAppPermissionGroup {
122 pub key: String,
123 pub label: String,
124 pub subgroups: Vec<InstalledAppPermissionSubgroup>,
125}
126
127#[derive(Debug, Clone, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
128pub struct InstalledAppInfo {
129 pub app_id: String,
130 pub name: String,
131 pub publisher_fingerprint: String,
135 pub publisher_name: String,
139 pub is_foundation_signed: bool,
142 pub launch_error: Option<LaunchError>,
146 pub can_remove: bool,
147 pub is_flux: bool,
150 pub version: String,
151 pub size_bytes: u64,
152 pub app_hash: [u8; 32],
154 pub description: String,
155 pub basic_permissions: Vec<InstalledAppPermissionGroup>,
157 pub approvable_permissions: Vec<InstalledAppPermissionGroup>,
159}
160
161#[derive(Debug, Clone, PartialEq, Eq, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
162pub enum SetAppPermissionGrantResult {
163 Updated,
164 AppNotFound,
165 PermissionNotFound,
166 NotUserGrantable,
167 Unauthorized,
168 StorageUnavailable,
169 InternalError,
170}
171
172#[derive(Debug, Clone, PartialEq, Eq, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
173pub struct PermissionRequestInfo {
174 #[rkyv(with = WithAppId)]
175 pub app_id: AppId,
176 pub app_name: String,
177 pub subgroup: String,
179 pub label: String,
181}
182
183#[derive(Debug, Clone, PartialEq, Eq, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
184pub enum PermissionRequestInfoResult {
185 Prompt(PermissionRequestInfo),
186 AlreadyApproved,
187 Denied,
188 NotGrantable,
189 AppNotFound,
190 Unauthorized,
191 InternalError,
192}
193
194#[derive(Debug, Clone, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
195pub struct ThirdPartyCertificateInfo {
196 pub name: String,
197 pub company: String,
198 pub contact_email: String,
199 pub support_url: String,
200 pub public_key: String,
202 pub fingerprint: String,
204 pub short_fingerprint: String,
206 pub added_unix_seconds: Option<u64>,
208 pub not_before_unix_seconds: u64,
209 pub not_after_unix_seconds: u64,
210 pub serial_number: String,
211 pub issuer: String,
212 pub subject: String,
213 pub basic_constraints: String,
214 pub key_usage: String,
215 pub extended_key_usage: String,
216}
217
218impl ThirdPartyCertificateInfo {
219 pub fn is_usable(&self) -> bool { !self.has_expired() && !self.is_not_yet_valid() }
222
223 pub fn has_expired(&self) -> bool { now_unix_seconds() > self.not_after_unix_seconds }
224
225 pub fn is_not_yet_valid(&self) -> bool { now_unix_seconds() < self.not_before_unix_seconds }
226}
227
228pub fn now_unix_seconds() -> u64 {
230 std::time::SystemTime::now()
231 .duration_since(std::time::UNIX_EPOCH)
232 .map(|elapsed| elapsed.as_secs())
233 .unwrap_or_default()
234}
235
236#[derive(Debug, Clone, Copy, PartialEq, Eq, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
239pub enum ThirdPartyCertificateError {
240 Invalid,
242 Expired {
243 not_after_unix_seconds: u64,
244 },
245 NotYetValid {
246 not_before_unix_seconds: u64,
247 },
248 FingerprintMismatch,
250 Internal,
251}
252
253#[derive(Debug, Clone, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
254pub enum RemoveThirdPartyCertificateResult {
255 Removed,
256 NotFound,
257 AppRequiresKey(String),
258 InternalError,
259}
260
261#[derive(Debug, Clone, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
262pub enum RemoveInstalledAppResult {
263 Removed,
264 NotSideloaded,
265 FluxAppsInstalled,
267 InternalError,
268}
269
270#[derive(Debug, Clone, server::Message, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
271#[response(Option<String>)]
272pub enum GetAppName {
273 ByAppId {
274 #[rkyv(with = WithAppId)]
275 id: AppId,
276 locale: String,
277 },
278
279 ByPid {
280 pid: PID,
281 locale: String,
282 },
283}
284
285impl GetAppName {
286 pub fn new_by_app_id(id: &AppId, locale: &str) -> Self {
287 Self::ByAppId { id: *id, locale: locale.to_string() }
288 }
289
290 pub fn new_by_pid(pid: PID, locale: &str) -> Self { Self::ByPid { pid, locale: locale.to_string() } }
291}
292
293#[derive(Debug, Clone, server::Message, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
294#[response(Vec<AppQrMatchRules>)]
295pub struct GetQrMatchRules {
297 #[rkyv(with = rkyv::with::Map<WithAppId>)]
298 pub app_ids: Vec<AppId>,
299}
300
301#[derive(Debug, Clone, Default, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
304pub struct AppFilter {
305 pub is_flux: Option<bool>,
306 pub sideloaded: Option<bool>,
309}
310
311impl AppFilter {
312 pub fn standard_only() -> Self { Self { is_flux: Some(false), ..Default::default() } }
314
315 pub fn flux_only() -> Self { Self { is_flux: Some(true), ..Default::default() } }
317
318 pub fn sideloaded_only() -> Self { Self { sideloaded: Some(true), ..Default::default() } }
320}
321
322#[derive(Debug, Clone, server::Message, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
323#[response(Vec<InstalledAppInfo>)]
324pub struct ListApps {
325 pub locale: String,
326 pub filter: AppFilter,
327}
328
329#[derive(Debug, Clone, Copy, PartialEq, Eq, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
331pub enum IconVariant {
332 Light,
333 Dark,
334}
335
336#[derive(Debug, Clone, server::Message, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
341#[response(Option<Vec<u8>>)]
342pub struct GetAppIcon {
343 pub app_id: String,
344 pub variant: IconVariant,
345}
346
347#[derive(Debug, Clone, Copy, PartialEq, Eq, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
350pub enum PermissionGrantDecision {
351 Allow,
353 Deny,
355 DenyForRun,
359}
360
361#[derive(Debug, Clone, server::Message, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
362#[response(SetAppPermissionGrantResult)]
363pub struct SetAppPermissionGrant {
364 pub app_id: String,
365 pub subgroup: String,
367 pub decision: PermissionGrantDecision,
368}
369
370#[derive(Debug, Clone, server::Message, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
371#[response(PermissionRequestInfoResult)]
372pub struct GetPermissionRequestInfo {
373 pub sender_app_id: [u8; 16],
376 pub server_sid: [u32; 4],
379 pub message_id: usize,
380 pub locale: String,
381}
382
383#[derive(Debug, Clone, server::Message, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
384#[response(Vec<ThirdPartyCertificateInfo>)]
385pub struct GetThirdPartyCertificates;
386
387#[derive(Debug, Clone, server::Message, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
388#[response(Result<ThirdPartyCertificateInfo, ThirdPartyCertificateError>)]
389pub struct PreviewThirdPartyCertificate {
390 pub certificate_pem: Vec<u8>,
391}
392
393#[derive(Debug, Clone, server::Message, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
394#[response(Result<ThirdPartyCertificateInfo, ThirdPartyCertificateError>)]
395pub struct ImportThirdPartyCertificate {
396 pub certificate_pem: Vec<u8>,
397 pub expected_fingerprint: String,
400}
401
402#[derive(Debug, Clone, server::Message, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
403#[response(RemoveThirdPartyCertificateResult)]
404pub struct RemoveThirdPartyCertificate {
405 pub fingerprint: String,
406 pub locale: String,
407}
408
409#[derive(Debug, Clone, Copy, PartialEq, Eq, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
413pub enum ArchiveLocation {
414 Internal,
415 Usb,
416 Airlock,
417}
418
419#[derive(Debug, Clone, PartialEq, Eq, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
420pub struct InstallAppArchiveResult {
421 pub app_name: String,
422}
423
424#[derive(Debug, Clone, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
427pub enum InstallError {
428 NotAnApp,
430 InvalidSignature,
432 FluxEmulatorMissing,
434 BuiltInApp,
437 PublisherMismatch,
440 AppRunning,
442 Fs(fs::Error),
444 Internal,
446}
447
448#[derive(Debug, Clone, server::Message, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
450#[response(Result<InstallAppArchiveResult, InstallError>)]
451pub struct InstallAppArchive {
452 pub path: String,
453 pub location: ArchiveLocation,
454 pub locale: String,
456}