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
use super::E2eiEnrollment;
use crate::{
    prelude::{E2eIdentityError, E2eIdentityResult, MlsCentral},
    CryptoError, CryptoResult,
};
use core_crypto_keystore::{
    entities::{E2eiRefreshToken, UniqueEntity},
    CryptoKeystoreResult,
};
use mls_crypto_provider::MlsCryptoProvider;
use openmls_traits::OpenMlsCryptoProvider;
use zeroize::Zeroize;

/// An OIDC refresh token managed by CoreCrypto to benefit from encryption-at-rest
#[derive(Debug, serde::Serialize, serde::Deserialize, Zeroize, derive_more::From, derive_more::Deref)]
#[zeroize(drop)]
pub struct RefreshToken(String);

impl E2eiEnrollment {
    /// Lets clients retrieve the OIDC refresh token to try to renew the user's authorization.
    /// If it's expired, the user needs to reauthenticate and they will update the refresh token
    /// in [E2eiEnrollment::new_oidc_challenge_request]
    pub fn get_refresh_token(&self) -> E2eIdentityResult<&str> {
        self.refresh_token
            .as_ref()
            .map(|rt| rt.as_str())
            .ok_or(E2eIdentityError::OutOfOrderEnrollment(
                "No OIDC refresh token registered yet or it has been persisted",
            ))
    }

    pub(crate) async fn replace_refresh_token(
        &self,
        backend: &MlsCryptoProvider,
        rt: RefreshToken,
    ) -> CryptoKeystoreResult<()> {
        let mut conn = backend.key_store().borrow_conn().await?;
        let rt = E2eiRefreshToken::from(rt);
        rt.replace(&mut conn).await
    }
}

impl MlsCentral {
    pub(crate) async fn find_refresh_token(&self) -> CryptoResult<RefreshToken> {
        let mut conn = self.mls_backend.key_store().borrow_conn().await?;
        E2eiRefreshToken::find_unique(&mut conn).await?.try_into()
    }
}

impl TryFrom<E2eiRefreshToken> for RefreshToken {
    type Error = CryptoError;

    fn try_from(mut entity: E2eiRefreshToken) -> CryptoResult<Self> {
        let content = std::mem::take(&mut entity.content);
        Ok(Self(String::from_utf8(content)?))
    }
}

impl From<RefreshToken> for E2eiRefreshToken {
    fn from(mut rt: RefreshToken) -> Self {
        let content = std::mem::take(&mut rt.0);
        Self {
            content: content.into_bytes(),
        }
    }
}