1use crate::db::types::Database;
2use crate::{
3 DatabaseKey,
4 error::{
5 BlockStreamError, CompressionConfigError, CryptographyError, DatabaseKeyError, InnerCipherConfigError, KdfConfigError,
6 OuterCipherConfigError, VariantDictionaryError, XmlParseError,
7 },
8 format::{
9 DatabaseVersion, DatabaseVersionParseError,
10 kdb::KdbOpenError,
11 kdb::parse_kdb,
12 kdbx3::{Kdbx3OpenError, decrypt_kdbx3, parse_kdbx3},
13 kdbx4::{Kdbx4OpenError, decrypt_kdbx4, parse_kdbx4},
14 },
15};
16
17#[derive(Debug, thiserror::Error)]
19pub enum DatabaseOpenError {
20 #[error(transparent)]
21 Io(#[from] std::io::Error),
22
23 #[error(transparent)]
24 Key(#[from] DatabaseKeyError),
25
26 #[error(transparent)]
27 DatabaseIntegrity(#[from] DatabaseIntegrityError),
28
29 #[error(transparent)]
30 Version(#[from] DatabaseVersionParseError),
31
32 #[error("Opening this database version is not supported")]
33 UnsupportedVersion,
34}
35
36#[derive(Debug, thiserror::Error)]
38pub enum DatabaseIntegrityError {
39 #[error(transparent)]
40 Kdb(#[from] KdbOpenError),
41
42 #[error(transparent)]
43 Kdbx3(#[from] Kdbx3OpenError),
44
45 #[error(transparent)]
46 Kdbx4(#[from] Kdbx4OpenError),
47
48 #[error(transparent)]
49 Version(#[from] DatabaseVersionParseError),
50
51 #[error("Invalid KDBX identifier")]
52 InvalidKDBXIdentifier,
53
54 #[error("Invalid KDBX version: {}.{}.{}", version, file_major_version, file_minor_version)]
55 InvalidKDBXVersion {
56 version: u32,
57 file_major_version: u32,
58 file_minor_version: u32,
59 },
60
61 #[error("Invalid header size: {}", size)]
62 InvalidFixedHeader { size: usize },
63
64 #[error("Invalid field length for type {}: {} (expected {})", field_type, field_size, expected_field_size)]
65 InvalidKDBFieldLength {
66 field_type: u16,
67 field_size: u32,
68 expected_field_size: u32,
69 },
70
71 #[error("Missing group level")]
72 MissingKDBGroupLevel,
73 #[error("Invalid KDBX header field ID: {}", field_id)]
74 InvalidKDBXHeaderFieldID { field_id: u8 },
75 #[error("Invalid group level {} (current level {})", group_level, current_level)]
76 InvalidKDBGroupLevel { group_level: u16, current_level: u16 },
77 #[error("Missing group ID")]
78 MissingKDBGroupId,
79 #[error("Invalid group ID {}", group_id)]
80 InvalidKDBGroupId { group_id: u32 },
81 #[error("Invalid group field type: {}", field_type)]
82 InvalidKDBGroupFieldType { field_type: u16 },
83 #[error("Invalid entry field type: {}", field_type)]
84 InvalidKDBEntryFieldType { field_type: u16 },
85 #[error("Incomplete group")]
86 IncompleteKDBGroup,
87 #[error("Incomplete entry")]
88 IncompleteKDBEntry,
89 #[error("Invalid fixed cipher ID: {}", cid)]
90 InvalidFixedCipherID { cid: u32 },
91 #[error("Header hash masmatch")]
92 HeaderHashMismatch,
93 #[error("Invalid outer header entry: {}", entry_type)]
94 InvalidOuterHeaderEntry { entry_type: u8 },
95 #[error("Incomplete outer header: Missing {}", missing_field)]
96 IncompleteOuterHeader { missing_field: String },
97 #[error("Invalid inner header entry: {}", entry_type)]
98 InvalidInnerHeaderEntry { entry_type: u8 },
99 #[error("Incomplete outer header: Missing {}", missing_field)]
100 IncompleteInnerHeader { missing_field: String },
101
102 #[error(transparent)]
103 Cryptography(#[from] CryptographyError),
104 #[error(transparent)]
105 Xml(#[from] XmlParseError),
106 #[error(transparent)]
107 OuterCipher(#[from] OuterCipherConfigError),
108 #[error(transparent)]
109 InnerCipher(#[from] InnerCipherConfigError),
110 #[error(transparent)]
111 Compression(#[from] CompressionConfigError),
112 #[error(transparent)]
113 BlockStream(#[from] BlockStreamError),
114 #[error(transparent)]
115 VariantDictionary(#[from] VariantDictionaryError),
116 #[error(transparent)]
117 KdfSettings(#[from] KdfConfigError),
118 #[error(transparent)]
119 Io(#[from] std::io::Error),
120}
121
122impl Database {
123 pub fn open(source: &mut dyn std::io::Read, key: DatabaseKey) -> Result<Database, DatabaseOpenError> {
125 let mut data = Vec::new();
126 source.read_to_end(&mut data)?;
127
128 Database::parse(data.as_ref(), key)
129 }
130
131 pub fn parse(data: &[u8], key: DatabaseKey) -> Result<Database, DatabaseOpenError> {
132 let database_version = DatabaseVersion::parse(data)?;
133
134 match database_version {
135 DatabaseVersion::KDB(_) => parse_kdb(data, &key),
136 DatabaseVersion::KDB2(_) => Err(DatabaseOpenError::UnsupportedVersion),
137 DatabaseVersion::KDB3(_) => parse_kdbx3(data, &key),
138 DatabaseVersion::KDB4(_) => parse_kdbx4(data, &key),
139 }
140 }
141
142 pub fn get_xml(source: &mut dyn std::io::Read, key: DatabaseKey) -> Result<Vec<u8>, DatabaseOpenError> {
144 let mut data = Vec::new();
145 source.read_to_end(&mut data)?;
146
147 let database_version = DatabaseVersion::parse(data.as_ref())?;
148
149 let data = match database_version {
150 DatabaseVersion::KDB(_) => return Err(DatabaseOpenError::UnsupportedVersion),
151 DatabaseVersion::KDB2(_) => return Err(DatabaseOpenError::UnsupportedVersion),
152 DatabaseVersion::KDB3(_) => decrypt_kdbx3(data.as_ref(), &key)?.2,
153 DatabaseVersion::KDB4(_) => decrypt_kdbx4(data.as_ref(), &key)?.3,
154 };
155
156 Ok(data)
157 }
158
159 pub fn get_version(source: &mut dyn std::io::Read) -> Result<DatabaseVersion, DatabaseIntegrityError> {
161 let mut data = vec![0; DatabaseVersion::get_version_header_size()];
162 _ = source.read(&mut data)?;
163 Ok(DatabaseVersion::parse(data.as_ref())?)
164 }
165}