1
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2024-11-24 15:19:26 -05:00

fix: batch upload authentication (#21397)

This commit is contained in:
Luca Casonato 2023-11-30 19:54:54 +01:00 committed by GitHub
parent 334c118c97
commit ffa09541d7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 90 additions and 65 deletions

View file

@ -4,6 +4,7 @@ use std::fmt::Write;
use std::io::IsTerminal;
use std::path::Path;
use std::path::PathBuf;
use std::rc::Rc;
use std::sync::Arc;
use base64::prelude::BASE64_STANDARD;
@ -227,21 +228,21 @@ async fn perform_publish(
let client = http_client.client()?;
let registry_url = crate::cache::DENO_REGISTRY_URL.to_string();
let authorization = match auth_method {
let permissions = packages
.iter()
.map(|package| Permission::VersionPublish {
scope: &package.scope,
package: &package.package,
version: &package.version,
tarball_hash: &package.tarball_hash,
})
.collect::<Vec<_>>();
let authorizations = match auth_method {
AuthMethod::Interactive => {
let verifier = uuid::Uuid::new_v4().to_string();
let challenge = BASE64_STANDARD.encode(sha2::Sha256::digest(&verifier));
let permissions = packages
.iter()
.map(|package| Permission::VersionPublish {
scope: &package.scope,
package: &package.package,
version: &package.version,
tarball_hash: &package.tarball_hash,
})
.collect::<Vec<_>>();
let response = client
.post(format!("{}authorizations", registry_url))
.json(&serde_json::json!({
@ -290,7 +291,12 @@ async fn perform_publish(
colors::gray("Authenticated as"),
colors::cyan(res.user.name)
);
break format!("Bearer {}", res.token);
let authorization: Rc<str> = format!("Bearer {}", res.token).into();
let mut authorizations = Vec::new();
for _ in &packages {
authorizations.push(authorization.clone());
}
break authorizations;
}
Err(err) => {
if err.code == "authorizationPending" {
@ -302,54 +308,65 @@ async fn perform_publish(
}
}
}
AuthMethod::Token(token) => format!("Bearer {}", token),
AuthMethod::Oidc(oidc_config) => {
let permissions = packages
.iter()
.map(|package| Permission::VersionPublish {
scope: &package.scope,
package: &package.package,
version: &package.version,
tarball_hash: &package.tarball_hash,
})
.collect::<Vec<_>>();
let audience = json!({ "permissions": permissions }).to_string();
let url = format!(
"{}&audience={}",
oidc_config.url,
percent_encoding::percent_encode(
audience.as_bytes(),
percent_encoding::NON_ALPHANUMERIC
)
);
let response = client
.get(url)
.bearer_auth(oidc_config.token)
.send()
.await
.context("Failed to get OIDC token")?;
let status = response.status();
let text = response.text().await.with_context(|| {
format!("Failed to get OIDC token: status {}", status)
})?;
if !status.is_success() {
bail!(
"Failed to get OIDC token: status {}, response: '{}'",
status,
text
);
AuthMethod::Token(token) => {
let authorization: Rc<str> = format!("Bearer {}", token).into();
let mut authorizations = Vec::new();
for _ in &packages {
authorizations.push(authorization.clone());
}
let OidcTokenResponse { value } = serde_json::from_str(&text)
.with_context(|| {
format!("Failed to parse OIDC token: '{}' (status {})", text, status)
authorizations
}
AuthMethod::Oidc(oidc_config) => {
let mut authorizations = Vec::new();
for permissions in permissions.chunks(16) {
let audience = json!({ "permissions": permissions }).to_string();
let url = format!(
"{}&audience={}",
oidc_config.url,
percent_encoding::percent_encode(
audience.as_bytes(),
percent_encoding::NON_ALPHANUMERIC
)
);
let response = client
.get(url)
.bearer_auth(&oidc_config.token)
.send()
.await
.context("Failed to get OIDC token")?;
let status = response.status();
let text = response.text().await.with_context(|| {
format!("Failed to get OIDC token: status {}", status)
})?;
format!("githuboidc {}", value)
if !status.is_success() {
bail!(
"Failed to get OIDC token: status {}, response: '{}'",
status,
text
);
}
let OidcTokenResponse { value } = serde_json::from_str(&text)
.with_context(|| {
format!(
"Failed to parse OIDC token: '{}' (status {})",
text, status
)
})?;
let authorization: Rc<str> = format!("githuboidc {}", value).into();
for _ in &packages {
authorizations.push(authorization.clone());
}
}
authorizations
}
};
for package in packages {
assert_eq!(packages.len(), authorizations.len());
for (package, authorization) in
packages.into_iter().zip(authorizations.into_iter())
{
println!(
"{} @{}/{}@{} ...",
colors::intense_blue("Publishing"),
@ -365,7 +382,7 @@ async fn perform_publish(
let response = client
.post(url)
.header(AUTHORIZATION, &authorization)
.header(AUTHORIZATION, &*authorization)
.header(CONTENT_ENCODING, "gzip")
.body(package.tarball)
.send()

View file

@ -18,25 +18,33 @@ pub fn create_gzipped_tarball(
unfurler: ImportMapUnfurler,
) -> Result<Bytes, AnyError> {
let mut tar = TarGzArchive::new();
let dir_url = Url::from_directory_path(&dir).unwrap();
let dir = dir
.canonicalize()
.map_err(|_| anyhow::anyhow!("Unable to canonicalize path {:?}", dir))?;
for entry in walkdir::WalkDir::new(dir).follow_links(false) {
for entry in walkdir::WalkDir::new(&dir).follow_links(false) {
let entry = entry?;
if entry.file_type().is_file() {
let url = Url::from_file_path(entry.path())
.map_err(|_| anyhow::anyhow!("Invalid file path {:?}", entry.path()))?;
let relative_path = dir_url
.make_relative(&url)
.expect("children can be relative to parent");
.map_err(|_| anyhow::anyhow!("Unable to convert path to url"))?;
let relative_path = entry
.path()
.strip_prefix(&dir)
.map_err(|err| anyhow::anyhow!("Unable to strip prefix: {err}"))?;
let relative_path = relative_path.to_str().ok_or_else(|| {
anyhow::anyhow!("Unable to convert path to string {:?}", relative_path)
})?;
let data = std::fs::read(entry.path())
.with_context(|| format!("Unable to read file {:?}", entry.path()))?;
let content = unfurler
.unfurl(&url, data)
.with_context(|| format!("Unable to unfurl file {:?}", entry.path()))?;
tar.add_file(relative_path, &content).with_context(|| {
format!("Unable to add file to tarball {:?}", entry.path())
})?;
tar
.add_file(relative_path.to_string(), &content)
.with_context(|| {
format!("Unable to add file to tarball {:?}", entry.path())
})?;
} else if entry.file_type().is_dir() {
// skip
} else {