Warn on `unwrap`, remove last remaining instances

Signed-off-by: Alexis Sellier <alexis@radicle.xyz>
This commit is contained in:
Alexis Sellier 2022-10-11 09:22:29 +02:00
parent 5ccf9a388a
commit a104f9681c
No known key found for this signature in database
11 changed files with 57 additions and 34 deletions

View File

@ -45,8 +45,7 @@ pub enum ListRefsError {
impl From<&RemoteId> for RefString { impl From<&RemoteId> for RefString {
fn from(id: &RemoteId) -> Self { fn from(id: &RemoteId) -> Self {
// PublicKey strings contain only legal characters. RefString::try_from(id.to_string()).expect("encoded public keys are valid ref strings")
RefString::try_from(id.to_string()).unwrap()
} }
} }
@ -137,7 +136,7 @@ pub fn initial_commit<'a>(
let tree_id = repo.index()?.write_tree()?; let tree_id = repo.index()?.write_tree()?;
let tree = repo.find_tree(tree_id)?; let tree = repo.find_tree(tree_id)?;
let oid = repo.commit(None, sig, sig, "Initial commit", &tree, &[])?; let oid = repo.commit(None, sig, sig, "Initial commit", &tree, &[])?;
let commit = repo.find_commit(oid).unwrap(); let commit = repo.find_commit(oid)?;
Ok(commit) Ok(commit)
} }
@ -154,20 +153,23 @@ pub fn commit<'a>(
let tree_id = repo.index()?.write_tree()?; let tree_id = repo.index()?.write_tree()?;
let tree = repo.find_tree(tree_id)?; let tree = repo.find_tree(tree_id)?;
let oid = repo.commit(Some(target.as_str()), &sig, &sig, message, &tree, &[parent])?; let oid = repo.commit(Some(target.as_str()), &sig, &sig, message, &tree, &[parent])?;
let commit = repo.find_commit(oid).unwrap(); let commit = repo.find_commit(oid)?;
Ok(commit) Ok(commit)
} }
/// Push the refs to the radicle remote. /// Push the refs to the radicle remote.
pub fn push(repo: &git2::Repository) -> Result<(), git2::Error> { pub fn push(repo: &git2::Repository) -> Result<(), git2::Error> {
// NOTE: This function is going away soon.
#![allow(clippy::unwrap_used)]
let mut remote = repo.find_remote("rad")?; let mut remote = repo.find_remote("rad")?;
let refspecs = remote.push_refspecs().unwrap(); let refspecs = remote.push_refspecs()?;
let refspec = refspecs.into_iter().next().unwrap().unwrap(); let refspec = refspecs.into_iter().next().unwrap().unwrap();
// The `git2` crate doesn't seem to support push refspecs with '*' in them, // The `git2` crate doesn't seem to support push refspecs with '*' in them,
// so we manually replace it with the current branch. // so we manually replace it with the current branch.
let head = repo.head().unwrap(); let head = repo.head()?;
let branch = head.shorthand().unwrap(); let branch = head.shorthand().unwrap();
let refspec = refspec.replace('*', branch); let refspec = refspec.replace('*', branch);

View File

@ -270,8 +270,8 @@ impl Doc<Unverified> {
} }
} }
pub fn from_json(bytes: &[u8]) -> Result<Self, serde_json::Error> { pub fn from_json(bytes: &[u8]) -> Result<Self, DocError> {
serde_json::from_slice(bytes) serde_json::from_slice(bytes).map_err(DocError::from)
} }
pub fn verified(self) -> Result<Doc<Verified>, VerificationError> { pub fn verified(self) -> Result<Doc<Verified>, VerificationError> {
@ -375,10 +375,16 @@ pub enum IdentityError {
MismatchedRoot(Oid), MismatchedRoot(Oid),
#[error("commit signature for {0} is invalid: {1}")] #[error("commit signature for {0} is invalid: {1}")]
InvalidSignature(PublicKey, crypto::Error), InvalidSignature(PublicKey, crypto::Error),
#[error("commit message for {0} is invalid")]
InvalidCommitMessage(Oid),
#[error("commit trailers for {0} are invalid: {1}")]
InvalidCommitTrailers(Oid, trailers::Error),
#[error("quorum not reached: {0} signatures for a threshold of {1}")] #[error("quorum not reached: {0} signatures for a threshold of {1}")]
QuorumNotReached(usize, usize), QuorumNotReached(usize, usize),
#[error("identity document error: {0}")] #[error("identity document error: {0}")]
Doc(#[from] DocError), Doc(#[from] DocError),
#[error("the document root is missing")]
MissingRoot,
} }
#[derive(Clone, Debug, PartialEq, Eq)] #[derive(Clone, Debug, PartialEq, Eq)]
@ -426,10 +432,10 @@ impl Identity<Untrusted> {
let mut history = repo.revwalk(head)?.collect::<Vec<_>>(); let mut history = repo.revwalk(head)?.collect::<Vec<_>>();
// Retrieve root document. // Retrieve root document.
let root_oid = history.pop().unwrap()?.into(); let root_oid = history.pop().ok_or(IdentityError::MissingRoot)??.into();
let root_blob = Doc::blob_at(root_oid, repo)?; let root_blob = Doc::blob_at(root_oid, repo)?;
let root: git::Oid = root_blob.id().into(); let root: git::Oid = root_blob.id().into();
let trusted = Doc::from_json(root_blob.content()).unwrap(); let trusted = Doc::from_json(root_blob.content())?;
let revision = history.len() as u32; let revision = history.len() as u32;
let mut trusted = trusted.verified()?; let mut trusted = trusted.verified()?;
@ -442,11 +448,14 @@ impl Identity<Untrusted> {
let blob = Doc::blob_at(oid.into(), repo)?; let blob = Doc::blob_at(oid.into(), repo)?;
let untrusted = Doc::from_json(blob.content()).map_err(DocError::from)?; let untrusted = Doc::from_json(blob.content()).map_err(DocError::from)?;
let untrusted = untrusted.verified()?; let untrusted = untrusted.verified()?;
let commit = repo.commit(oid.into())?.unwrap(); let commit = repo.commit(oid.into())?;
let msg = commit.message_raw().unwrap(); let msg = commit
.message_raw()
.ok_or_else(|| IdentityError::InvalidCommitMessage(oid.into()))?;
// Keys that signed the *current* document version. // Keys that signed the *current* document version.
signatures = trailers::parse_signatures(msg).unwrap(); signatures = trailers::parse_signatures(msg)
.map_err(|e| IdentityError::InvalidCommitTrailers(oid.into(), e))?;
for (pk, sig) in &signatures { for (pk, sig) in &signatures {
if let Err(err) = pk.verify(blob.content(), sig) { if let Err(err) = pk.verify(blob.content(), sig) {
return Err(IdentityError::InvalidSignature(*pk, err)); return Err(IdentityError::InvalidSignature(*pk, err));

View File

@ -5,8 +5,21 @@ use std::os::unix::fs::DirBuilderExt;
use std::os::unix::prelude::OpenOptionsExt; use std::os::unix::prelude::OpenOptionsExt;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use thiserror::Error;
use crate::crypto;
use crate::crypto::{PublicKey, SecretKey}; use crate::crypto::{PublicKey, SecretKey};
#[derive(Debug, Error)]
pub enum Error {
#[error(transparent)]
Io(#[from] io::Error),
#[error("invalid key file format: {0}")]
FromUtf8Error(#[from] std::string::FromUtf8Error),
#[error("invalid key format: {0}")]
Crypto(#[from] crypto::Error),
}
pub struct UnsafeKeystore { pub struct UnsafeKeystore {
path: PathBuf, path: PathBuf,
} }
@ -18,7 +31,7 @@ impl UnsafeKeystore {
} }
} }
pub fn put(&mut self, public: &PublicKey, secret: &SecretKey) -> Result<(), io::Error> { pub fn put(&mut self, public: &PublicKey, secret: &SecretKey) -> Result<(), Error> {
// TODO: Zeroize secret key. // TODO: Zeroize secret key.
let public = public.to_pem(); let public = public.to_pem();
let secret = secret.to_pem(); let secret = secret.to_pem();
@ -45,14 +58,14 @@ impl UnsafeKeystore {
Ok(()) Ok(())
} }
pub fn get(&self) -> Result<(PublicKey, SecretKey), io::Error> { pub fn get(&self) -> Result<(PublicKey, SecretKey), Error> {
let public = fs::read(self.path.join("radicle.pub"))?; let public = fs::read(self.path.join("radicle.pub"))?;
let public = String::from_utf8(public).unwrap(); let public = String::from_utf8(public)?;
let public = PublicKey::from_pem(&public).unwrap(); let public = PublicKey::from_pem(&public)?;
let secret = fs::read(self.path.join("radicle"))?; let secret = fs::read(self.path.join("radicle"))?;
let secret = String::from_utf8(secret).unwrap(); let secret = String::from_utf8(secret)?;
let secret = SecretKey::from_pem(&secret).unwrap(); let secret = SecretKey::from_pem(&secret)?;
Ok((public, secret)) Ok((public, secret))
} }

View File

@ -1,4 +1,5 @@
#![allow(clippy::match_like_matches_macro)] #![allow(clippy::match_like_matches_macro)]
#![cfg_attr(not(test), warn(clippy::unwrap_used))]
pub mod collections; pub mod collections;
pub mod crypto; pub mod crypto;
pub mod git; pub mod git;

View File

@ -14,7 +14,7 @@ use std::path::PathBuf;
use std::{env, io}; use std::{env, io};
use crate::crypto::{KeyPair, PublicKey, SecretKey, Signature, Signer}; use crate::crypto::{KeyPair, PublicKey, SecretKey, Signature, Signer};
use crate::keystore::UnsafeKeystore; use crate::keystore::{Error, UnsafeKeystore};
use crate::node; use crate::node;
use crate::storage::git::Storage; use crate::storage::git::Storage;
@ -42,7 +42,7 @@ pub struct Profile {
} }
impl Profile { impl Profile {
pub fn init(keypair: KeyPair) -> Result<Self, io::Error> { pub fn init(keypair: KeyPair) -> Result<Self, Error> {
let home = self::home()?; let home = self::home()?;
let mut keystore = UnsafeKeystore::new(&home.join("keys")); let mut keystore = UnsafeKeystore::new(&home.join("keys"));
let public = keypair.pk.into(); let public = keypair.pk.into();
@ -61,7 +61,7 @@ impl Profile {
}) })
} }
pub fn load() -> Result<Self, io::Error> { pub fn load() -> Result<Self, Error> {
let home = self::home()?; let home = self::home()?;
let (public, secret) = UnsafeKeystore::new(&home.join("keys")).get()?; let (public, secret) = UnsafeKeystore::new(&home.join("keys")).get()?;
let signer = UnsafeSigner { public, secret }; let signer = UnsafeSigner { public, secret };

View File

@ -144,7 +144,7 @@ impl radicle_ssh::key::Private for SecretKey {
let public = r.read_string()?; let public = r.read_string()?;
let pair = r.read_string()?; let pair = r.read_string()?;
let _comment = r.read_string()?; let _comment = r.read_string()?;
let key = crypto::SecretKey::from_slice(pair).unwrap(); let key = crypto::SecretKey::from_slice(pair)?;
if public != key.public_key().as_ref() { if public != key.public_key().as_ref() {
return Err(SecretKeyError::Mismatch); return Err(SecretKeyError::Mismatch);

View File

@ -247,7 +247,7 @@ pub trait ReadRepository {
remote: &RemoteId, remote: &RemoteId,
reference: &RefStr, reference: &RefStr,
) -> Result<git2::Reference, git_ext::Error>; ) -> Result<git2::Reference, git_ext::Error>;
fn commit(&self, oid: Oid) -> Result<Option<git2::Commit>, git2::Error>; fn commit(&self, oid: Oid) -> Result<git2::Commit, git_ext::Error>;
fn revwalk(&self, head: Oid) -> Result<git2::Revwalk, git2::Error>; fn revwalk(&self, head: Oid) -> Result<git2::Revwalk, git2::Error>;
fn reference_oid(&self, remote: &RemoteId, reference: &RefStr) -> Result<Oid, git_ext::Error>; fn reference_oid(&self, remote: &RemoteId, reference: &RefStr) -> Result<Oid, git_ext::Error>;
fn references(&self, remote: &RemoteId) -> Result<Refs, Error>; fn references(&self, remote: &RemoteId) -> Result<Refs, Error>;

View File

@ -28,7 +28,6 @@ pub static REMOTES_GLOB: Lazy<refspec::PatternString> =
pub static SIGNATURES_GLOB: Lazy<refspec::PatternString> = pub static SIGNATURES_GLOB: Lazy<refspec::PatternString> =
Lazy::new(|| refspec::pattern!("refs/remotes/*/radicle/signature")); Lazy::new(|| refspec::pattern!("refs/remotes/*/radicle/signature"));
// FIXME: Should this be here?
#[derive(Error, Debug)] #[derive(Error, Debug)]
pub enum ProjectError { pub enum ProjectError {
#[error("identity branches diverge from each other")] #[error("identity branches diverge from each other")]
@ -424,14 +423,10 @@ impl ReadRepository for Repository {
self.backend.find_reference(&name).map_err(git::Error::from) self.backend.find_reference(&name).map_err(git::Error::from)
} }
fn commit(&self, oid: Oid) -> Result<Option<git2::Commit>, git2::Error> { fn commit(&self, oid: Oid) -> Result<git2::Commit, git::Error> {
self.backend.find_commit(oid.into()).map(Some).or_else(|e| { self.backend
if git::ext::is_not_found_err(&e) { .find_commit(oid.into())
Ok(None) .map_err(git::Error::from)
} else {
Err(e)
}
})
} }
fn revwalk(&self, head: Oid) -> Result<git2::Revwalk, git2::Error> { fn revwalk(&self, head: Oid) -> Result<git2::Revwalk, git2::Error> {

View File

@ -52,10 +52,12 @@ impl Smart {
/// Take a stream from the map. /// Take a stream from the map.
/// This makes the stream unavailable until it is re-inserted. /// This makes the stream unavailable until it is re-inserted.
pub fn take(&self, id: &Id) -> Option<Stream> { pub fn take(&self, id: &Id) -> Option<Stream> {
#[allow(clippy::unwrap_used)]
self.streams.lock().unwrap().remove(id) self.streams.lock().unwrap().remove(id)
} }
pub fn insert(&self, id: Id, stream: Stream) { pub fn insert(&self, id: Id, stream: Stream) {
#[allow(clippy::unwrap_used)]
self.streams.lock().unwrap().insert(id, stream); self.streams.lock().unwrap().insert(id, stream);
} }
} }

View File

@ -1,3 +1,4 @@
#![allow(clippy::unwrap_used)]
pub mod arbitrary; pub mod arbitrary;
pub mod assert; pub mod assert;
pub mod fixtures; pub mod fixtures;

View File

@ -97,7 +97,7 @@ impl ReadRepository for MockRepository {
todo!() todo!()
} }
fn commit(&self, _oid: Oid) -> Result<Option<git2::Commit>, git2::Error> { fn commit(&self, _oid: Oid) -> Result<git2::Commit, git_ext::Error> {
todo!() todo!()
} }