1use std::process;
2
3use thiserror::Error;
4
5#[derive(Clone)]
6pub struct AuthToken(String);
7
8#[derive(Error, Debug)]
9pub enum Error {
10 #[error("token command failed: {0}")]
11 TokenCommandInvocationFailed(#[from] std::io::Error),
12
13 #[error("token command failed: {0}")]
14 TokenCommandInvocationInvalidUtf8(#[from] std::string::FromUtf8Error),
15
16 #[error("token command failed, stderr: {0}")]
17 TokenCommandFailed(String),
18
19 #[error("token command produced stderr: {0}")]
20 TokenCommandStderr(String),
21
22 #[error("token command output empty")]
23 TokenCommandEmptyOutput,
24
25 #[error("token command output did not contain any newline")]
26 TokenCommandNoNewlineInOutput,
27}
28
29impl AuthToken {
30 pub fn access(&self) -> &str {
31 &self.0
32 }
33}
34
35pub fn get_token_from_command(command: &str) -> Result<AuthToken, Error> {
36 let output = process::Command::new("/usr/bin/env")
37 .arg("sh")
38 .arg("-c")
39 .arg(command)
40 .output()?;
41
42 let stderr = String::from_utf8(output.stderr)?;
43 let stdout = String::from_utf8(output.stdout)?;
44
45 if !output.status.success() {
46 return Err(Error::TokenCommandFailed(stderr));
47 }
48
49 if !stderr.is_empty() {
50 return Err(Error::TokenCommandStderr(stderr));
51 }
52
53 if stdout.is_empty() {
54 return Err(Error::TokenCommandEmptyOutput);
55 }
56
57 let token = stdout
58 .split('\n')
59 .next()
60 .ok_or(Error::TokenCommandNoNewlineInOutput)?;
61
62 Ok(AuthToken(token.to_owned()))
63}