1use std::fmt;
4
5use ap_noise::Psk;
6use ap_proxy_protocol::IdentityFingerprint;
7use serde::{Deserialize, Serialize};
8
9pub type PskId = String;
15
16#[derive(Debug, Clone, Serialize, Deserialize)]
18#[serde(rename_all = "camelCase")]
19pub enum CredentialQuery {
20 Domain(String),
22 Id(String),
24 Search(String),
26}
27
28impl CredentialQuery {
29 pub fn search_string(&self) -> &str {
31 match self {
32 Self::Domain(d) => d.as_str(),
33 Self::Id(id) => id.as_str(),
34 Self::Search(s) => s.as_str(),
35 }
36 }
37}
38
39impl fmt::Display for CredentialQuery {
40 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
41 match self {
42 CredentialQuery::Domain(d) => write!(f, "domain: {d}"),
43 CredentialQuery::Id(id) => write!(f, "id: {id}"),
44 CredentialQuery::Search(s) => write!(f, "search: {s}"),
45 }
46 }
47}
48
49#[derive(Debug, Clone)]
51pub enum ConnectionMode {
52 New { rendezvous_code: String },
54 NewPsk {
56 psk: Psk,
57 remote_fingerprint: IdentityFingerprint,
58 },
59 Existing {
61 remote_fingerprint: IdentityFingerprint,
62 },
63}
64
65#[derive(Clone, Serialize, Deserialize)]
67#[serde(rename_all = "camelCase")]
68pub struct CredentialData {
69 #[serde(skip_serializing_if = "Option::is_none")]
71 pub username: Option<String>,
72 #[serde(skip_serializing_if = "Option::is_none")]
74 pub password: Option<String>,
75 #[serde(skip_serializing_if = "Option::is_none")]
77 pub totp: Option<String>,
78 #[serde(skip_serializing_if = "Option::is_none")]
80 pub uri: Option<String>,
81 #[serde(skip_serializing_if = "Option::is_none")]
83 pub notes: Option<String>,
84 #[serde(skip_serializing_if = "Option::is_none")]
86 pub credential_id: Option<String>,
87 #[serde(default)]
89 #[serde(skip_serializing_if = "Option::is_none")]
90 pub domain: Option<String>,
91}
92
93impl std::fmt::Debug for CredentialData {
94 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
95 f.debug_struct("CredentialData")
96 .field("domain", &self.domain)
97 .field("username", &self.username)
98 .field("password", &self.password.as_ref().map(|_| "[REDACTED]"))
99 .field("totp", &self.totp.as_ref().map(|_| "[REDACTED]"))
100 .field("notes", &self.notes.as_ref().map(|_| "[REDACTED]"))
101 .field("credential_id", &self.credential_id)
102 .finish()
103 }
104}
105
106#[derive(Debug, Clone, Serialize, Deserialize)]
108#[serde(tag = "type", rename_all = "kebab-case")]
109pub(crate) enum ProtocolMessage {
110 #[serde(rename = "handshake-init")]
112 HandshakeInit {
113 data: String,
114 ciphersuite: String,
115 #[serde(default, skip_serializing_if = "Option::is_none")]
118 psk_id: Option<PskId>,
119 },
120 #[serde(rename = "handshake-response")]
122 HandshakeResponse { data: String, ciphersuite: String },
123 CredentialRequest { encrypted: String },
125 CredentialResponse { encrypted: String },
127}
128
129#[derive(Debug, Clone, Serialize, Deserialize)]
131pub(crate) struct CredentialRequestPayload {
132 #[serde(rename = "type")]
133 pub request_type: String,
134 pub query: CredentialQuery,
135 pub timestamp: u64,
136 #[serde(rename = "requestId")]
137 pub request_id: String,
138}
139
140#[derive(Debug, Clone, Serialize, Deserialize)]
142pub(crate) struct CredentialResponsePayload {
143 #[serde(skip_serializing_if = "Option::is_none")]
144 pub credential: Option<CredentialData>,
145 #[serde(skip_serializing_if = "Option::is_none")]
146 pub error: Option<String>,
147 #[serde(rename = "requestId")]
148 #[serde(skip_serializing_if = "Option::is_none")]
149 pub request_id: Option<String>,
150}