feat(users): per-user sealed folders users/<id>/{home,apps,data,permissions}; storage SET_USER/LOCK/PURGE; init sign-in/sign-out loop (purge fresh/removed/guest, seed from factory, session start/stop); shell logout; pm user+system app shelves; terminal SIGNED_OUT; per-program stack (gatekeeper 12p); 128K load scratch
This commit is contained in:
@@ -7,6 +7,8 @@ use crate::grants::Grants;
|
||||
use crate::protocol::{DIR_ENTRY_SIZE, DIR_NAME_SIZE, MAX_PATH, StorageRequest, StorageResponse};
|
||||
use crate::scope::Scope;
|
||||
|
||||
mod session;
|
||||
|
||||
const MAX_CLIENTS: usize = 8;
|
||||
/// Handles at or past this are never valid (the file systems hand out
|
||||
/// fewer), so ownership fits a small table.
|
||||
@@ -54,6 +56,8 @@ pub struct StorageServer<F: FileSystem, H: Host> {
|
||||
/// init; handed to the file system (and forgotten here) once all in.
|
||||
key: [Option<[usize; 2]>; 2],
|
||||
seed: [Option<[usize; 2]>; 2],
|
||||
/// Whose areas they open, said first.
|
||||
user: Option<types::user::UserFolder>,
|
||||
unlocked: bool,
|
||||
}
|
||||
|
||||
@@ -68,6 +72,7 @@ impl<F: FileSystem, H: Host> StorageServer<F, H> {
|
||||
log: None,
|
||||
key: [None; 2],
|
||||
seed: [None; 2],
|
||||
user: None,
|
||||
unlocked: false,
|
||||
}
|
||||
}
|
||||
@@ -91,27 +96,6 @@ impl<F: FileSystem, H: Host> StorageServer<F, H> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Only the unbadged holder (init), each half only once: nobody can
|
||||
/// replace the key or the seed later.
|
||||
fn set_half(&mut self, badge: usize, seed: bool, half: usize, words: [usize; 2]) -> StorageResponse {
|
||||
let halves = if seed { &mut self.seed } else { &mut self.key };
|
||||
match (badge, self.unlocked, halves.get_mut(half)) {
|
||||
(0, false, Some(slot @ None)) => *slot = Some(words),
|
||||
_ => return StorageResponse::Error,
|
||||
}
|
||||
if let ([Some(k0), Some(k1)], [Some(s0), Some(s1)]) = (self.key, self.seed) {
|
||||
let bytes = |w: [usize; 4]| -> [u8; 32] { core::array::from_fn(|i| w[i / 8].to_le_bytes()[i % 8]) };
|
||||
let (mut master, mut seed) = (bytes([k0[0], k0[1], k1[0], k1[1]]), bytes([s0[0], s0[1], s1[0], s1[1]]));
|
||||
self.fs.unlock(&master, &seed);
|
||||
master.fill(0);
|
||||
seed.fill(0);
|
||||
self.key = [None; 2];
|
||||
self.seed = [None; 2];
|
||||
self.unlocked = true;
|
||||
}
|
||||
StorageResponse::Ok
|
||||
}
|
||||
|
||||
/// Whether the encrypted areas are open: the key and seed are in.
|
||||
pub fn unlocked(&self) -> bool {
|
||||
self.unlocked
|
||||
@@ -300,7 +284,7 @@ impl<F: FileSystem, H: Host> StorageServer<F, H> {
|
||||
None => R::NotFound,
|
||||
};
|
||||
let response = match request {
|
||||
Attach | SetLog | SetKey { .. } | SetSeed { .. } | Release => R::Error,
|
||||
Attach | SetLog | SetKey { .. } | SetSeed { .. } | SetUser { .. } | Lock | Purge { .. } | Release => R::Error,
|
||||
Grant { path_len, write } => {
|
||||
let narrower = scope.narrow(&buf[sent(path_len)], write);
|
||||
return match narrower.and_then(|s| grants.add(badge, s, |b| host.mint(b))) {
|
||||
@@ -412,6 +396,9 @@ impl<F: FileSystem, H: Host> Server for StorageServer<F, H> {
|
||||
Some(StorageRequest::SetLog) => (self.set_log(badge, cap).encode(), None),
|
||||
Some(StorageRequest::SetKey { half, words }) => (self.set_half(badge, false, half, words).encode(), None),
|
||||
Some(StorageRequest::SetSeed { half, words }) => (self.set_half(badge, true, half, words).encode(), None),
|
||||
Some(StorageRequest::SetUser { id, guest }) => (self.set_user(badge, id, guest).encode(), None),
|
||||
Some(StorageRequest::Lock) => (self.lock(badge).encode(), None),
|
||||
Some(StorageRequest::Purge { path_len }) => (self.purge(badge, path_len).encode(), None),
|
||||
// A badge storage never issued, or one it has taken back.
|
||||
Some(request) => match self.grants.scope(badge) {
|
||||
None => (StorageResponse::Denied.encode(), None),
|
||||
|
||||
Reference in New Issue
Block a user