1use crate::crypto;
11use crate::error::{Error, Result};
12use crate::ops::{check_checksums, KeyGenerator, Signer, Verifier};
13use std::path::PathBuf;
14
15#[derive(Debug, PartialEq, Eq, Clone, Copy)]
17pub enum Mode {
18 Check,
20 Generate,
22 Sign,
24 Verify,
26}
27
28#[derive(Default, Debug, Clone)]
48pub struct Signify {
49 pub mode: Option<Mode>,
51 pub comment: Option<String>,
53 pub embed: bool,
55 pub msg_file: Option<PathBuf>,
57 pub nopass: bool,
59 pub pubkey: Option<PathBuf>,
61 pub quiet: bool,
63 pub seckey: Option<PathBuf>,
65 pub sig_file: Option<PathBuf>,
67 pub gzip: bool,
69 pub key_id: Option<i32>,
71 pub args: Vec<PathBuf>,
73}
74
75impl Signify {
76 pub fn execute(&self) -> Result<()> {
81 match self.mode {
82 Some(Mode::Generate) => self.execute_generate(),
83 Some(Mode::Sign) => self.execute_sign(),
84 Some(Mode::Verify) => self.execute_verify(),
85 Some(Mode::Check) => self.execute_check(),
86 None => Err(Error::MissingMode),
87 }
88 }
89
90 fn execute_generate(&self) -> Result<()> {
91 let pubkey_path = self
92 .pubkey
93 .clone()
94 .unwrap_or_else(|| PathBuf::from("key.pub"));
95 let seckey_path = self
96 .seckey
97 .clone()
98 .unwrap_or_else(|| PathBuf::from("key.sec"));
99 let rounds = if self.nopass {
100 0
101 } else {
102 crypto::DEFAULT_ROUNDS
103 };
104 let comment = self.comment.as_deref().unwrap_or("signify key");
105
106 let mut generator = KeyGenerator::new().rounds(rounds).comment(comment);
107 if let Some(id) = self.key_id {
108 generator = generator.key_id(id);
109 }
110 generator.generate(&pubkey_path, &seckey_path)
111 }
112
113 fn execute_sign(&self) -> Result<()> {
114 let Some(seckey_path) = &self.seckey else {
115 return Err(Error::RequiredArg("-s"));
116 };
117
118 let Some(msg_path) = &self.msg_file else {
119 return Err(Error::Arg("missing -m".into()));
120 };
121
122 let sig_path = self.sig_file.clone().unwrap_or_else(|| {
123 let mut path = msg_path.clone();
124 path.set_extension("sig");
125 path
126 });
127
128 let mut signer = Signer::new()
129 .seckey(seckey_path)
130 .embed(self.embed)
131 .gzip(self.gzip);
132
133 if let Some(id) = self.key_id {
134 signer = signer.key_id(id);
135 }
136
137 signer.sign(msg_path, &sig_path)
138 }
139
140 fn execute_verify(&self) -> Result<()> {
141 let (msg_path, sig_path) = if self.gzip {
142 let sig = self
143 .sig_file
144 .clone()
145 .or_else(|| self.args.first().cloned())
146 .unwrap_or_else(|| PathBuf::from("-"));
147 let msg = self.msg_file.clone().unwrap_or_else(|| PathBuf::from("-"));
148 (msg, sig)
149 } else {
150 let msg = if self.embed {
151 self.msg_file.clone().unwrap_or_else(|| {
152 self.sig_file.as_ref().map_or_else(
153 || PathBuf::from("msg.out"),
154 |sig| {
155 let mut path = sig.clone();
156 path.set_extension("");
157 path
158 },
159 )
160 })
161 } else if let Some(msg) = &self.msg_file {
162 msg.clone()
163 } else {
164 return Err(Error::Arg("missing -m".into()));
165 };
166
167 let sig = self
168 .sig_file
169 .clone()
170 .or_else(|| self.args.first().cloned())
171 .unwrap_or_else(|| {
172 let mut path = msg.clone();
173 if let Some(ext) = path.extension() {
174 let mut ext_str = ext.to_os_string();
175 ext_str.push(".sig");
176 path.set_extension(ext_str);
177 } else {
178 path.set_extension("sig");
179 }
180 path
181 });
182 (msg, sig)
183 };
184
185 let mut verifier = Verifier::new()
186 .quiet(self.quiet)
187 .embed(self.embed)
188 .gzip(self.gzip);
189
190 if let Some(path) = &self.pubkey {
191 verifier = verifier.pubkey(path);
192 }
193
194 verifier.verify(&msg_path, &sig_path)
195 }
196
197 fn execute_check(&self) -> Result<()> {
198 let Some(pubkey_path) = &self.pubkey else {
199 return Err(Error::RequiredArg("-p"));
200 };
201
202 let Some(sig_path) = &self.sig_file else {
203 return Err(Error::RequiredArg("-x"));
204 };
205
206 check_checksums(pubkey_path, sig_path, self.quiet)
207 }
208}