credentialhelper/
client.rs

1// Copyright 2023 EngFlow, Inc. All rights reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use std::io::Cursor;
16use std::process::Command;
17use std::process::Stdio;
18
19use crate::credential_helper::CredentialHelper;
20use crate::protocol::GetCredentialsRequest;
21use crate::protocol::GetCredentialsResponse;
22
23pub struct Client {
24    credential_helper_path: String,
25}
26
27impl Client {
28    pub fn new<S: Into<String>>(credential_helper_path: S) -> Result<Client, ()> {
29        return Ok(Client {
30            credential_helper_path: credential_helper_path.into(),
31        });
32    }
33}
34
35impl CredentialHelper for Client {
36    fn get_credentials(
37        &self,
38        request: GetCredentialsRequest,
39        additional_parameters: Vec<String>,
40    ) -> Result<GetCredentialsResponse, String> {
41        match Command::new(self.credential_helper_path.as_str())
42            .arg("get")
43            .args(additional_parameters)
44            .stdin(Stdio::piped())
45            .stdout(Stdio::piped())
46            .spawn()
47        {
48            Ok(mut child) => {
49                // Intentionally ignore errors from writing to child's `stdin`.
50                _ = request.serialize(child.stdin.as_mut().unwrap());
51
52                match child.wait_with_output() {
53                    Ok(output) => {
54                        match GetCredentialsResponse::deserialize(Cursor::new(output.stdout)) {
55                            Ok(response) => {
56                                return Ok(response);
57                            }
58                            Err(_) => {
59                                return Err(
60                                    "Could not read response from credential helper".to_string()
61                                );
62                            }
63                        }
64                    }
65                    Err(_) => {
66                        return Err("Could not read response from credential helper".to_string());
67                    }
68                };
69            }
70            Err(_) => {
71                return Err("Could not start credential helper".to_string());
72            }
73        };
74    }
75}