use std::collections::HashMap;
use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use serde_with::{DeserializeFromStr, SerializeDisplay};
use struct_metadata::Described;
use strum::IntoEnumIterator;
use crate::{ElasticMeta, Readable, };
use crate::types::{Email, UpperString, ExpandingClassification};
#[derive(SerializeDisplay, DeserializeFromStr, strum::Display, strum::EnumString, strum::FromRepr, Described, Clone, Copy, Debug)]
#[metadata_type(ElasticMeta)]
#[strum(serialize_all = "snake_case")]
pub enum UserType {
Admin = 0,
User = 1,
SignatureManager = 2,
SignatureImporter = 3,
Viewer = 4,
Submitter = 5,
Custom = 6,
}
#[derive(SerializeDisplay, DeserializeFromStr, strum::Display, strum::EnumString, Described, Clone, Copy)]
#[metadata_type(ElasticMeta)]
#[strum(serialize_all = "lowercase")]
pub enum Scope {R, W, RW, C}
#[derive(SerializeDisplay, DeserializeFromStr, strum::Display, strum::EnumString, strum::FromRepr, strum::EnumIter, Described, Clone, Copy, PartialEq, Eq, Debug, PartialOrd, Ord)]
#[metadata_type(ElasticMeta)]
#[strum(serialize_all = "snake_case")]
pub enum UserRole {
AlertManage = 0,
AlertView = 1,
ApikeyAccess = 2,
BundleDownload = 3,
FileDetail = 4,
FileDownload = 5,
FilePurge = 33,
HeuristicView = 6,
OboAccess = 7,
ReplayTrigger = 8,
SafelistView = 9,
SafelistManage = 10,
SignatureDownload = 11,
SignatureView = 12,
SubmissionCreate = 13,
SubmissionDelete = 14,
SubmissionManage = 15,
SubmissionView = 16,
WorkflowManage = 17,
WorkflowView = 18,
Administration = 19,
ReplaySystem = 20,
SignatureImport = 21,
SignatureManage = 22,
ArchiveView = 23,
ArchiveManage = 24,
ArchiveTrigger = 25,
ArchiveDownload = 26,
SelfManage = 27,
RetrohuntView = 28,
RetrohuntRun = 29,
ExternalQuery = 30,
BadlistView = 31,
BadlistManage = 32,
ArchiveComment = 35,
AssistantUse = 34,
SubmissionCustomize = 36,
}
const USER_ROLES_BASIC: [UserRole; 31] = [
UserRole::AlertManage,
UserRole::AlertView,
UserRole::ArchiveTrigger,
UserRole::ArchiveView,
UserRole::ArchiveManage,
UserRole::ArchiveDownload,
UserRole::ArchiveComment,
UserRole::ApikeyAccess,
UserRole::BundleDownload,
UserRole::ExternalQuery,
UserRole::FileDetail,
UserRole::FileDownload,
UserRole::HeuristicView,
UserRole::OboAccess,
UserRole::ReplayTrigger,
UserRole::SafelistView,
UserRole::SafelistManage,
UserRole::SelfManage,
UserRole::SignatureDownload,
UserRole::SignatureView,
UserRole::SubmissionCreate,
UserRole::SubmissionDelete,
UserRole::SubmissionManage,
UserRole::SubmissionView,
UserRole::WorkflowManage,
UserRole::WorkflowView,
UserRole::RetrohuntView,
UserRole::RetrohuntRun,
UserRole::BadlistView,
UserRole::BadlistManage,
UserRole::SubmissionCustomize,
];
impl UserType {
#[must_use]
pub fn roles(&self) -> Vec<UserRole> {
match self {
UserType::Admin => UserRole::iter().collect(),
UserType::SignatureImporter => vec![
UserRole::BadlistManage,
UserRole::SafelistManage,
UserRole::SelfManage,
UserRole::SignatureDownload,
UserRole::SignatureImport,
UserRole::SignatureView
],
UserType::SignatureManager => {
let mut roles: Vec<_> = UserRole::iter().collect();
roles.push(UserRole::SignatureManage);
roles
},
UserType::User => USER_ROLES_BASIC.into_iter().collect(),
UserType::Viewer => vec![
UserRole::AlertView,
UserRole::ApikeyAccess,
UserRole::BadlistView,
UserRole::FileDetail,
UserRole::OboAccess,
UserRole::HeuristicView,
UserRole::SafelistView,
UserRole::SelfManage,
UserRole::SignatureView,
UserRole::SubmissionView,
UserRole::WorkflowView,
],
UserType::Submitter => vec![
UserRole::ApikeyAccess,
UserRole::OboAccess,
UserRole::SelfManage,
UserRole::SubmissionCreate,
UserRole::ReplayTrigger,
UserRole::RetrohuntRun,
],
UserType::Custom => vec![],
}
}
}
#[derive(SerializeDisplay, DeserializeFromStr, strum::Display, strum::EnumString, Described, Clone, Copy, Debug, PartialEq, Eq)]
#[metadata_type(ElasticMeta)]
pub enum AclCatagory {R, W, E, C}
impl AclCatagory {
#[must_use]
pub fn roles(&self) -> &[UserRole] {
match self {
AclCatagory::R => &[
UserRole::AlertView,
UserRole::ArchiveView,
UserRole::ArchiveDownload,
UserRole::BadlistView,
UserRole::BundleDownload,
UserRole::ExternalQuery,
UserRole::FileDetail,
UserRole::FileDownload,
UserRole::HeuristicView,
UserRole::SafelistView,
UserRole::SignatureDownload,
UserRole::SignatureView,
UserRole::SubmissionView,
UserRole::WorkflowView,
UserRole::RetrohuntView,
],
AclCatagory::W => &[
UserRole::AlertManage,
UserRole::ArchiveTrigger,
UserRole::ArchiveManage,
UserRole::BadlistManage,
UserRole::ReplayTrigger,
UserRole::SafelistManage,
UserRole::SubmissionCreate,
UserRole::SubmissionDelete,
UserRole::SubmissionManage,
UserRole::RetrohuntRun,
UserRole::SubmissionCustomize,
],
AclCatagory::E => &[
UserRole::Administration,
UserRole::ApikeyAccess,
UserRole::FilePurge,
UserRole::OboAccess,
UserRole::ReplaySystem,
UserRole::SelfManage,
UserRole::SignatureImport,
UserRole::SignatureManage,
UserRole::WorkflowManage
],
AclCatagory::C => &[],
}
}
}
pub fn load_roles_form_acls(acls: &[AclCatagory], current_roles: &[UserRole]) -> Vec<UserRole> {
if !current_roles.is_empty() {
return current_roles.to_vec()
}
let mut roles = vec![];
for acl in acls {
roles.extend_from_slice(acl.roles())
}
roles.sort_unstable();
roles.dedup();
return roles
}
pub fn load_roles(types: &[UserType], current_roles: &[UserRole]) -> Vec<UserRole> {
if !current_roles.is_empty() {
return current_roles.to_vec()
}
let mut roles = vec![];
for user_type in types {
roles.extend_from_slice(&user_type.roles());
}
roles.sort_unstable();
roles.dedup();
return roles
}
#[derive(Serialize, Deserialize, Described)]
#[metadata_type(ElasticMeta)]
#[metadata(index=false, store=false)]
pub struct Apps {
pub client_id: String,
pub netloc: String,
pub scope: Scope,
pub server: String,
#[serde(default)]
pub roles: Vec<UserRole>,
}
#[derive(Serialize, Deserialize, Described)]
#[metadata_type(ElasticMeta)]
#[metadata(index=true, store=true)]
pub struct User {
#[metadata(index=false, store=false)]
#[serde(default)]
pub agrees_with_tos: Option<DateTime<Utc>>,
#[metadata(store=false, mapping="integer")]
#[serde(default)]
pub api_quota: Option<u64>,
#[metadata(store=false, mapping="integer")]
#[serde(default)]
pub api_daily_quota: Option<u64>,
#[metadata(index=false, store=false)]
#[serde(default)]
pub apps: HashMap<String, Apps>,
#[metadata(index=false, store=false)]
#[serde(default)]
pub can_impersonate: bool,
#[metadata(copyto="__text__")]
#[serde(flatten, default="unrestricted_expanding_classification")]
pub classification: ExpandingClassification<true>,
#[metadata(store=false, copyto="__text__")]
#[serde(default)]
pub dn: Option<String>,
#[metadata(copyto="__text__")]
#[serde(default)]
pub email: Option<Email>,
#[metadata(copyto="__text__")]
#[serde(default)]
pub groups: Vec<UpperString>,
#[metadata(copyto="__text__", store=false)]
#[serde(default)]
identity_id: Option<String>,
#[serde(default="default_user_is_active")]
pub is_active: bool,
#[metadata(copyto="__text__")]
pub name: String,
#[metadata(index=false, store=false)]
#[serde(default)]
pub otp_sk: Option<String>,
#[metadata(index=false, store=false)]
pub password: String,
#[metadata(store=false, mapping="integer")]
#[serde(default)]
pub submission_quota: Option<u64>,
#[metadata(store=false, mapping="integer")]
#[serde(default)]
pub submission_async_quota: Option<u64>,
#[metadata(store=false, mapping="integer")]
#[serde(default)]
pub submission_daily_quota: Option<u64>,
#[serde(rename="type", default="default_user_types")]
pub user_types: Vec<UserType>,
#[serde(default)]
pub roles: Vec<UserRole>,
#[metadata(index=false, store=false)]
#[serde(default)]
pub security_tokens: HashMap<String, String>,
#[metadata(copyto="__text__")]
pub uname: String,
}
pub fn default_user_types() -> Vec<UserType> { vec![UserType::User] }
fn default_user_is_active() -> bool { true }
impl Readable for User {
fn set_from_archive(&mut self, _from_archive: bool) {}
}
impl User {
pub fn create_test_user() -> Self {
User {
agrees_with_tos: None,
api_quota: None,
api_daily_quota: None,
apps: Default::default(),
can_impersonate: false,
classification: ExpandingClassification::try_unrestricted().unwrap(),
dn: None,
email: None,
groups: Default::default(),
identity_id: None,
is_active: default_user_is_active(),
name: "User".to_owned(),
otp_sk: None,
password: Default::default(),
submission_quota: None,
submission_async_quota: None,
submission_daily_quota: None,
user_types: default_user_types(),
roles: Default::default(),
security_tokens: Default::default(),
uname: "user".to_owned(),
}
}
}