Skip to content

Commit

Permalink
remove util module
Browse files Browse the repository at this point in the history
that's more the core of the lib
  • Loading branch information
glehmann committed Feb 4, 2024
1 parent 36b7c5a commit 14a4158
Show file tree
Hide file tree
Showing 8 changed files with 228 additions and 228 deletions.
2 changes: 1 addition & 1 deletion src/decrypt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use serde_yaml as sy;

use crate::cli::DecryptArgs;
use crate::error::Result;
use crate::util::{decrypt_yaml, load_identities, stdin_or_file, stdout_or_file};
use crate::{decrypt_yaml, load_identities, stdin_or_file, stdout_or_file};

pub fn decrypt(args: &DecryptArgs) -> Result<()> {
let identities = load_identities(&args.keys, &args.key_files)?;
Expand Down
2 changes: 1 addition & 1 deletion src/edit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use treediff::Mutable;

use crate::cli::EditArgs;
use crate::error::{IOResultExt, Result, YageError};
use crate::util::{decrypt_yaml, encrypt_yaml, load_identities, load_recipients};
use crate::{decrypt_yaml, encrypt_yaml, load_identities, load_recipients};

pub fn edit(args: &EditArgs) -> Result<()> {
let identities = load_identities(&args.keys, &args.key_files)?;
Expand Down
2 changes: 1 addition & 1 deletion src/encrypt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use serde_yaml as sy;

use crate::cli::EncryptArgs;
use crate::error::Result;
use crate::util::{encrypt_yaml, load_recipients, stdin_or_file, stdout_or_file};
use crate::{encrypt_yaml, load_recipients, stdin_or_file, stdout_or_file};

pub fn encrypt(args: &EncryptArgs) -> Result<()> {
let recipients = load_recipients(&args.recipients, &args.recipient_files)?;
Expand Down
2 changes: 1 addition & 1 deletion src/env.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use serde_yaml as sy;

use crate::cli::EnvArgs;
use crate::error::{Result, YageError};
use crate::util::{decrypt_yaml, load_identities, stdin_or_file};
use crate::{decrypt_yaml, load_identities, stdin_or_file};

pub fn env(args: &EnvArgs) -> Result<()> {
let identities = load_identities(&args.keys, &args.key_files)?;
Expand Down
2 changes: 1 addition & 1 deletion src/keygen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use age::x25519::Identity;

use crate::cli::KeygenArgs;
use crate::error::{IOResultExt, Result};
use crate::util::{stdout_or_file, stdout_or_private_file};
use crate::{stdout_or_file, stdout_or_private_file};

pub fn keygen(args: &KeygenArgs) -> Result<()> {
let key = Identity::generate();
Expand Down
223 changes: 222 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,225 @@ pub mod env;
pub mod error;
pub mod keygen;
pub mod pubkey;
pub mod util;

use std::fs::{File, OpenOptions};
use std::io::{stdin, stdout, BufRead, BufReader, Read, Write};
#[cfg(unix)]
use std::os::unix::fs::OpenOptionsExt;
use std::path::Path;
use std::path::PathBuf;
use std::str::FromStr;

use age::x25519;
use base64::prelude::*;
use path_absolutize::Absolutize;
use serde_yaml as sy;
use substring::Substring;

use crate::error::{IOResultExt, Result, YageError};

pub fn stdout_or_file(path: &Path) -> Result<Box<dyn Write>> {
Ok(if path == Path::new("-") {
Box::new(stdout())
} else {
Box::new(File::create(path).path_ctx(path)?)
})
}

pub fn stdout_or_private_file(path: &Path) -> Result<Box<dyn Write>> {
Ok(if path == Path::new("-") {
Box::new(stdout())
} else {
// make sure the directory is private
let real_path = path.absolutize().path_ctx(path)?;
let dir = real_path.parent().ok_or(YageError::InvalidFileName {
path: path.to_owned(),
})?;
if let Err(e) = fs_mistrust::Mistrust::new().check_directory(dir) {
warn!("directory {dir:?} is not private: {e}");
}
let mut file_opts = OpenOptions::new();
file_opts.write(true).create_new(true);
#[cfg(unix)]
file_opts.mode(0o600);
Box::new(file_opts.open(path).path_ctx(path)?)
})
}

pub fn stdin_or_file(path: &Path) -> Result<BufReader<Box<dyn Read>>> {
Ok(if path == Path::new("-") {
BufReader::new(Box::new(stdin()))
} else {
BufReader::new(Box::new(File::open(path).path_ctx(path)?))
})
}

pub fn stdin_or_private_file(path: &Path) -> Result<BufReader<Box<dyn Read>>> {
Ok(if path == Path::new("-") {
BufReader::new(Box::new(stdin()))
} else {
if let Err(e) = fs_mistrust::Mistrust::new()
.verifier()
.require_file()
.check(path)
{
warn!("file {path:?} is not private: {e}");
}
BufReader::new(Box::new(File::open(path).path_ctx(path)?))
})
}

pub fn is_yage_encoded(s: &str) -> bool {
s.starts_with("yage[") && s.ends_with(']')
}

pub fn decrypt_yaml(value: &sy::Value, identities: &[x25519::Identity]) -> Result<sy::Value> {
match value {
sy::Value::Mapping(mapping) => {
let mut output = sy::Mapping::new();
for (key, value) in mapping {
let key = key.clone();
let value = decrypt_yaml(value, identities)?;
output.insert(key, value);
}
Ok(sy::Value::Mapping(output))
}
sy::Value::Sequence(sequence) => {
let mut output = Vec::new();
for value in sequence {
let value = decrypt_yaml(value, identities)?;
output.push(value);
}
Ok(sy::Value::Sequence(output))
}
sy::Value::String(encrypted) => {
let decrypted = decrypt_value(encrypted, identities)?;
Ok(decrypted)
}
_ => Ok(value.clone()),
}
}

pub fn decrypt_value(s: &str, identities: &[x25519::Identity]) -> Result<sy::Value> {
if is_yage_encoded(s) {
// remove the yage[…] prefix and suffix
let encoded = s.substring(5, s.len() - 1);
let encrypted = BASE64_STANDARD.decode(encoded)?;
let decryptor = match age::Decryptor::new(&encrypted[..])? {
age::Decryptor::Recipients(d) => Ok(d),
_ => Err(YageError::PassphraseUnsupported),
}?;
let mut decrypted = vec![];
let mut reader = decryptor.decrypt(identities.iter().map(|i| i as &dyn age::Identity))?;
reader.read_to_end(&mut decrypted)?;
let value: sy::Value = sy::from_slice(&decrypted)?;
Ok(value)
} else {
Ok(sy::Value::String(s.to_owned()))
}
}

pub fn load_identities(keys: &[String], key_files: &[PathBuf]) -> Result<Vec<x25519::Identity>> {
let mut identities: Vec<x25519::Identity> = Vec::new();
for key in keys.iter() {
debug!("loading key: {key}");
let key = x25519::Identity::from_str(key)
.map_err(|e| YageError::KeyParse { message: e.into() })?;
identities.push(key);
}
for key_file in key_files.iter() {
debug!("loading key file: {key_file:?}");
let input = stdin_or_private_file(key_file)?;
let keys = age::IdentityFile::from_buffer(input).path_ctx(key_file)?;
for key in keys.into_identities() {
let age::IdentityFileEntry::Native(key) = key;
identities.push(key);
}
}
Ok(identities)
}

pub fn encrypt_yaml(value: &sy::Value, recipients: &[x25519::Recipient]) -> Result<sy::Value> {
match value {
sy::Value::Mapping(mapping) => {
let mut output = sy::Mapping::new();
for (key, value) in mapping {
let key = key.clone();
let value = encrypt_yaml(value, recipients)?;
output.insert(key, value);
}
Ok(sy::Value::Mapping(output))
}
sy::Value::Sequence(sequence) => {
let mut output = Vec::new();
for value in sequence {
let value = encrypt_yaml(value, recipients)?;
output.push(value);
}
Ok(sy::Value::Sequence(output))
}
sy::Value::String(s) => {
let output = if is_yage_encoded(s) {
// keep the already encrypted value
s.to_owned()
} else {
encrypt_value(value, recipients)?
};
Ok(sy::Value::String(output))
}
sy::Value::Number(_) => {
let output = encrypt_value(value, recipients)?;
Ok(sy::Value::String(output))
}
_ => Ok(value.clone()),
}
}

pub fn encrypt_value(value: &sy::Value, recipients: &[x25519::Recipient]) -> Result<String> {
type Recipients = Vec<Box<dyn age::Recipient + Send + 'static>>;
let data = sy::to_string(value)?;
let recipients = recipients
.iter()
.map(|r| Box::new(r.clone()) as Box<dyn age::Recipient + Send + 'static>)
.collect::<Recipients>();
let mut encrypted = vec![];
let encryptor = age::Encryptor::with_recipients(recipients).ok_or(YageError::NoRecipients)?;
// let mut armored = ArmoredWriter::wrap_output(&mut encrypted, Format::AsciiArmor)?;
let mut writer = encryptor.wrap_output(&mut encrypted)?;
writer.write_all(data.as_bytes())?;
writer.finish()?;
let encoded = BASE64_STANDARD.encode(&encrypted);
Ok(format!("yage[{encoded}]"))
}

pub fn load_recipients(
recipients: &[String],
recipients_paths: &[PathBuf],
) -> Result<Vec<x25519::Recipient>> {
let mut res: Vec<x25519::Recipient> = Vec::new();
// read the recipient from the command line
for recipient in recipients.iter() {
debug!("loading recipient: {recipient}");
let recipient =
x25519::Recipient::from_str(recipient).map_err(|e| YageError::RecipientParse {
recipient: recipient.to_owned(),
message: e.into(),
})?;
res.push(recipient);
}
// read the recipient from the files
for path in recipients_paths.iter() {
debug!("loading recipient file: {path:?}");
let input = stdin_or_file(path)?;
for recipient in input.lines() {
let recipient = recipient.path_ctx(path)?;
let recipient =
x25519::Recipient::from_str(&recipient).map_err(|e| YageError::RecipientParse {
recipient: recipient.to_owned(),
message: e.into(),
})?;
res.push(recipient);
}
}
Ok(res)
}
2 changes: 1 addition & 1 deletion src/pubkey.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::cli::PubkeyArgs;
use crate::error::{IOResultExt, Result};
use crate::util::{load_identities, stdout_or_file};
use crate::{load_identities, stdout_or_file};

pub fn pubkey(args: &PubkeyArgs) -> Result<()> {
let keys = load_identities(&args.keys, &args.key_files)?;
Expand Down
Loading

0 comments on commit 14a4158

Please sign in to comment.