2026-02-08 01:17:33 +01:00
|
|
|
use core::fmt::{Debug, Formatter};
|
|
|
|
|
|
2026-02-13 03:00:46 +01:00
|
|
|
use alloc::rc::Rc;
|
2026-01-31 15:24:36 +01:00
|
|
|
use chrono::NaiveDateTime;
|
|
|
|
|
use password_hash::Key;
|
|
|
|
|
use serde::{Deserialize, Serialize};
|
2026-02-13 03:00:46 +01:00
|
|
|
use slint::{Model, SharedString, VecModel};
|
2026-01-31 15:24:36 +01:00
|
|
|
use spectre_api_sys::{SpectreAlgorithm, SpectreCounter, SpectreResultType};
|
|
|
|
|
|
2026-02-08 01:17:33 +01:00
|
|
|
#[derive(Deserialize, Serialize, Default)]
|
2026-01-31 15:24:36 +01:00
|
|
|
pub struct SpectreUsersConfig {
|
2026-02-08 01:17:33 +01:00
|
|
|
#[serde(with = "vec_model")]
|
|
|
|
|
pub users: Rc<VecModel<SpectreUserConfig>>,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Debug for SpectreUsersConfig {
|
|
|
|
|
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
|
|
|
|
|
f.debug_struct("SpectreUsersConfig")
|
|
|
|
|
.field_with("users", |f| {
|
|
|
|
|
f.debug_list().entries(self.users.iter()).finish()
|
|
|
|
|
})
|
|
|
|
|
.finish()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Clone for SpectreUsersConfig {
|
|
|
|
|
fn clone(&self) -> Self {
|
|
|
|
|
Self {
|
|
|
|
|
users: Rc::new(self.users.iter().collect()),
|
|
|
|
|
}
|
|
|
|
|
}
|
2026-01-31 15:24:36 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Deserialize, Serialize, Clone, Debug, PartialEq, Eq)]
|
|
|
|
|
pub struct SpectreUserConfig {
|
2026-02-04 03:14:21 +01:00
|
|
|
pub username: SharedString,
|
2026-01-31 15:24:36 +01:00
|
|
|
#[serde(with = "serde_bytes")]
|
|
|
|
|
pub encrypted_key: Key,
|
|
|
|
|
#[serde(with = "serde_bytes")]
|
|
|
|
|
pub key_id: [u8; 32],
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Deserialize, Serialize, Clone, Debug, PartialEq, Eq)]
|
|
|
|
|
pub struct SpectreSiteConfig {
|
|
|
|
|
#[serde(with = "with_repr")]
|
|
|
|
|
pub algorithm: SpectreAlgorithm,
|
|
|
|
|
pub counter: SpectreCounter::Type,
|
|
|
|
|
#[serde(rename = "type")]
|
|
|
|
|
#[serde(with = "with_repr")]
|
|
|
|
|
pub result_type: SpectreResultType,
|
2026-02-04 03:14:21 +01:00
|
|
|
pub password: Option<SharedString>,
|
2026-01-31 15:24:36 +01:00
|
|
|
#[serde(with = "with_repr")]
|
|
|
|
|
pub login_type: SpectreResultType,
|
2026-02-04 03:14:21 +01:00
|
|
|
pub login_name: Option<SharedString>,
|
2026-01-31 15:24:36 +01:00
|
|
|
pub uses: u32,
|
|
|
|
|
pub last_used: NaiveDateTime,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Default for SpectreSiteConfig {
|
|
|
|
|
fn default() -> Self {
|
|
|
|
|
Self {
|
|
|
|
|
algorithm: SpectreAlgorithm::Current,
|
|
|
|
|
counter: SpectreCounter::Default,
|
|
|
|
|
result_type: SpectreResultType::SpectreResultDefaultResult,
|
|
|
|
|
password: None,
|
|
|
|
|
login_type: SpectreResultType::SpectreResultDefaultLogin,
|
|
|
|
|
login_name: None,
|
|
|
|
|
uses: 0,
|
|
|
|
|
last_used: Default::default(),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
2026-01-31 15:36:36 +01:00
|
|
|
pub struct SpectreSite {
|
2026-02-04 03:14:21 +01:00
|
|
|
pub username: SharedString,
|
|
|
|
|
pub site_name: SharedString,
|
2026-01-31 15:24:36 +01:00
|
|
|
pub config: SpectreSiteConfig,
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-08 01:17:33 +01:00
|
|
|
mod vec_model {
|
|
|
|
|
use alloc::{rc::Rc, vec::Vec};
|
|
|
|
|
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
|
|
|
|
use slint::{Model, VecModel};
|
|
|
|
|
|
|
|
|
|
#[allow(unused)]
|
|
|
|
|
pub fn serialize<T, S>(value: &Rc<VecModel<T>>, serializer: S) -> Result<S::Ok, S::Error>
|
|
|
|
|
where
|
|
|
|
|
T: Serialize,
|
|
|
|
|
VecModel<T>: Model<Data = T>,
|
|
|
|
|
S: Serializer,
|
|
|
|
|
{
|
|
|
|
|
let vec: Vec<T> = value.iter().collect();
|
|
|
|
|
vec.serialize(serializer)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[allow(unused)]
|
|
|
|
|
pub fn deserialize<'de, T, D>(deserializer: D) -> Result<Rc<VecModel<T>>, D::Error>
|
|
|
|
|
where
|
|
|
|
|
T: Deserialize<'de>,
|
|
|
|
|
D: Deserializer<'de>,
|
|
|
|
|
{
|
|
|
|
|
let vec = Vec::<T>::deserialize(deserializer)?;
|
|
|
|
|
Ok(Rc::new(VecModel::from(vec)))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-31 15:24:36 +01:00
|
|
|
mod with_repr {
|
|
|
|
|
use serde::{Deserialize, Deserializer, Serializer};
|
|
|
|
|
use spectre_api_sys::{SpectreAlgorithm, SpectreResultType};
|
|
|
|
|
|
|
|
|
|
pub trait ReprConvert: Copy {
|
|
|
|
|
type Repr: Copy;
|
|
|
|
|
|
|
|
|
|
fn into_repr(self) -> Self::Repr;
|
|
|
|
|
fn from_repr(repr: Self::Repr) -> Self;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl ReprConvert for SpectreAlgorithm {
|
|
|
|
|
type Repr = u32;
|
|
|
|
|
|
|
|
|
|
fn from_repr(repr: Self::Repr) -> Self {
|
|
|
|
|
unsafe { core::mem::transmute::<Self::Repr, Self>(repr) }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn into_repr(self) -> Self::Repr {
|
|
|
|
|
self as Self::Repr
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl ReprConvert for SpectreResultType {
|
|
|
|
|
type Repr = u32;
|
|
|
|
|
|
|
|
|
|
fn from_repr(repr: Self::Repr) -> Self {
|
|
|
|
|
unsafe { core::mem::transmute::<Self::Repr, Self>(repr) }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn into_repr(self) -> Self::Repr {
|
|
|
|
|
self as Self::Repr
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-31 15:36:36 +01:00
|
|
|
#[allow(unused)]
|
2026-01-31 15:24:36 +01:00
|
|
|
pub fn serialize<T, S>(value: &T, serializer: S) -> Result<S::Ok, S::Error>
|
|
|
|
|
where
|
|
|
|
|
T: ReprConvert<Repr = u32>,
|
|
|
|
|
S: Serializer,
|
|
|
|
|
{
|
|
|
|
|
serializer.serialize_u32(value.into_repr())
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-31 15:36:36 +01:00
|
|
|
#[allow(unused)]
|
2026-01-31 15:24:36 +01:00
|
|
|
pub fn deserialize<'de, T, D>(deserializer: D) -> Result<T, D::Error>
|
|
|
|
|
where
|
|
|
|
|
T: ReprConvert<Repr = u32>,
|
|
|
|
|
D: Deserializer<'de>,
|
|
|
|
|
{
|
|
|
|
|
<u32 as Deserialize>::deserialize(deserializer).map(T::from_repr)
|
|
|
|
|
}
|
|
|
|
|
}
|