Skip to content

Commit

Permalink
feat: ✨ Introduce FromFile trait and uniform the from_file functi…
Browse files Browse the repository at this point in the history
…on calls.
  • Loading branch information
Jisu-Woniu committed Nov 23, 2023
1 parent a2d9411 commit 5f271c4
Show file tree
Hide file tree
Showing 8 changed files with 125 additions and 71 deletions.
26 changes: 26 additions & 0 deletions src-tauri/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions src-tauri/crypto/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,15 @@ version.workspace = true

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
async-trait = "0.1.74"
chrono = "0.4.31"
hex = "0.4.3"
pgp = "0.10.2"
serde = { version = "1.0.193", features = ["derive"] }
smallvec = "1.11.2"
thiserror = "1.0.50"
zeroize = "1.7.0"
tokio-util = { version = "0.7.10", features = ["io-util"] }

[dependencies.tokio]
features = ["fs", "io-util", "macros", "rt-multi-thread"]
Expand Down
55 changes: 55 additions & 0 deletions src-tauri/crypto/src/from_file.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
use std::{io::Read, path::Path};

use async_trait::async_trait;
use pgp::{
errors::Error as PgpError,
packet::{Packet, PacketParser},
Deserializable, Signature, SignedPublicKey, SignedSecretKey,
};
use tokio::{
fs::File,
io::{AsyncRead, BufReader},
};
use tokio_util::io::SyncIoBridge;

use crate::Result;

#[async_trait]
pub(crate) trait FromFile: Sized {
fn try_from_reader(reader: impl Read + Send + Unpin) -> Result<Self>;
fn try_from_async_reader(async_reader: impl AsyncRead + Send + Unpin) -> Result<Self> {
Self::try_from_reader(SyncIoBridge::new(async_reader))
}
async fn try_from_file(path: impl AsRef<Path> + Send) -> Result<Self> {
let file = File::open(path).await?;
Ok(Self::try_from_async_reader(BufReader::new(file))?)
}
}

macro_rules! impl_from_file {
($type:ty) => {
impl FromFile for $type {
fn try_from_reader(reader: impl Read + Send + Unpin) -> Result<Self> {
Ok(Self::from_bytes(reader)?)
}
}
};
}

impl_from_file!(SignedSecretKey);
impl_from_file!(SignedPublicKey);

impl FromFile for Signature {
fn try_from_reader(reader: impl Read + Send + Unpin) -> Result<Self> {
let signature = PacketParser::new(reader)
.find_map(|packet| {
if let Ok(Packet::Signature(s)) = packet {
Some(s)
} else {
None
}
})
.ok_or(PgpError::MissingPackets)?;
Ok(signature)
}
}
16 changes: 1 addition & 15 deletions src-tauri/crypto/src/key_pair.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
use std::path::Path;

use pgp::{
crypto::{hash::HashAlgorithm, sym::SymmetricKeyAlgorithm},
types::{CompressionAlgorithm, SecretKeyTrait as _},
Deserializable, KeyType, SecretKeyParamsBuilder, SignedPublicKey, SignedSecretKey,
KeyType, SecretKeyParamsBuilder, SignedPublicKey, SignedSecretKey,
};
use smallvec::smallvec;
use tokio::fs;

use crate::Result;

Expand Down Expand Up @@ -69,14 +66,3 @@ impl KeyPair {
&self.public_key
}
}

pub(crate) async fn secret_key_from_file(path: impl AsRef<Path>) -> Result<SignedSecretKey> {
let input = fs::read_to_string(path).await?;
Ok(SignedSecretKey::from_string(&input)?.0)
}

#[allow(dead_code)]
pub(crate) async fn public_key_from_file(path: impl AsRef<Path>) -> Result<SignedPublicKey> {
let input = fs::read_to_string(path).await?;
Ok(SignedPublicKey::from_string(&input)?.0)
}
10 changes: 4 additions & 6 deletions src-tauri/crypto/src/keygen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,9 +71,8 @@ mod tests {

use crate::{key_pair::KeyPair, Result};

#[tokio::test]
#[ignore = "Manual testing for file generation."]
async fn test() -> Result<()> {
#[test]
fn test() -> Result<()> {
let key_pair = KeyPair::generate("example", "[email protected]", String::new)?;
let (secret_key, public_key) = (key_pair.secret_key(), key_pair.public_key());
println!("{}", secret_key.to_armored_string(None)?);
Expand All @@ -82,9 +81,8 @@ mod tests {
Ok(())
}

#[tokio::test]
#[ignore = "Manual testing for file parsing."]
async fn extract_key_info() -> Result<()> {
#[test]
fn extract_key_info() -> Result<()> {
let secret_key_str = KeyPair::generate("example", "[email protected]", String::new)?
.secret_key()
.to_armored_string(None)?;
Expand Down
3 changes: 2 additions & 1 deletion src-tauri/crypto/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@
//! Cryptographic functions for the digital signature app.
pub mod error;
mod from_file;
mod key_pair;
pub mod keygen;
mod secret_file;
pub mod signing;

pub use error::Result;
pub use error::{Error, Result};
55 changes: 18 additions & 37 deletions src-tauri/crypto/src/signing.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
//! Utilities for signing files.
use std::path::Path;
use std::path::{Path, PathBuf};

use chrono::Utc;
use pgp::{
packet::{self, SignatureConfigBuilder, SignatureType, Subpacket, SubpacketData},
types::{PublicKeyTrait, SecretKeyTrait},
Signature,
Signature, SignedSecretKey,
};
use tokio::fs::{read, File};

use crate::{key_pair, Result};
use crate::{from_file::FromFile, Result};

/// Generate a signature of the given data.
fn sign(data: &[u8], secret_key: &impl SecretKeyTrait) -> Result<Signature> {
Expand Down Expand Up @@ -45,9 +45,9 @@ fn verify(data: &[u8], public_key: &impl PublicKeyTrait, signature: &Signature)
pub async fn sign_file_with_key(
file_path: impl AsRef<Path>,
secret_key_path: impl AsRef<Path>,
) -> Result<Signature> {
) -> Result<PathBuf> {
let file_data = read(&file_path).await?;
let secret_key = key_pair::secret_key_from_file(secret_key_path).await?;
let secret_key = SignedSecretKey::try_from_file(secret_key_path.as_ref()).await?;
let signature = sign(&file_data, &secret_key)?;
let mut signature_path = file_path.as_ref().to_owned();
signature_path.as_mut_os_string().push(".sig");
Expand All @@ -59,22 +59,20 @@ pub async fn sign_file_with_key(
.into_std()
.await;
packet::write_packet(&mut signature_file, &signature)?;
Ok(signature)
Ok(signature_path)
}

#[cfg(test)]
mod tests {

use pgp::{
errors::Error as PgpError,
packet::{self, Packet, PacketParser},
};
use pgp::{Signature, SignedPublicKey};
use temp_dir::TempDir;
use tokio::fs::{self, read};
use tokio::fs::write;

use super::{sign, verify};
use super::{sign, sign_file_with_key, verify};
use crate::{
key_pair::{self, public_key_from_file, KeyPair},
from_file::FromFile,
key_pair::KeyPair,
keygen::{write_key_pair, KeyPairPath},
Result,
};
Expand Down Expand Up @@ -119,30 +117,13 @@ mod tests {
let data = b"Hello, world!";

let data_path = tmp_dir.path().join("data");
fs::write(&data_path, data).await?;

let sig_data: Vec<u8> = {
let file_data = read(&data_path).await?;
let secret_key = key_pair::secret_key_from_file(secret_key_path).await?;
let signature = sign(&file_data, &secret_key)?;
let mut buffer = Vec::new();
packet::write_packet(&mut buffer, &signature)?;
buffer
};

let public_key = public_key_from_file(&public_key_path).await?;

dbg!(tmp_dir.path());

dbg!(&sig_data);
let packet = PacketParser::new(sig_data.as_slice())
.next()
.ok_or(PgpError::MissingPackets)??;
let signature = if let Packet::Signature(s) = packet {
Ok(s)
} else {
Err(PgpError::InvalidInput)
}?;
write(&data_path, data).await?;

let public_key = SignedPublicKey::try_from_file(&public_key_path).await?;

let sig_path = sign_file_with_key(&data_path, secret_key_path).await?;

let signature = Signature::try_from_file(sig_path).await?;

dbg!(&signature);

Expand Down
29 changes: 17 additions & 12 deletions src-tauri/src/error.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,26 @@
use std::{
fmt::{self, Display, Formatter},
fmt::{self, Debug, Display, Formatter},
io,
};

use serde::Serialize;

#[derive(Debug)]
pub struct Error(anyhow::Error);

impl Debug for Error {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "{:?}", self.0)
}
}

impl Display for Error {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.0)
}
}

impl std::error::Error for Error {}

pub type Result<T> = std::result::Result<T, Error>;

impl From<anyhow::Error> for Error {
Expand All @@ -16,8 +29,8 @@ impl From<anyhow::Error> for Error {
}
}

impl From<digital_signature_crypto::error::Error> for Error {
fn from(value: digital_signature_crypto::error::Error) -> Self {
impl From<digital_signature_crypto::Error> for Error {
fn from(value: digital_signature_crypto::Error) -> Self {
Self(anyhow::Error::from(value))
}
}
Expand All @@ -28,14 +41,6 @@ impl From<io::Error> for Error {
}
}

impl Display for Error {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.0)
}
}

impl std::error::Error for Error {}

impl Serialize for Error {
fn serialize<S>(&self, serializer: S) -> std::prelude::v1::Result<S::Ok, S::Error>
where
Expand Down

0 comments on commit 5f271c4

Please sign in to comment.