1use keyring::Entry;
2use std::{
3 collections::HashMap,
4 fmt::Display,
5 io::{self, Read},
6};
7
8pub mod db;
9pub mod error;
10pub mod github;
11
12use error::GitError;
13
14#[allow(dead_code)] #[derive(Debug)]
18pub struct Request {
19 pub host: String,
20 protocol: String,
21 pub path: Option<String>,
22}
23
24impl Request {
25 pub fn from_stdin() -> Result<Self, GitError> {
26 let mut buf = String::new();
27 let _ = io::stdin().read_to_string(&mut buf)?;
28 let stdin_info: HashMap<String, String> = buf
29 .lines()
30 .filter_map(|l| {
31 l.split_once("=")
32 .map(|(k, v)| (k.trim().to_string(), v.trim().to_string()))
33 })
34 .collect();
35
36 Ok(Request {
37 protocol: stdin_info
38 .get("protocol")
39 .ok_or(GitError::MissingInfo(String::from("protocol")))?
40 .to_string(),
41 host: stdin_info
42 .get("host")
43 .ok_or(GitError::MissingInfo(String::from("host")))?
44 .to_string(),
45 path: stdin_info.get("path").cloned(),
46 })
47 }
48}
49
50#[derive(Clone)]
51pub struct Login {
52 pub username: String,
53 pub host: String,
54 pub email: Option<String>,
55}
56
57impl Login {
58 pub fn new(username: String, host: String, email: Option<String>) -> Self {
59 Self {
60 username,
61 host,
62 email,
63 }
64 }
65
66 fn entry(&self) -> Entry {
67 let identifier = format!("{}@{}", self.username, self.host);
68 match Entry::new("git-auth", &identifier) {
69 Ok(entry) => entry,
70 Err(keyring::error::Error::TooLong(_, max)) => {
71 Entry::new("git-auth", identifier.split_at(max as usize).0)
72 .expect("Expected entry creation success after handling length")
73 }
74 Err(err) => panic!("Unrecoverable error in login creation:\n{err}"),
75 }
76 }
77
78 pub fn get_password(&self) -> keyring::Result<String> {
79 self.entry().get_password()
80 }
81 pub fn set_password(&self, password: &str) -> keyring::Result<()> {
82 self.entry().set_password(password)
83 }
84}
85
86impl Display for Login {
87 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
88 match &self.email {
89 Some(email) => write!(f, "{}, ({})", self.username, email),
90 None => write!(f, "{}", self.username),
91 }
92 }
93}
94
95pub fn send_creds(creds: &Login) -> keyring::Result<()> {
96 println!("username={}", creds.username);
97 println!("password={}", creds.get_password()?);
98 println!("quit=1");
99 Ok(())
100}