client: allow storing the client token in a separate file

This commit is contained in:
Robin Appelman 2023-05-22 19:27:47 +02:00
parent 5f85e35a25
commit 4badbff966
4 changed files with 45 additions and 9 deletions

View file

@ -62,7 +62,7 @@ pub struct StructuredApiError {
impl ApiClient { impl ApiClient {
pub fn from_server_config(config: ServerConfig) -> Result<Self> { pub fn from_server_config(config: ServerConfig) -> Result<Self> {
let client = build_http_client(config.token.as_deref()); let client = build_http_client(config.token()?.as_deref());
Ok(Self { Ok(Self {
endpoint: Url::parse(&config.endpoint)?, endpoint: Url::parse(&config.endpoint)?,

View file

@ -3,7 +3,7 @@ use clap::Parser;
use crate::cache::ServerName; use crate::cache::ServerName;
use crate::cli::Opts; use crate::cli::Opts;
use crate::config::{Config, ServerConfig}; use crate::config::{Config, ServerConfig, ServerTokenConfig};
/// Log into an Attic server. /// Log into an Attic server.
#[derive(Debug, Parser)] #[derive(Debug, Parser)]
@ -32,8 +32,10 @@ pub async fn run(opts: Opts) -> Result<()> {
server.endpoint = sub.endpoint.to_owned(); server.endpoint = sub.endpoint.to_owned();
if sub.token.is_some() { if let Some(token) = &sub.token {
server.token = sub.token.to_owned(); server.token = Some(ServerTokenConfig::Raw {
token: token.clone(),
});
} }
} else { } else {
eprintln!("✍️ Configuring server \"{}\"", sub.name.as_str()); eprintln!("✍️ Configuring server \"{}\"", sub.name.as_str());
@ -42,7 +44,10 @@ pub async fn run(opts: Opts) -> Result<()> {
sub.name.to_owned(), sub.name.to_owned(),
ServerConfig { ServerConfig {
endpoint: sub.endpoint.to_owned(), endpoint: sub.endpoint.to_owned(),
token: sub.token.to_owned(), token: sub
.token
.to_owned()
.map(|token| ServerTokenConfig::Raw { token }),
}, },
); );
} }

View file

@ -49,7 +49,7 @@ pub async fn run(opts: Opts) -> Result<()> {
nix_config.add_trusted_public_key(&public_key); nix_config.add_trusted_public_key(&public_key);
// Modify netrc // Modify netrc
if let Some(token) = &server.token { if let Some(token) = server.token()? {
eprintln!("+ Access Token"); eprintln!("+ Access Token");
let mut nix_netrc = NixNetrc::load().await?; let mut nix_netrc = NixNetrc::load().await?;

View file

@ -5,13 +5,13 @@
//! experience (e.g., `attic login`). //! experience (e.g., `attic login`).
use std::collections::HashMap; use std::collections::HashMap;
use std::fs::{self, OpenOptions, Permissions}; use std::fs::{self, read_to_string, OpenOptions, Permissions};
use std::io::Write; use std::io::Write;
use std::ops::{Deref, DerefMut}; use std::ops::{Deref, DerefMut};
use std::os::unix::fs::{OpenOptionsExt, PermissionsExt}; use std::os::unix::fs::{OpenOptionsExt, PermissionsExt};
use std::path::PathBuf; use std::path::PathBuf;
use anyhow::{anyhow, Result}; use anyhow::{anyhow, Context, Result};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use xdg::BaseDirectories; use xdg::BaseDirectories;
@ -52,7 +52,38 @@ pub struct ConfigData {
#[derive(Debug, Clone, Deserialize, Serialize)] #[derive(Debug, Clone, Deserialize, Serialize)]
pub struct ServerConfig { pub struct ServerConfig {
pub endpoint: String, pub endpoint: String,
pub token: Option<String>, #[serde(flatten)]
pub token: Option<ServerTokenConfig>,
}
impl ServerConfig {
pub fn token(&self) -> Result<Option<String>> {
self.token.as_ref().map(|token| token.get()).transpose()
}
}
/// Configured server token
#[derive(Debug, Clone, Deserialize, Serialize)]
#[serde(untagged)]
pub enum ServerTokenConfig {
Raw {
token: String,
},
File {
#[serde(rename = "token-file")]
token_file: String,
},
}
impl ServerTokenConfig {
/// Get the token either directly from the config or through the token file
pub fn get(&self) -> Result<String> {
match self {
ServerTokenConfig::Raw { token } => Ok(token.clone()),
ServerTokenConfig::File { token_file } => Ok(read_to_string(token_file)
.with_context(|| format!("Failed to read token from {token_file}"))?),
}
}
} }
/// Wrapper that automatically saves the config once dropped. /// Wrapper that automatically saves the config once dropped.