auth.rs
1 //! Controller for children `database` and `memory` components 2 3 mod database; 4 mod memory; 5 6 use anyhow::Result; 7 use database::Database; 8 use memory::Memory; 9 use r2d2::Pool; 10 use r2d2_sqlite::SqliteConnectionManager; 11 use sqlite::Transaction; 12 13 /// Auth pair operations 14 pub struct Auth { 15 database: Database, 16 memory: Memory, 17 } 18 19 impl Auth { 20 // Constructors 21 22 /// Create new `Self` 23 pub fn build(database_pool: &Pool<SqliteConnectionManager>) -> Result<Self> { 24 // Init `Self` 25 let this = Self { 26 database: Database::build(database_pool), 27 memory: Memory::new(), 28 }; 29 30 // Build initial index 31 Self::index(&this)?; 32 33 // Done 34 Ok(this) 35 } 36 37 // Actions 38 39 /// Apply `profile_identity_id` certificate as the auth for `scope` 40 /// * deactivate active auth by remove previous records from `Self` database 41 /// * reindex `Self` memory index on success 42 /// * return last insert `profile_identity_auth_id` on success 43 pub fn apply(&self, profile_identity_id: i64, request: &str) -> Result<i64> { 44 // Cleanup records match `scope` (unauthorize) 45 self.remove(request)?; 46 47 // Create new record (auth) 48 let profile_identity_auth_id = self 49 .database 50 .add(profile_identity_id, &filter_scope(request))?; 51 52 // Reindex 53 self.index()?; 54 55 // Done 56 Ok(profile_identity_auth_id) 57 } 58 59 /// Remove all records match request (unauthorize) 60 pub fn remove(&self, request: &str) -> Result<()> { 61 for record in self.database.records_scope(Some(&filter_scope(request)))? { 62 self.database.delete(record.id)?; 63 } 64 self.index()?; 65 Ok(()) 66 } 67 68 /// Remove all records match `profile_identity_id` foreign reference key 69 pub fn remove_ref(&self, profile_identity_id: i64) -> Result<()> { 70 for record in self.database.records_ref(profile_identity_id)? { 71 self.database.delete(record.id)?; 72 } 73 self.index()?; 74 Ok(()) 75 } 76 77 /// Create new `Memory` index from `Database` for `Self` 78 pub fn index(&self) -> Result<()> { 79 // Clear previous records 80 self.memory.clear()?; 81 // Build new index 82 for record in self.database.records_scope(None)? { 83 self.memory.add(record.scope, record.profile_identity_id)?; 84 } 85 Ok(()) 86 } 87 88 // Getters 89 90 /// Check request string matches condition 91 pub fn is_matches(&self, request: &str, profile_identity_id: i64) -> bool { 92 self.memory 93 .match_scope(&filter_scope(request)) 94 .is_some_and(|auth| auth.profile_identity_id == profile_identity_id) 95 } 96 97 /// Check request string matches condition 98 pub fn total(&self, profile_identity_id: i64) -> usize { 99 self.memory.total(profile_identity_id) 100 } 101 102 /// Collect certificate scope vector from `Profile` database for `profile_identity_id` 103 pub fn scope(&self, profile_identity_id: i64) -> Vec<String> { 104 let mut scope = Vec::new(); 105 match self.database.records_scope(None) { 106 Ok(result) => { 107 for auth in result 108 .iter() 109 .filter(|this| this.profile_identity_id == profile_identity_id) 110 { 111 scope.push(auth.scope.clone()) 112 } 113 } 114 Err(_) => todo!(), 115 } 116 scope 117 } 118 119 /// Get memory item string match request 120 pub fn get(&self, request: &str) -> Option<memory::Auth> { 121 self.memory.match_scope(&filter_scope(request)) 122 } 123 } 124 125 // Tools 126 127 pub fn migrate(tx: &Transaction) -> Result<()> { 128 // Migrate self components 129 database::init(tx)?; 130 131 // Delegate migration to childs 132 // nothing yet.. 133 134 Ok(()) 135 } 136 137 /// Get valid identity scope for given URL 138 /// * helper function for different protocol drivers implementation 139 fn filter_scope(url: &str) -> String { 140 use gtk::glib::{Regex, RegexCompileFlags, RegexMatchFlags}; 141 142 match Regex::split_simple( 143 r"^\w+://(.*)", 144 url, 145 RegexCompileFlags::DEFAULT, 146 RegexMatchFlags::DEFAULT, 147 ) 148 .get(1) 149 { 150 Some(postfix) => postfix.to_string(), 151 None => url.to_string(), 152 } 153 .trim() 154 .trim_end_matches("/") 155 .to_lowercase() 156 }