mod auth;
mod tokens;
pub use self::auth::pam_authenticate;
pub use self::tokens::Token;
pub use errors::AuthError;
use crypto::{encoding, hashing, random};
use std::collections::HashMap;
use {
meta::MetaDomain,
traits::{AutoEncoder, Base64AutoEncoder},
};
#[derive(Hash, Serialize, Deserialize, Clone, PartialEq, Eq)]
pub enum Access {
Vault(Role),
Record(Role, String),
}
impl AutoEncoder for Access {}
#[derive(Hash, Serialize, Deserialize, Clone, PartialEq, Eq)]
pub enum Role {
Reader,
Editor,
Admin,
}
impl AutoEncoder for Role {}
#[derive(Serialize, Deserialize, Clone)]
pub struct User {
name: String,
pw_hash: String,
rights: HashMap<Access, Role>,
token: Option<String>,
}
impl User {
pub fn register(name: &str, pw: &str) -> Self {
Self {
name: name.into(),
pw_hash: encoding::base64_encode(&hashing::blake2(pw, name).to_vec()),
rights: HashMap::new(),
token: None,
}
}
pub fn verify(&self, pw: &str) -> bool {
self.pw_hash == encoding::base64_encode(&hashing::blake2(pw, &self.name).to_vec())
}
pub fn token(&mut self) -> String {
if self.token.is_none() {
self.token = Some(encoding::base64_encode(&random::bytes(256)));
}
self.token.as_ref().unwrap().clone()
}
pub fn has_access(&self, item: Access) -> Option<Role> {
self.rights.get(&item).map(|i| i.clone())
}
pub fn give_access(&mut self, item: Access, role: Role) {
self.rights.insert(item, role);
}
}
impl AutoEncoder for User {}
#[derive(Serialize, Deserialize)]
pub struct UserStore {
users: HashMap<String, User>,
registry: HashMap<String, Vec<Access>>,
}
impl UserStore {
pub fn get_token(&mut self, access: Vec<Access>) -> String {
let token = ::crypto::encoding::base64_encode(&::crypto::random::bytes(128));
self.registry.insert(
token.clone(),
if access.is_empty() {
vec![Access::Vault(Role::Reader)]
} else {
access
},
);
token
}
pub fn get_user(&self, name: &str) -> Option<&User> {
self.users.get(name)
}
pub fn get_all(&self) -> &HashMap<String, User> {
&self.users
}
pub fn add(&mut self, user: User) -> Option<()> {
self.users.insert(user.name.clone(), user);
Some(())
}
}
impl Default for UserStore {
fn default() -> Self {
Self {
users: HashMap::new(),
registry: HashMap::new(),
}
}
}
impl AutoEncoder for UserStore {}
impl From<(MetaDomain, MetaDomain)> for UserStore {
fn from((users, registry): (MetaDomain, MetaDomain)) -> Self {
Self {
users: users
.all()
.iter()
.map(|(k, v)| {
(
k.clone(),
match v {
::Payload::Text(s) => User::decode(&String::from_base64(s)).unwrap(),
_ => unreachable!(),
},
)
})
.collect(),
registry: registry
.all()
.iter()
.map(|(k, v)| {
(
k.clone(),
match v {
::Payload::List(regs) => regs
.iter()
.map(|reg| {
Access::decode(&String::from_base64(match reg {
::Payload::Text(s) => s,
_ => unreachable!(),
})).unwrap()
})
.collect(),
_ => unreachable!(),
},
)
})
.collect(),
}
}
}
impl From<UserStore> for (MetaDomain, MetaDomain) {
fn from(us: UserStore) -> Self {
(
MetaDomain::new("userstore").fill(
us.users
.iter()
.map(|(name, user)| {
(
name.clone(),
::Payload::Text(user.encode().unwrap().to_base64()),
)
})
.collect(),
),
MetaDomain::new("registry").fill(
us.registry
.iter()
.map(|(name, reg)| {
(
name.clone(),
::Payload::List(
reg.iter()
.map(|reg| ::Payload::Text(reg.encode().unwrap().to_base64()))
.collect(),
),
)
})
.collect(),
),
)
}
}