1use crate::engine::{AuthorizeEngine, SharedEngine};
4use crate::matrix::MatrixBuilder;
5use crate::owner::OwnerRegistry;
6use sova_core::{App, Plugin};
7use sova_db::DbHandle;
8use std::future::Future;
9use std::sync::Arc;
10
11type ConfigureFn = Box<dyn FnOnce(&mut MatrixBuilder) + Send>;
12
13pub struct ScopeAuthState {
14 pub engine: SharedEngine,
15}
16
17pub struct ScopeAuth {
18 configure_fn: Option<ConfigureFn>,
19 owners: OwnerRegistry,
20}
21
22impl ScopeAuth {
23 pub fn new() -> Self {
24 Self {
25 configure_fn: None,
26 owners: OwnerRegistry::default(),
27 }
28 }
29
30 pub fn configure(mut self, f: impl FnOnce(&mut MatrixBuilder) + Send + 'static) -> Self {
31 self.configure_fn = Some(Box::new(f));
32 self
33 }
34
35 pub fn owner<F, Fut>(mut self, kind: &'static str, f: F) -> Self
36 where
37 F: Fn(DbHandle, i64) -> Fut + Send + Sync + 'static,
38 Fut: Future<Output = sova_core::Result<Option<i64>>> + Send + 'static,
39 {
40 self.owners.register(kind, crate::owner::callback_owner(f));
41 self
42 }
43}
44
45impl Default for ScopeAuth {
46 fn default() -> Self {
47 Self::new()
48 }
49}
50
51impl Plugin for ScopeAuth {
52 fn id(&self) -> &'static str {
53 "scope"
54 }
55
56 fn requires(&self) -> &'static [&'static str] {
57 &["db"]
58 }
59
60 fn meta(&self) -> sova_core::PluginMeta {
61 sova_core::PluginMeta::new("ScopeAuth")
62 .description("Scoped RBAC: membership, role matrix, ownership hooks, cache, audit")
63 .version(env!("CARGO_PKG_VERSION"))
64 }
65
66 fn install(self, app: &mut App) {
67 let mut builder = MatrixBuilder::default();
68 if let Some(f) = self.configure_fn {
69 f(&mut builder);
70 }
71 let matrices = builder.build();
72 let engine = Arc::new(AuthorizeEngine::new(matrices, self.owners));
73 app.state(ScopeAuthState { engine });
74 }
75}