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
use crate::JoplinReaderError;
use std::fs;
use std::io::{prelude::*, BufReader};
use std::path::Path;
use sjcl::decrypt_raw;
pub type MasterKey = String;
pub fn load_master_key(
key_path: &Path,
key_id: String,
passphrase: String,
) -> Result<MasterKey, JoplinReaderError> {
let file = match fs::File::open(key_path) {
Ok(file) => file,
Err(_) => {
return Err(JoplinReaderError::FileReadError {
message: "Failed to open file".to_string(),
})
}
};
let reader = BufReader::new(file);
let mut id: Option<String> = None;
let mut content: Option<String> = None;
for line in reader.lines() {
let line = match line {
Ok(line) => line,
Err(_) => {
return Err(JoplinReaderError::FileReadError {
message: "Failed to read file".to_string(),
})
}
};
let mut iter = line.splitn(2, ":");
let key = iter.next();
let value = iter.next();
if let (Some(key), Some(value)) = (key, value) {
match key {
"id" => id = Some(value.to_string().trim().to_string()),
"content" => content = Some(value.to_string()),
_ => { }
};
}
}
if let None = id {
return Err(JoplinReaderError::FileReadError {
message: "No `id` specified in key".to_string(),
});
}
if let None = content {
return Err(JoplinReaderError::FileReadError {
message: "No `content` specified in key".to_string(),
});
}
let id = id.unwrap();
let content = content.unwrap();
if id != key_id {
return Err(JoplinReaderError::KeyIdMismatch);
}
let plaintext = match decrypt_raw(content, passphrase) {
Ok(pt) => pt,
Err(_) => {
return Err(JoplinReaderError::DecryptionError {
message: "Failed to load master key".to_string(),
});
}
};
Ok(String::from_utf8(plaintext).unwrap())
}