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
//! Error types for tsafe-core.
//!
//! All fallible public functions return [`SafeResult<T>`], which is an alias for
//! `Result<T, SafeError>`. Callers can match on specific variants for structured
//! error handling or surface the `Display` message (derived by `thiserror`) for
//! user-facing output.
use thiserror::Error;
/// Top-level error type for all tsafe-core operations.
#[derive(Debug, Error)]
pub enum SafeError {
#[error("vault not found: {path}")]
VaultNotFound { path: String },
#[error("vault already exists: {path}")]
VaultAlreadyExists { path: String },
#[error("secret not found: {key}")]
SecretNotFound { key: String },
#[error("secret already exists: {key}")]
SecretAlreadyExists { key: String },
#[error("profile not found: {name}")]
ProfileNotFound { name: String },
#[error("decryption failed — wrong password or corrupted vault")]
DecryptionFailed,
#[error("crypto error: {context}")]
Crypto { context: String },
#[error("invalid vault: {reason}")]
InvalidVault { reason: String },
#[error("import parse error in {file}: {reason}")]
ImportParse { file: String, reason: String },
#[error("no snapshots available to restore profile '{profile}'")]
NoSnapshotAvailable { profile: String },
#[error("snapshot not found: {path}")]
SnapshotNotFound { path: String },
#[error("vault schema migration failed: {reason}")]
MigrationFailed { reason: String },
#[error("vault is corrupted and could not be auto-healed: {reason}")]
VaultCorrupted { reason: String },
/// The OS credential store entry for biometric/keyring unlock is stale.
///
/// This occurs when the vault password was rotated, a new fingerprint enrolled,
/// or the biometric enrollment changed after `tsafe biometric enable` was run.
/// The stored credential no longer matches — the user must re-enroll explicitly.
///
/// Callers MUST NOT silently fall through to another method. Surface this
/// error with a clear message directing the user to `tsafe biometric re-enroll`.
#[error(
"stale biometric credential: the stored credential no longer matches the vault (password \
was rotated or biometric enrollment changed). Run `tsafe biometric re-enroll` to \
restore password-free unlock."
)]
StaleBiometricCredential,
/// The Windows Hello verification dialog was dismissed by the user before
/// completing. The vault unlock is not permitted; the caller must not fall
/// through to another unlock method.
#[error("Windows Hello verification was canceled by the user")]
BiometricCanceled,
/// A Windows Hello verification attempt failed for a reason other than
/// user cancellation (device not ready, OS error, etc.).
#[error("Windows Hello verification failed: {0}")]
BiometricFailed(String),
#[error("io error: {0}")]
Io(#[from] std::io::Error),
#[error("serialization error: {0}")]
Serialization(#[from] serde_json::Error),
}
/// Convenience alias for `Result<T, SafeError>`.
pub type SafeResult<T> = Result<T, SafeError>;