/ src / profile / identity / auth.rs
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  }