Skip to content

Commit

Permalink
curl can authenticate the proxy now and store or reject credentials.
Browse files Browse the repository at this point in the history
  • Loading branch information
Byron committed Nov 17, 2022
1 parent ae74985 commit 63b9050
Show file tree
Hide file tree
Showing 4 changed files with 40 additions and 5 deletions.
2 changes: 1 addition & 1 deletion crate-status.md
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ Check out the [performance discussion][git-traverse-performance] as well.
| 01 | | |
| 02 | X | |
| 03 | | X |
| 04 | | |
| 04 | X | |
| 05 | | |

* **01** -> async
Expand Down
4 changes: 2 additions & 2 deletions git-repository/src/repository/config/transport.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
use crate::bstr::BStr;
use git_transport::client::http::options::ProxyAuthMethod;
use std::any::Any;
use std::sync::{Arc, Mutex};

impl crate::Repository {
/// Produce configuration suitable for `url`, as differentiated by its protocol/scheme, to be passed to a transport instance via
Expand Down Expand Up @@ -34,8 +32,10 @@ impl crate::Repository {
use crate::bstr::ByteVec;
use crate::config::cache::util::{ApplyLeniency, ApplyLeniencyDefault};
use git_transport::client::http;
use git_transport::client::http::options::ProxyAuthMethod;
use std::borrow::Cow;
use std::convert::{TryFrom, TryInto};
use std::sync::{Arc, Mutex};

fn try_cow_to_string(
v: Cow<'_, BStr>,
Expand Down
37 changes: 36 additions & 1 deletion git-transport/src/client/blocking_io/http/curl/remote.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,13 @@ struct Handler {
send_data: Option<pipe::Writer>,
receive_body: Option<pipe::Reader>,
checked_status: bool,
last_status: usize,
}

impl Handler {
fn reset(&mut self) {
self.checked_status = false;
self.last_status = 0;
}
fn parse_status_inner(data: &[u8]) -> Result<usize, Box<dyn std::error::Error + Send + Sync>> {
let code = data
Expand Down Expand Up @@ -65,9 +67,11 @@ impl curl::easy::Handler for Handler {
writer.write_all(data).is_ok()
} else {
self.checked_status = true;
self.last_status = 200;
match Handler::parse_status(data) {
None => true,
Some((status, err)) => {
self.last_status = status;
writer
.channel
.send(Err(io::Error::new(
Expand Down Expand Up @@ -126,7 +130,7 @@ pub fn new() -> (
proxy,
proxy_auth_method,
user_agent,
proxy_authenticate: _,
proxy_authenticate,
backend: _,
},
} in req_recv
Expand All @@ -138,6 +142,8 @@ pub fn new() -> (
for header in extra_headers {
headers.append(&header)?;
}

let mut proxy_auth_action = None;
if let Some(proxy) = proxy {
handle.proxy(&proxy)?;
let proxy_type = if proxy.starts_with("socks5h") {
Expand All @@ -152,6 +158,19 @@ pub fn new() -> (
curl::easy::ProxyType::Http
};
handle.proxy_type(proxy_type)?;

if let Some((obtain_creds_action, authenticate)) = proxy_authenticate {
let creds = authenticate.lock().expect("no panics in other threads")(obtain_creds_action)
.map_err(|err| {
let mut e = curl::Error::new(0);
e.set_extra(err.to_string());
e
})?
.expect("action to fetch credentials");
handle.proxy_username(&creds.identity.username)?;
handle.proxy_password(&creds.identity.password)?;
proxy_auth_action = Some((creds.next, authenticate));
}
}
if let Some(user_agent) = user_agent {
handle.useragent(&user_agent)?;
Expand Down Expand Up @@ -209,6 +228,10 @@ pub fn new() -> (
if let Err(err) = handle.perform() {
let handler = handle.get_mut();
handler.reset();

if let Some((action, authenticate)) = proxy_auth_action {
authenticate.lock().expect("no panics in other threads")(action.erase()).ok();
}
let err = Err(io::Error::new(io::ErrorKind::Other, err));
handler.receive_body.take();
match (handler.send_header.take(), handler.send_data.take()) {
Expand All @@ -228,6 +251,18 @@ pub fn new() -> (
};
} else {
let handler = handle.get_mut();
if let Some((action, authenticate)) = proxy_auth_action {
authenticate.lock().expect("no panics in other threads")(if handler.last_status == 200 {
action.store()
} else {
action.erase()
})
.map_err(|err| {
let mut e = curl::Error::new(0);
e.set_extra(err.to_string());
e
})?;
}
handler.reset();
handler.receive_body.take();
handler.send_header.take();
Expand Down
2 changes: 1 addition & 1 deletion git-transport/src/client/blocking_io/http/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ pub struct Options {
pub proxy_auth_method: options::ProxyAuthMethod,
/// If authentication is needed for the proxy as its URL contains a username, this method must be set to provide a password
/// for it before making the request, and to store it if the connection succeeds.
pub proxy_authenticate: Option<Arc<AuthenticateFn>>,
pub proxy_authenticate: Option<(git_credentials::helper::Action, Arc<std::sync::Mutex<AuthenticateFn>>)>,
/// The `HTTP` `USER_AGENT` string presented to an `HTTP` server, notably not the user agent present to the `git` server.
///
/// If not overridden, it defaults to the user agent provided by `curl`, which is a deviation from how `git` handles this.
Expand Down

0 comments on commit 63b9050

Please sign in to comment.