pub(crate) struct VaultSession {
client: VaultClient,
email: String,
state: RwLock<SessionState>,
unlock_gate: Mutex<()>,
refresh_gate: Mutex<()>,
updates: UpdateFanout,
idle_minutes: Option<u64>,
last_used: Mutex<Option<SystemTime>>,
lock_generation: AtomicU64,
audit: Option<VaultAudit>,
}Expand description
One process-wide Vaultwarden session.
Fields§
§client: VaultClient§email: String§state: RwLock<SessionState>§unlock_gate: Mutex<()>Serializes unlocks, so two parked cards that both carry a password cannot race: the first wins and the second reads an unlocked session.
refresh_gate: Mutex<()>Serializes refreshes. A rotating refresh token is spent once, so two concurrent 401s must not both redeem it; the second reads the token the first stored.
updates: UpdateFanoutWhere a rotation is announced: the enrolment blobs hold the old token and the client that owns one rewrites it from this.
idle_minutes: Option<u64>The configured idle bound in minutes, or None for no idle lock.
last_used: Mutex<Option<SystemTime>>When the session was last used, for the idle clock. Wall clock, not
Instant: a monotonic clock stops while the machine sleeps, so an
overnight lid-close would never reach the bound.
lock_generation: AtomicU64Bumped by every lock, so an unlock whose network work was overtaken by a lock does not install its keys under it.
audit: Option<VaultAudit>Implementations§
Source§impl VaultSession
impl VaultSession
Sourcepub(crate) fn with_client(
config: &VaultConfig,
app_support: Option<&Path>,
config_dir: &Path,
client: VaultClient,
updates: UpdateFanout,
) -> Result<Self, VaultError>
pub(crate) fn with_client( config: &VaultConfig, app_support: Option<&Path>, config_dir: &Path, client: VaultClient, updates: UpdateFanout, ) -> Result<Self, VaultError>
Build the session’s audit around a client the workspace built. The
audit path is <app-support>/vault/audit-<config-dir-store-key>.jsonl;
a missing app-support dir leaves the session usable and the audit off.
Sourcepub(crate) fn idle_minutes(&self) -> Option<u64>
pub(crate) fn idle_minutes(&self) -> Option<u64>
The idle bound the config set, for the settings card.
Sourcepub(crate) fn is_locked(&self) -> bool
pub(crate) fn is_locked(&self) -> bool
Whether the derived keys are absent. A session that has never unlocked, one whose refresh failed and one past its idle bound all read locked.
Sourcefn lock_if_idle(&self)
fn lock_if_idle(&self)
Lock a session that has gone unused past its configured bound. The clock is read here rather than kept by a timer, so the lock lands on the first touch after the bound - and a session nothing touches is never read unlocked by anyone.
Sourcepub(crate) fn keys(&self) -> Result<Arc<Unlocked>, VaultError>
pub(crate) fn keys(&self) -> Result<Arc<Unlocked>, VaultError>
The unlocked keys. A caller that needs crypto reads these; a locked session returns its own error rather than an option a caller forgets.
Sourcepub(crate) fn enrolment_material(&self) -> Option<VaultReleased>
pub(crate) fn enrolment_material(&self) -> Option<VaultReleased>
The material a client wraps to enrol this device: the current refresh
token and the account’s user key, base64 - or None when the session
holds no tokens or keys, and when it holds no refresh token, because a
blob built on material that cannot refresh is a shortcut to nothing.
Sourcefn announce_rotation(&self, refresh_token: String)
fn announce_rotation(&self, refresh_token: String)
Tell every view the refresh token rotated. The token is a secret: it rides the live socket for the client that owns an enrolment to rewrite its blob, and no store keeps it.
Sourcepub(crate) async fn unlock(
&self,
password: &str,
two_factor: Option<&str>,
) -> Result<(), VaultError>
pub(crate) async fn unlock( &self, password: &str, two_factor: Option<&str>, ) -> Result<(), VaultError>
Derive the master key and unlock the account, storing the tokens and the user/private/organization keys. Idempotent: a session another card already unlocked is left alone.
Sourcepub(crate) async fn unlock_released(
&self,
refresh_token: &str,
user_key: &str,
) -> Result<(), VaultError>
pub(crate) async fn unlock_released( &self, refresh_token: &str, user_key: &str, ) -> Result<(), VaultError>
Unlock from material a client released through its platform authenticator: the enrolment’s refresh token and the account’s user key.
The destination is the password unlock’s - a token, a sync and the
held keys - without the master password crossing on this start. The
server cannot prove the released user key (client-side enforcement is
the design); a wrong one fails when the private key will not unwrap.
Idempotent like Self::unlock: a session another card unlocked is
left alone.
Sourcefn access_token(&self) -> Result<Zeroizing<String>, VaultError>
fn access_token(&self) -> Result<Zeroizing<String>, VaultError>
The current access token, or Locked when there is none. The clone is
zeroized when the caller drops it.
Sourcepub(crate) async fn refresh(
&self,
spent: &str,
) -> Result<Zeroizing<String>, VaultError>
pub(crate) async fn refresh( &self, spent: &str, ) -> Result<Zeroizing<String>, VaultError>
Refresh the access token. A missing or rejected refresh token clears the keys and tokens, which is what makes the next held call ask for the master password; a session with no refresh token must lock too, or the card would never ask and every call would repeat the 401.
spent is the token that got the 401. Another call may have refreshed
while this one waited on the gate; its token is then current and the
refresh token was already spent, so that answer is handed back instead
of redeeming the same refresh token twice.
Sourcepub(crate) fn lock(&self)
pub(crate) fn lock(&self)
Drop the tokens and the derived keys. The key types zeroize on drop. A lock that found a session open announces it, so every view’s vault card redraws - the settings page’s own among them.
Sourcepub(crate) fn note_decrypt_failure(
&self,
caller: &SessionSlot,
item: Option<&str>,
)
pub(crate) fn note_decrypt_failure( &self, caller: &SessionSlot, item: Option<&str>, )
A decryption failure under a key that has not changed means the account rotated its keys: drop them, so the next held call asks for the master password rather than repeating a failure against stale keys.
Sourcepub(crate) async fn ensure_keys_current(
&self,
caller: &SessionSlot,
item: Option<&str>,
) -> Result<SyncData, VaultError>
pub(crate) async fn ensure_keys_current( &self, caller: &SessionSlot, item: Option<&str>, ) -> Result<SyncData, VaultError>
A write must not run against keys the account rotated while the session stayed open: its ciphertext would be unreadable after the next unlock. The wrapped user key’s fingerprint from unlock is compared with the one a fresh sync carries. The sync comes back so a write can stamp the account id from the same read that verified the key.
Sourcepub(crate) fn note_key_unverifiable(
&self,
caller: &SessionSlot,
item: Option<&str>,
)
pub(crate) fn note_key_unverifiable( &self, caller: &SessionSlot, item: Option<&str>, )
Drop the keys when a sync cannot prove which user key the account holds, so the next call asks for the master password instead of writing under an unverified unlock.
Sourcepub(crate) fn note_key_rotation(&self, caller: &SessionSlot, item: Option<&str>)
pub(crate) fn note_key_rotation(&self, caller: &SessionSlot, item: Option<&str>)
Drop the keys after an account rotation; re-entering the master password is the only thing that fixes it.
Sourcepub(crate) async fn sync(&self) -> Result<SyncData, VaultError>
pub(crate) async fn sync(&self) -> Result<SyncData, VaultError>
GET /api/sync, through the refresh path.
pub(crate) async fn get_cipher(&self, id: &str) -> Result<Value, VaultError>
pub(crate) async fn create_cipher( &self, body: &Value, ) -> Result<Value, VaultError>
pub(crate) async fn update_cipher( &self, id: &str, body: &Value, ) -> Result<Value, VaultError>
pub(crate) async fn trash_cipher(&self, id: &str) -> Result<Value, VaultError>
pub(crate) async fn restore_cipher(&self, id: &str) -> Result<Value, VaultError>
pub(crate) async fn list_folders(&self) -> Result<Vec<Folder>, VaultError>
pub(crate) async fn create_folder( &self, name: &str, ) -> Result<Value, VaultError>
pub(crate) async fn update_folder( &self, id: &str, name: &str, ) -> Result<Value, VaultError>
pub(crate) async fn delete_folder(&self, id: &str) -> Result<Value, VaultError>
pub(crate) async fn create_attachment_slot( &self, cipher_id: &str, body: &Value, ) -> Result<Value, VaultError>
pub(crate) async fn upload_attachment( &self, cipher_id: &str, attachment_id: &str, data: &[u8], ) -> Result<Value, VaultError>
pub(crate) async fn get_attachment_meta( &self, cipher_id: &str, attachment_id: &str, ) -> Result<AttachmentMeta, VaultError>
pub(crate) async fn download_attachment( &self, url: &str, max_bytes: u64, ) -> Result<Vec<u8>, VaultError>
pub(crate) async fn delete_attachment( &self, cipher_id: &str, attachment_id: &str, ) -> Result<Value, VaultError>
Auto Trait Implementations§
impl !Freeze for VaultSession
impl !RefUnwindSafe for VaultSession
impl !UnwindSafe for VaultSession
impl Send for VaultSession
impl Sync for VaultSession
impl Unpin for VaultSession
impl UnsafeUnpin for VaultSession
Blanket Implementations§
§impl<T> AnySync for T
impl<T> AnySync for T
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
impl<S, T> Duplex<S> for Twhere
T: FromSample<S> + ToSample<S>,
§impl<S> FromSample<S> for S
impl<S> FromSample<S> for S
fn from_sample_(s: S) -> S
§impl<T> Instrument for T
impl<T> Instrument for T
§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more