1#![allow(dead_code)]
8#![allow(static_mut_refs)]
9
10extern crate alloc;
11use alloc::string::String;
12use alloc::vec::Vec;
13
14use crate::kernel::draw::{Color, Screen};
15use crate::kernel::fs;
16use crate::kernel::timer;
17
18#[derive(Debug, Clone, Copy, PartialEq, Eq)]
19pub enum LoginState {
20 SetupInput, SetupConfirm, Locked, Unlocked, }
25
26pub struct LoginManager {
27 state: LoginState,
28 current_input: Vec<u8>,
29 setup_password: Vec<u8>,
30 saved_password_hash: [u8; 32],
31 error_ticks_end: usize,
32 error_msg: &'static str,
33 pub needs_redraw: bool,
34}
35
36pub fn sha256(data: &[u8]) -> [u8; 32] {
38 let mut h: [u32; 8] = [
39 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab,
40 0x5be0cd19,
41 ];
42
43 let k: [u32; 64] = [
44 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4,
45 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe,
46 0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f,
47 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7,
48 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc,
49 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b,
50 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, 0x19a4c116,
51 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
52 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7,
53 0xc67178f2,
54 ];
55
56 let len = data.len();
57 let mut padded = alloc::vec![0u8; ((len + 8 + 64) / 64) * 64];
58 padded[..len].copy_from_slice(data);
59 padded[len] = 0x80;
60
61 let bit_len = (len as u64) * 8;
62 let bit_len_bytes = bit_len.to_be_bytes();
63 let pad_len = padded.len();
64 padded[pad_len - 8..].copy_from_slice(&bit_len_bytes);
65
66 for block in padded.chunks_exact(64) {
67 let mut w = [0u32; 64];
68 for i in 0..16 {
69 let mut bytes = [0u8; 4];
70 bytes.copy_from_slice(&block[i * 4..(i + 1) * 4]);
71 w[i] = u32::from_be_bytes(bytes);
72 }
73
74 for i in 16..64 {
75 let s0 = w[i - 15].rotate_right(7) ^ w[i - 15].rotate_right(18) ^ (w[i - 15] >> 3);
76 let s1 = w[i - 2].rotate_right(17) ^ w[i - 2].rotate_right(19) ^ (w[i - 2] >> 10);
77 w[i] = w[i - 16]
78 .wrapping_add(s0)
79 .wrapping_add(w[i - 7])
80 .wrapping_add(s1);
81 }
82
83 let mut a = h[0];
84 let mut b = h[1];
85 let mut c = h[2];
86 let mut d = h[3];
87 let mut e = h[4];
88 let mut f = h[5];
89 let mut g = h[6];
90 let mut h_val = h[7];
91
92 for i in 0..64 {
93 let s1 = e.rotate_right(6) ^ e.rotate_right(11) ^ e.rotate_right(25);
94 let ch = (e & f) ^ ((!e) & g);
95 let temp1 = h_val
96 .wrapping_add(s1)
97 .wrapping_add(ch)
98 .wrapping_add(k[i])
99 .wrapping_add(w[i]);
100 let s0 = a.rotate_right(2) ^ a.rotate_right(13) ^ a.rotate_right(22);
101 let maj = (a & b) ^ (a & c) ^ (b & c);
102 let temp2 = s0.wrapping_add(maj);
103
104 h_val = g;
105 g = f;
106 f = e;
107 e = d.wrapping_add(temp1);
108 d = c;
109 c = b;
110 b = a;
111 a = temp1.wrapping_add(temp2);
112 }
113
114 h[0] = h[0].wrapping_add(a);
115 h[1] = h[1].wrapping_add(b);
116 h[2] = h[2].wrapping_add(c);
117 h[3] = h[3].wrapping_add(d);
118 h[4] = h[4].wrapping_add(e);
119 h[5] = h[5].wrapping_add(f);
120 h[6] = h[6].wrapping_add(g);
121 h[7] = h[7].wrapping_add(h_val);
122 }
123
124 let mut result = [0u8; 32];
125 for i in 0..8 {
126 result[i * 4..(i + 1) * 4].copy_from_slice(&h[i].to_be_bytes());
127 }
128 result
129}
130
131impl Default for LoginManager {
132 fn default() -> Self {
133 Self::new()
134 }
135}
136
137impl LoginManager {
138 pub fn new() -> Self {
139 let mut mgr = Self {
140 state: LoginState::Locked,
141 current_input: Vec::new(),
142 setup_password: Vec::new(),
143 saved_password_hash: [0u8; 32],
144 error_ticks_end: 0,
145 error_msg: "",
146 needs_redraw: true,
147 };
148
149 mgr.check_saved_password();
150 mgr
151 }
152
153 fn check_saved_password(&mut self) {
155 if let Some((_, data)) = fs::get_fs().read_file("password.cfg") {
156 if data.len() == 32 {
157 self.saved_password_hash.copy_from_slice(&data[0..32]);
158 self.state = LoginState::Locked;
159 return;
160 }
161 }
162 self.state = LoginState::SetupInput;
165 }
166
167 pub fn is_unlocked(&self) -> bool {
168 self.state == LoginState::Unlocked
169 }
170
171 pub fn handle_key_input(&mut self, c: char) {
173 let current_ticks = timer::get_ticks();
174 if current_ticks < self.error_ticks_end {
175 self.error_ticks_end = 0;
176 self.current_input.clear();
177 self.needs_redraw = true;
178 }
179
180 if (' '..='~').contains(&c) {
182 if self.current_input.len() < 32 {
183 self.current_input.push(c as u8);
184 self.needs_redraw = true;
185 }
186 } else if c == '\x08' {
187 if !self.current_input.is_empty() {
189 self.current_input.pop();
190 self.needs_redraw = true;
191 }
192 } else if c == '\x1B' {
193 if !self.current_input.is_empty() {
195 self.current_input.clear();
196 self.needs_redraw = true;
197 }
198 } else if c == '\n' {
199 if !self.current_input.is_empty() {
201 self.process_completed_input();
202 }
203 }
204 }
205
206 fn process_completed_input(&mut self) {
208 match self.state {
209 LoginState::Locked => {
210 let input_hash = sha256(&self.current_input);
211 if input_hash == self.saved_password_hash {
212 crate::warn!("[SYS] === [Login] Success: Locked -> Unlocked ===");
213 self.state = LoginState::Unlocked;
214 } else {
215 crate::info!("[SYS] === [Login] Failed: Incorrect password ===");
216 self.trigger_error("Incorrect password. Please try again.");
217 }
218 }
219 LoginState::SetupInput => {
220 crate::info!("[SYS] === [Login] SetupInput password set. Confirming... ===");
221 self.setup_password = self.current_input.clone();
222 self.current_input.clear();
223 self.state = LoginState::SetupConfirm;
224 self.needs_redraw = true;
225 }
226 LoginState::SetupConfirm => {
227 if self.current_input == self.setup_password {
228 let hash = sha256(&self.current_input);
229 crate::info!("[SYS] === [Login] SetupConfirm matched. Saving password... ===");
230 if fs::get_fs().save_file("password.cfg", &hash, "").is_ok() {
231 crate::warn!("[SYS] === [Login] Password saved. State: Unlocked ===");
233 self.saved_password_hash = hash;
234 self.state = LoginState::Unlocked;
235 let _ = fs::get_fs().delete_file("pin.cfg");
237 } else {
238 crate::info!("[SYS] === [Login] Password save FAILED ===");
239 self.trigger_error("Storage Error. Try again.");
240 self.state = LoginState::SetupInput;
241 }
242 } else {
243 crate::info!("[SYS] === [Login] Passwords mismatch ===");
244 self.trigger_error("Passwords mismatch. Please restart.");
245 self.state = LoginState::SetupInput;
246 self.setup_password.clear();
247 }
248 }
249 _ => {}
250 }
251 }
252
253 fn trigger_error(&mut self, msg: &'static str) {
254 self.error_msg = msg;
255 self.error_ticks_end = timer::get_ticks() + 150; self.current_input.clear();
257 self.needs_redraw = true;
258 }
259
260 pub fn handle_mouse_input(&mut self, _mx: u32, _my: u32, left_btn: bool, _wheel: i32) {
263 if left_btn {
264 let current_ticks = timer::get_ticks();
265 if current_ticks < self.error_ticks_end {
266 self.error_ticks_end = 0;
267 self.current_input.clear();
268 self.needs_redraw = true;
269 }
270 }
271 }
272
273 pub fn draw(&mut self, screen: &Screen) {
275 let current_ticks = timer::get_ticks();
276 if current_ticks >= self.error_ticks_end && self.error_ticks_end != 0 {
277 self.error_ticks_end = 0;
278 self.needs_redraw = true;
279 }
280
281 let cx = screen.width / 2;
282 let cy = screen.height / 2;
283 let theme = crate::kernel::config::get_config().theme;
284
285 screen.boxfill(0, 0, screen.width - 1, screen.height - 1, Color(theme.login_screen_bg));
287
288 let dw = 500;
290 let dh = 300;
291 let dx0 = cx - dw / 2;
292 let dy0 = cy - dh / 2;
293 let dx1 = cx + dw / 2;
294 let dy1 = cy + dh / 2;
295
296 screen.boxfill(dx0 - 6, dy0 - 6, dx1 + 6, dy1 + 6, Color(theme.login_dialog_shadow));
298 screen.boxfill(dx0, dy0, dx1, dy1, Color(theme.login_dialog_bg));
300
301 let border_color = if self.error_ticks_end > 0 {
303 Color(theme.focus_highlight) } else {
305 Color(theme.login_dialog_border)
306 };
307 draw_border(screen, dx0, dy0, dx1, dy1, border_color.0);
308
309 let title = match self.state {
311 LoginState::SetupInput => "Create Your Password",
312 LoginState::SetupConfirm => "Confirm Your Password",
313 LoginState::Locked => "AtmOS Security Shield",
314 _ => "Access Granted",
315 };
316
317 let title_w = crate::kernel::vector_font::get_vector_string_width(title, 24);
318 let title_x = cx - title_w / 2;
319 screen.draw_string_vector(title_x, dy0 + 36, title, Color(theme.login_text_fg), 24);
320
321 if self.error_ticks_end > 0 {
323 let err_w = get_string_width_ja(self.error_msg);
324 let err_x = cx - err_w / 2;
325 screen.draw_string_ja(err_x, dy0 + 72, self.error_msg, Color(theme.focus_highlight));
326 } else {
327 let sub = match self.state {
328 LoginState::SetupInput => "Enter a new secure alphanumeric password",
329 LoginState::SetupConfirm => "Re-enter to verify and commit",
330 LoginState::Locked => "Enter security password to decrypt environment",
331 _ => "",
332 };
333 let sub_w = get_string_width_ja(sub);
334 let sub_x = cx - sub_w / 2;
335 screen.draw_string_ja(sub_x, dy0 + 72, sub, Color(theme.login_dialog_border));
336 }
337
338 let field_w = 400;
340 let field_h = 48;
341 let fx0 = cx - field_w / 2;
342 let fy0 = dy0 + 130;
343 let fx1 = cx + field_w / 2;
344 let fy1 = fy0 + field_h;
345
346 screen.boxfill(fx0, fy0, fx1, fy1, Color(theme.login_field_bg));
348 let field_border = if self.error_ticks_end > 0 {
349 theme.focus_highlight } else {
351 theme.login_field_border
352 };
353 draw_border(screen, fx0, fy0, fx1, fy1, field_border);
354
355 let mut mask_str = String::new();
357 for _ in 0..self.current_input.len() {
358 mask_str.push('*');
359 }
360
361 let mask_w = crate::kernel::vector_font::get_vector_string_width(&mask_str, 20);
362 let mask_x = cx - mask_w / 2;
363 screen.draw_string_vector(mask_x, fy0 + 14, &mask_str, Color(theme.login_text_fg), 20);
364
365 let show_caret = (timer::get_ticks() / 25).is_multiple_of(2);
368 if show_caret {
369 let caret_x = mask_x + mask_w;
370 screen.boxfill(caret_x, fy0 + 12, caret_x + 2, fy0 + 36, Color(theme.login_caret));
371 }
372
373 let hint = "Press [Enter] to submit / [Esc] to clear";
375 let hint_w = get_string_width_ja(hint);
376 let hint_x = cx - hint_w / 2;
377 screen.draw_string_ja(hint_x, dy0 + 240, hint, Color(theme.login_hint_fg));
378
379 self.needs_redraw = false;
380 }
381}
382
383fn draw_border(screen: &Screen, x0: u32, y0: u32, x1: u32, y1: u32, color_val: u32) {
385 if x0 >= x1 || y0 >= y1 {
386 return;
387 }
388 screen.boxfill(x0, y0, x1, y0 + 1, Color(color_val));
389 screen.boxfill(x0, y1 - 1, x1, y1, Color(color_val));
390 screen.boxfill(x0, y0, x0 + 1, y1, Color(color_val));
391 screen.boxfill(x1 - 1, y0, x1, y1, Color(color_val));
392}
393
394fn get_string_width_ja(s: &str) -> u32 {
395 let mut width = 0;
396 for c in s.chars() {
397 if (c as u32) < 128 {
398 width += 8;
399 } else {
400 width += 16;
401 }
402 }
403 width
404}