mirror of
https://github.com/pesde-pkg/pesde.git
synced 2024-12-12 11:00:36 +00:00
feat: improve auth system for registry changes
This commit is contained in:
parent
66a885b4e6
commit
c7c1daab36
15 changed files with 183 additions and 270 deletions
|
@ -8,6 +8,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
## [Unreleased]
|
||||
### Added
|
||||
- Support full version requirements in workspace version field by @daimond113
|
||||
- Improved authentication system for registry changes by @daimond113
|
||||
|
||||
### Fixed
|
||||
- Correct `pesde.toml` inclusion message in `publish` command by @daimond113
|
||||
|
|
|
@ -1,23 +1,51 @@
|
|||
use crate::cli::config::{read_config, write_config};
|
||||
use anyhow::Context;
|
||||
use gix::bstr::BStr;
|
||||
use keyring::Entry;
|
||||
use serde::Deserialize;
|
||||
use reqwest::header::AUTHORIZATION;
|
||||
use serde::{ser::SerializeMap, Deserialize, Serialize};
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
pub fn get_token() -> anyhow::Result<Option<String>> {
|
||||
match std::env::var("PESDE_TOKEN") {
|
||||
Ok(token) => return Ok(Some(token)),
|
||||
Err(std::env::VarError::NotPresent) => {}
|
||||
Err(e) => return Err(e.into()),
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Tokens(pub BTreeMap<gix::Url, String>);
|
||||
|
||||
impl Serialize for Tokens {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: serde::ser::Serializer,
|
||||
{
|
||||
let mut map = serializer.serialize_map(Some(self.0.len()))?;
|
||||
for (k, v) in &self.0 {
|
||||
map.serialize_entry(&k.to_bstring().to_string(), v)?;
|
||||
}
|
||||
map.end()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> Deserialize<'de> for Tokens {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: serde::de::Deserializer<'de>,
|
||||
{
|
||||
Ok(Tokens(
|
||||
BTreeMap::<String, String>::deserialize(deserializer)?
|
||||
.into_iter()
|
||||
.map(|(k, v)| gix::Url::from_bytes(BStr::new(&k)).map(|k| (k, v)))
|
||||
.collect::<Result<_, _>>()
|
||||
.map_err(serde::de::Error::custom)?,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_tokens() -> anyhow::Result<Tokens> {
|
||||
let config = read_config()?;
|
||||
if let Some(token) = config.token {
|
||||
return Ok(Some(token));
|
||||
if !config.tokens.0.is_empty() {
|
||||
return Ok(config.tokens);
|
||||
}
|
||||
|
||||
match Entry::new("token", env!("CARGO_PKG_NAME")) {
|
||||
match Entry::new("tokens", env!("CARGO_PKG_NAME")) {
|
||||
Ok(entry) => match entry.get_password() {
|
||||
Ok(token) => return Ok(Some(token)),
|
||||
Ok(token) => return serde_json::from_str(&token).context("failed to parse tokens"),
|
||||
Err(keyring::Error::PlatformFailure(_) | keyring::Error::NoEntry) => {}
|
||||
Err(e) => return Err(e.into()),
|
||||
},
|
||||
|
@ -25,32 +53,32 @@ pub fn get_token() -> anyhow::Result<Option<String>> {
|
|||
Err(e) => return Err(e.into()),
|
||||
}
|
||||
|
||||
Ok(None)
|
||||
Ok(Tokens(BTreeMap::new()))
|
||||
}
|
||||
|
||||
pub fn set_token(token: Option<&str>) -> anyhow::Result<()> {
|
||||
let entry = match Entry::new("token", env!("CARGO_PKG_NAME")) {
|
||||
Ok(entry) => entry,
|
||||
Err(e) => return Err(e.into()),
|
||||
};
|
||||
pub fn set_tokens(tokens: Tokens) -> anyhow::Result<()> {
|
||||
let entry = Entry::new("tokens", env!("CARGO_PKG_NAME"))?;
|
||||
let json = serde_json::to_string(&tokens).context("failed to serialize tokens")?;
|
||||
|
||||
let result = if let Some(token) = token {
|
||||
entry.set_password(token)
|
||||
} else {
|
||||
entry.delete_credential()
|
||||
};
|
||||
|
||||
match result {
|
||||
match entry.set_password(&json) {
|
||||
Ok(()) => return Ok(()),
|
||||
Err(keyring::Error::PlatformFailure(_) | keyring::Error::NoEntry) => {}
|
||||
Err(e) => return Err(e.into()),
|
||||
}
|
||||
|
||||
let mut config = read_config()?;
|
||||
config.token = token.map(|s| s.to_string());
|
||||
write_config(&config)?;
|
||||
config.tokens = tokens;
|
||||
write_config(&config).map_err(Into::into)
|
||||
}
|
||||
|
||||
Ok(())
|
||||
pub fn set_token(repo: &gix::Url, token: Option<&str>) -> anyhow::Result<()> {
|
||||
let mut tokens = get_tokens()?;
|
||||
if let Some(token) = token {
|
||||
tokens.0.insert(repo.clone(), token.to_string());
|
||||
} else {
|
||||
tokens.0.remove(repo);
|
||||
}
|
||||
set_tokens(tokens)
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
|
@ -64,7 +92,7 @@ pub fn get_token_login(
|
|||
) -> anyhow::Result<String> {
|
||||
let response = reqwest
|
||||
.get("https://api.github.com/user")
|
||||
.header("Authorization", access_token)
|
||||
.header(AUTHORIZATION, access_token)
|
||||
.send()
|
||||
.context("failed to send user request")?
|
||||
.error_for_status()
|
||||
|
|
|
@ -5,24 +5,16 @@ use serde::Deserialize;
|
|||
use url::Url;
|
||||
|
||||
use pesde::{
|
||||
errors::ManifestReadError,
|
||||
source::{pesde::PesdePackageSource, traits::PackageSource},
|
||||
Project,
|
||||
};
|
||||
|
||||
use crate::cli::{
|
||||
auth::{get_token_login, set_token},
|
||||
config::read_config,
|
||||
};
|
||||
use crate::cli::auth::{get_token_login, set_token};
|
||||
|
||||
#[derive(Debug, Args)]
|
||||
pub struct LoginCommand {
|
||||
/// The index to use. Defaults to `default`, or the configured default index if current directory doesn't have a manifest
|
||||
#[arg(short, long)]
|
||||
index: Option<String>,
|
||||
|
||||
/// The token to use for authentication, skipping login
|
||||
#[arg(short, long, conflicts_with = "index")]
|
||||
#[arg(short, long)]
|
||||
token: Option<String>,
|
||||
}
|
||||
|
||||
|
@ -55,41 +47,13 @@ enum AccessTokenResponse {
|
|||
impl LoginCommand {
|
||||
pub fn authenticate_device_flow(
|
||||
&self,
|
||||
index_url: &gix::Url,
|
||||
project: &Project,
|
||||
reqwest: &reqwest::blocking::Client,
|
||||
) -> anyhow::Result<String> {
|
||||
let manifest = match project.deser_manifest() {
|
||||
Ok(manifest) => Some(manifest),
|
||||
Err(e) => match e {
|
||||
ManifestReadError::Io(e) if e.kind() == std::io::ErrorKind::NotFound => None,
|
||||
e => return Err(e.into()),
|
||||
},
|
||||
};
|
||||
println!("logging in into {index_url}");
|
||||
|
||||
let index_url = match self.index.as_deref() {
|
||||
Some(index) => match index.try_into() {
|
||||
Ok(url) => Some(url),
|
||||
Err(_) => None,
|
||||
},
|
||||
None => match manifest {
|
||||
Some(_) => None,
|
||||
None => Some(read_config()?.default_index),
|
||||
},
|
||||
};
|
||||
|
||||
let index_url = match index_url {
|
||||
Some(url) => url,
|
||||
None => {
|
||||
let index_name = self.index.as_deref().unwrap_or("default");
|
||||
|
||||
match manifest.unwrap().indices.get(index_name) {
|
||||
Some(index) => index.clone(),
|
||||
None => anyhow::bail!("Index {index_name} not found"),
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let source = PesdePackageSource::new(index_url);
|
||||
let source = PesdePackageSource::new(index_url.clone());
|
||||
source.refresh(project).context("failed to refresh index")?;
|
||||
|
||||
let config = source
|
||||
|
@ -182,24 +146,32 @@ impl LoginCommand {
|
|||
anyhow::bail!("code expired, please re-run the login command");
|
||||
}
|
||||
|
||||
pub fn run(self, project: Project, reqwest: reqwest::blocking::Client) -> anyhow::Result<()> {
|
||||
pub fn run(
|
||||
self,
|
||||
index_url: gix::Url,
|
||||
project: Project,
|
||||
reqwest: reqwest::blocking::Client,
|
||||
) -> anyhow::Result<()> {
|
||||
let token_given = self.token.is_some();
|
||||
let token = match self.token {
|
||||
Some(token) => token,
|
||||
None => self.authenticate_device_flow(&project, &reqwest)?,
|
||||
None => self.authenticate_device_flow(&index_url, &project, &reqwest)?,
|
||||
};
|
||||
|
||||
let token = if token_given {
|
||||
println!("set token");
|
||||
println!("set token for {index_url}");
|
||||
token
|
||||
} else {
|
||||
let token = format!("Bearer {token}");
|
||||
println!("logged in as {}", get_token_login(&reqwest, &token)?.bold());
|
||||
println!(
|
||||
"logged in as {} for {index_url}",
|
||||
get_token_login(&reqwest, &token)?.bold()
|
||||
);
|
||||
|
||||
token
|
||||
};
|
||||
|
||||
set_token(Some(&token))?;
|
||||
set_token(&index_url, Some(&token))?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -5,10 +5,10 @@ use clap::Args;
|
|||
pub struct LogoutCommand {}
|
||||
|
||||
impl LogoutCommand {
|
||||
pub fn run(self) -> anyhow::Result<()> {
|
||||
set_token(None)?;
|
||||
pub fn run(self, index_url: gix::Url) -> anyhow::Result<()> {
|
||||
set_token(&index_url, None)?;
|
||||
|
||||
println!("logged out");
|
||||
println!("logged out of {index_url}");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -1,31 +1,69 @@
|
|||
use clap::Subcommand;
|
||||
use pesde::Project;
|
||||
use crate::cli::config::read_config;
|
||||
use clap::{Args, Subcommand};
|
||||
use pesde::{errors::ManifestReadError, Project};
|
||||
|
||||
mod login;
|
||||
mod logout;
|
||||
mod set_token_override;
|
||||
mod whoami;
|
||||
|
||||
#[derive(Debug, Args)]
|
||||
pub struct AuthSubcommand {
|
||||
/// The index to use. Defaults to `default`, or the configured default index if current directory doesn't have a manifest
|
||||
#[arg(short, long)]
|
||||
pub index: Option<String>,
|
||||
|
||||
#[clap(subcommand)]
|
||||
pub command: AuthCommands,
|
||||
}
|
||||
|
||||
#[derive(Debug, Subcommand)]
|
||||
pub enum AuthCommands {
|
||||
/// Logs in into GitHub, and stores the token
|
||||
/// Sets a token for an index. Optionally gets it from GitHub
|
||||
Login(login::LoginCommand),
|
||||
/// Removes the stored token
|
||||
Logout(logout::LogoutCommand),
|
||||
/// Prints the username of the currently logged-in user
|
||||
#[clap(name = "whoami")]
|
||||
WhoAmI(whoami::WhoAmICommand),
|
||||
/// Sets a token override for a specific repository
|
||||
SetTokenOverride(set_token_override::SetTokenOverrideCommand),
|
||||
}
|
||||
|
||||
impl AuthCommands {
|
||||
impl AuthSubcommand {
|
||||
pub fn run(self, project: Project, reqwest: reqwest::blocking::Client) -> anyhow::Result<()> {
|
||||
match self {
|
||||
AuthCommands::Login(login) => login.run(project, reqwest),
|
||||
AuthCommands::Logout(logout) => logout.run(),
|
||||
AuthCommands::WhoAmI(whoami) => whoami.run(reqwest),
|
||||
AuthCommands::SetTokenOverride(set_token_override) => set_token_override.run(),
|
||||
let manifest = match project.deser_manifest() {
|
||||
Ok(manifest) => Some(manifest),
|
||||
Err(e) => match e {
|
||||
ManifestReadError::Io(e) if e.kind() == std::io::ErrorKind::NotFound => None,
|
||||
e => return Err(e.into()),
|
||||
},
|
||||
};
|
||||
|
||||
let index_url = match self.index.as_deref() {
|
||||
Some(index) => match index.try_into() {
|
||||
Ok(url) => Some(url),
|
||||
Err(_) => None,
|
||||
},
|
||||
None => match manifest {
|
||||
Some(_) => None,
|
||||
None => Some(read_config()?.default_index),
|
||||
},
|
||||
};
|
||||
|
||||
let index_url = match index_url {
|
||||
Some(url) => url,
|
||||
None => {
|
||||
let index_name = self.index.as_deref().unwrap_or("default");
|
||||
|
||||
match manifest.unwrap().indices.get(index_name) {
|
||||
Some(index) => index.clone(),
|
||||
None => anyhow::bail!("index {index_name} not found"),
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
match self.command {
|
||||
AuthCommands::Login(login) => login.run(index_url, project, reqwest),
|
||||
AuthCommands::Logout(logout) => logout.run(index_url),
|
||||
AuthCommands::WhoAmI(whoami) => whoami.run(index_url, reqwest),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,31 +0,0 @@
|
|||
use crate::cli::config::{read_config, write_config};
|
||||
use clap::Args;
|
||||
|
||||
#[derive(Debug, Args)]
|
||||
pub struct SetTokenOverrideCommand {
|
||||
/// The repository to add the token to
|
||||
#[arg(index = 1, value_parser = crate::cli::parse_gix_url)]
|
||||
repository: gix::Url,
|
||||
|
||||
/// The token to set
|
||||
#[arg(index = 2)]
|
||||
token: Option<String>,
|
||||
}
|
||||
|
||||
impl SetTokenOverrideCommand {
|
||||
pub fn run(self) -> anyhow::Result<()> {
|
||||
let mut config = read_config()?;
|
||||
|
||||
if let Some(token) = self.token {
|
||||
println!("set token for {}", self.repository);
|
||||
config.token_overrides.insert(self.repository, token);
|
||||
} else {
|
||||
println!("removed token for {}", self.repository);
|
||||
config.token_overrides.remove(&self.repository);
|
||||
}
|
||||
|
||||
write_config(&config)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
use crate::cli::{auth::get_token_login, get_token};
|
||||
use crate::cli::auth::{get_token_login, get_tokens};
|
||||
use clap::Args;
|
||||
use colored::Colorize;
|
||||
|
||||
|
@ -6,16 +6,24 @@ use colored::Colorize;
|
|||
pub struct WhoAmICommand {}
|
||||
|
||||
impl WhoAmICommand {
|
||||
pub fn run(self, reqwest: reqwest::blocking::Client) -> anyhow::Result<()> {
|
||||
let token = match get_token()? {
|
||||
pub fn run(
|
||||
self,
|
||||
index_url: gix::Url,
|
||||
reqwest: reqwest::blocking::Client,
|
||||
) -> anyhow::Result<()> {
|
||||
let tokens = get_tokens()?;
|
||||
let token = match tokens.0.get(&index_url) {
|
||||
Some(token) => token,
|
||||
None => {
|
||||
println!("not logged in");
|
||||
println!("not logged in into {index_url}");
|
||||
return Ok(());
|
||||
}
|
||||
};
|
||||
|
||||
println!("logged in as {}", get_token_login(&reqwest, &token)?.bold());
|
||||
println!(
|
||||
"logged in as {} into {index_url}",
|
||||
get_token_login(&reqwest, token)?.bold()
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -23,8 +23,7 @@ mod update;
|
|||
#[derive(Debug, clap::Subcommand)]
|
||||
pub enum Subcommand {
|
||||
/// Authentication-related commands
|
||||
#[command(subcommand)]
|
||||
Auth(auth::AuthCommands),
|
||||
Auth(auth::AuthSubcommand),
|
||||
|
||||
/// Configuration-related commands
|
||||
#[command(subcommand)]
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use anyhow::Context;
|
||||
use clap::Args;
|
||||
use colored::Colorize;
|
||||
use reqwest::StatusCode;
|
||||
use reqwest::{header::AUTHORIZATION, StatusCode};
|
||||
use semver::VersionReq;
|
||||
use std::{
|
||||
io::{Seek, Write},
|
||||
|
@ -457,13 +457,11 @@ impl PublishCommand {
|
|||
.finish()
|
||||
.context("failed to get archive bytes")?;
|
||||
|
||||
let source = PesdePackageSource::new(
|
||||
manifest
|
||||
let index_url = manifest
|
||||
.indices
|
||||
.get(DEFAULT_INDEX_NAME)
|
||||
.context("missing default index")?
|
||||
.clone(),
|
||||
);
|
||||
.context("missing default index")?;
|
||||
let source = PesdePackageSource::new(index_url.clone());
|
||||
source
|
||||
.refresh(project)
|
||||
.context("failed to refresh source")?;
|
||||
|
@ -501,14 +499,19 @@ impl PublishCommand {
|
|||
return Ok(());
|
||||
}
|
||||
|
||||
let response = reqwest
|
||||
let mut request = reqwest
|
||||
.post(format!("{}/v0/packages", config.api()))
|
||||
.multipart(reqwest::blocking::multipart::Form::new().part(
|
||||
"tarball",
|
||||
reqwest::blocking::multipart::Part::bytes(archive).file_name("package.tar.gz"),
|
||||
))
|
||||
.send()
|
||||
.context("failed to send request")?;
|
||||
));
|
||||
|
||||
if let Some(token) = project.auth_config().tokens().get(index_url) {
|
||||
log::debug!("using token for {index_url}");
|
||||
request = request.header(AUTHORIZATION, token);
|
||||
}
|
||||
|
||||
let response = request.send().context("failed to send request")?;
|
||||
|
||||
let status = response.status();
|
||||
let text = response.text().context("failed to get response text")?;
|
||||
|
|
|
@ -1,10 +1,7 @@
|
|||
use std::collections::BTreeMap;
|
||||
|
||||
use crate::cli::{auth::Tokens, home_dir};
|
||||
use anyhow::Context;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::cli::home_dir;
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct CliConfig {
|
||||
#[serde(
|
||||
|
@ -18,15 +15,7 @@ pub struct CliConfig {
|
|||
)]
|
||||
pub scripts_repo: gix::Url,
|
||||
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub token: Option<String>,
|
||||
#[serde(
|
||||
default,
|
||||
skip_serializing_if = "BTreeMap::is_empty",
|
||||
serialize_with = "crate::cli::serialize_string_url_map",
|
||||
deserialize_with = "crate::cli::deserialize_string_url_map"
|
||||
)]
|
||||
pub token_overrides: BTreeMap<gix::Url, String>,
|
||||
pub tokens: Tokens,
|
||||
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub last_checked_updates: Option<(chrono::DateTime<chrono::Utc>, semver::Version)>,
|
||||
|
@ -42,8 +31,7 @@ impl Default for CliConfig {
|
|||
.try_into()
|
||||
.unwrap(),
|
||||
|
||||
token: None,
|
||||
token_overrides: Default::default(),
|
||||
tokens: Tokens(Default::default()),
|
||||
|
||||
last_checked_updates: None,
|
||||
}
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
use crate::cli::auth::get_token;
|
||||
use anyhow::Context;
|
||||
use gix::bstr::BStr;
|
||||
use indicatif::MultiProgress;
|
||||
use pesde::{
|
||||
lockfile::{DependencyGraph, DownloadedGraph, Lockfile},
|
||||
|
@ -10,7 +8,6 @@ use pesde::{
|
|||
Project,
|
||||
};
|
||||
use relative_path::RelativePathBuf;
|
||||
use serde::{ser::SerializeMap, Deserialize, Deserializer, Serializer};
|
||||
use std::{
|
||||
collections::{BTreeMap, HashSet},
|
||||
fs::create_dir_all,
|
||||
|
@ -188,30 +185,6 @@ pub fn parse_gix_url(s: &str) -> Result<gix::Url, gix::url::parse::Error> {
|
|||
s.try_into()
|
||||
}
|
||||
|
||||
pub fn serialize_string_url_map<S: Serializer>(
|
||||
url: &BTreeMap<gix::Url, String>,
|
||||
serializer: S,
|
||||
) -> Result<S::Ok, S::Error> {
|
||||
let mut map = serializer.serialize_map(Some(url.len()))?;
|
||||
for (k, v) in url {
|
||||
map.serialize_entry(&k.to_bstring().to_string(), v)?;
|
||||
}
|
||||
map.end()
|
||||
}
|
||||
|
||||
pub fn deserialize_string_url_map<'de, D: Deserializer<'de>>(
|
||||
deserializer: D,
|
||||
) -> Result<BTreeMap<gix::Url, String>, D::Error> {
|
||||
BTreeMap::<String, String>::deserialize(deserializer)?
|
||||
.into_iter()
|
||||
.map(|(k, v)| {
|
||||
gix::Url::from_bytes(BStr::new(&k))
|
||||
.map(|k| (k, v))
|
||||
.map_err(serde::de::Error::custom)
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn download_graph(
|
||||
project: &Project,
|
||||
|
|
33
src/lib.rs
33
src/lib.rs
|
@ -44,8 +44,7 @@ pub(crate) const LINK_LIB_NO_FILE_FOUND: &str = "____pesde_no_export_file_found"
|
|||
/// Struct containing the authentication configuration
|
||||
#[derive(Debug, Default, Clone)]
|
||||
pub struct AuthConfig {
|
||||
default_token: Option<String>,
|
||||
token_overrides: HashMap<gix::Url, String>,
|
||||
tokens: HashMap<gix::Url, String>,
|
||||
git_credentials: Option<Account>,
|
||||
}
|
||||
|
||||
|
@ -55,18 +54,12 @@ impl AuthConfig {
|
|||
AuthConfig::default()
|
||||
}
|
||||
|
||||
/// Sets the default token
|
||||
pub fn with_default_token<S: AsRef<str>>(mut self, token: Option<S>) -> Self {
|
||||
self.default_token = token.map(|s| s.as_ref().to_string());
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the token overrides
|
||||
pub fn with_token_overrides<I: IntoIterator<Item = (gix::Url, S)>, S: AsRef<str>>(
|
||||
/// Set the tokens
|
||||
pub fn with_tokens<I: IntoIterator<Item = (gix::Url, S)>, S: AsRef<str>>(
|
||||
mut self,
|
||||
tokens: I,
|
||||
) -> Self {
|
||||
self.token_overrides = tokens
|
||||
self.tokens = tokens
|
||||
.into_iter()
|
||||
.map(|(url, s)| (url, s.as_ref().to_string()))
|
||||
.collect();
|
||||
|
@ -79,27 +72,15 @@ impl AuthConfig {
|
|||
self
|
||||
}
|
||||
|
||||
/// Get the default token
|
||||
pub fn default_token(&self) -> Option<&str> {
|
||||
self.default_token.as_deref()
|
||||
}
|
||||
|
||||
/// Get the token overrides
|
||||
pub fn token_overrides(&self) -> &HashMap<gix::Url, String> {
|
||||
&self.token_overrides
|
||||
/// Get the tokens
|
||||
pub fn tokens(&self) -> &HashMap<gix::Url, String> {
|
||||
&self.tokens
|
||||
}
|
||||
|
||||
/// Get the git credentials
|
||||
pub fn git_credentials(&self) -> Option<&Account> {
|
||||
self.git_credentials.as_ref()
|
||||
}
|
||||
|
||||
pub(crate) fn get_token(&self, url: &gix::Url) -> Option<&str> {
|
||||
self.token_overrides
|
||||
.get(url)
|
||||
.map(|s| s.as_str())
|
||||
.or(self.default_token.as_deref())
|
||||
}
|
||||
}
|
||||
|
||||
/// The main struct of the pesde library, representing a project
|
||||
|
|
18
src/main.rs
18
src/main.rs
|
@ -14,9 +14,7 @@ use std::{
|
|||
use crate::cli::version::{
|
||||
check_for_updates, current_version, get_or_download_version, max_installed_version,
|
||||
};
|
||||
use crate::cli::{
|
||||
auth::get_token, config::read_config, home_dir, repos::update_repo_dependencies, HOME_DIR,
|
||||
};
|
||||
use crate::cli::{auth::get_tokens, home_dir, repos::update_repo_dependencies, HOME_DIR};
|
||||
|
||||
mod cli;
|
||||
pub mod util;
|
||||
|
@ -187,14 +185,14 @@ fn run() -> anyhow::Result<()> {
|
|||
let data_dir = home_dir()?.join("data");
|
||||
create_dir_all(&data_dir).expect("failed to create data directory");
|
||||
|
||||
let token = get_token()?;
|
||||
|
||||
let home_cas_dir = data_dir.join("cas");
|
||||
create_dir_all(&home_cas_dir).expect("failed to create cas directory");
|
||||
let project_root = get_root(&project_root_dir);
|
||||
let cas_dir = if get_root(&home_cas_dir) == project_root {
|
||||
log::debug!("using home cas dir");
|
||||
home_cas_dir
|
||||
} else {
|
||||
log::debug!("using cas dir in {}", project_root.display());
|
||||
project_root.join(HOME_DIR).join("cas")
|
||||
};
|
||||
|
||||
|
@ -203,19 +201,11 @@ fn run() -> anyhow::Result<()> {
|
|||
project_workspace_dir,
|
||||
data_dir,
|
||||
cas_dir,
|
||||
AuthConfig::new()
|
||||
.with_default_token(token.clone())
|
||||
.with_token_overrides(read_config()?.token_overrides),
|
||||
AuthConfig::new().with_tokens(get_tokens()?.0),
|
||||
);
|
||||
|
||||
let reqwest = {
|
||||
let mut headers = reqwest::header::HeaderMap::new();
|
||||
if let Some(token) = token {
|
||||
headers.insert(
|
||||
reqwest::header::AUTHORIZATION,
|
||||
token.parse().context("failed to create auth header")?,
|
||||
);
|
||||
}
|
||||
|
||||
headers.insert(
|
||||
reqwest::header::ACCEPT,
|
||||
|
|
|
@ -7,7 +7,7 @@ use std::{
|
|||
|
||||
use gix::Url;
|
||||
use relative_path::RelativePathBuf;
|
||||
use reqwest::header::{HeaderMap, ACCEPT, AUTHORIZATION};
|
||||
use reqwest::header::{ACCEPT, AUTHORIZATION};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use pkg_ref::PesdePackageRef;
|
||||
|
@ -273,29 +273,14 @@ impl PackageSource for PesdePackageSource {
|
|||
.replace("{PACKAGE_VERSION}", &pkg_ref.version.to_string())
|
||||
.replace("{PACKAGE_TARGET}", &pkg_ref.target.to_string());
|
||||
|
||||
let mut headers = HeaderMap::new();
|
||||
headers.insert(
|
||||
ACCEPT,
|
||||
"application/octet-stream"
|
||||
.parse()
|
||||
.map_err(|e| errors::DownloadError::InvalidHeaderValue("Accept".to_string(), e))?,
|
||||
);
|
||||
let mut request = reqwest.get(&url).header(ACCEPT, "application/octet-stream");
|
||||
|
||||
if let Some(token) = project.auth_config.get_token(&self.repo_url) {
|
||||
log::debug!("using token for pesde package download");
|
||||
headers.insert(
|
||||
AUTHORIZATION,
|
||||
token.parse().map_err(|e| {
|
||||
errors::DownloadError::InvalidHeaderValue("Authorization".to_string(), e)
|
||||
})?,
|
||||
);
|
||||
if let Some(token) = project.auth_config.tokens().get(&self.repo_url) {
|
||||
log::debug!("using token for {}", self.repo_url);
|
||||
request = request.header(AUTHORIZATION, token);
|
||||
}
|
||||
|
||||
let response = reqwest
|
||||
.get(url)
|
||||
.headers(headers)
|
||||
.send()?
|
||||
.error_for_status()?;
|
||||
let response = request.send()?.error_for_status()?;
|
||||
let bytes = response.bytes()?;
|
||||
|
||||
let mut decoder = flate2::read::GzDecoder::new(bytes.as_ref());
|
||||
|
@ -583,9 +568,5 @@ pub mod errors {
|
|||
/// Error writing index file
|
||||
#[error("error reading index file")]
|
||||
ReadIndex(#[source] std::io::Error),
|
||||
|
||||
/// A header value was invalid
|
||||
#[error("invalid header {0} value")]
|
||||
InvalidHeaderValue(String, #[source] reqwest::header::InvalidHeaderValue),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ use std::{
|
|||
|
||||
use gix::Url;
|
||||
use relative_path::RelativePathBuf;
|
||||
use reqwest::header::{HeaderMap, AUTHORIZATION};
|
||||
use reqwest::header::AUTHORIZATION;
|
||||
use serde::Deserialize;
|
||||
use tempfile::tempdir;
|
||||
|
||||
|
@ -178,33 +178,19 @@ impl PackageSource for WallyPackageSource {
|
|||
pkg_ref.version
|
||||
);
|
||||
|
||||
let mut headers = HeaderMap::new();
|
||||
headers.insert(
|
||||
let mut request = reqwest.get(&url).header(
|
||||
"Wally-Version",
|
||||
std::env::var("PESDE_WALLY_VERSION")
|
||||
.as_deref()
|
||||
.unwrap_or("0.3.2")
|
||||
.parse()
|
||||
.map_err(|e| {
|
||||
errors::DownloadError::InvalidHeaderValue("Wally-Version".to_string(), e)
|
||||
})?,
|
||||
.unwrap_or("0.3.2"),
|
||||
);
|
||||
|
||||
if let Some(token) = project.auth_config.get_token(&self.repo_url) {
|
||||
log::debug!("using token for wally package download");
|
||||
headers.insert(
|
||||
AUTHORIZATION,
|
||||
token.parse().map_err(|e| {
|
||||
errors::DownloadError::InvalidHeaderValue("Authorization".to_string(), e)
|
||||
})?,
|
||||
);
|
||||
if let Some(token) = project.auth_config.tokens().get(&self.repo_url) {
|
||||
log::debug!("using token for {}", self.repo_url);
|
||||
request = request.header(AUTHORIZATION, token);
|
||||
}
|
||||
|
||||
let response = reqwest
|
||||
.get(url)
|
||||
.headers(headers)
|
||||
.send()?
|
||||
.error_for_status()?;
|
||||
let response = request.send()?.error_for_status()?;
|
||||
let bytes = response.bytes()?;
|
||||
|
||||
let mut archive = zip::ZipArchive::new(std::io::Cursor::new(bytes))?;
|
||||
|
@ -355,9 +341,5 @@ pub mod errors {
|
|||
/// Error writing index file
|
||||
#[error("error writing index file")]
|
||||
WriteIndex(#[source] std::io::Error),
|
||||
|
||||
/// A header value was invalid
|
||||
#[error("invalid header {0} value")]
|
||||
InvalidHeaderValue(String, #[source] reqwest::header::InvalidHeaderValue),
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue