|
|
@ -58,21 +58,40 @@ impl Ord for Item { |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
fn decode(line: String) -> Result<String, io::Error> { |
|
|
|
struct Encoder { |
|
|
|
|
|
|
|
password: String |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
impl Encoder { |
|
|
|
|
|
|
|
pub fn from(password: String) -> Encoder { |
|
|
|
|
|
|
|
Encoder { password: password } |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// TODO: get by ref
|
|
|
|
|
|
|
|
pub fn encode(&self, line: String) -> String { |
|
|
|
|
|
|
|
BASE64_STANDARD.encode(line) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// TODO: review error type
|
|
|
|
|
|
|
|
pub fn decode(&self, line: String) -> io::Result<String> { |
|
|
|
let content = BASE64_STANDARD.decode(line).map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?; |
|
|
|
let content = BASE64_STANDARD.decode(line).map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?; |
|
|
|
match String::from_utf8(content) { |
|
|
|
match String::from_utf8(content) { |
|
|
|
Ok(s) => Ok(s), |
|
|
|
Ok(s) => Ok(s), |
|
|
|
Err(e) => Err(io::Error::new(io::ErrorKind::InvalidData, e)) |
|
|
|
Err(e) => Err(io::Error::new(io::ErrorKind::InvalidData, e)) |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
pub struct DB { |
|
|
|
pub struct DB { |
|
|
|
pub items: HashSet::<Item>, |
|
|
|
pub items: HashSet::<Item>, |
|
|
|
path: String |
|
|
|
path: String, |
|
|
|
|
|
|
|
encoder: Encoder |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
impl DB { |
|
|
|
impl DB { |
|
|
|
pub fn new(path: &str) -> io::Result<DB> { |
|
|
|
pub fn new(path: &str, password: String) -> io::Result<DB> { |
|
|
|
|
|
|
|
let encoder = Encoder::from(password); |
|
|
|
|
|
|
|
// TODO: throw error is password is incorrect
|
|
|
|
let file = fs::File::open(path)?; |
|
|
|
let file = fs::File::open(path)?; |
|
|
|
let reader = io::BufReader::new(file); |
|
|
|
let reader = io::BufReader::new(file); |
|
|
|
let mut items = HashSet::<Item>::new(); |
|
|
|
let mut items = HashSet::<Item>::new(); |
|
|
@ -80,11 +99,10 @@ impl DB { |
|
|
|
for line in reader.lines() { |
|
|
|
for line in reader.lines() { |
|
|
|
match line { |
|
|
|
match line { |
|
|
|
Ok(line) => { |
|
|
|
Ok(line) => { |
|
|
|
// TODO: check content
|
|
|
|
|
|
|
|
if id.is_none() { |
|
|
|
if id.is_none() { |
|
|
|
id = Some(line); |
|
|
|
id = Some(line); |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
let content = decode(line)?; |
|
|
|
let content = encoder.decode(line)?; |
|
|
|
items.insert(Item::from(id.unwrap(), content)); |
|
|
|
items.insert(Item::from(id.unwrap(), content)); |
|
|
|
id = None; |
|
|
|
id = None; |
|
|
|
} |
|
|
|
} |
|
|
@ -96,7 +114,8 @@ impl DB { |
|
|
|
} |
|
|
|
} |
|
|
|
let result = DB { |
|
|
|
let result = DB { |
|
|
|
items: items, |
|
|
|
items: items, |
|
|
|
path: String::from(path) |
|
|
|
path: String::from(path), |
|
|
|
|
|
|
|
encoder: encoder |
|
|
|
}; |
|
|
|
}; |
|
|
|
Ok(result) |
|
|
|
Ok(result) |
|
|
|
} |
|
|
|
} |
|
|
@ -114,7 +133,7 @@ impl DB { |
|
|
|
|
|
|
|
|
|
|
|
for item in self.items.iter() { |
|
|
|
for item in self.items.iter() { |
|
|
|
writeln!(file, "{}", item.id)?; |
|
|
|
writeln!(file, "{}", item.id)?; |
|
|
|
let content = BASE64_STANDARD.encode(item.content.clone()); |
|
|
|
let content = self.encoder.encode(item.content.clone()); |
|
|
|
writeln!(file, "{}", content)?; |
|
|
|
writeln!(file, "{}", content)?; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|