blob: 53fe03ffb38d8299d8cf13b2604d1cbd0f4fa11f [file] [log] [blame]
David Drysdaleea3835e2024-07-19 11:42:56 +01001// Copyright 2020, The Android Open Source Project
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15//! Tests for legacy keyblob processing.
16
17#![allow(dead_code)]
18use super::*;
19use crate::legacy_blob::test_utils::legacy_blob_test_vectors::*;
20use crate::legacy_blob::test_utils::*;
21use anyhow::{anyhow, Result};
22use keystore2_crypto::aes_gcm_decrypt;
23use keystore2_test_utils::TempDir;
24use rand::Rng;
25use std::convert::TryInto;
26use std::ops::Deref;
27use std::string::FromUtf8Error;
28
29#[test]
30fn decode_encode_alias_test() {
31 static ALIAS: &str = "#({}test[])😗";
32 static ENCODED_ALIAS: &str = "+S+X{}test[]+Y.`-O-H-G";
33 // Second multi byte out of range ------v
34 static ENCODED_ALIAS_ERROR1: &str = "+S+{}test[]+Y";
35 // Incomplete multi byte ------------------------v
36 static ENCODED_ALIAS_ERROR2: &str = "+S+X{}test[]+";
37 // Our encoding: ".`-O-H-G"
38 // is UTF-8: 0xF0 0x9F 0x98 0x97
39 // is UNICODE: U+1F617
40 // is 😗
41 // But +H below is a valid encoding for 0x18 making this sequence invalid UTF-8.
42 static ENCODED_ALIAS_ERROR_UTF8: &str = ".`-O+H-G";
43
44 assert_eq!(ENCODED_ALIAS, &LegacyBlobLoader::encode_alias(ALIAS));
45 assert_eq!(ALIAS, &LegacyBlobLoader::decode_alias(ENCODED_ALIAS).unwrap());
46 assert_eq!(
47 Some(&Error::BadEncoding),
48 LegacyBlobLoader::decode_alias(ENCODED_ALIAS_ERROR1)
49 .unwrap_err()
50 .root_cause()
51 .downcast_ref::<Error>()
52 );
53 assert_eq!(
54 Some(&Error::BadEncoding),
55 LegacyBlobLoader::decode_alias(ENCODED_ALIAS_ERROR2)
56 .unwrap_err()
57 .root_cause()
58 .downcast_ref::<Error>()
59 );
60 assert!(LegacyBlobLoader::decode_alias(ENCODED_ALIAS_ERROR_UTF8)
61 .unwrap_err()
62 .root_cause()
63 .downcast_ref::<FromUtf8Error>()
64 .is_some());
65
66 for _i in 0..100 {
67 // Any valid UTF-8 string should be en- and decoded without loss.
68 let alias_str = rand::thread_rng().gen::<[char; 20]>().iter().collect::<String>();
69 let random_alias = alias_str.as_bytes();
70 let encoded = LegacyBlobLoader::encode_alias(&alias_str);
71 let decoded = match LegacyBlobLoader::decode_alias(&encoded) {
72 Ok(d) => d,
73 Err(_) => panic!("random_alias: {:x?}\nencoded {}", random_alias, encoded),
74 };
75 assert_eq!(random_alias.to_vec(), decoded.bytes().collect::<Vec<u8>>());
76 }
77}
78
79#[test]
80fn read_golden_key_blob_test() -> anyhow::Result<()> {
81 let blob = LegacyBlobLoader::new_from_stream_decrypt_with(&mut &*BLOB, |_, _, _, _, _| {
82 Err(anyhow!("should not be called"))
83 })
84 .unwrap();
85 assert!(!blob.is_encrypted());
86 assert!(!blob.is_fallback());
87 assert!(!blob.is_strongbox());
88 assert!(!blob.is_critical_to_device_encryption());
89 assert_eq!(blob.value(), &BlobValue::Generic([0xde, 0xed, 0xbe, 0xef].to_vec()));
90
91 let blob =
92 LegacyBlobLoader::new_from_stream_decrypt_with(&mut &*REAL_LEGACY_BLOB, |_, _, _, _, _| {
93 Err(anyhow!("should not be called"))
94 })
95 .unwrap();
96 assert!(!blob.is_encrypted());
97 assert!(!blob.is_fallback());
98 assert!(!blob.is_strongbox());
99 assert!(!blob.is_critical_to_device_encryption());
100 assert_eq!(blob.value(), &BlobValue::Decrypted(REAL_LEGACY_BLOB_PAYLOAD.try_into().unwrap()));
101 Ok(())
102}
103
104#[test]
105fn read_aes_gcm_encrypted_key_blob_test() {
106 let blob = LegacyBlobLoader::new_from_stream_decrypt_with(
107 &mut &*AES_GCM_ENCRYPTED_BLOB,
108 |d, iv, tag, salt, key_size| {
109 assert_eq!(salt, None);
110 assert_eq!(key_size, None);
111 assert_eq!(
112 iv,
113 &[
114 0xbd, 0xdb, 0x8d, 0x69, 0x72, 0x56, 0xf0, 0xf5, 0xa4, 0x02, 0x88, 0x7f, 0x00,
115 0x00, 0x00, 0x00,
116 ]
117 );
118 assert_eq!(
119 tag,
120 &[
121 0x50, 0xd9, 0x97, 0x95, 0x37, 0x6e, 0x28, 0x6a, 0x28, 0x9d, 0x51, 0xb9, 0xb9,
122 0xe0, 0x0b, 0xc3
123 ][..]
124 );
125 aes_gcm_decrypt(d, iv, tag, AES_KEY).context("Trying to decrypt blob.")
126 },
127 )
128 .unwrap();
129 assert!(blob.is_encrypted());
130 assert!(!blob.is_fallback());
131 assert!(!blob.is_strongbox());
132 assert!(!blob.is_critical_to_device_encryption());
133
134 assert_eq!(blob.value(), &BlobValue::Decrypted(DECRYPTED_PAYLOAD.try_into().unwrap()));
135}
136
137#[test]
138fn read_golden_key_blob_too_short_test() {
139 let error =
140 LegacyBlobLoader::new_from_stream_decrypt_with(&mut &BLOB[0..15], |_, _, _, _, _| {
141 Err(anyhow!("should not be called"))
142 })
143 .unwrap_err();
144 assert_eq!(Some(&Error::BadLen), error.root_cause().downcast_ref::<Error>());
145}
146
147#[test]
148fn test_is_empty() {
149 let temp_dir = TempDir::new("test_is_empty").expect("Failed to create temp dir.");
150 let legacy_blob_loader = LegacyBlobLoader::new(temp_dir.path());
151
152 assert!(legacy_blob_loader.is_empty().expect("Should succeed and be empty."));
153
154 let _db =
155 crate::database::KeystoreDB::new(temp_dir.path(), None).expect("Failed to open database.");
156
157 assert!(legacy_blob_loader.is_empty().expect("Should succeed and still be empty."));
158
159 std::fs::create_dir(&*temp_dir.build().push("user_0")).expect("Failed to create user_0.");
160
161 assert!(!legacy_blob_loader.is_empty().expect("Should succeed but not be empty."));
162
163 std::fs::create_dir(&*temp_dir.build().push("user_10")).expect("Failed to create user_10.");
164
165 assert!(!legacy_blob_loader.is_empty().expect("Should succeed but still not be empty."));
166
167 std::fs::remove_dir_all(&*temp_dir.build().push("user_0")).expect("Failed to remove user_0.");
168
169 assert!(!legacy_blob_loader.is_empty().expect("Should succeed but still not be empty."));
170
171 std::fs::remove_dir_all(&*temp_dir.build().push("user_10")).expect("Failed to remove user_10.");
172
173 assert!(legacy_blob_loader.is_empty().expect("Should succeed and be empty again."));
174}
175
176#[test]
177fn test_legacy_blobs() -> anyhow::Result<()> {
178 let temp_dir = TempDir::new("legacy_blob_test").unwrap();
179 std::fs::create_dir(&*temp_dir.build().push("user_0")).unwrap();
180
181 std::fs::write(&*temp_dir.build().push("user_0").push(".masterkey"), SUPERKEY).unwrap();
182
183 std::fs::write(
184 &*temp_dir.build().push("user_0").push("10223_USRPKEY_authbound"),
185 USRPKEY_AUTHBOUND,
186 )
187 .unwrap();
188 std::fs::write(
189 &*temp_dir.build().push("user_0").push(".10223_chr_USRPKEY_authbound"),
190 USRPKEY_AUTHBOUND_CHR,
191 )
192 .unwrap();
193 std::fs::write(
194 &*temp_dir.build().push("user_0").push("10223_USRCERT_authbound"),
195 USRCERT_AUTHBOUND,
196 )
197 .unwrap();
198 std::fs::write(
199 &*temp_dir.build().push("user_0").push("10223_CACERT_authbound"),
200 CACERT_AUTHBOUND,
201 )
202 .unwrap();
203
204 std::fs::write(
205 &*temp_dir.build().push("user_0").push("10223_USRPKEY_non_authbound"),
206 USRPKEY_NON_AUTHBOUND,
207 )
208 .unwrap();
209 std::fs::write(
210 &*temp_dir.build().push("user_0").push(".10223_chr_USRPKEY_non_authbound"),
211 USRPKEY_NON_AUTHBOUND_CHR,
212 )
213 .unwrap();
214 std::fs::write(
215 &*temp_dir.build().push("user_0").push("10223_USRCERT_non_authbound"),
216 USRCERT_NON_AUTHBOUND,
217 )
218 .unwrap();
219 std::fs::write(
220 &*temp_dir.build().push("user_0").push("10223_CACERT_non_authbound"),
221 CACERT_NON_AUTHBOUND,
222 )
223 .unwrap();
224
225 let legacy_blob_loader = LegacyBlobLoader::new(temp_dir.path());
226
227 if let (Some((Blob { flags, value }, _params)), Some(cert), Some(chain)) =
228 legacy_blob_loader.load_by_uid_alias(10223, "authbound", &None)?
229 {
230 assert_eq!(flags, 4);
231 assert_eq!(
232 value,
233 BlobValue::Encrypted {
234 data: USRPKEY_AUTHBOUND_ENC_PAYLOAD.to_vec(),
235 iv: USRPKEY_AUTHBOUND_IV.to_vec(),
236 tag: USRPKEY_AUTHBOUND_TAG.to_vec()
237 }
238 );
239 assert_eq!(&cert[..], LOADED_CERT_AUTHBOUND);
240 assert_eq!(&chain[..], LOADED_CACERT_AUTHBOUND);
241 } else {
242 panic!("");
243 }
244
245 if let (Some((Blob { flags, value: _ }, _params)), Some(cert), Some(chain)) =
246 legacy_blob_loader.load_by_uid_alias(10223, "authbound", &None)?
247 {
248 assert_eq!(flags, 4);
249 //assert_eq!(value, BlobValue::Encrypted(..));
250 assert_eq!(&cert[..], LOADED_CERT_AUTHBOUND);
251 assert_eq!(&chain[..], LOADED_CACERT_AUTHBOUND);
252 } else {
253 panic!("");
254 }
255 if let (Some((Blob { flags, value }, _params)), Some(cert), Some(chain)) =
256 legacy_blob_loader.load_by_uid_alias(10223, "non_authbound", &None)?
257 {
258 assert_eq!(flags, 0);
259 assert_eq!(value, BlobValue::Decrypted(LOADED_USRPKEY_NON_AUTHBOUND.try_into()?));
260 assert_eq!(&cert[..], LOADED_CERT_NON_AUTHBOUND);
261 assert_eq!(&chain[..], LOADED_CACERT_NON_AUTHBOUND);
262 } else {
263 panic!("");
264 }
265
266 legacy_blob_loader.remove_keystore_entry(10223, "authbound").expect("This should succeed.");
267 legacy_blob_loader.remove_keystore_entry(10223, "non_authbound").expect("This should succeed.");
268
269 assert_eq!(
270 (None, None, None),
271 legacy_blob_loader.load_by_uid_alias(10223, "authbound", &None)?
272 );
273 assert_eq!(
274 (None, None, None),
275 legacy_blob_loader.load_by_uid_alias(10223, "non_authbound", &None)?
276 );
277
278 // The database should not be empty due to the super key.
279 assert!(!legacy_blob_loader.is_empty()?);
280 assert!(!legacy_blob_loader.is_empty_user(0)?);
281
282 // The database should be considered empty for user 1.
283 assert!(legacy_blob_loader.is_empty_user(1)?);
284
285 legacy_blob_loader.remove_super_key(0);
286
287 // Now it should be empty.
288 assert!(legacy_blob_loader.is_empty_user(0)?);
289 assert!(legacy_blob_loader.is_empty()?);
290
291 Ok(())
292}
293
294struct TestKey(ZVec);
295
296impl crate::utils::AesGcmKey for TestKey {
297 fn key(&self) -> &[u8] {
298 &self.0
299 }
300}
301
302impl Deref for TestKey {
303 type Target = [u8];
304 fn deref(&self) -> &Self::Target {
305 &self.0
306 }
307}
308
309#[test]
310fn test_with_encrypted_characteristics() -> anyhow::Result<()> {
311 let temp_dir = TempDir::new("test_with_encrypted_characteristics").unwrap();
312 std::fs::create_dir(&*temp_dir.build().push("user_0")).unwrap();
313
314 let pw: Password = PASSWORD.into();
315 let pw_key = TestKey(pw.derive_key_pbkdf2(SUPERKEY_SALT, 32).unwrap());
316 let super_key =
317 Arc::new(TestKey(pw_key.decrypt(SUPERKEY_PAYLOAD, SUPERKEY_IV, SUPERKEY_TAG).unwrap()));
318
319 std::fs::write(&*temp_dir.build().push("user_0").push(".masterkey"), SUPERKEY).unwrap();
320
321 std::fs::write(
322 &*temp_dir.build().push("user_0").push("10223_USRPKEY_authbound"),
323 USRPKEY_AUTHBOUND,
324 )
325 .unwrap();
326 make_encrypted_characteristics_file(
327 &*temp_dir.build().push("user_0").push(".10223_chr_USRPKEY_authbound"),
328 &super_key,
329 KEY_PARAMETERS,
330 )
331 .unwrap();
332 std::fs::write(
333 &*temp_dir.build().push("user_0").push("10223_USRCERT_authbound"),
334 USRCERT_AUTHBOUND,
335 )
336 .unwrap();
337 std::fs::write(
338 &*temp_dir.build().push("user_0").push("10223_CACERT_authbound"),
339 CACERT_AUTHBOUND,
340 )
341 .unwrap();
342
343 let legacy_blob_loader = LegacyBlobLoader::new(temp_dir.path());
344
345 assert_eq!(
346 legacy_blob_loader
347 .load_by_uid_alias(10223, "authbound", &None)
348 .unwrap_err()
349 .root_cause()
350 .downcast_ref::<Error>(),
351 Some(&Error::LockedComponent)
352 );
353
354 assert_eq!(
355 legacy_blob_loader.load_by_uid_alias(10223, "authbound", &Some(super_key)).unwrap(),
356 (
357 Some((
358 Blob {
359 flags: 4,
360 value: BlobValue::Encrypted {
361 data: USRPKEY_AUTHBOUND_ENC_PAYLOAD.to_vec(),
362 iv: USRPKEY_AUTHBOUND_IV.to_vec(),
363 tag: USRPKEY_AUTHBOUND_TAG.to_vec()
364 }
365 },
366 structured_test_params()
367 )),
368 Some(LOADED_CERT_AUTHBOUND.to_vec()),
369 Some(LOADED_CACERT_AUTHBOUND.to_vec())
370 )
371 );
372
373 legacy_blob_loader.remove_keystore_entry(10223, "authbound").expect("This should succeed.");
374
375 assert_eq!(
376 (None, None, None),
377 legacy_blob_loader.load_by_uid_alias(10223, "authbound", &None).unwrap()
378 );
379
380 // The database should not be empty due to the super key.
381 assert!(!legacy_blob_loader.is_empty().unwrap());
382 assert!(!legacy_blob_loader.is_empty_user(0).unwrap());
383
384 // The database should be considered empty for user 1.
385 assert!(legacy_blob_loader.is_empty_user(1).unwrap());
386
387 legacy_blob_loader.remove_super_key(0);
388
389 // Now it should be empty.
390 assert!(legacy_blob_loader.is_empty_user(0).unwrap());
391 assert!(legacy_blob_loader.is_empty().unwrap());
392
393 Ok(())
394}
395
396#[test]
397fn test_with_encrypted_certificates() -> anyhow::Result<()> {
398 let temp_dir = TempDir::new("test_with_encrypted_certificates").unwrap();
399 std::fs::create_dir(&*temp_dir.build().push("user_0")).unwrap();
400
401 let pw: Password = PASSWORD.into();
402 let pw_key = TestKey(pw.derive_key_pbkdf2(SUPERKEY_SALT, 32).unwrap());
403 let super_key =
404 Arc::new(TestKey(pw_key.decrypt(SUPERKEY_PAYLOAD, SUPERKEY_IV, SUPERKEY_TAG).unwrap()));
405
406 std::fs::write(&*temp_dir.build().push("user_0").push(".masterkey"), SUPERKEY).unwrap();
407
408 std::fs::write(
409 &*temp_dir.build().push("user_0").push("10223_USRPKEY_authbound"),
410 USRPKEY_AUTHBOUND,
411 )
412 .unwrap();
413 std::fs::write(
414 &*temp_dir.build().push("user_0").push(".10223_chr_USRPKEY_authbound"),
415 USRPKEY_AUTHBOUND_CHR,
416 )
417 .unwrap();
418 make_encrypted_usr_cert_file(
419 &*temp_dir.build().push("user_0").push("10223_USRCERT_authbound"),
420 &super_key,
421 LOADED_CERT_AUTHBOUND,
422 )
423 .unwrap();
424 make_encrypted_ca_cert_file(
425 &*temp_dir.build().push("user_0").push("10223_CACERT_authbound"),
426 &super_key,
427 LOADED_CACERT_AUTHBOUND,
428 )
429 .unwrap();
430
431 let legacy_blob_loader = LegacyBlobLoader::new(temp_dir.path());
432
433 assert_eq!(
434 legacy_blob_loader
435 .load_by_uid_alias(10223, "authbound", &None)
436 .unwrap_err()
437 .root_cause()
438 .downcast_ref::<Error>(),
439 Some(&Error::LockedComponent)
440 );
441
442 assert_eq!(
443 legacy_blob_loader.load_by_uid_alias(10223, "authbound", &Some(super_key)).unwrap(),
444 (
445 Some((
446 Blob {
447 flags: 4,
448 value: BlobValue::Encrypted {
449 data: USRPKEY_AUTHBOUND_ENC_PAYLOAD.to_vec(),
450 iv: USRPKEY_AUTHBOUND_IV.to_vec(),
451 tag: USRPKEY_AUTHBOUND_TAG.to_vec()
452 }
453 },
454 structured_test_params_cache()
455 )),
456 Some(LOADED_CERT_AUTHBOUND.to_vec()),
457 Some(LOADED_CACERT_AUTHBOUND.to_vec())
458 )
459 );
460
461 legacy_blob_loader.remove_keystore_entry(10223, "authbound").expect("This should succeed.");
462
463 assert_eq!(
464 (None, None, None),
465 legacy_blob_loader.load_by_uid_alias(10223, "authbound", &None).unwrap()
466 );
467
468 // The database should not be empty due to the super key.
469 assert!(!legacy_blob_loader.is_empty().unwrap());
470 assert!(!legacy_blob_loader.is_empty_user(0).unwrap());
471
472 // The database should be considered empty for user 1.
473 assert!(legacy_blob_loader.is_empty_user(1).unwrap());
474
475 legacy_blob_loader.remove_super_key(0);
476
477 // Now it should be empty.
478 assert!(legacy_blob_loader.is_empty_user(0).unwrap());
479 assert!(legacy_blob_loader.is_empty().unwrap());
480
481 Ok(())
482}
483
484#[test]
485fn test_in_place_key_migration() -> anyhow::Result<()> {
486 let temp_dir = TempDir::new("test_in_place_key_migration").unwrap();
487 std::fs::create_dir(&*temp_dir.build().push("user_0")).unwrap();
488
489 let pw: Password = PASSWORD.into();
490 let pw_key = TestKey(pw.derive_key_pbkdf2(SUPERKEY_SALT, 32).unwrap());
491 let super_key =
492 Arc::new(TestKey(pw_key.decrypt(SUPERKEY_PAYLOAD, SUPERKEY_IV, SUPERKEY_TAG).unwrap()));
493
494 std::fs::write(&*temp_dir.build().push("user_0").push(".masterkey"), SUPERKEY).unwrap();
495
496 std::fs::write(
497 &*temp_dir.build().push("user_0").push("10223_USRPKEY_authbound"),
498 USRPKEY_AUTHBOUND,
499 )
500 .unwrap();
501 std::fs::write(
502 &*temp_dir.build().push("user_0").push(".10223_chr_USRPKEY_authbound"),
503 USRPKEY_AUTHBOUND_CHR,
504 )
505 .unwrap();
506 make_encrypted_usr_cert_file(
507 &*temp_dir.build().push("user_0").push("10223_USRCERT_authbound"),
508 &super_key,
509 LOADED_CERT_AUTHBOUND,
510 )
511 .unwrap();
512 make_encrypted_ca_cert_file(
513 &*temp_dir.build().push("user_0").push("10223_CACERT_authbound"),
514 &super_key,
515 LOADED_CACERT_AUTHBOUND,
516 )
517 .unwrap();
518
519 let legacy_blob_loader = LegacyBlobLoader::new(temp_dir.path());
520
521 assert_eq!(
522 legacy_blob_loader
523 .load_by_uid_alias(10223, "authbound", &None)
524 .unwrap_err()
525 .root_cause()
526 .downcast_ref::<Error>(),
527 Some(&Error::LockedComponent)
528 );
529
530 let super_key: Option<Arc<dyn AesGcm>> = Some(super_key);
531
532 assert_eq!(
533 legacy_blob_loader.load_by_uid_alias(10223, "authbound", &super_key).unwrap(),
534 (
535 Some((
536 Blob {
537 flags: 4,
538 value: BlobValue::Encrypted {
539 data: USRPKEY_AUTHBOUND_ENC_PAYLOAD.to_vec(),
540 iv: USRPKEY_AUTHBOUND_IV.to_vec(),
541 tag: USRPKEY_AUTHBOUND_TAG.to_vec()
542 }
543 },
544 structured_test_params_cache()
545 )),
546 Some(LOADED_CERT_AUTHBOUND.to_vec()),
547 Some(LOADED_CACERT_AUTHBOUND.to_vec())
548 )
549 );
550
551 legacy_blob_loader.move_keystore_entry(10223, 10224, "authbound", "boundauth").unwrap();
552
553 assert_eq!(
554 legacy_blob_loader
555 .load_by_uid_alias(10224, "boundauth", &None)
556 .unwrap_err()
557 .root_cause()
558 .downcast_ref::<Error>(),
559 Some(&Error::LockedComponent)
560 );
561
562 assert_eq!(
563 legacy_blob_loader.load_by_uid_alias(10224, "boundauth", &super_key).unwrap(),
564 (
565 Some((
566 Blob {
567 flags: 4,
568 value: BlobValue::Encrypted {
569 data: USRPKEY_AUTHBOUND_ENC_PAYLOAD.to_vec(),
570 iv: USRPKEY_AUTHBOUND_IV.to_vec(),
571 tag: USRPKEY_AUTHBOUND_TAG.to_vec()
572 }
573 },
574 structured_test_params_cache()
575 )),
576 Some(LOADED_CERT_AUTHBOUND.to_vec()),
577 Some(LOADED_CACERT_AUTHBOUND.to_vec())
578 )
579 );
580
581 legacy_blob_loader.remove_keystore_entry(10224, "boundauth").expect("This should succeed.");
582
583 assert_eq!(
584 (None, None, None),
585 legacy_blob_loader.load_by_uid_alias(10224, "boundauth", &None).unwrap()
586 );
587
588 // The database should not be empty due to the super key.
589 assert!(!legacy_blob_loader.is_empty().unwrap());
590 assert!(!legacy_blob_loader.is_empty_user(0).unwrap());
591
592 // The database should be considered empty for user 1.
593 assert!(legacy_blob_loader.is_empty_user(1).unwrap());
594
595 legacy_blob_loader.remove_super_key(0);
596
597 // Now it should be empty.
598 assert!(legacy_blob_loader.is_empty_user(0).unwrap());
599 assert!(legacy_blob_loader.is_empty().unwrap());
600
601 Ok(())
602}
603
604#[test]
605fn list_non_existing_user() -> Result<()> {
606 let temp_dir = TempDir::new("list_non_existing_user").unwrap();
607 let legacy_blob_loader = LegacyBlobLoader::new(temp_dir.path());
608
609 assert!(legacy_blob_loader.list_user(20)?.is_empty());
610
611 Ok(())
612}
613
614#[test]
615fn list_legacy_keystore_entries_on_non_existing_user() -> Result<()> {
616 let temp_dir = TempDir::new("list_legacy_keystore_entries_on_non_existing_user").unwrap();
617 let legacy_blob_loader = LegacyBlobLoader::new(temp_dir.path());
618
619 assert!(legacy_blob_loader.list_legacy_keystore_entries_for_user(20)?.is_empty());
620
621 Ok(())
622}
623
624#[test]
625fn test_move_keystore_entry() {
626 let temp_dir = TempDir::new("test_move_keystore_entry").unwrap();
627 std::fs::create_dir(&*temp_dir.build().push("user_0")).unwrap();
628
629 const SOME_CONTENT: &[u8] = b"some content";
630 const ANOTHER_CONTENT: &[u8] = b"another content";
631 const SOME_FILENAME: &str = "some_file";
632 const ANOTHER_FILENAME: &str = "another_file";
633
634 std::fs::write(&*temp_dir.build().push("user_0").push(SOME_FILENAME), SOME_CONTENT).unwrap();
635
636 std::fs::write(&*temp_dir.build().push("user_0").push(ANOTHER_FILENAME), ANOTHER_CONTENT)
637 .unwrap();
638
639 // Non existent source id silently ignored.
640 assert!(LegacyBlobLoader::move_keystore_file_if_exists(
641 1,
642 2,
643 "non_existent",
644 ANOTHER_FILENAME,
645 "ignored",
646 |_, alias, _| temp_dir.build().push("user_0").push(alias).to_path_buf()
647 )
648 .is_ok());
649
650 // Content of another_file has not changed.
651 let another_content =
652 std::fs::read(&*temp_dir.build().push("user_0").push(ANOTHER_FILENAME)).unwrap();
653 assert_eq!(&another_content, ANOTHER_CONTENT);
654
655 // Check that some_file still exists.
656 assert!(temp_dir.build().push("user_0").push(SOME_FILENAME).exists());
657 // Existing target files are silently overwritten.
658
659 assert!(LegacyBlobLoader::move_keystore_file_if_exists(
660 1,
661 2,
662 SOME_FILENAME,
663 ANOTHER_FILENAME,
664 "ignored",
665 |_, alias, _| temp_dir.build().push("user_0").push(alias).to_path_buf()
666 )
667 .is_ok());
668
669 // Content of another_file is now "some content".
670 let another_content =
671 std::fs::read(&*temp_dir.build().push("user_0").push(ANOTHER_FILENAME)).unwrap();
672 assert_eq!(&another_content, SOME_CONTENT);
673
674 // Check that some_file no longer exists.
675 assert!(!temp_dir.build().push("user_0").push(SOME_FILENAME).exists());
676}