LZOGKBJXRQJKXHYNNENJFGNLP5SHIXGSV6HDB7UVOP7FSA5EUNCQC
X2MMGGXQEXJQKXV77LMQWY2BLMLOD6WRDGS3ZX3Z4NUDRAI5IDCAC
2MLOE3FPVT4ZXC4L74VC7GV2IXATZQNFLJECDPZZ7MTSW4A6XT5QC
44RUBHREQUNI4B36WSV7CUK5CVVIKG2AQOQJQZ7HU3BHY6W6AUEQC
MEK57BADGFCCZDNPUPUZGOJGNNS5R7UWRWCNJELKONGKOLLAQDDAC
M37JTFEIT6NHRDJOE7K6JWKFJF7327JMZDMX7GC2DQNECZKODBXQC
4HTHYIA3GLMUBUMAI7CQMZA4KE47EUXOP24XLUEYFRMOG57CJLMAC
UMF6N7CZA4CTSPKQFZSZXA3VRHWQAKEA5GUNIEAAVRWC7FUSSKAAC
SXEYMYF7P4RZMZ46WPL4IZUTSQ2ATBWYZX7QNVMS3SGOYXYOHAGQC
ZDK3GNDBWXJ2OXFDYB72ZCEBGLBF4MKE5K3PVHDZATHJ7HJIDPRQC
DO2Y5TY5JQISUHCVNPI2FXO7WWZVJQ3LGPWF4DNADMGZRIO6PT2QC
IQ4FCHPZYGTZHCQHUIRCMUI5LCHIDSJCM2AZXGRJARWLCPPLXZOQC
FBXYP7QM7SG6P2JDJVQPPCRKJE3GVYXNQ5GVV4GRDUNG6Q4ZRDJQC
OIOMXESDNMLOTMNYCZZBYSBAQTYPAXXMUHTLA2AYCMNHZMPSLX2AC
H4AU6QRPRDRFW3V7NN5CJ6DHLEUBYGNLRZ5GYV6ULBGRMOPCJQXQC
MU5GSJAW65PEG3BRYUKZ7O37BPHW3MOX3S5E2RFOXKGUOJEEDQ5AC
A3RM526Y7LUXNYW4TL56YKQ5GVOK2R5D7JJVTSQ6TT5MEXIR6YAAC
4OJWMSOWWNT5N4W4FDMKBZB5UARCLGV3SRZVKGR4EFAYFUMUHM7AC
TI7PCK7JLPU4KYE65XIMBUPPY7DRPVDAETPDFMG3VAQGGDRGQHPQC
SNZ3OAMCPUGFYON5SZHQQQK46ZZMVMJECJYEUCMG657UVLY2PNBQC
4KJ45IJLTIE35KQZUSFMFS67RNENG4P2FZMKMULJLGGYMKJUVRSQC
EEBKW7VTILH6AGGV57ZIJ3DJGYHDSYBWGU3C7Q4WWAKSVNUGIYMQC
I24UEJQLCH2SOXA4UHIYWTRDCHSOPU7AFTRUOTX7HZIAV4AZKYEQC
IIV3EL2XYI2X7HZWKXEXQFAE3R3KC2Q7SGOT3Q332HSENMYVF32QC
TEDGMEHFZK6QKSXVOHM3Z4MYZC26EDCWRURHWKOU2JLETWJIJPLQC
TPEH2XNBS5RO4IEVKENVF6P65AH7IX64KK2JAYMSJT3J5GXO67EAC
GYXIF25T2BCTCWCQI5DQOF3F4HBWDJUDJUMZ2WLHVBIOYATJTFAQC
VAPBIG46QVLGCASUE2QLISQ6657CZRAMNEG2PRK7FKEKAYM7FS3QC
LYTVEPH3W5UHF7MAYFWBT6NVNC42HEVKJGGMFDKUDZDNDOI33YJQC
SN7AGY6SLIWVKLBHQQ2MZ7VYY4BBFKROC5F3M6FVVFIGT25QNX7AC
2K7JLB4Z7BS5VFNWD4DO3MKYU7VNPA5MTVHVSDI3FQZ5ICM6XM6QC
std::fs::create_dir_all(&path)?;
for id in resp.id.iter() {
path.push(&id.public_key.key);
debug!("recv identity: {:?} {:?}", id, path);
let mut id_file = std::fs::File::create(&path)?;
serde_json::to_writer_pretty(&mut id_file, &id.as_portable())?;
path.pop();
if let Some(resp) = resp {
std::fs::create_dir_all(&path)?;
for id in resp.id.iter() {
path.push(&id.public_key.key);
debug!("recv identity: {:?} {:?}", id, path);
let mut id_file = std::fs::File::create(&path)?;
serde_json::to_writer_pretty(&mut id_file, &id.as_portable())?;
path.pop();
}
Ok(resp.rev)
} else {
Ok(0)
Ok(resp.rev)
}
pub async fn prove(
&mut self,
key: libpijul::key::SKey,
) -> Result<(), anyhow::Error> {
debug!("prove {:?}", self.url);
let url = format!("{}/{}", self.url, super::DOT_DIR);
let q = [("challenge", key.public_key().key)];
let mut req = self
.client
.get(&url)
.query(&q)
.header(reqwest::header::USER_AGENT, USER_AGENT);
for (k, v) in self.headers.iter() {
debug!("kv = {:?} {:?}", k, v);
req = req.header(k.as_str(), v.as_str());
}
let res = req.send().await?;
if !res.status().is_success() {
bail!("HTTP error {:?}", res.status())
}
let resp = res.bytes().await?;
debug!("resp = {:?}", resp);
let sig = key.sign_raw(&resp)?;
debug!("sig = {:?}", sig);
let q = [("prove", &sig)];
let mut req = self
.client
.get(&url)
.query(&q)
.header(reqwest::header::USER_AGENT, USER_AGENT);
for (k, v) in self.headers.iter() {
debug!("kv = {:?} {:?}", k, v);
req = req.header(k.as_str(), v.as_str());
}
let res = req.send().await?;
if !res.status().is_success() {
bail!("HTTP error {:?}", res.status())
}
Ok(())
use crate::remote::RemoteRepo;
if let RemoteRepo::Ssh(ssh) = repo
.remote(
None,
Some(&self.config.author.username),
&remote,
crate::DEFAULT_CHANNEL,
no_cert_check,
false,
)
.await?
{
ssh
} else {
bail!("No such remote: {}", remote)
}
} else if let Some(mut ssh) = crate::remote::ssh::ssh_remote(Some(&self.config.author.username), &remote, false) {
if let Some(c) = ssh.connect(&remote, crate::DEFAULT_CHANNEL).await? {
c
} else {
bail!("No such remote: {}", remote)
}
repo.remote(
None,
Some(&self.config.author.username),
&remote,
crate::DEFAULT_CHANNEL,
no_cert_check,
false,
)
.await?
use clap::Parser;
use std::convert::Infallible;
use std::net::SocketAddr;
use hyper::{Body, Request, Response, Server};
use hyper::service::{make_service_fn, service_fn};
use tokio::sync::mpsc::channel;
use tokio::select;
use crate::config::global_config_dir;
#[derive(Parser, Debug)]
pub struct Client {
/// Url to authenticate to.
#[clap(value_name = "URL")]
url: String,
}
impl Client {
pub async fn run(self) -> Result<(), anyhow::Error> {
let url = url::Url::parse(&self.url)?;
let mut cache_path = None;
if let Some(mut cached) = global_config_dir() {
cached.push("cache");
if let Some(host) = url.host_str() {
std::fs::create_dir_all(&cached)?;
cached.push(host);
if let Ok(token) = std::fs::read_to_string(&cached) {
println!("Bearer {}", token);
return Ok(())
} else {
cache_path = Some(cached);
}
}
}
let (tx, mut rx) = channel::<String>(1);
let make_service = make_service_fn(|_conn| {
let tx = tx.clone();
async move {
let handle = move |req: Request<_>| {
let qq: Option<String> = if let Some(q) = req.uri().query() {
let eq = "token=";
if q.starts_with(eq) {
Some(q.split_at(eq.len()).1.to_string())
} else {
None
}
} else {
None
};
let tx = tx.clone();
async move {
if let Some(qq) = qq {
tx.send(qq).await.unwrap();
let resp = Response::builder()
.header("Content-Type", "text/html")
.body(Body::from(include_str!("client.html")))
.unwrap();
Ok::<_, Infallible>(resp)
} else {
Ok::<_, Infallible>(
Response::builder()
.status(404)
.body("Not found".into())
.unwrap()
)
}
}
};
Ok::<_, Infallible>(service_fn(handle))
}
});
let mut port = 3000;
loop {
let addr = SocketAddr::from(([127, 0, 0, 1], port));
if let Ok(server) = Server::try_bind(&addr) {
let mut url = url::Url::parse(&self.url)?;
url.query_pairs_mut().append_pair("port", &port.to_string());
open::that(&url.to_string())?;
let server = server.serve(make_service);
select!{
x = server => {
if let Err(e) = x {
eprintln!("server error: {}", e);
}
break
}
x = rx.recv() => {
if let Some(x) = x {
if let Some(cache_path) = cache_path {
std::fs::write(&cache_path, &x)?;
}
println!("Bearer {}", x);
}
break
}
}
}
if port < u16::MAX {
port += 1
} else {
break
}
}
Ok(())
}
}