1#[cfg(feature = "session")]
2mod session;
3mod utils;
4
5#[cfg(feature = "types")]
6pub use {types::stores, smart_account_auth as saa_types};
7#[cfg(feature = "utils")]
8pub use utils::*;
9
10
11#[cfg(feature = "session")]
12pub use {
13 session::{handle_session_action, handle_session_query},
14 types::{
15 macros::{session_query, session_action},
16 sessions::{queries::*, actions::*}
17 }
18};
19
20pub use types::{
21 StoredCredentials, UpdateOperation
22};
23
24
25use smart_account_auth::{
26 msgs::SignedDataMsg, CheckOption, CredentialId,
27 CredentialName, CredentialRecord, ReplayParams,
28 ReplayProtection, VerifiedData
29};
30
31use types::{
32 stores::{ACCOUNT_NUMBER, HAS_NATIVES, PRIMARY_ID, CREDENTIAL_INFOS as CREDS},
33 errors::{AuthError, CredentialError, ReplayError, StorageError},
34 wasm::{ensure, Deps, DepsMut, Env, Storage},
35 serde::Serialize,
36};
37
38use std::fmt::Display;
39
40
41
42
43pub fn account_number(
44 storage: &dyn Storage
45) -> u64 {
46 ACCOUNT_NUMBER.load(storage).unwrap_or(0)
47}
48
49
50
51
52pub fn verify_native(
53 storage: &dyn Storage,
54 sender: String
55) -> Result<(), StorageError> {
56 ensure!(CREDS.has(storage, sender), StorageError::NotFound);
57 Ok(())
58}
59
60
61pub fn verify_data(
62 deps: Deps,
63 msg: SignedDataMsg
64) -> Result<(), AuthError> {
65 utils::cred_from_signed(deps, msg)?;
66 Ok(())
67}
68
69
70
71
72pub fn verify_signed<T : Serialize + Display + Clone>(
73 deps: Deps,
74 env: &Env,
75 messages: Vec<T>,
76 signed: SignedDataMsg
77) -> Result<(), AuthError> {
78 let msgs = messages.iter()
79 .map(|m| m.to_string())
80 .collect::<Vec<String>>();
81 let nonce = account_number(deps.storage);
82 let cred = utils::cred_from_signed(deps, signed)?;
83 cred.protect_reply(env, ReplayParams::new(nonce, CheckOption::Messages(msgs)))?;
84 Ok(())
85}
86
87
88
89pub fn verify_signed_actions<T : Serialize + Display + Clone>(
90 deps: &mut DepsMut,
91 env: &Env,
92 messages: Vec<T>,
93 signed: SignedDataMsg
94) -> Result<(), AuthError> {
95 let msgs = messages.iter()
96 .map(|m| m.to_string())
97 .collect::<Vec<String>>();
98 let nonce = account_number(deps.storage);
99 let cred = utils::cred_from_signed(deps.as_ref(), signed)?;
100 cred.protect_reply(env, ReplayParams::new(nonce, CheckOption::Messages(msgs)))?;
101 ACCOUNT_NUMBER.save(deps.storage, &(nonce + 1))?;
102 Ok(())
103}
104
105
106
107
108
109pub fn get_stored_credentials(
110 storage: &dyn Storage
111) -> Result<StoredCredentials, StorageError> {
112 Ok(StoredCredentials {
113 has_natives : utils::has_natives(storage),
114 records : utils::get_credentials(storage)?,
115 account_number : account_number(storage),
116 primary_id : PRIMARY_ID.load(storage)
117 .map_err(|_| StorageError::NotFound)?,
118 #[cfg(feature = "session")]
119 sessions : None,
120 })
121}
122
123
124pub fn save_credentials(
125 storage: &mut dyn Storage,
126 data: &VerifiedData
127) -> Result<(), StorageError> {
128 ACCOUNT_NUMBER.save(storage, &data.nonce)?;
129 PRIMARY_ID.save(storage, &data.primary_id)?;
130 HAS_NATIVES.save(storage, &data.has_natives)?;
131 data.credentials
132 .iter()
133 .try_for_each(|(id, info)|
134 CREDS.save(storage, id.clone(), info))
135 .map_err(|e| StorageError::Write("credentials".to_string(), e.to_string()))
136}
137
138
139
140
141
142
143pub fn reset_credentials(
144 storage: &mut dyn Storage,
145 acc_number: bool,
146 #[cfg(feature = "session")]
147 sessions: bool
148) -> Result<(), StorageError> {
149 PRIMARY_ID.remove(storage);
150 HAS_NATIVES.remove(storage);
151 CREDS.clear(storage);
152 if acc_number { ACCOUNT_NUMBER.remove(storage); }
153 #[cfg(feature = "session")]
154 if sessions {
155 types::stores::SESSIONS.clear(storage);
156 }
157 Ok(())
158}
159
160
161
162pub fn update_credentials(
163 storage : &mut dyn Storage,
164 op: &UpdateOperation<VerifiedData>,
165) -> Result<(), AuthError> {
166 match op {
167 UpdateOperation::Add(data) => {
168 add_credentials(storage, &data)?;
169 },
170 UpdateOperation::Remove(idx) => {
171 remove_credentials(storage, idx)?;
172 }
173 }
174 Ok(())
175}
176
177
178
179pub fn add_credentials(
180 storage : &mut dyn Storage,
181 data : &VerifiedData,
182) -> Result<(), AuthError> {
183 let nonce = ACCOUNT_NUMBER.load(storage).unwrap_or(0);
184 ensure!(data.nonce == nonce, ReplayError::InvalidNonce(nonce));
185 if data.override_primary { PRIMARY_ID.save(storage, &data.primary_id)?; };
186 ACCOUNT_NUMBER.save(storage, &(nonce +1))?;
187 HAS_NATIVES.update(storage, |had_natives| Ok::<bool, StorageError>(had_natives || data.has_natives))?;
188
189 data.credentials
190 .iter()
191 .try_for_each(|(id, info)| {
192 CREDS.save(storage, id.clone(), &info)
193 .map_err(|e| AuthError::Storage(
194 StorageError::Write(id.to_string(), e.to_string())
195 ))
196 }
197 )
198}
199
200
201
202pub fn remove_credentials(
203 storage: &mut dyn Storage,
204 idx: &Vec<CredentialId>,
205) -> Result<Vec<CredentialRecord>, AuthError> {
206 ensure!(!idx.is_empty(), CredentialError::NoCredentials);
207
208 let idx = idx.iter()
209 .map(|id| id.clone())
210 .collect::<Vec<_>>();
211
212 let all_creds = utils::get_credentials(storage)?;
213 let had_natives = HAS_NATIVES.load(storage)?;
214 let verifying_id = PRIMARY_ID.load(storage)?;
215
216 let (to_remove, remaining): (Vec<_>, Vec<_>) = all_creds
217 .into_iter()
218 .partition(|(id, _)| idx.contains(id));
219
220 ensure!(!remaining.is_empty(), CredentialError::NoneLeft);
221
222 let (
223 native_changed,
224 verifying_removed
225 ) = to_remove
226 .into_iter()
227 .fold((false, false), |(
228 mut has_native,
229 mut has_verifying
230 ), (id, info)| {
231 if info.name == CredentialName::Native {
232 has_native = true;
233 }
234 if id == verifying_id {
235 has_verifying = true;
236 }
237 CREDS.remove(storage, id);
238 (has_native, has_verifying)
239 });
240
241
242 if had_natives && native_changed {
243 let still_has = remaining
244 .iter()
245 .any(|(_, info)| info.name == CredentialName::Native);
246 HAS_NATIVES.save(storage, &still_has)?;
247 }
248
249 if verifying_removed {
250 if let Some((id, _)) = remaining.first() {
251 PRIMARY_ID.save(storage, id)?;
252 } else {
253 return Err(CredentialError::NoneLeft.into());
254 }
255 }
256
257 Ok(remaining)
258}
259
260
261
262
263