1mod utils;
2#[cfg(feature = "utils")]
3mod methods;
4#[cfg(feature = "session")]
5mod session;
6
7
8pub use types::{StoredCredentials, UpdateOperation};
9
10#[cfg(feature = "session")]
11pub use {
12 types::{sessions::{queries::*, actions::*}, macros::{session_action, session_query}},
13 session::{handle_session_actions, handle_session_queries},
14};
15#[cfg(feature = "types")]
16pub use {
17 types::stores, smart_account_auth as saa_types
18};
19
20#[cfg(feature = "utils")]
21pub use {methods::*, utils::*};
22
23
24
25use smart_account_auth::{
26 traits::Verifiable,
27 msgs::SignedDataMsg,
28 CredentialData, CredentialRecord, CredentialInfo, CredentialName, CredentialId,
29 ensure
30};
31use types::{
32 stores::{ACCOUNT_NUMBER, HAS_NATIVES, VERIFYING_ID, CREDENTIAL_INFOS as CREDS},
33 wasm::{Api, Env, MessageInfo, Storage},
34 errors::{AuthError, StorageError},
35 serde
36};
37
38
39pub fn account_number(
40 storage: &dyn Storage
41) -> u64 {
42 ACCOUNT_NUMBER.load(storage).unwrap_or(0)
43}
44
45
46
47
48pub fn verify_native(
49 storage: &dyn Storage,
50 sender: String
51) -> Result<(), StorageError> {
52 ensure!(CREDS.has(storage, sender), StorageError::NotFound);
53 Ok(())
54}
55
56
57pub fn verify_signed(
58 api: &dyn Api,
59 storage: &dyn Storage,
60 env: &Env,
61 msg: SignedDataMsg
62) -> Result<(), AuthError> {
63 utils::convert_validate(msg.data.as_slice(), env, account_number(storage))?;
64 utils::cred_from_signed(api, storage, msg)?;
65 Ok(())
66}
67
68
69
70pub fn verify_signed_actions<T : serde::de::DeserializeOwned>(
71 api: &dyn Api,
72 storage: &mut dyn Storage,
73 env: &Env,
74 msg: SignedDataMsg
75) -> Result<Vec<T>, AuthError> {
76 let nonce = account_number(storage);
77 let signed = utils::convert_validate_return(msg.data.as_slice(), env, nonce)?;
78 utils::cred_from_signed(api, storage, msg)?;
79 ACCOUNT_NUMBER.save(storage, &(nonce + 1))?;
80 Ok(signed.messages)
81}
82
83
84
85
86
87pub fn has_natives(
88 storage: &dyn Storage
89) -> bool {
90 HAS_NATIVES.load(storage).unwrap_or(false)
91}
92
93
94
95pub fn get_stored_credentials(
96 storage: &dyn Storage
97) -> Result<StoredCredentials, StorageError> {
98
99
100 Ok(StoredCredentials {
101 has_natives: has_natives(storage),
102 verifying_id: VERIFYING_ID.load(storage).map_err(|_| StorageError::NotFound)?,
103 records: utils::get_credential_records(storage)?,
104 account_number: account_number(storage),
105 #[cfg(feature = "session")]
106 sessions : None,
107 })
108}
109
110
111
112
113pub fn save_credentials(
114 api: &dyn Api,
115 storage: &mut dyn Storage,
116 env: &Env,
117 info: &MessageInfo,
118 data: &CredentialData
119) -> Result<CredentialData, AuthError> {
120 let data = data.with_native(info);
121 data.validate()?;
122 data.checked_replay( env, 0u64)?;
123
124 ACCOUNT_NUMBER.save(storage, &1u64)?;
125
126 let mut has_natives = false;
127 for cred in data.credentials.iter() {
128 cred.verify_cosmwasm(api)?;
129 let info = cred.info();
130 if info.name == CredentialName::Native {
131 has_natives = true
132 }
133 CREDS.save(storage, cred.id(), &info)?;
134 }
135 HAS_NATIVES.save(storage, &has_natives)?;
136
137 let verifying = match data.primary_index {
138 Some(i) => data.credentials[i as usize].id(),
139 None => data.credentials.first().unwrap().id()
140 };
141 VERIFYING_ID.save(storage, &verifying)?;
142 Ok(data)
143}
144
145
146
147
148
149
150
151pub fn reset_credentials(
152 storage: &mut dyn Storage,
153 acc_number: bool,
154 #[cfg(feature = "session")]
155 sessions: bool
156) -> Result<(), StorageError> {
157 VERIFYING_ID.remove(storage);
158 HAS_NATIVES.remove(storage);
159 CREDS.clear(storage);
160 if acc_number {
161 ACCOUNT_NUMBER.remove(storage);
162 }
163 #[cfg(feature = "session")]
164 {
165 if sessions {
166 types::stores::SESSIONS.clear(storage);
167 }
168 }
169 Ok(())
170}
171
172
173
174
175pub fn update_credentials(
209 api: &dyn Api,
210 storage: &mut dyn Storage,
211 op: UpdateOperation,
212) -> Result<(), AuthError> {
213 let had_natives = HAS_NATIVES.load(storage)?;
214 match op {
215 UpdateOperation::Add(data) => {
216 add_credentials(api, storage, data, had_natives)
217 },
218 UpdateOperation::Remove(idx) => {
219 remove_credentials(storage, idx, had_natives)?;
220 Ok(())
221 }
222 }
223}
224
225
226
227
228
229pub fn add_credentials(
230 api: &dyn Api,
231 storage: &mut dyn Storage,
232 data: CredentialData,
233 had_natives: bool
234) -> Result<(), AuthError> {
235
236 data.validate()?;
237 data.verify_cosmwasm(api)?;
238
239 if let Some(ix) = data.primary_index {
240 VERIFYING_ID.save(storage, &data.credentials[ix as usize].id())?;
241 }
242
243 let mut has_natives = had_natives;
244
245 for cred in data.credentials.iter() {
246 let id = cred.id();
247 ensure!(!CREDS.has(storage, id.clone()), StorageError::AlreadyExists);
248 let info = cred.info();
249 if !has_natives && info.name == CredentialName::Native {
250 has_natives = true;
251 }
252 CREDS.save(storage, id, &info)?;
253 }
254
255 if !had_natives && has_natives {
256 HAS_NATIVES.save(storage, &true)?;
257 }
258
259 if !VERIFYING_ID.exists(storage) {
260 VERIFYING_ID.save(storage, &data.credentials[0].id())?;
261 }
262 Ok(())
263}
264
265
266
267pub fn remove_credentials(
268 storage: &mut dyn Storage,
269 idx: Vec<CredentialId>,
270 had_natives: bool
271) -> Result<Vec<CredentialRecord>, AuthError> {
272 ensure!(!idx.is_empty(), AuthError::generic("Must supply at least one credential to remove"));
273
274 let all_creds = utils::get_credential_records(storage)?;
275 let left = all_creds.len() - idx.len();
276 ensure!(left > 0, AuthError::generic("Must leave at least one credential"));
277
278 let verifying_id = VERIFYING_ID.load(storage)?;
279 let mut native_changed = false;
280 let mut verifying_removed = false;
281
282 let remaining : Vec<(String, CredentialInfo)> = all_creds
283 .into_iter()
284 .filter(|(id, info)| {
285 if idx.contains(id) {
286 if info.name == CredentialName::Native {
287 native_changed = true;
288 }
289 if *id == verifying_id {
290 verifying_removed = true;
291 }
292 CREDS.remove(storage, id.to_string());
293 false
294 } else {
295 true
296 }
297 }).collect();
298
299 if had_natives && native_changed {
300 let still_has = remaining
301 .iter()
302 .any(|(_, info)| info.name == CredentialName::Native);
303 HAS_NATIVES.save(storage, &still_has)?;
304 }
305
306 if verifying_removed {
307 let first = remaining.first().unwrap();
308 VERIFYING_ID.save(storage, &first.0)?;
309 }
310
311 Ok(remaining)
312}
313