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