/*
* Copyright (c) 2023 Stalwart Labs Ltd.
*
* This file is part of Stalwart Mail Server.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
* in the LICENSE file at the top-level directory of this distribution.
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*
* You can be released from the requirements of the AGPLv3 license by
* purchasing a commercial license. Please contact licensing@stalw.art
* for more details.
*/
pub mod lookup;
pub mod manage;
use std::{fmt::Display, slice::Iter};
use store::{write::key::KeySerializer, Deserialize, Serialize, U32_LEN};
use utils::codec::leb128::Leb128Iterator;
use crate::{Principal, Type};
pub(super) struct PrincipalIdType {
pub account_id: u32,
pub typ: Type,
}
impl Serialize for Principal {
fn serialize(self) -> Vec {
(&self).serialize()
}
}
impl Serialize for &Principal {
fn serialize(self) -> Vec {
let mut serializer = KeySerializer::new(
U32_LEN * 3
+ 2
+ self.name.len()
+ self.emails.iter().map(|s| s.len()).sum::()
+ self.secrets.iter().map(|s| s.len()).sum::()
+ self.member_of.len() * U32_LEN
+ self.description.as_ref().map(|s| s.len()).unwrap_or(0),
)
.write(1u8)
.write_leb128(self.id)
.write(self.typ as u8)
.write_leb128(self.quota)
.write_leb128(self.name.len())
.write(self.name.as_bytes())
.write_leb128(self.description.as_ref().map_or(0, |s| s.len()))
.write(self.description.as_deref().unwrap_or_default().as_bytes());
for list in [&self.secrets, &self.emails] {
serializer = serializer.write_leb128(list.len());
for value in list {
serializer = serializer.write_leb128(value.len()).write(value.as_bytes());
}
}
serializer = serializer.write_leb128(self.member_of.len());
for id in &self.member_of {
serializer = serializer.write_leb128(*id);
}
serializer.finalize()
}
}
impl Deserialize for Principal {
fn deserialize(bytes: &[u8]) -> store::Result {
deserialize(bytes)
.ok_or_else(|| store::Error::InternalError("Failed to deserialize principal".into()))
}
}
impl Serialize for PrincipalIdType {
fn serialize(self) -> Vec {
KeySerializer::new(U32_LEN + 1)
.write_leb128(self.account_id)
.write(self.typ as u8)
.finalize()
}
}
impl Deserialize for PrincipalIdType {
fn deserialize(bytes: &[u8]) -> store::Result {
let mut bytes = bytes.iter();
Ok(PrincipalIdType {
account_id: bytes.next_leb128().ok_or_else(|| {
store::Error::InternalError("Failed to deserialize principal account id".into())
})?,
typ: Type::from_u8(*bytes.next().ok_or_else(|| {
store::Error::InternalError("Failed to deserialize principal id type".into())
})?),
})
}
}
impl PrincipalIdType {
pub fn new(account_id: u32, typ: Type) -> Self {
Self { account_id, typ }
}
}
fn deserialize(bytes: &[u8]) -> Option> {
let mut bytes = bytes.iter();
if bytes.next()? != &1 {
return None;
}
Principal {
id: bytes.next_leb128()?,
typ: Type::from_u8(*bytes.next()?),
quota: bytes.next_leb128()?,
name: deserialize_string(&mut bytes)?,
description: deserialize_string(&mut bytes).map(|v| {
if !v.is_empty() {
Some(v)
} else {
None
}
})?,
secrets: deserialize_string_list(&mut bytes)?,
emails: deserialize_string_list(&mut bytes)?,
member_of: deserialize_u32_list(&mut bytes)?,
}
.into()
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
pub enum PrincipalField {
#[serde(rename = "name")]
Name,
#[serde(rename = "type")]
Type,
#[serde(rename = "quota")]
Quota,
#[serde(rename = "description")]
Description,
#[serde(rename = "secrets")]
Secrets,
#[serde(rename = "emails")]
Emails,
#[serde(rename = "memberOf")]
MemberOf,
}
#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
pub struct PrincipalUpdate {
action: PrincipalAction,
field: PrincipalField,
value: PrincipalValue,
}
#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
pub enum PrincipalAction {
#[serde(rename = "set")]
Set,
#[serde(rename = "addItem")]
AddItem,
#[serde(rename = "removeItem")]
RemoveItem,
}
#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
#[serde(untagged)]
pub enum PrincipalValue {
String(String),
StringList(Vec),
Integer(u32),
Type(Type),
}
impl PrincipalUpdate {
pub fn set(field: PrincipalField, value: PrincipalValue) -> PrincipalUpdate {
PrincipalUpdate {
action: PrincipalAction::Set,
field,
value,
}
}
pub fn add_item(field: PrincipalField, value: PrincipalValue) -> PrincipalUpdate {
PrincipalUpdate {
action: PrincipalAction::AddItem,
field,
value,
}
}
pub fn remove_item(field: PrincipalField, value: PrincipalValue) -> PrincipalUpdate {
PrincipalUpdate {
action: PrincipalAction::RemoveItem,
field,
value,
}
}
}
impl Display for PrincipalField {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
PrincipalField::Name => write!(f, "name"),
PrincipalField::Type => write!(f, "type"),
PrincipalField::Quota => write!(f, "quota"),
PrincipalField::Description => write!(f, "description"),
PrincipalField::Secrets => write!(f, "secrets"),
PrincipalField::Emails => write!(f, "emails"),
PrincipalField::MemberOf => write!(f, "memberOf"),
}
}
}
fn deserialize_string(bytes: &mut Iter<'_, u8>) -> Option {
let len = bytes.next_leb128()?;
let mut string = Vec::with_capacity(len);
for _ in 0..len {
string.push(*bytes.next()?);
}
String::from_utf8(string).ok()
}
fn deserialize_string_list(bytes: &mut Iter<'_, u8>) -> Option> {
let len = bytes.next_leb128()?;
let mut list = Vec::with_capacity(len);
for _ in 0..len {
list.push(deserialize_string(bytes)?);
}
Some(list)
}
fn deserialize_u32_list(bytes: &mut Iter<'_, u8>) -> Option> {
let len = bytes.next_leb128()?;
let mut list = Vec::with_capacity(len);
for _ in 0..len {
list.push(bytes.next_leb128()?);
}
Some(list)
}
impl Type {
pub fn parse(value: &str) -> Option {
match value {
"individual" | "superuser" => Some(Type::Individual),
"group" => Some(Type::Group),
"resource" => Some(Type::Resource),
"location" => Some(Type::Location),
"list" => Some(Type::List),
_ => None,
}
}
pub fn from_u8(value: u8) -> Self {
match value {
0 => Type::Individual,
1 => Type::Group,
2 => Type::Resource,
3 => Type::Location,
4 => Type::Superuser,
5 => Type::List,
_ => Type::Other,
}
}
pub fn into_base_type(self) -> Self {
match self {
Type::Superuser => Type::Individual,
any => any,
}
}
}