]>
Commit | Line | Data |
---|---|---|
1 | use std::io::Read; | |
2 | ||
3 | use crate::helper::{Action, Context, Error, NextAction, Outcome, Result}; | |
4 | ||
5 | impl Action { | |
6 | /// Send ourselves to the given `write` which is expected to be credentials-helper compatible | |
7 | pub fn send(&self, mut write: impl std::io::Write) -> std::io::Result<()> { | |
8 | match self { | |
9 | Action::Get(ctx) => ctx.write_to(write), | |
10 | Action::Store(last) | Action::Erase(last) => { | |
11 | write.write_all(last).ok(); | |
12 | write.write_all(&[b'\n']).ok(); | |
13 | Ok(()) | |
14 | } | |
15 | } | |
16 | } | |
17 | } | |
18 | ||
19 | /// Invoke the given `helper` with `action` in `context`. | |
20 | /// | |
21 | /// Usually the first call is performed with [`Action::Get`] to obtain `Some` identity, which subsequently can be used if it is complete. | |
22 | /// Note that it may also only contain the username _or_ password, and should start out with everything the helper needs. | |
23 | /// On successful usage, use [`NextAction::store()`], otherwise [`NextAction::erase()`], which is when this function | |
24 | /// returns `Ok(None)` as no outcome is expected. | |
25 | pub fn invoke(helper: &mut crate::Program, action: &Action) -> Result { | |
26 | match raw(helper, action)? { | |
27 | None => Ok(None), | |
28 | Some(stdout) => { | |
29 | let ctx = Context::from_bytes(stdout.as_slice())?; | |
30 | Ok(Some(Outcome { | |
31 | username: ctx.username, | |
32 | password: ctx.password, | |
33 | quit: ctx.quit.unwrap_or(false), | |
34 | next: NextAction { | |
35 | previous_output: stdout.into(), | |
36 | }, | |
37 | })) | |
38 | } | |
39 | } | |
40 | } | |
41 | ||
42 | pub(crate) fn raw(helper: &mut crate::Program, action: &Action) -> std::result::Result<Option<Vec<u8>>, Error> { | |
43 | let (stdin, stdout) = helper.start(action)?; | |
44 | if let (Action::Get(_), None) = (&action, &stdout) { | |
45 | panic!("BUG: `Helper` impls must return an output handle to read output from if Action::Get is provided") | |
46 | } | |
47 | action.send(stdin)?; | |
48 | let stdout = stdout | |
49 | .map(|mut stdout| { | |
50 | let mut buf = Vec::new(); | |
51 | stdout.read_to_end(&mut buf).map(|_| buf) | |
52 | }) | |
53 | .transpose() | |
54 | .map_err(|err| Error::CredentialsHelperFailed { source: err })?; | |
55 | helper.finish().map_err(|err| { | |
56 | if err.kind() == std::io::ErrorKind::Other { | |
57 | Error::CredentialsHelperFailed { source: err } | |
58 | } else { | |
59 | err.into() | |
60 | } | |
61 | })?; | |
62 | ||
63 | match matches!(action, Action::Get(_)).then(|| stdout).flatten() { | |
64 | None => Ok(None), | |
65 | Some(stdout) => Ok(Some(stdout)), | |
66 | } | |
67 | } |