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 { 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(mut file: P) -> Result { 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, } #[derive(Deserialize, Debug)] pub struct Window { pub tabs: Vec, pub selected: usize, } #[derive(Deserialize, Debug)] pub struct Tab { pub entries: Vec, #[serde(rename = "lastAccessed")] pub last_accessed: u64, pub hidden: bool, #[serde(rename = "searchMode")] pub search_mode: Option, #[serde(rename = "userContextId")] pub user_context_id: u32, pub attributes: TabAttributes, #[serde(rename = "extData")] pub ext_data: Option>, pub index: usize, #[serde(rename = "requestedIndex")] pub requested_index: Option, pub image: Option, } #[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, #[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 {}