saa_wasm/
lib.rs

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/* 
264
265
266
267pub fn add_credentials(
268    deps: &mut DepsMut,
269    data: VerifiedData,
270    sender: &str
271) -> Result<Vec<CredentialRecord>, AuthError> {
272    data.validate(sender)?;
273
274    let had_natives = HAS_NATIVES.load(deps.storage)?;
275    let nonce = account_number(deps.storage);
276
277    ACCOUNT_NUMBER.save(deps.storage, &(nonce +1) )?;
278
279    if let Some(ix) = data.primary_index {
280        VERIFYING_ID.save(deps.storage, &data.credentials[ix].id())?;
281    }
282
283    let mut has_natives = had_natives;
284    let mut records = Vec::with_capacity(data.credentials.len());
285
286    for cred in data.credentials.iter() {
287        let id = cred.id();
288        ensure!(!CREDS.has(deps.storage, id.clone()), StorageError::AlreadyExists(id));
289        let info: CredentialInfo = cred.verify(deps.as_ref())?;
290        if !has_natives && info.name == CredentialName::Native {
291            has_natives = true;
292        }
293        CREDS.save(deps.storage, id.clone(), &info)?;
294        records.push((id, info));
295    }
296
297    if !had_natives && has_natives {
298        HAS_NATIVES.save(deps.storage, &true)?;
299    }   
300
301    if !VERIFYING_ID.exists(deps.storage) {
302        VERIFYING_ID.save(deps.storage, &data.credentials[0].id())?;
303    }
304    Ok(records)
305}
306
307
308
309 */