1use crate::cap::Cap;
16use crate::error::CapSecError;
17use crate::permission::Permission;
18use std::marker::PhantomData;
19use std::sync::atomic::{AtomicU8, Ordering};
20use std::sync::{Arc, Mutex};
21use std::time::Instant;
22
23#[derive(Debug, Clone)]
32pub struct LogEntry {
33 pub timestamp: Instant,
35 pub permission: &'static str,
37 pub granted: bool,
39}
40
41pub struct LoggedCap<P: Permission> {
55 _phantom: PhantomData<P>,
56 _not_send: PhantomData<*const ()>,
57 log: Arc<Mutex<Vec<LogEntry>>>,
58}
59
60impl<P: Permission> LoggedCap<P> {
61 pub fn new(_cap: Cap<P>) -> Self {
63 Self {
64 _phantom: PhantomData,
65 _not_send: PhantomData,
66 log: Arc::new(Mutex::new(Vec::new())),
67 }
68 }
69
70 pub fn try_cap(&self) -> Result<Cap<P>, CapSecError> {
75 let entry = LogEntry {
76 timestamp: Instant::now(),
77 permission: std::any::type_name::<P>(),
78 granted: true,
79 };
80 let mut log = self.log.lock().unwrap_or_else(|e| e.into_inner());
81 log.push(entry);
82 Ok(Cap::new())
83 }
84
85 pub fn is_active(&self) -> bool {
87 true
88 }
89
90 pub fn entries(&self) -> Vec<LogEntry> {
92 let log = self.log.lock().unwrap_or_else(|e| e.into_inner());
93 log.clone()
94 }
95
96 pub fn entry_count(&self) -> usize {
98 let log = self.log.lock().unwrap_or_else(|e| e.into_inner());
99 log.len()
100 }
101
102 pub fn make_send(self) -> LoggedSendCap<P> {
104 LoggedSendCap {
105 _phantom: PhantomData,
106 log: self.log,
107 }
108 }
109}
110
111impl<P: Permission> Clone for LoggedCap<P> {
112 fn clone(&self) -> Self {
113 Self {
114 _phantom: PhantomData,
115 _not_send: PhantomData,
116 log: Arc::clone(&self.log),
117 }
118 }
119}
120
121pub struct LoggedSendCap<P: Permission> {
130 _phantom: PhantomData<P>,
131 log: Arc<Mutex<Vec<LogEntry>>>,
132}
133
134unsafe impl<P: Permission> Send for LoggedSendCap<P> {}
137unsafe impl<P: Permission> Sync for LoggedSendCap<P> {}
138
139impl<P: Permission> LoggedSendCap<P> {
140 pub fn try_cap(&self) -> Result<Cap<P>, CapSecError> {
142 let entry = LogEntry {
143 timestamp: Instant::now(),
144 permission: std::any::type_name::<P>(),
145 granted: true,
146 };
147 let mut log = self.log.lock().unwrap_or_else(|e| e.into_inner());
148 log.push(entry);
149 Ok(Cap::new())
150 }
151
152 pub fn is_active(&self) -> bool {
154 true
155 }
156
157 pub fn entries(&self) -> Vec<LogEntry> {
159 let log = self.log.lock().unwrap_or_else(|e| e.into_inner());
160 log.clone()
161 }
162
163 pub fn entry_count(&self) -> usize {
165 let log = self.log.lock().unwrap_or_else(|e| e.into_inner());
166 log.len()
167 }
168}
169
170impl<P: Permission> Clone for LoggedSendCap<P> {
171 fn clone(&self) -> Self {
172 Self {
173 _phantom: PhantomData,
174 log: Arc::clone(&self.log),
175 }
176 }
177}
178
179pub struct DualKeyCap<P: Permission> {
196 _phantom: PhantomData<P>,
197 _not_send: PhantomData<*const ()>,
198 approvals: Arc<AtomicU8>,
199}
200
201impl<P: Permission> DualKeyCap<P> {
202 pub fn new(_cap: Cap<P>) -> (Self, ApproverA, ApproverB) {
208 let approvals = Arc::new(AtomicU8::new(0));
209 let cap = Self {
210 _phantom: PhantomData,
211 _not_send: PhantomData,
212 approvals: Arc::clone(&approvals),
213 };
214 let a = ApproverA {
215 approvals: Arc::clone(&approvals),
216 };
217 let b = ApproverB { approvals };
218 (cap, a, b)
219 }
220
221 pub fn try_cap(&self) -> Result<Cap<P>, CapSecError> {
226 if self.approvals.load(Ordering::Acquire) == 3 {
227 Ok(Cap::new())
228 } else {
229 Err(CapSecError::InsufficientApprovals)
230 }
231 }
232
233 pub fn is_active(&self) -> bool {
235 self.approvals.load(Ordering::Acquire) == 3
236 }
237
238 pub fn make_send(self) -> DualKeySendCap<P> {
240 DualKeySendCap {
241 _phantom: PhantomData,
242 approvals: self.approvals,
243 }
244 }
245}
246
247impl<P: Permission> Clone for DualKeyCap<P> {
248 fn clone(&self) -> Self {
249 Self {
250 _phantom: PhantomData,
251 _not_send: PhantomData,
252 approvals: Arc::clone(&self.approvals),
253 }
254 }
255}
256
257pub struct DualKeySendCap<P: Permission> {
266 _phantom: PhantomData<P>,
267 approvals: Arc<AtomicU8>,
268}
269
270unsafe impl<P: Permission> Send for DualKeySendCap<P> {}
273unsafe impl<P: Permission> Sync for DualKeySendCap<P> {}
274
275impl<P: Permission> DualKeySendCap<P> {
276 pub fn try_cap(&self) -> Result<Cap<P>, CapSecError> {
278 if self.approvals.load(Ordering::Acquire) == 3 {
279 Ok(Cap::new())
280 } else {
281 Err(CapSecError::InsufficientApprovals)
282 }
283 }
284
285 pub fn is_active(&self) -> bool {
287 self.approvals.load(Ordering::Acquire) == 3
288 }
289}
290
291impl<P: Permission> Clone for DualKeySendCap<P> {
292 fn clone(&self) -> Self {
293 Self {
294 _phantom: PhantomData,
295 approvals: Arc::clone(&self.approvals),
296 }
297 }
298}
299
300pub struct ApproverA {
311 approvals: Arc<AtomicU8>,
312}
313
314impl ApproverA {
315 pub fn approve(&self) {
317 self.approvals.fetch_or(0b01, Ordering::Release);
318 }
319
320 pub fn is_approved(&self) -> bool {
322 self.approvals.load(Ordering::Acquire) & 0b01 != 0
323 }
324}
325
326pub struct ApproverB {
332 approvals: Arc<AtomicU8>,
333}
334
335impl ApproverB {
336 pub fn approve(&self) {
338 self.approvals.fetch_or(0b10, Ordering::Release);
339 }
340
341 pub fn is_approved(&self) -> bool {
343 self.approvals.load(Ordering::Acquire) & 0b10 != 0
344 }
345}
346
347#[cfg(test)]
348mod tests {
349 use super::*;
350 use crate::permission::FsRead;
351 use std::mem::size_of;
352
353 #[test]
356 fn logged_cap_try_cap_succeeds() {
357 let root = crate::root::test_root();
358 let cap = root.grant::<FsRead>();
359 let lcap = LoggedCap::new(cap);
360 assert!(lcap.try_cap().is_ok());
361 }
362
363 #[test]
364 fn logged_cap_records_entry() {
365 let root = crate::root::test_root();
366 let cap = root.grant::<FsRead>();
367 let lcap = LoggedCap::new(cap);
368 let _ = lcap.try_cap();
369 let entries = lcap.entries();
370 assert_eq!(entries.len(), 1);
371 assert!(entries[0].permission.contains("FsRead"));
372 assert!(entries[0].granted);
373 }
374
375 #[test]
376 fn logged_cap_multiple_entries() {
377 let root = crate::root::test_root();
378 let cap = root.grant::<FsRead>();
379 let lcap = LoggedCap::new(cap);
380 let _ = lcap.try_cap();
381 let _ = lcap.try_cap();
382 let _ = lcap.try_cap();
383 assert_eq!(lcap.entry_count(), 3);
384 }
385
386 #[test]
387 fn logged_cap_entries_snapshot() {
388 let root = crate::root::test_root();
389 let cap = root.grant::<FsRead>();
390 let lcap = LoggedCap::new(cap);
391 let _ = lcap.try_cap();
392 let snapshot = lcap.entries();
393 let _ = lcap.try_cap();
394 assert_eq!(snapshot.len(), 1);
396 assert_eq!(lcap.entry_count(), 2);
397 }
398
399 #[test]
400 fn logged_send_cap_crosses_threads() {
401 let root = crate::root::test_root();
402 let cap = root.grant::<FsRead>();
403 let lcap = LoggedCap::new(cap);
404 let send_cap = lcap.make_send();
405
406 std::thread::spawn(move || {
407 assert!(send_cap.try_cap().is_ok());
408 })
409 .join()
410 .unwrap();
411 }
412
413 #[test]
414 fn cloned_logged_cap_shares_log() {
415 let root = crate::root::test_root();
416 let cap = root.grant::<FsRead>();
417 let lcap = LoggedCap::new(cap);
418 let lcap2 = lcap.clone();
419
420 let _ = lcap.try_cap();
421 let _ = lcap2.try_cap();
422
423 assert_eq!(lcap.entry_count(), 2);
424 assert_eq!(lcap2.entry_count(), 2);
425 }
426
427 #[test]
428 fn logged_cap_is_small() {
429 assert!(size_of::<LoggedCap<FsRead>>() <= 2 * size_of::<usize>());
430 }
431
432 #[test]
433 fn logged_cap_entry_has_correct_permission_name() {
434 let root = crate::root::test_root();
435 let cap = root.grant::<FsRead>();
436 let lcap = LoggedCap::new(cap);
437 let _ = lcap.try_cap();
438 let entries = lcap.entries();
439 assert!(entries[0].permission.contains("FsRead"));
440 }
441
442 #[test]
445 fn dual_key_try_cap_fails_without_approvals() {
446 let root = crate::root::test_root();
447 let cap = root.grant::<FsRead>();
448 let (dcap, _a, _b) = DualKeyCap::new(cap);
449 assert!(matches!(
450 dcap.try_cap(),
451 Err(CapSecError::InsufficientApprovals)
452 ));
453 }
454
455 #[test]
456 fn dual_key_try_cap_fails_with_one_approval() {
457 let root = crate::root::test_root();
458 let cap = root.grant::<FsRead>();
459 let (dcap, a, _b) = DualKeyCap::new(cap);
460 a.approve();
461 assert!(matches!(
462 dcap.try_cap(),
463 Err(CapSecError::InsufficientApprovals)
464 ));
465 }
466
467 #[test]
468 fn dual_key_try_cap_succeeds_with_both_approvals() {
469 let root = crate::root::test_root();
470 let cap = root.grant::<FsRead>();
471 let (dcap, a, b) = DualKeyCap::new(cap);
472 a.approve();
473 b.approve();
474 assert!(dcap.try_cap().is_ok());
475 }
476
477 #[test]
478 fn dual_key_approval_order_irrelevant() {
479 let root = crate::root::test_root();
480 let cap = root.grant::<FsRead>();
481 let (dcap, a, b) = DualKeyCap::new(cap);
482 b.approve();
483 a.approve();
484 assert!(dcap.try_cap().is_ok());
485 }
486
487 #[test]
488 fn dual_key_approve_is_idempotent() {
489 let root = crate::root::test_root();
490 let cap = root.grant::<FsRead>();
491 let (dcap, a, _b) = DualKeyCap::new(cap);
492 a.approve();
493 a.approve(); assert!(matches!(
496 dcap.try_cap(),
497 Err(CapSecError::InsufficientApprovals)
498 ));
499 }
500
501 #[test]
502 fn dual_key_approvers_are_send_sync() {
503 fn assert_send_sync<T: Send + Sync>() {}
504 assert_send_sync::<ApproverA>();
505 assert_send_sync::<ApproverB>();
506 }
507
508 #[test]
509 fn dual_key_send_cap_crosses_threads() {
510 let root = crate::root::test_root();
511 let cap = root.grant::<FsRead>();
512 let (dcap, a, b) = DualKeyCap::new(cap);
513 a.approve();
514 b.approve();
515 let send_cap = dcap.make_send();
516
517 std::thread::spawn(move || {
518 assert!(send_cap.try_cap().is_ok());
519 })
520 .join()
521 .unwrap();
522 }
523
524 #[test]
525 fn dual_key_approval_crosses_threads() {
526 let root = crate::root::test_root();
527 let cap = root.grant::<FsRead>();
528 let (dcap, a, b) = DualKeyCap::new(cap);
529
530 a.approve();
531
532 std::thread::spawn(move || {
533 b.approve();
534 })
535 .join()
536 .unwrap();
537
538 assert!(dcap.try_cap().is_ok());
539 }
540
541 #[test]
542 fn cloned_dual_key_shares_approval() {
543 let root = crate::root::test_root();
544 let cap = root.grant::<FsRead>();
545 let (dcap, a, b) = DualKeyCap::new(cap);
546 let dcap2 = dcap.clone();
547
548 a.approve();
549 b.approve();
550
551 assert!(dcap.try_cap().is_ok());
552 assert!(dcap2.try_cap().is_ok());
553 }
554
555 #[test]
556 fn dual_key_cap_is_small() {
557 assert!(size_of::<DualKeyCap<FsRead>>() <= 2 * size_of::<usize>());
558 }
559}