use std::collections::BTreeMap;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
pub enum HmacAlgorithm {
#[serde(rename = "SHA-256")]
#[default]
Sha256,
#[serde(rename = "SHA-384")]
Sha384,
#[serde(rename = "SHA-512")]
Sha512,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ChallengeParameters {
pub algorithm: String,
pub cost: u32,
#[serde(skip_serializing_if = "Option::is_none")]
pub data: Option<BTreeMap<String, serde_json::Value>>,
#[serde(rename = "expiresAt", skip_serializing_if = "Option::is_none")]
pub expires_at: Option<u64>,
#[serde(rename = "keyLength")]
pub key_length: usize,
#[serde(rename = "keyPrefix")]
pub key_prefix: String,
#[serde(rename = "keySignature", skip_serializing_if = "Option::is_none")]
pub key_signature: Option<String>,
#[serde(rename = "memoryCost", skip_serializing_if = "Option::is_none")]
pub memory_cost: Option<u32>,
pub nonce: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub parallelism: Option<u32>,
pub salt: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Challenge {
pub parameters: ChallengeParameters,
#[serde(skip_serializing_if = "Option::is_none")]
pub signature: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Solution {
pub counter: u32,
#[serde(rename = "derivedKey")]
pub derived_key: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub time: Option<f64>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Payload {
pub challenge: Challenge,
pub solution: Solution,
}
#[derive(Debug, Clone)]
pub struct VerifySolutionResult {
pub expired: bool,
pub invalid_signature: Option<bool>,
pub invalid_solution: Option<bool>,
pub time: f64,
pub verified: bool,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ServerSignaturePayload {
pub algorithm: String,
#[serde(rename = "apiKey", skip_serializing_if = "Option::is_none")]
pub api_key: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub id: Option<String>,
pub signature: String,
#[serde(rename = "verificationData")]
pub verification_data: String,
pub verified: bool,
}
#[derive(Debug, Clone, Default, Serialize)]
pub struct ServerSignatureVerificationData {
#[serde(skip_serializing_if = "Option::is_none")]
pub classification: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub email: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub expire: Option<u64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub fields: Option<Vec<String>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub fields_hash: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub ip_address: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub reasons: Option<Vec<String>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub score: Option<f64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub time: Option<f64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub verified: Option<bool>,
#[serde(flatten)]
pub extra: BTreeMap<String, String>,
}
#[derive(Debug, Clone)]
pub struct VerifyServerSignatureResult {
pub expired: bool,
pub invalid_signature: bool,
pub invalid_solution: bool,
pub time: f64,
pub verified: bool,
pub verification_data: Option<ServerSignatureVerificationData>,
}
pub struct CreateChallengeOptions {
pub algorithm: String,
pub counter: Option<u32>,
pub cost: u32,
pub data: Option<BTreeMap<String, serde_json::Value>>,
pub expires_at: Option<u64>,
pub hmac_algorithm: HmacAlgorithm,
pub hmac_key_signature_secret: Option<String>,
pub hmac_signature_secret: Option<String>,
pub key_length: usize,
pub key_prefix: String,
pub key_prefix_length: Option<usize>,
pub memory_cost: Option<u32>,
pub parallelism: Option<u32>,
}
impl Default for CreateChallengeOptions {
fn default() -> Self {
Self {
algorithm: "PBKDF2/SHA-256".to_string(),
counter: None,
cost: 100_000,
data: None,
expires_at: None,
hmac_algorithm: HmacAlgorithm::Sha256,
hmac_key_signature_secret: None,
hmac_signature_secret: None,
key_length: 32,
key_prefix: "00".to_string(),
key_prefix_length: None,
memory_cost: None,
parallelism: None,
}
}
}
pub struct SolveChallengeOptions<'a> {
pub challenge: &'a Challenge,
pub counter_start: u32,
pub counter_step: u32,
pub timeout_ms: u64,
}
impl<'a> SolveChallengeOptions<'a> {
pub fn new(challenge: &'a Challenge) -> Self {
Self {
challenge,
counter_start: 0,
counter_step: 1,
timeout_ms: 90_000,
}
}
}
pub struct VerifySolutionOptions<'a> {
pub challenge: &'a Challenge,
pub solution: &'a Solution,
pub hmac_algorithm: HmacAlgorithm,
pub hmac_key_signature_secret: Option<String>,
pub hmac_signature_secret: String,
}
impl<'a> VerifySolutionOptions<'a> {
pub fn new(
challenge: &'a Challenge,
solution: &'a Solution,
hmac_signature_secret: impl Into<String>,
) -> Self {
Self {
challenge,
solution,
hmac_algorithm: HmacAlgorithm::Sha256,
hmac_key_signature_secret: None,
hmac_signature_secret: hmac_signature_secret.into(),
}
}
}