bitwarden_core/secrets_manager/
state.rs1use std::{fmt::Debug, path::Path};
7
8use bitwarden_crypto::{EncString, KeyDecryptable, KeyEncryptable};
9use bitwarden_encoding::B64;
10use serde::{Deserialize, Serialize};
11
12use crate::auth::AccessToken;
13
14const STATE_VERSION: u32 = 1;
17
18#[cfg(feature = "secrets")]
20#[derive(Serialize, Deserialize, Debug)]
21pub(crate) struct ClientState {
22 pub(crate) version: u32,
23 pub(crate) token: String,
24 pub(crate) encryption_key: B64,
25}
26
27#[allow(missing_docs)]
28#[derive(Debug, thiserror::Error)]
29pub enum StateFileError {
30 #[error(transparent)]
31 Crypto(#[from] bitwarden_crypto::CryptoError),
32 #[error(transparent)]
33 Serde(#[from] serde_json::Error),
34 #[error(transparent)]
35 Io(#[from] std::io::Error),
36
37 #[error("The state file version is invalid")]
38 InvalidStateFileVersion,
39}
40
41impl ClientState {
42 pub fn new(token: String, encryption_key: B64) -> Self {
43 Self {
44 version: STATE_VERSION,
45 token,
46 encryption_key,
47 }
48 }
49}
50
51pub(crate) fn get(
53 state_file: &Path,
54 access_token: &AccessToken,
55) -> Result<ClientState, StateFileError> {
56 let file_content = std::fs::read_to_string(state_file)?;
57
58 let encrypted_state: EncString = file_content.parse()?;
59 let decrypted_state: String = encrypted_state.decrypt_with_key(&access_token.encryption_key)?;
60 let client_state: ClientState = serde_json::from_str(&decrypted_state)?;
61
62 if client_state.version != STATE_VERSION {
63 return Err(StateFileError::InvalidStateFileVersion);
64 }
65
66 Ok(client_state)
67}
68
69pub(crate) fn set(
71 state_file: &Path,
72 access_token: &AccessToken,
73 state: ClientState,
74) -> Result<(), StateFileError> {
75 let serialized_state: String = serde_json::to_string(&state)?;
76 let encrypted_state: EncString =
77 serialized_state.encrypt_with_key(&access_token.encryption_key)?;
78 let state_string: String = encrypted_state.to_string();
79
80 Ok(std::fs::write(state_file, state_string)?)
81}