1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
// Wire
// Copyright (C) 2022 Wire Swiss GmbH

// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program. If not, see http://www.gnu.org/licenses/.

#![doc = include_str!("../README.md")]
#![doc = include_str!("../../docs/KEYSTORE_IMPLEMENTATION.md")]

mod error;
pub use error::*;

pub mod connection;
pub use connection::Connection;
pub mod entities;
pub mod transaction;

pub(crate) mod mls;
pub use self::mls::CryptoKeystoreMls;
pub use self::mls::{deser, ser};

cfg_if::cfg_if! {
    if #[cfg(feature = "proteus-keystore")] {
        pub(crate) mod proteus;
        pub use self::proteus::CryptoKeystoreProteus;
    }
}

#[cfg(not(target_family = "wasm"))]
use sha2::{Digest, Sha256};

#[cfg(feature = "dummy-entity")]
pub mod dummy_entity {
    use crate::{
        entities::{Entity, EntityBase, EntityFindParams, StringEntityId},
        CryptoKeystoreResult, MissingKeyErrorKind,
    };

    #[derive(Debug, Eq, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
    pub struct DummyStoreValue;
    #[cfg_attr(target_family = "wasm", async_trait::async_trait(?Send))]
    #[cfg_attr(not(target_family = "wasm"), async_trait::async_trait)]
    impl EntityBase for DummyStoreValue {
        type ConnectionType = crate::connection::KeystoreDatabaseConnection;
        type AutoGeneratedFields = ();
        const COLLECTION_NAME: &'static str = "";

        fn to_missing_key_err_kind() -> MissingKeyErrorKind {
            MissingKeyErrorKind::MlsGroup
        }

        fn to_transaction_entity(self) -> crate::transaction::dynamic_dispatch::Entity {
            unimplemented!("Not implemented")
        }
    }

    #[cfg_attr(target_family = "wasm", async_trait::async_trait(?Send))]
    #[cfg_attr(not(target_family = "wasm"), async_trait::async_trait)]
    impl Entity for DummyStoreValue {
        fn id_raw(&self) -> &[u8] {
            b""
        }

        async fn find_all(
            _conn: &mut Self::ConnectionType,
            _params: EntityFindParams,
        ) -> CryptoKeystoreResult<Vec<Self>> {
            Ok(vec![])
        }
        async fn find_one(
            _conn: &mut Self::ConnectionType,
            _id: &StringEntityId,
        ) -> CryptoKeystoreResult<Option<Self>> {
            Ok(Some(DummyStoreValue))
        }
        async fn find_many(conn: &mut Self::ConnectionType, ids: &[StringEntityId]) -> CryptoKeystoreResult<Vec<Self>> {
            // Default, inefficient & naive method
            let mut ret = Vec::with_capacity(ids.len());
            for id in ids {
                if let Some(entity) = Self::find_one(conn, id).await? {
                    ret.push(entity);
                }
            }

            Ok(ret)
        }
        async fn count(_conn: &mut Self::ConnectionType) -> CryptoKeystoreResult<usize> {
            Ok(0)
        }

        #[cfg(target_family = "wasm")]
        fn encrypt(&mut self, _cipher: &aes_gcm::Aes256Gcm) -> CryptoKeystoreResult<()> {
            Ok(())
        }
        #[cfg(target_family = "wasm")]
        fn decrypt(&mut self, _cipher: &aes_gcm::Aes256Gcm) -> CryptoKeystoreResult<()> {
            Ok(())
        }
    }

    #[derive(Debug, Clone, PartialEq, Eq)]
    pub struct DummyValue(Vec<u8>);

    impl From<&str> for DummyValue {
        fn from(id: &str) -> Self {
            DummyValue(format!("dummy value {id}").into_bytes())
        }
    }
}

/// Used to calculate ID hashes for some MlsEntities' SQLite tables (not used on wasm).
/// We only use sha256 on platforms where we use SQLite.
/// On wasm, we use IndexedDB, a key-value store, via the idb crate.
#[cfg(not(target_family = "wasm"))]
pub(crate) fn sha256(data: &[u8]) -> String {
    let mut hasher = Sha256::new();
    hasher.update(data);
    format!("{:x}", hasher.finalize())
}