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
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
|
use std::{collections::HashMap, fs::File, io};
use anyhow::{Context, Result};
use lz4_flex::decompress_size_prepended;
use serde::Deserialize;
use serde_json::Value;
use url::Url;
use crate::task::Project;
pub mod handle;
pub use handle::handle;
impl Project {
pub(super) fn get_sessionstore(&self) -> Result<SessionStore> {
let path = dirs::home_dir()
.expect("Will exist")
.join(".mozilla/firefox")
.join(self.to_project_display())
.join("sessionstore-backups/recovery.jsonlz4");
let file = decompress_mozlz4(
File::open(&path)
.with_context(|| format!("Failed to open path '{}'", path.display()))?,
)
.with_context(|| format!("Failed to decompress file as mozlzh '{}'", path.display()))?;
let contents: SessionStore = serde_json::from_str(&file).with_context(|| {
format!(
"Failed to deserialize file ('{}') as session store.",
path.display()
)
})?;
Ok(contents)
}
}
fn decompress_mozlz4<P: io::Read>(mut file: P) -> Result<String> {
const MOZLZ4_MAGIC_NUMBER: &[u8] = b"mozLz40\0";
let mut buf = [0u8; 8];
file.read_exact(&mut buf)
.context("Failed to read the mozlz40 header.")?;
assert_eq!(buf, MOZLZ4_MAGIC_NUMBER);
let mut buf = vec![];
file.read_to_end(&mut buf).context("Failed to read file")?;
let uncompressed = decompress_size_prepended(&buf).context("Failed to decompress file")?;
Ok(String::from_utf8(uncompressed).expect("This should be valid json and thus utf8"))
}
#[derive(Deserialize, Debug)]
pub struct SessionStore {
pub windows: Vec<Window>,
}
#[derive(Deserialize, Debug)]
pub struct Window {
pub tabs: Vec<Tab>,
pub selected: usize,
}
#[derive(Deserialize, Debug)]
pub struct Tab {
pub entries: Vec<TabEntry>,
#[serde(rename = "lastAccessed")]
pub last_accessed: u64,
pub hidden: bool,
#[serde(rename = "searchMode")]
pub search_mode: Option<Value>,
#[serde(rename = "userContextId")]
pub user_context_id: u32,
pub attributes: TabAttributes,
#[serde(rename = "extData")]
pub ext_data: Option<HashMap<String, Value>>,
pub index: usize,
#[serde(rename = "requestedIndex")]
pub requested_index: Option<u32>,
pub image: Option<Url>,
}
#[derive(Deserialize, Debug)]
pub struct TabEntry {
pub url: Url,
pub title: String,
#[serde(rename = "cacheKey")]
pub cache_key: u32,
#[serde(rename = "ID")]
pub id: u32,
#[serde(rename = "docshellUUID")]
pub docshell_uuid: Value,
#[serde(rename = "resultPrincipalURI")]
pub result_principal_uri: Option<Url>,
#[serde(rename = "hasUserInteraction")]
pub has_user_interaction: bool,
#[serde(rename = "triggeringPrincipal_base64")]
pub triggering_principal_base64: Value,
#[serde(rename = "docIdentifier")]
pub doc_identifier: u32,
pub persist: bool,
}
#[derive(Deserialize, Debug, Clone, Copy)]
pub struct TabAttributes {}
|