Skip to main content

core_api/host/
permissions.rs

1//! OS authorization for one Host identity; independent of any Space.
2//!
3//! Installed packages declare uses per OS. The Host merges uses by PermissionKey,
4//! including stopped services. Merely reading this snapshot MUST NOT request OS
5//! authorization. Local Network has no general passive status API: a probe result
6//! is historical evidence, never a silently refreshed system setting.
7use serde::{Deserialize, Serialize};
8use std::collections::BTreeMap;
9
10pub type PlatformPermissionRequirements = BTreeMap<String, Vec<PermissionRequirement>>;
11
12/// Automation is authorized per target application, not as one global switch.
13#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
14#[serde(tag = "id", rename_all = "camelCase", deny_unknown_fields)]
15pub enum PermissionKey {
16    LocalNetwork {},
17    Bluetooth {},
18    Microphone {},
19    Reminders {},
20    Automation {
21        #[serde(rename = "targetBundleId")]
22        target_bundle_id: String,
23    },
24}
25
26#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
27#[serde(rename_all = "camelCase", deny_unknown_fields)]
28pub struct PermissionRequirement {
29    pub permission: PermissionKey,
30    /// Human-readable affected capability; denial need not disable the service.
31    pub feature: String,
32    pub reason: String,
33}
34
35#[derive(Debug, Clone, Serialize, Deserialize)]
36#[serde(rename_all = "camelCase", deny_unknown_fields)]
37pub struct PermissionUse {
38    pub component_id: String,
39    pub component_name: String,
40    pub feature: String,
41    pub reason: String,
42}
43
44#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
45#[serde(rename_all = "camelCase")]
46pub enum PermissionState {
47    Unknown,
48    NotDetermined,
49    Granted,
50    Denied,
51    Restricted,
52    Unsupported,
53}
54
55#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
56#[serde(rename_all = "camelCase")]
57pub enum PermissionEvidence {
58    /// A passive OS authorization query, not hardware availability.
59    System,
60    /// A previous explicit request/probe; observedAtMs is mandatory.
61    Probe,
62    Unavailable,
63}
64
65#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
66#[serde(rename_all = "camelCase")]
67pub enum PermissionAction {
68    Request,
69    OpenSettings,
70}
71
72#[derive(Debug, Clone, Serialize, Deserialize)]
73#[serde(rename_all = "camelCase", deny_unknown_fields)]
74pub struct HostPermission {
75    pub permission: PermissionKey,
76    pub state: PermissionState,
77    pub evidence: PermissionEvidence,
78    pub observed_at_ms: Option<i64>,
79    pub uses: Vec<PermissionUse>,
80    /// Mechanisms supported by this Host, NOT authority for a remote caller.
81    pub supported_actions: Vec<PermissionAction>,
82    pub error: Option<String>,
83}
84
85#[derive(Debug, Clone, Serialize, Deserialize)]
86#[serde(rename_all = "camelCase", deny_unknown_fields)]
87pub struct PermissionDeclarationError {
88    pub component_id: String,
89    pub message: String,
90}
91
92#[derive(Debug, Clone, Serialize, Deserialize)]
93#[serde(rename_all = "camelCase", deny_unknown_fields)]
94pub struct HostPermissions {
95    pub host_id: String,
96    pub subject_id: String,
97    pub subject_name: String,
98    pub host_version: String,
99    pub platform: String,
100    pub observed_at_ms: i64,
101    pub permissions: Vec<HostPermission>,
102    /// Missing, malformed or unsupported declarations must remain visible.
103    /// An empty permission list is not proof that the inventory is complete.
104    pub declaration_errors: Vec<PermissionDeclarationError>,
105}
106
107/// Internal local-control request. Not an App Facade operation. The server must
108/// verify the local control credential and Host identity; this DTO deliberately
109/// has no caller-controlled isLocal flag or arbitrary Settings URL.
110#[derive(Debug, Clone, Serialize, Deserialize)]
111#[serde(rename_all = "camelCase", deny_unknown_fields)]
112pub struct HostPermissionRequest {
113    pub host_id: String,
114    pub permission: PermissionKey,
115}
116
117pub const HOST_PERMISSIONS_PATH: &str = "/v1/permissions";
118pub const HOST_PERMISSION_REQUEST_PATH: &str = "/internal/permissions/request";
119pub const HOST_PERMISSION_SETTINGS_PATH: &str = "/internal/permissions/open-settings";