Skip to main content

atmos/kernel/
app_sandbox.rs

1#![allow(dead_code)]
2
3use crate::os_lib::json::{parse_json, JsonValue};
4use alloc::string::String;
5use alloc::vec::Vec;
6
7/// アプリケーションのメタデータ情報を保持する構造体。
8/// `manifest.json` から読み込まれ、ウィンドウの初期設定や権限管理に利用されます。
9#[derive(Debug, Clone)]
10pub struct AppManifest {
11    pub name: String,
12    pub version: String,
13    pub display_name: String,
14    pub description: String,
15    pub entry: String,
16    pub permissions: Vec<String>,
17    /// 通常表示("normal")状態で起動する際の初期ウィンドウ幅
18    pub width: Option<u32>,
19    /// 通常表示("normal")状態で起動する際の初期ウィンドウ高さ
20    pub height: Option<u32>,
21}
22
23impl Default for AppManifest {
24    fn default() -> Self {
25        AppManifest {
26            name: String::from("unknown"),
27            version: String::from("1.0.0"),
28            display_name: String::from("Unknown App"),
29            description: String::new(),
30            entry: String::from("main.aura"),
31            permissions: Vec::new(),
32            width: None,
33            height: None,
34        }
35    }
36}
37
38impl AppManifest {
39    pub fn parse(json_str: &str) -> Option<Self> {
40        let json = parse_json(json_str).ok()?;
41
42        if let JsonValue::Object(map) = json {
43            let name = match map.get("name") {
44                Some(JsonValue::String(s)) => s.clone(),
45                _ => return None,
46            };
47
48            let version = match map.get("version") {
49                Some(JsonValue::String(s)) => s.clone(),
50                _ => String::from("1.0.0"),
51            };
52
53            let display_name = match map.get("display_name") {
54                Some(JsonValue::String(s)) => s.clone(),
55                _ => name.clone(),
56            };
57
58            let description = match map.get("description") {
59                Some(JsonValue::String(s)) => s.clone(),
60                _ => String::new(),
61            };
62
63            let entry = match map.get("entry") {
64                Some(JsonValue::String(s)) => s.clone(),
65                _ => String::from("main.aura"),
66            };
67
68            let mut permissions = Vec::new();
69            if let Some(JsonValue::Array(arr)) = map.get("permissions") {
70                for item in arr {
71                    if let JsonValue::String(s) = item {
72                        permissions.push(s.clone());
73                    }
74                }
75            }
76
77            // manifest.json からウィンドウのデフォルトサイズ定義(幅・高さ)を数値としてパース
78            let width = match map.get("width") {
79                Some(JsonValue::Number(n)) => Some(*n as u32),
80                _ => None,
81            };
82            let height = match map.get("height") {
83                Some(JsonValue::Number(n)) => Some(*n as u32),
84                _ => None,
85            };
86
87            return Some(AppManifest {
88                name,
89                version,
90                display_name,
91                description,
92                entry,
93                permissions,
94                width,
95                height,
96            });
97        }
98        None
99    }
100
101    pub fn has_permission(&self, perm: &str) -> bool {
102        self.permissions.iter().any(|p| p == perm)
103    }
104}
105
106#[derive(Debug, Clone)]
107pub struct AppSandbox {
108    pub app_id: usize,
109    pub manifest: AppManifest,
110    pub data_dir: String,
111}
112
113impl AppSandbox {
114    pub fn new(app_id: usize, manifest: AppManifest) -> Self {
115        let data_dir = alloc::format!("/data/apps/{}/", manifest.name);
116        Self {
117            app_id,
118            manifest,
119            data_dir,
120        }
121    }
122
123    // サンドボックス内のパス解決と権限チェック
124    // 許可されたパスなら絶対パスを返し、ダメなら None を返す
125    pub fn resolve_path(&self, requested_path: &str) -> Option<String> {
126        // パストラバーサル対策 (簡易)
127        if requested_path.contains("..") {
128            return None;
129        }
130
131        // 自身のデータディレクトリ内のアクセスは常に許可
132        if requested_path.starts_with(&self.data_dir) {
133            return Some(String::from(requested_path));
134        }
135
136        // グローバルファイルシステムへのアクセス要求
137        if self.manifest.has_permission("fs_global") {
138            return Some(String::from(requested_path));
139        }
140
141        // ユーザーディレクトリへのアクセス要求
142        if requested_path.starts_with("/user/") && self.manifest.has_permission("fs_user") {
143            return Some(String::from(requested_path));
144        }
145
146        None
147    }
148}