forked from nrabulinski/attic
client: allow storing the client token in a separate file
This commit is contained in:
parent
5f85e35a25
commit
4badbff966
4 changed files with 45 additions and 9 deletions
|
@ -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)?,
|
||||||
|
|
|
@ -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 }),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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?;
|
||||||
|
|
|
@ -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.
|
||||||
|
|
Loading…
Reference in a new issue