Skip to content

Commit

Permalink
Merge pull request #122 from DeterminateSystems/authenticate-requests
Browse files Browse the repository at this point in the history
Add authentication to core FlakeHub client
  • Loading branch information
lucperkins authored Jul 9, 2024
2 parents 0c719dc + 5a12394 commit 3e7f1dc
Show file tree
Hide file tree
Showing 8 changed files with 303 additions and 404 deletions.
65 changes: 2 additions & 63 deletions src/cli/cmd/add/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,10 @@ use std::process::ExitCode;

use clap::Parser;
use color_eyre::eyre::WrapErr;
use reqwest::header::{HeaderValue, ACCEPT, AUTHORIZATION};
use serde::Deserialize;

use self::flake::InputsInsertionLocation;

use super::CommandExecute;
use super::{CommandExecute, FlakeHubClient};

const FALLBACK_FLAKE_CONTENTS: &str = r#"{
description = "My new flake.";
Expand Down Expand Up @@ -191,64 +189,5 @@ pub(crate) async fn get_flakehub_project_and_url(
project: &str,
version: Option<&str>,
) -> color_eyre::Result<(String, url::Url)> {
let mut headers = reqwest::header::HeaderMap::new();
headers.insert(ACCEPT, HeaderValue::from_static("application/json"));

let xdg = xdg::BaseDirectories::new()?;
// $XDG_CONFIG_HOME/fh/auth; basically ~/.config/fh/auth
let token_path = xdg.get_config_file("flakehub/auth");

if token_path.exists() {
let token = tokio::fs::read_to_string(&token_path)
.await
.wrap_err_with(|| format!("Could not open {}", token_path.display()))?;

headers.insert(
AUTHORIZATION,
HeaderValue::from_str(&format!("Bearer {token}"))?,
);
}

let client = reqwest::Client::builder()
.user_agent(crate::APP_USER_AGENT)
.default_headers(headers)
.build()?;

let mut flakehub_json_url = api_addr.clone();
{
let mut path_segments_mut = flakehub_json_url
.path_segments_mut()
.expect("flakehub url cannot be base (this should never happen)");

match version {
Some(version) => {
path_segments_mut
.push("version")
.push(org)
.push(project)
.push(version);
}
None => {
path_segments_mut.push("f").push(org).push(project);
}
}
}

#[derive(Debug, Deserialize)]
struct ProjectCanonicalNames {
project: String,
// FIXME: detect Nix version and strip .tar.gz if it supports it
pretty_download_url: url::Url,
}

let res = client.get(&flakehub_json_url.to_string()).send().await?;

if let Err(e) = res.error_for_status_ref() {
let err_text = res.text().await?;
return Err(e).wrap_err(err_text)?;
};

let res = res.json::<ProjectCanonicalNames>().await?;

Ok((res.project, res.pretty_download_url))
FlakeHubClient::project_and_url(api_addr.as_ref(), org, project, version).await
}
69 changes: 2 additions & 67 deletions src/cli/cmd/eject/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,10 @@ use std::path::PathBuf;
use std::process::ExitCode;

use clap::Parser;
use color_eyre::eyre::WrapErr;
use once_cell::sync::Lazy;
use reqwest::header::{HeaderValue, ACCEPT, AUTHORIZATION};
use serde::Deserialize;
use tracing::{span, Level};

use super::CommandExecute;
use super::{CommandExecute, FlakeHubClient, ProjectMetadata};

static ROLLING_RELEASE_BUILD_META_REGEX: Lazy<regex::Regex> =
Lazy::new(|| regex::Regex::new(r"(rev)-.{40}").unwrap());
Expand Down Expand Up @@ -177,7 +174,7 @@ async fn eject_flakehub_input_to_github(
source_github_owner_repo_pair,
source_subdirectory,
version,
} = get_metadata_from_flakehub(api_addr, org, project, version).await?;
} = FlakeHubClient::metadata(api_addr.as_ref(), org, project, version).await?;

let maybe_version_or_branch = match source_github_owner_repo_pair.to_lowercase().as_str() {
"nixos/nixpkgs" => {
Expand Down Expand Up @@ -237,68 +234,6 @@ fn separate_year_from_month_in_version(version: &str) -> Option<String> {
version
}

#[derive(Debug, Deserialize)]
struct ProjectMetadata {
source_github_owner_repo_pair: String,
source_subdirectory: Option<String>,
version: String,
}

#[tracing::instrument(skip_all)]
async fn get_metadata_from_flakehub(
api_addr: &url::Url,
org: &str,
project: &str,
version: &str,
) -> color_eyre::Result<ProjectMetadata> {
let mut headers = reqwest::header::HeaderMap::new();
headers.insert(ACCEPT, HeaderValue::from_static("application/json"));

let xdg = xdg::BaseDirectories::new()?;
// $XDG_CONFIG_HOME/fh/auth; basically ~/.config/fh/auth
let token_path = xdg.get_config_file("flakehub/auth");

if token_path.exists() {
let token = tokio::fs::read_to_string(&token_path)
.await
.wrap_err_with(|| format!("Could not open {}", token_path.display()))?;

headers.insert(
AUTHORIZATION,
HeaderValue::from_str(&format!("Bearer {token}"))?,
);
}

let client = reqwest::Client::builder()
.user_agent(crate::APP_USER_AGENT)
.default_headers(headers)
.build()?;

let mut flakehub_json_url = api_addr.clone();
{
let mut path_segments_mut = flakehub_json_url
.path_segments_mut()
.expect("flakehub url cannot be base (this should never happen)");

path_segments_mut
.push("version")
.push(org)
.push(project)
.push(version);
}

let res = client.get(&flakehub_json_url.to_string()).send().await?;

if let Err(e) = res.error_for_status_ref() {
let err_text = res.text().await?;
return Err(e).wrap_err(err_text)?;
};

let res = res.json::<ProjectMetadata>().await?;

Ok(res)
}

#[cfg(test)]
mod test {
use axum::{extract::Path, response::IntoResponse};
Expand Down
83 changes: 39 additions & 44 deletions src/cli/cmd/init/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,10 @@ use std::{
};
use url::Url;

use crate::cli::cmd::{init::handlers::Elm, list::FLAKEHUB_WEB_ROOT};
use crate::{
cli::cmd::{init::handlers::Elm, list::FLAKEHUB_WEB_ROOT},
flakehub_url,
};

use super::FlakeHubClient;

Expand All @@ -31,36 +34,6 @@ use self::{

use super::{CommandExecute, FhError};

// A helper struct for creating FlakeHub URLs
pub(crate) struct FlakeHubUrl;

impl FlakeHubUrl {
fn version(org: &str, project: &str, version: &str) -> String {
let mut url = Url::parse(FLAKEHUB_WEB_ROOT)
.expect("failed to parse flakehub web root url (this should never happen)");

let version = format!("{version}.tar.gz");

{
let mut segs = url
.path_segments_mut()
.expect("flakehub url cannot be base (this should never happen)");

segs.push("f").push(org).push(project).push(&version);
}

url.to_string()
}

fn latest(org: &str, project: &str) -> String {
Self::version(org, project, "*")
}

fn unstable(org: &str, project: &str) -> String {
Self::version(org, project, "0.1.*")
}
}

// Nixpkgs references
const NIXPKGS_LATEST: &str = "latest stable (currently 24.05)";
const NIXPKGS_24_05: &str = "24.05";
Expand Down Expand Up @@ -117,22 +90,34 @@ impl CommandExecute for InitSubcommand {
.as_str()
{
// MAYBE: find an enum-based approach to this
NIXPKGS_LATEST => FlakeHubUrl::latest("NixOS", "nixpkgs"),
NIXPKGS_24_05 => FlakeHubUrl::version("NixOS", "nixpkgs", "0.2405.*"),
NIXPKGS_UNSTABLE => FlakeHubUrl::unstable("NixOS", "nixpkgs"),
NIXPKGS_SPECIFIC => select_nixpkgs(&self.api_addr).await?,
NIXPKGS_LATEST => flakehub_url!(FLAKEHUB_WEB_ROOT, "f", "NixOS", "nixpkgs", "*"),
NIXPKGS_24_05 => {
flakehub_url!(FLAKEHUB_WEB_ROOT, "f", "NixOS", "nixpkgs", "0.2405.*")
}
NIXPKGS_UNSTABLE => {
flakehub_url!(FLAKEHUB_WEB_ROOT, "f", "NixOS", "nixpkgs", "0.1.*")
}
NIXPKGS_SPECIFIC => select_nixpkgs(self.api_addr.as_ref()).await?,
// Just in case
_ => return Err(FhError::Unreachable(String::from("nixpkgs selection")).into()),
};

flake
.inputs
.insert(String::from("nixpkgs"), Input::new(&nixpkgs_version, None));
flake.inputs.insert(
String::from("nixpkgs"),
Input::new(nixpkgs_version.as_ref(), None),
);

flake.inputs.insert(
String::from("flake-schemas"),
Input::new(
&FlakeHubUrl::latest("DeterminateSystems", "flake-schemas"),
flakehub_url!(
FLAKEHUB_WEB_ROOT,
"f",
"DeterminateSystems",
"flake-schemas",
"*"
)
.as_str(),
None,
),
);
Expand Down Expand Up @@ -218,7 +203,11 @@ impl CommandExecute for InitSubcommand {
if use_flake_compat {
flake.inputs.insert(
String::from("flake-compat"),
Input::new(&FlakeHubUrl::latest("edolstra", "flake-compat"), None),
Input::new(
flakehub_url!(FLAKEHUB_WEB_ROOT, "flake", "edolstra", "flake-compat", "*")
.as_str(),
None,
),
);
write(
PathBuf::from("default.nix"),
Expand Down Expand Up @@ -292,10 +281,16 @@ fn command_exists(cmd: &str) -> bool {
Command::new(cmd).output().is_ok()
}

async fn select_nixpkgs(api_addr: &Url) -> Result<String, FhError> {
let client = &FlakeHubClient::new(api_addr)?;
let releases = client.releases("NixOS", "nixpkgs").await?;
async fn select_nixpkgs(api_addr: &str) -> Result<Url, FhError> {
let releases = FlakeHubClient::releases(api_addr, "NixOS", "nixpkgs").await?;
let releases: Vec<&str> = releases.iter().map(|r| r.version.as_str()).collect();
let release = Prompt::select("Choose one of the following Nixpkgs releases:", &releases);
Ok(FlakeHubUrl::version("NixOS", "nixpkgs", &release))
let version = format!("{release}.tar.gz");
Ok(flakehub_url!(
FLAKEHUB_WEB_ROOT,
"f",
"NixOS",
"nixpkgs",
&version
))
}
Loading

0 comments on commit 3e7f1dc

Please sign in to comment.