sos_migrate/import/csv/
firefox.rs1use async_trait::async_trait;
4use serde::Deserialize;
5use sos_core::crypto::AccessKey;
6use sos_vault::Vault;
7use sos_vfs as vfs;
8use std::path::{Path, PathBuf};
9use tokio::io::AsyncRead;
10use url::Url;
11
12use super::{GenericCsvConvert, GenericCsvEntry, GenericPasswordRecord};
13use crate::{import::read_csv_records, Convert, Result};
14
15#[derive(Deserialize)]
17pub struct FirefoxPasswordRecord {
18 pub url: Url,
20 pub username: String,
22 pub password: String,
24 #[serde(rename = "httpRealm")]
26 pub http_realm: String,
27 #[serde(rename = "formActionOrigin")]
29 pub form_action_origin: String,
30 pub guid: String,
32 #[serde(rename = "timeCreated")]
34 pub time_created: String,
35 #[serde(rename = "timeLastUsed")]
37 pub time_last_used: String,
38 #[serde(rename = "timePasswordChanged")]
40 pub time_password_changed: String,
41}
42
43impl From<FirefoxPasswordRecord> for GenericPasswordRecord {
44 fn from(value: FirefoxPasswordRecord) -> Self {
45 Self {
46 label: value.url.to_string(),
47 url: vec![value.url],
48 username: value.username,
49 password: value.password,
50 otp_auth: None,
51 tags: None,
52 note: None,
53 }
54 }
55}
56
57impl From<FirefoxPasswordRecord> for GenericCsvEntry {
58 fn from(value: FirefoxPasswordRecord) -> Self {
59 Self::Password(value.into())
60 }
61}
62
63pub async fn parse_reader<R: AsyncRead + Unpin + Send>(
65 reader: R,
66) -> Result<Vec<FirefoxPasswordRecord>> {
67 read_csv_records::<FirefoxPasswordRecord, _>(reader).await
68}
69
70pub async fn parse_path<P: AsRef<Path>>(
72 path: P,
73) -> Result<Vec<FirefoxPasswordRecord>> {
74 parse_reader(vfs::File::open(path).await?).await
75}
76
77pub struct FirefoxPasswordCsv;
79
80#[async_trait]
81impl Convert for FirefoxPasswordCsv {
82 type Input = PathBuf;
83
84 async fn convert(
85 &self,
86 source: Self::Input,
87 vault: Vault,
88 key: &AccessKey,
89 ) -> crate::Result<Vault> {
90 let records: Vec<GenericCsvEntry> = parse_path(source)
91 .await?
92 .into_iter()
93 .map(|r| r.into())
94 .collect();
95 GenericCsvConvert.convert(records, vault, key).await
96 }
97}