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
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
use crate::errors::*;
use crate::blobs::Blob;
use crate::cmd::Cmd;
use crate::db::ttl;
use crate::models::*;
use crate::shell::Shell;
use serde::{Serialize, Deserialize};
use std::io::{self, Write};
use structopt::StructOpt;
use structopt::clap::AppSettings;
use strum_macros::{EnumString, IntoStaticStr};
#[derive(Debug, StructOpt)]
#[structopt(global_settings = &[AppSettings::ColoredHelp])]
pub struct Args {
#[structopt(short="f", long="format", possible_values=Format::variants())]
format: Format,
}
impl Cmd for Args {
fn run(self, rl: &mut Shell) -> Result<()> {
ttl::reap_expired(rl)?;
match self.format {
Format::Json => export::<JsonFormat>(rl),
Format::JsonBlobs => export::<JsonBlobsFormat>(rl),
}
}
}
fn export<T: ExportFormat + Serialize>(rl: &mut Shell) -> Result<()> {
let export = T::load(rl)?;
let mut stdout = io::stdout();
serde_json::to_writer(&mut stdout, &export)?;
stdout.write_all(b"\n")?;
Ok(())
}
#[derive(Debug, Serialize, Deserialize)]
#[derive(EnumString, IntoStaticStr)]
#[strum(serialize_all = "kebab_case")]
pub enum Format {
Json,
JsonBlobs,
}
impl Format {
#[inline]
fn variants() -> &'static [&'static str] {
&[
"json",
"json-blobs",
]
}
}
trait ExportFormat {
fn load(rl: &mut Shell) -> Result<Box<Self>>;
}
#[derive(Serialize, Deserialize)]
struct JsonFormat {
accounts: Vec<Account>,
breaches: Vec<Breach>,
breach_emails: Vec<BreachEmail>,
devices: Vec<Device>,
domains: Vec<Domain>,
emails: Vec<Email>,
images: Vec<Image>,
ipaddrs: Vec<IpAddr>,
netblocks: Vec<Netblock>,
networks: Vec<Netblock>,
network_devices: Vec<NetworkDevice>,
phonenumbers: Vec<PhoneNumber>,
ports: Vec<Port>,
subdomains: Vec<Subdomain>,
subdomain_ipaddrs: Vec<SubdomainIpAddr>,
urls: Vec<Url>,
}
impl ExportFormat for JsonFormat {
fn load(rl: &mut Shell) -> Result<Box<JsonFormat>> {
let db = rl.db();
Ok(Box::new(JsonFormat {
accounts: Account::list(db)?,
breaches: Breach::list(db)?,
breach_emails: BreachEmail::list(db)?,
devices: Device::list(db)?,
domains: Domain::list(db)?,
emails: Email::list(db)?,
images: Image::list(db)?,
ipaddrs: IpAddr::list(db)?,
netblocks: Netblock::list(db)?,
networks: Netblock::list(db)?,
network_devices: NetworkDevice::list(db)?,
phonenumbers: PhoneNumber::list(db)?,
ports: Port::list(db)?,
subdomains: Subdomain::list(db)?,
subdomain_ipaddrs: SubdomainIpAddr::list(db)?,
urls: Url::list(db)?,
}))
}
}
#[derive(Serialize, Deserialize)]
struct JsonBlobsFormat {
models: JsonFormat,
blobs: Vec<Blob>,
}
impl ExportFormat for JsonBlobsFormat {
fn load(rl: &mut Shell) -> Result<Box<JsonBlobsFormat>> {
let models = *JsonFormat::load(rl)?;
let storage = rl.blobs();
let blobs = storage.list()?
.into_iter()
.map(|id| storage.load(&id))
.collect::<Result<Vec<_>>>()?;
Ok(Box::new(JsonBlobsFormat {
models,
blobs,
}))
}
}