keyfork-bug: initial commit, refactor use of unwrap() and expect() to use keyfork-bug
This commit is contained in:
parent
354eae5a6a
commit
472d0288f9
|
@ -1700,6 +1700,10 @@ dependencies = [
|
|||
"anyhow",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "keyfork-bug"
|
||||
version = "0.1.0"
|
||||
|
||||
[[package]]
|
||||
name = "keyfork-crossterm"
|
||||
version = "0.27.1"
|
||||
|
@ -1761,6 +1765,7 @@ dependencies = [
|
|||
"hex-literal",
|
||||
"hmac",
|
||||
"k256",
|
||||
"keyfork-bug",
|
||||
"keyfork-mnemonic-util",
|
||||
"keyfork-slip10-test-data",
|
||||
"ripemd",
|
||||
|
@ -1773,6 +1778,7 @@ dependencies = [
|
|||
name = "keyfork-entropy"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"keyfork-bug",
|
||||
"smex",
|
||||
]
|
||||
|
||||
|
@ -1793,6 +1799,7 @@ dependencies = [
|
|||
"bip39",
|
||||
"hex",
|
||||
"hmac",
|
||||
"keyfork-bug",
|
||||
"pbkdf2",
|
||||
"serde_json",
|
||||
"sha2",
|
||||
|
@ -1803,6 +1810,7 @@ dependencies = [
|
|||
name = "keyfork-prompt"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"keyfork-bug",
|
||||
"keyfork-crossterm",
|
||||
"keyfork-mnemonic-util",
|
||||
"thiserror",
|
||||
|
@ -1813,6 +1821,7 @@ name = "keyfork-qrcode"
|
|||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"image",
|
||||
"keyfork-bug",
|
||||
"keyfork-zbar",
|
||||
"rqrr",
|
||||
"thiserror",
|
||||
|
@ -1828,6 +1837,7 @@ dependencies = [
|
|||
"card-backend",
|
||||
"card-backend-pcsc",
|
||||
"hkdf",
|
||||
"keyfork-bug",
|
||||
"keyfork-derive-openpgp",
|
||||
"keyfork-mnemonic-util",
|
||||
"keyfork-prompt",
|
||||
|
@ -1873,6 +1883,7 @@ version = "0.1.0"
|
|||
dependencies = [
|
||||
"bincode",
|
||||
"hex-literal",
|
||||
"keyfork-bug",
|
||||
"keyfork-derive-path-data",
|
||||
"keyfork-derive-util",
|
||||
"keyfork-frame",
|
||||
|
|
|
@ -15,6 +15,7 @@ members = [
|
|||
"crates/qrcode/keyfork-zbar",
|
||||
"crates/qrcode/keyfork-zbar-sys",
|
||||
"crates/util/keyfork-bin",
|
||||
"crates/util/keyfork-bug",
|
||||
"crates/util/keyfork-crossterm",
|
||||
"crates/util/keyfork-entropy",
|
||||
"crates/util/keyfork-frame",
|
||||
|
|
|
@ -32,6 +32,7 @@ tower = { version = "0.4.13", features = ["tokio", "util"] }
|
|||
thiserror = "1.0.47"
|
||||
serde = { version = "1.0.186", features = ["derive"] }
|
||||
tempfile = { version = "3.10.0", default-features = false }
|
||||
keyfork-bug = { version = "0.1.0", path = "../../util/keyfork-bug" }
|
||||
|
||||
[dev-dependencies]
|
||||
hex-literal = "0.4.1"
|
||||
|
|
|
@ -7,6 +7,8 @@ use crate::{middleware, Keyforkd, ServiceBuilder, UnixServer};
|
|||
|
||||
use tokio::runtime::Builder;
|
||||
|
||||
use keyfork_bug::bug;
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
#[error("This error can never be instantiated")]
|
||||
#[doc(hidden)]
|
||||
|
@ -54,8 +56,10 @@ where
|
|||
.worker_threads(2)
|
||||
.enable_io()
|
||||
.build()
|
||||
.expect("tokio threaded IO runtime");
|
||||
let socket_dir = tempfile::tempdir().expect("can't create tempdir");
|
||||
.expect(bug!(
|
||||
"can't make tokio threaded IO runtime, should be enabled via feature flags"
|
||||
));
|
||||
let socket_dir = tempfile::tempdir().expect(bug!("can't create tempdir"));
|
||||
let socket_path = socket_dir.path().join("keyforkd.sock");
|
||||
rt.block_on(async move {
|
||||
let (tx, mut rx) = tokio::sync::mpsc::channel(1);
|
||||
|
@ -63,25 +67,28 @@ where
|
|||
let socket_path = socket_path.clone();
|
||||
let seed = seed.to_vec();
|
||||
async move {
|
||||
let mut server = UnixServer::bind(&socket_path).expect("can't bind unix socket");
|
||||
tx.send(()).await.expect("couldn't send server start signal");
|
||||
let mut server =
|
||||
UnixServer::bind(&socket_path).expect(bug!("can't bind unix socket"));
|
||||
tx.send(())
|
||||
.await
|
||||
.expect(bug!("couldn't send server start signal"));
|
||||
let service = ServiceBuilder::new()
|
||||
.layer(middleware::BincodeLayer::new())
|
||||
.service(Keyforkd::new(seed.to_vec()));
|
||||
server.run(service).await.unwrap();
|
||||
server.run(service).await.expect(bug!("Unable to start service"));
|
||||
}
|
||||
});
|
||||
|
||||
rx.recv()
|
||||
.await
|
||||
.expect("can't receive server start signal from channel");
|
||||
.expect(bug!("can't receive server start signal from channel"));
|
||||
let test_handle = tokio::task::spawn_blocking(move || closure(&socket_path));
|
||||
|
||||
let result = test_handle.await;
|
||||
server_handle.abort();
|
||||
result
|
||||
})
|
||||
.expect("runtime could not join all threads")
|
||||
.expect(bug!("runtime could not join all threads"))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
|
|
@ -29,6 +29,7 @@ thiserror = "1.0.47"
|
|||
# Optional, not personally audited
|
||||
k256 = { version = "0.13.1", default-features = false, features = ["std", "arithmetic"], optional = true }
|
||||
ed25519-dalek = { version = "2.0.0", optional = true }
|
||||
keyfork-bug = { version = "0.1.0", path = "../../util/keyfork-bug" }
|
||||
|
||||
[dev-dependencies]
|
||||
hex-literal = "0.4.1"
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
use crate::{DerivationIndex, DerivationPath, ExtendedPublicKey, PrivateKey, PublicKey};
|
||||
|
||||
use keyfork_bug::bug;
|
||||
|
||||
use hmac::{Hmac, Mac};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use sha2::Sha512;
|
||||
|
@ -124,7 +126,7 @@ mod serde_with {
|
|||
let variable_len_bytes = <&[u8]>::deserialize(deserializer)?;
|
||||
let bytes: [u8; 32] = variable_len_bytes
|
||||
.try_into()
|
||||
.expect("unable to parse serialized private key; no support for static len");
|
||||
.expect(bug!("unable to parse serialized private key; no support for static len"));
|
||||
Ok(K::from_bytes(&bytes))
|
||||
}
|
||||
}
|
||||
|
@ -171,7 +173,7 @@ where
|
|||
|
||||
fn new_internal(seed: &[u8]) -> Self {
|
||||
let hash = HmacSha512::new_from_slice(&K::key().bytes().collect::<Vec<_>>())
|
||||
.expect("HmacSha512 InvalidLength should be infallible")
|
||||
.expect(bug!("HmacSha512 InvalidLength should be infallible"))
|
||||
.chain_update(seed)
|
||||
.finalize()
|
||||
.into_bytes();
|
||||
|
@ -180,10 +182,10 @@ where
|
|||
Self::new_from_parts(
|
||||
private_key
|
||||
.try_into()
|
||||
.expect("KEY_SIZE / 8 did not give a 32 byte slice"),
|
||||
.expect(bug!("KEY_SIZE / 8 did not give a 32 byte slice")),
|
||||
0,
|
||||
// Checked: chain_code is always the same length, hash is static size
|
||||
chain_code.try_into().expect("Invalid chain code length"),
|
||||
chain_code.try_into().expect(bug!("Invalid chain code length")),
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -405,7 +407,7 @@ where
|
|||
let depth = self.depth.checked_add(1).ok_or(Error::Depth)?;
|
||||
|
||||
let mut hmac = HmacSha512::new_from_slice(&self.chain_code)
|
||||
.expect("HmacSha512 InvalidLength should be infallible");
|
||||
.expect(bug!("HmacSha512 InvalidLength should be infallible"));
|
||||
if index.is_hardened() {
|
||||
hmac.update(&[0]);
|
||||
hmac.update(&self.private_key.to_bytes());
|
||||
|
@ -423,7 +425,7 @@ where
|
|||
.derive_child(
|
||||
&private_key
|
||||
.try_into()
|
||||
.expect("Invalid length for private key"),
|
||||
.expect(bug!("Invalid length for private key")),
|
||||
)
|
||||
.map_err(|_| Error::Derivation)?;
|
||||
|
||||
|
@ -432,7 +434,7 @@ where
|
|||
depth,
|
||||
chain_code: chain_code
|
||||
.try_into()
|
||||
.expect("Invalid length for chain code"),
|
||||
.expect(bug!("Invalid length for chain code")),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,6 +4,8 @@ use hmac::{Hmac, Mac};
|
|||
use sha2::Sha512;
|
||||
use thiserror::Error;
|
||||
|
||||
use keyfork_bug::bug;
|
||||
|
||||
const KEY_SIZE: usize = 256;
|
||||
|
||||
/// Errors associated with creating or deriving Extended Public Keys.
|
||||
|
@ -142,9 +144,11 @@ where
|
|||
let (child_key, chain_code) = hmac.split_at(KEY_SIZE / 8);
|
||||
let derived_key = self
|
||||
.public_key
|
||||
.derive_child(child_key.try_into().expect("Invalid key length"))
|
||||
.derive_child(child_key.try_into().expect(bug!("Invalid key length")))
|
||||
.map_err(|_| Error::Derivation)?;
|
||||
let chain_code = chain_code.try_into().expect("Invalid chain code length");
|
||||
let chain_code = chain_code
|
||||
.try_into()
|
||||
.expect(bug!("Invalid chain code length"));
|
||||
|
||||
Ok(Self {
|
||||
public_key: derived_key,
|
||||
|
|
|
@ -2,6 +2,8 @@ use crate::PublicKey;
|
|||
|
||||
use thiserror::Error;
|
||||
|
||||
use keyfork_bug::bug;
|
||||
|
||||
pub(crate) type PrivateKeyBytes = [u8; 32];
|
||||
|
||||
/// Functions required to use an `ExtendedPrivateKey`.
|
||||
|
@ -115,7 +117,7 @@ impl PrivateKey for k256::SecretKey {
|
|||
}
|
||||
|
||||
fn from_bytes(b: &PrivateKeyBytes) -> Self {
|
||||
Self::from_slice(b).expect("Invalid private key bytes")
|
||||
Self::from_slice(b).expect(bug!("Invalid private key bytes"))
|
||||
}
|
||||
|
||||
fn to_bytes(&self) -> PrivateKeyBytes {
|
||||
|
@ -134,13 +136,13 @@ impl PrivateKey for k256::SecretKey {
|
|||
let other = *other;
|
||||
// Checked: See above nonzero check
|
||||
let scalar = Option::<NonZeroScalar>::from(NonZeroScalar::from_repr(other.into()))
|
||||
.expect("Should have been able to get a NonZeroScalar");
|
||||
.expect(bug!("Should have been able to get a NonZeroScalar"));
|
||||
|
||||
let derived_scalar = self.to_nonzero_scalar().as_ref() + scalar.as_ref();
|
||||
Ok(
|
||||
Option::<NonZeroScalar>::from(NonZeroScalar::new(derived_scalar))
|
||||
.map(Into::into)
|
||||
.expect("Should be able to make Key"),
|
||||
.expect(bug!("Should be able to make Key")),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,6 +5,8 @@ use ripemd::Ripemd160;
|
|||
use sha2::Sha256;
|
||||
use thiserror::Error;
|
||||
|
||||
use keyfork_bug::bug;
|
||||
|
||||
pub(crate) type PublicKeyBytes = [u8; 33];
|
||||
|
||||
/// Functions required to use an `ExtendedPublicKey`.
|
||||
|
@ -63,7 +65,7 @@ pub trait PublicKey: Sized {
|
|||
// Note: Safety assured by type returned from Ripemd160
|
||||
hash[..4]
|
||||
.try_into()
|
||||
.expect("Ripemd160 returned too little data")
|
||||
.expect(bug!("Ripemd160 returned too little data"))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -108,10 +110,11 @@ impl PublicKey for k256::PublicKey {
|
|||
}
|
||||
// Checked: See above
|
||||
let scalar = Option::<NonZeroScalar>::from(NonZeroScalar::from_repr(other.into()))
|
||||
.expect("Should have been able to get a NonZeroScalar");
|
||||
.expect(bug!("Should have been able to get a NonZeroScalar"));
|
||||
|
||||
let point = self.to_projective() + (AffinePoint::generator() * *scalar);
|
||||
Ok(Self::from_affine(point.into()).expect("Could not from_affine after scalar arithmetic"))
|
||||
Ok(Self::from_affine(point.into())
|
||||
.expect(bug!("Could not from_affine after scalar arithmetic")))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -150,10 +153,11 @@ impl TestPublicKey {
|
|||
#[allow(dead_code)]
|
||||
pub fn from_bytes(b: &[u8]) -> Self {
|
||||
Self {
|
||||
key: b.try_into().unwrap(),
|
||||
key: b
|
||||
.try_into()
|
||||
.expect(bug!("invalid size when constructing TestPublicKey")),
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
impl PublicKey for TestPublicKey {
|
||||
|
|
|
@ -36,3 +36,4 @@ card-backend-pcsc = { version = "0.5.0", optional = true }
|
|||
openpgp-card-sequoia = { version = "0.2.0", optional = true, default-features = false }
|
||||
openpgp-card = { version = "0.4.0", optional = true }
|
||||
sequoia-openpgp = { version = "1.17.0", optional = true, default-features = false }
|
||||
keyfork-bug = { version = "0.1.0", path = "../util/keyfork-bug" }
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#![doc = include_str!("../README.md")]
|
||||
#![allow(clippy::expect_fun_call)]
|
||||
|
||||
use std::{
|
||||
io::{stdin, stdout, Read, Write},
|
||||
|
@ -10,6 +11,7 @@ use aes_gcm::{
|
|||
Aes256Gcm, KeyInit, Nonce,
|
||||
};
|
||||
use hkdf::Hkdf;
|
||||
use keyfork_bug::{bug, POISONED_MUTEX};
|
||||
use keyfork_mnemonic_util::{English, Mnemonic};
|
||||
use keyfork_prompt::{
|
||||
validators::{mnemonic::MnemonicSetValidator, Validator},
|
||||
|
@ -200,7 +202,7 @@ pub trait Format {
|
|||
{
|
||||
prompt
|
||||
.lock()
|
||||
.unwrap()
|
||||
.expect(bug!(POISONED_MUTEX))
|
||||
.prompt_message(PromptMessage::Text(QRCODE_PROMPT.to_string()))?;
|
||||
if let Ok(Some(hex)) =
|
||||
keyfork_qrcode::scan_camera(std::time::Duration::from_secs(30), 0)
|
||||
|
@ -211,7 +213,7 @@ pub trait Format {
|
|||
} else {
|
||||
prompt
|
||||
.lock()
|
||||
.unwrap()
|
||||
.expect(bug!(POISONED_MUTEX))
|
||||
.prompt_message(PromptMessage::Text(QRCODE_ERROR.to_string()))?;
|
||||
};
|
||||
}
|
||||
|
@ -225,7 +227,7 @@ pub trait Format {
|
|||
};
|
||||
let [nonce_mnemonic, pubkey_mnemonic] = prompt
|
||||
.lock()
|
||||
.unwrap()
|
||||
.expect(bug!(POISONED_MUTEX))
|
||||
.prompt_validated_wordlist::<English, _>(
|
||||
QRCODE_COULDNT_READ,
|
||||
3,
|
||||
|
@ -305,7 +307,10 @@ pub trait Format {
|
|||
let mut qrcode_data = our_pubkey_mnemonic.to_bytes();
|
||||
qrcode_data.extend(payload_mnemonic.as_bytes());
|
||||
if let Ok(qrcode) = qrencode(&smex::encode(&qrcode_data), ErrorCorrection::Highest) {
|
||||
prompt.lock().unwrap().prompt_message(PromptMessage::Text(
|
||||
prompt
|
||||
.lock()
|
||||
.expect(bug!(POISONED_MUTEX))
|
||||
.prompt_message(PromptMessage::Text(
|
||||
concat!(
|
||||
"A QR code will be displayed after this prompt. ",
|
||||
"Send the QR code back to the operator combining the shards. ",
|
||||
|
@ -315,14 +320,14 @@ pub trait Format {
|
|||
))?;
|
||||
prompt
|
||||
.lock()
|
||||
.unwrap()
|
||||
.expect(bug!(POISONED_MUTEX))
|
||||
.prompt_message(PromptMessage::Data(qrcode))?;
|
||||
}
|
||||
}
|
||||
|
||||
prompt
|
||||
.lock()
|
||||
.unwrap()
|
||||
.expect(bug!(POISONED_MUTEX))
|
||||
.prompt_message(PromptMessage::Text(format!(
|
||||
"Upon request, these words should be sent: {our_pubkey_mnemonic} {payload_mnemonic}"
|
||||
)))?;
|
||||
|
|
|
@ -1,14 +1,17 @@
|
|||
//! OpenPGP Shard functionality.
|
||||
|
||||
#![allow(clippy::expect_fun_call)]
|
||||
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
io::{Read, Write},
|
||||
marker::PhantomData,
|
||||
path::Path,
|
||||
str::FromStr,
|
||||
sync::{Arc, Mutex},
|
||||
marker::PhantomData,
|
||||
};
|
||||
|
||||
use keyfork_bug::bug;
|
||||
use keyfork_derive_openpgp::{
|
||||
derive_util::{DerivationPath, VariableLengthSeed},
|
||||
XPrv,
|
||||
|
@ -186,9 +189,7 @@ pub struct OpenPGP<P: PromptHandler> {
|
|||
impl<P: PromptHandler> OpenPGP<P> {
|
||||
#[allow(clippy::new_without_default, missing_docs)]
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
p: PhantomData,
|
||||
}
|
||||
Self { p: PhantomData }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -223,6 +224,8 @@ impl<P: PromptHandler> OpenPGP<P> {
|
|||
}
|
||||
}
|
||||
|
||||
const METADATA_MESSAGE_MISSING: &str = "Metadata message was not found in parsed packets";
|
||||
|
||||
impl<P: PromptHandler> Format for OpenPGP<P> {
|
||||
type Error = Error;
|
||||
type PublicKey = Cert;
|
||||
|
@ -235,16 +238,16 @@ impl<P: PromptHandler> Format for OpenPGP<P> {
|
|||
let seed = VariableLengthSeed::new(seed);
|
||||
// build cert to sign encrypted shares
|
||||
let userid = UserID::from("keyfork-sss");
|
||||
let path = DerivationPath::from_str("m/7366512'/0'").expect("valid derivation path");
|
||||
let path = DerivationPath::from_str("m/7366512'/0'").expect(bug!("valid derivation path"));
|
||||
let xprv = XPrv::new(seed)
|
||||
.derive_path(&path)
|
||||
.expect("valid derivation");
|
||||
.expect(bug!("valid derivation"));
|
||||
keyfork_derive_openpgp::derive(
|
||||
xprv,
|
||||
&[KeyFlags::empty().set_certification().set_signing()],
|
||||
&userid,
|
||||
)
|
||||
.expect("valid cert creation")
|
||||
.expect(bug!("valid cert creation"))
|
||||
}
|
||||
|
||||
fn format_encrypted_header(
|
||||
|
@ -258,21 +261,26 @@ impl<P: PromptHandler> Format for OpenPGP<P> {
|
|||
// Note: Sequoia does not export private keys on a Cert, only on a TSK
|
||||
signing_key
|
||||
.serialize(&mut pp)
|
||||
.expect("serialize cert into bytes");
|
||||
.expect(bug!("serialize cert into bytes"));
|
||||
for cert in key_data {
|
||||
cert.serialize(&mut pp)
|
||||
.expect("serialize pubkey into bytes");
|
||||
.expect(bug!("serialize pubkey into bytes"));
|
||||
}
|
||||
|
||||
// verify packet pile
|
||||
let mut iter = openpgp::cert::CertParser::from_bytes(&pp[SHARD_METADATA_OFFSET..])
|
||||
.expect("should have certs");
|
||||
let first_cert = iter.next().transpose().ok().flatten().expect("first cert");
|
||||
.expect(bug!("should have certs"));
|
||||
let first_cert = iter
|
||||
.next()
|
||||
.transpose()
|
||||
.ok()
|
||||
.flatten()
|
||||
.expect(bug!("first cert"));
|
||||
assert_eq!(signing_key, &first_cert);
|
||||
|
||||
for (packet_cert, cert) in iter.zip(key_data) {
|
||||
assert_eq!(
|
||||
&packet_cert.expect("parsed packet cert"),
|
||||
&packet_cert.expect(bug!("parsed packet cert")),
|
||||
cert,
|
||||
"packet pile could not recreate cert: {}",
|
||||
cert.fingerprint(),
|
||||
|
@ -385,7 +393,7 @@ impl<P: PromptHandler> Format for OpenPGP<P> {
|
|||
.map_err(Error::Sequoia)?
|
||||
.into_iter()
|
||||
.next()
|
||||
.expect("serialized message should be parseable");
|
||||
.expect(bug!("serialized message should be parseable"));
|
||||
|
||||
Ok(message)
|
||||
}
|
||||
|
@ -425,7 +433,9 @@ impl<P: PromptHandler> Format for OpenPGP<P> {
|
|||
|
||||
let mut encrypted_messages = encrypted_data.iter();
|
||||
|
||||
let metadata = encrypted_messages.next().expect("metdata");
|
||||
let metadata = encrypted_messages
|
||||
.next()
|
||||
.expect(bug!(METADATA_MESSAGE_MISSING));
|
||||
let metadata_content = decrypt_metadata(metadata, &policy, &mut keyring, &mut manager)?;
|
||||
|
||||
let (threshold, root_cert, certs) = decode_metadata_v1(&metadata_content)?;
|
||||
|
@ -482,7 +492,9 @@ impl<P: PromptHandler> Format for OpenPGP<P> {
|
|||
|
||||
let mut encrypted_messages = encrypted_data.iter();
|
||||
|
||||
let metadata = encrypted_messages.next().expect("metadata");
|
||||
let metadata = encrypted_messages
|
||||
.next()
|
||||
.expect(bug!(METADATA_MESSAGE_MISSING));
|
||||
let metadata_content = decrypt_metadata(metadata, &policy, &mut keyring, &mut manager)?;
|
||||
|
||||
let (threshold, root_cert, certs) = decode_metadata_v1(&metadata_content)?;
|
||||
|
@ -625,7 +637,12 @@ fn decrypt_with_manager<P: PromptHandler>(
|
|||
|
||||
// Iterate over all fingerprints and use key_by_fingerprints to assoc with Enc. Message
|
||||
if let Some(fp) = manager.load_any_fingerprint(unused_fingerprints)? {
|
||||
let cert_keyid = cert_by_fingerprint.get(&fp).unwrap().clone();
|
||||
let cert_keyid = cert_by_fingerprint
|
||||
.get(&fp)
|
||||
.expect(bug!(
|
||||
"manager loaded fingerprint not from unused_fingerprints"
|
||||
))
|
||||
.clone();
|
||||
if let Some(message) = messages.remove(&cert_keyid) {
|
||||
let message = message.decrypt_with(policy, &mut *manager)?;
|
||||
decrypted_messages.insert(cert_keyid, message);
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
#![allow(clippy::expect_fun_call)]
|
||||
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
use keyfork_bug::{bug, POISONED_MUTEX};
|
||||
use keyfork_prompt::{Error as PromptError, PromptHandler};
|
||||
|
||||
use super::openpgp::{
|
||||
|
@ -140,7 +143,7 @@ impl<P: PromptHandler> DecryptionHelper for &mut Keyring<P> {
|
|||
let passphrase = self
|
||||
.pm
|
||||
.lock()
|
||||
.unwrap()
|
||||
.expect(bug!(POISONED_MUTEX))
|
||||
.prompt_passphrase(&message)
|
||||
.context("Decryption passphrase")?;
|
||||
secret_key
|
||||
|
|
|
@ -1,8 +1,11 @@
|
|||
#![allow(clippy::expect_fun_call)]
|
||||
|
||||
use std::{
|
||||
collections::{HashMap, HashSet},
|
||||
sync::{Arc, Mutex},
|
||||
};
|
||||
|
||||
use keyfork_bug::{bug, POISONED_MUTEX};
|
||||
use keyfork_prompt::{
|
||||
validators::{PinValidator, Validator},
|
||||
Error as PromptError, Message, PromptHandler,
|
||||
|
@ -100,7 +103,7 @@ impl<P: PromptHandler> SmartcardManager<P> {
|
|||
}
|
||||
self.pm
|
||||
.lock()
|
||||
.unwrap()
|
||||
.expect(bug!(POISONED_MUTEX))
|
||||
.prompt_message(Message::Text(
|
||||
"No smart card was found. Please plug in a smart card and press enter"
|
||||
.to_string(),
|
||||
|
@ -160,7 +163,7 @@ impl<P: PromptHandler> SmartcardManager<P> {
|
|||
|
||||
self.pm
|
||||
.lock()
|
||||
.unwrap()
|
||||
.expect(bug!(POISONED_MUTEX))
|
||||
.prompt_message(Message::Text(
|
||||
"Please plug in a smart card and press enter".to_string(),
|
||||
))?;
|
||||
|
@ -261,10 +264,10 @@ impl<P: PromptHandler> DecryptionHelper for &mut SmartcardManager<P> {
|
|||
} else {
|
||||
format!("Unlock card {card_id} ({cardholder_name})\n{rpea}: {attempts}\n\nPIN: ")
|
||||
};
|
||||
let temp_pin = self
|
||||
.pm
|
||||
let temp_pin =
|
||||
self.pm
|
||||
.lock()
|
||||
.unwrap()
|
||||
.expect(bug!(POISONED_MUTEX))
|
||||
.prompt_validated_passphrase(&message, 3, &pin_validator)?;
|
||||
let verification_status = transaction.verify_user_pin(temp_pin.as_str().trim());
|
||||
match verification_status {
|
||||
|
@ -277,7 +280,7 @@ impl<P: PromptHandler> DecryptionHelper for &mut SmartcardManager<P> {
|
|||
Err(CardError::CardStatus(StatusBytes::IncorrectParametersCommandDataField)) => {
|
||||
self.pm
|
||||
.lock()
|
||||
.unwrap()
|
||||
.expect(bug!(POISONED_MUTEX))
|
||||
.prompt_message(Message::Text("Invalid PIN length entered.".to_string()))?;
|
||||
}
|
||||
Err(_) => {}
|
||||
|
|
|
@ -8,13 +8,14 @@ license = "MIT"
|
|||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[features]
|
||||
default = []
|
||||
default = ["bin"]
|
||||
bin = ["decode-backend-rqrr"]
|
||||
decode-backend-rqrr = ["dep:rqrr"]
|
||||
decode-backend-zbar = ["dep:keyfork-zbar"]
|
||||
|
||||
[dependencies]
|
||||
image = { version = "0.24.7", default-features = false, features = ["jpeg"] }
|
||||
keyfork-bug = { version = "0.1.0", path = "../../util/keyfork-bug" }
|
||||
keyfork-zbar = { version = "0.1.0", path = "../keyfork-zbar", optional = true }
|
||||
rqrr = { version = "0.6.0", optional = true }
|
||||
thiserror = "1.0.56"
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
//! Encoding and decoding QR codes.
|
||||
|
||||
use keyfork_bug as bug;
|
||||
|
||||
use image::io::Reader as ImageReader;
|
||||
use std::{
|
||||
io::{Cursor, Write},
|
||||
|
@ -98,11 +100,13 @@ pub fn qrencode(
|
|||
Ok(result)
|
||||
}
|
||||
|
||||
const VIDEO_FORMAT_READ_ERROR: &str = "Failed to read video device format";
|
||||
|
||||
/// Continuously scan the `index`-th camera for a QR code.
|
||||
#[cfg(feature = "decode-backend-rqrr")]
|
||||
pub fn scan_camera(timeout: Duration, index: usize) -> Result<Option<String>, QRCodeScanError> {
|
||||
let device = Device::new(index)?;
|
||||
let mut fmt = device.format().expect("Failed to read format");
|
||||
let mut fmt = device.format().unwrap_or_else(bug::panic!(VIDEO_FORMAT_READ_ERROR));
|
||||
fmt.fourcc = FourCC::new(b"MPG1");
|
||||
device.set_format(&fmt)?;
|
||||
let mut stream = Stream::with_buffers(&device, Type::VideoCapture, 4)?;
|
||||
|
@ -133,7 +137,7 @@ pub fn scan_camera(timeout: Duration, index: usize) -> Result<Option<String>, QR
|
|||
#[cfg(feature = "decode-backend-zbar")]
|
||||
pub fn scan_camera(timeout: Duration, index: usize) -> Result<Option<String>, QRCodeScanError> {
|
||||
let device = Device::new(index)?;
|
||||
let mut fmt = device.format().expect("Failed to read format");
|
||||
let mut fmt = device.format().unwrap_or_else(bug::panic!(VIDEO_FORMAT_READ_ERROR));
|
||||
fmt.fourcc = FourCC::new(b"MPG1");
|
||||
device.set_format(&fmt)?;
|
||||
let mut stream = Stream::with_buffers(&device, Type::VideoCapture, 4)?;
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
[package]
|
||||
name = "keyfork-bug"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
|
@ -0,0 +1,108 @@
|
|||
//! Keyfork Bug Reporting Utilities.
|
||||
//!
|
||||
//! # Examples
|
||||
//!
|
||||
//! ```rust
|
||||
//! use std::{fs::File, io::Write};
|
||||
//! use keyfork_bug as bug;
|
||||
//!
|
||||
//! let option = Some("hello world!");
|
||||
//! let value = option.expect(bug::bug!("missing str value!"));
|
||||
//!
|
||||
//! let mut output_file = File::create("/dev/null").expect(bug::bug!("can't open /dev/null"));
|
||||
//! output_file
|
||||
//! .write_all(value.as_bytes())
|
||||
//! .unwrap_or_else(bug::panic!("Can't write to file: {}", value));
|
||||
//! ```
|
||||
//!
|
||||
//! ```rust,should_panic
|
||||
//! use std::fs::File;
|
||||
//! use keyfork_bug as bug;
|
||||
//!
|
||||
//! let mut output_file = File::open("/dev/nukk").expect(bug::bug!("can't open /dev/null"));
|
||||
//! ```
|
||||
|
||||
/// The mutex was poisoned and is unusable.
|
||||
pub const POISONED_MUTEX: &str = "The mutex was poisoned and is unusable";
|
||||
|
||||
/// Automatically generate a bug report message for Keyfork. This macro is intended to use when
|
||||
/// using `Result::expect()` or `Option::expect()` to retrieve information about the callsite where
|
||||
/// the bug was located.
|
||||
///
|
||||
/// # Examples
|
||||
/// ```rust
|
||||
/// use keyfork_bug::bug;
|
||||
///
|
||||
/// let option = Some(0u32);
|
||||
/// let value = option.expect(bug!("missing u32 value!"));
|
||||
/// ```
|
||||
///
|
||||
/// ```rust
|
||||
/// use keyfork_bug::bug;
|
||||
///
|
||||
/// let error_message = "This is a really long error message that should not be in the macro.";
|
||||
/// let option = Some(0u32);
|
||||
/// let value = option.expect(bug!(error_message));
|
||||
/// ```
|
||||
///
|
||||
/// ```rust,should_panic
|
||||
/// use keyfork_bug::bug;
|
||||
///
|
||||
/// let option: Option<u32> = None;
|
||||
/// let value = option.expect(bug!("missing u32 value!"));
|
||||
/// ```
|
||||
#[macro_export]
|
||||
macro_rules! bug {
|
||||
($input:literal) => {
|
||||
concat!(
|
||||
"Keyfork encountered a BUG at: [",
|
||||
file!(),
|
||||
":",
|
||||
line!(),
|
||||
":",
|
||||
column!(),
|
||||
"]: ",
|
||||
$input,
|
||||
"\n\nReport this bug to <team@distrust.co>, this behavior is unexpected!"
|
||||
)
|
||||
};
|
||||
($input:ident) => {
|
||||
format!(
|
||||
concat!("Keyfork encountered a BUG at: [{file}:{line}:{column}]: {input}\n\n",
|
||||
"Report this bug to <team@distrust.co>, this behavior is unexpected!"
|
||||
),
|
||||
file=file!(),
|
||||
line=line!(),
|
||||
column=column!(),
|
||||
input=$input,
|
||||
).as_str()
|
||||
};
|
||||
($($arg:tt)*) => {{
|
||||
let message = format!($($arg)*);
|
||||
$crate::bug!(message)
|
||||
}};
|
||||
}
|
||||
|
||||
/// Return a closure that, when called, panics with a bug report message for Keyfork. Returning a
|
||||
/// closure can help handle the `clippy::expect_fun_call` lint. The closure accepts an error
|
||||
/// argument, so it is suitable for being used with [`Result`] types instead of [`Option`] types.
|
||||
///
|
||||
/// # Examples
|
||||
/// ```rust
|
||||
/// use std::fs::File;
|
||||
/// use keyfork_bug as bug;
|
||||
///
|
||||
/// let file = File::open("/dev/null").unwrap_or_else(bug::panic!("couldn't open /dev/null"));
|
||||
/// ```
|
||||
#[macro_export]
|
||||
macro_rules! panic {
|
||||
($input:literal) => { |e| {
|
||||
std::panic!("{}\n{}", $crate::bug!($input), e)
|
||||
}};
|
||||
($input:ident) => { |e| {
|
||||
std::panic!("{}\n{}", $crate::bug!($input), e)
|
||||
}};
|
||||
($($arg:tt)*) => { |e| {
|
||||
std::panic!("{}\n{}", $crate::bug!($($arg)*), e)
|
||||
}};
|
||||
}
|
|
@ -11,4 +11,5 @@ default = ["bin"]
|
|||
bin = ["smex"]
|
||||
|
||||
[dependencies]
|
||||
keyfork-bug = { version = "0.1.0", path = "../keyfork-bug" }
|
||||
smex = { version = "0.1.0", path = "../smex", optional = true }
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
//! Utilities for reading entropy from secure sources.
|
||||
|
||||
use keyfork_bug::bug;
|
||||
|
||||
use std::{
|
||||
fs::{read_dir, read_to_string, File},
|
||||
io::Read,
|
||||
|
@ -9,15 +11,16 @@ static WARNING_LINKS: [&str; 1] =
|
|||
["https://lore.kernel.org/lkml/20211223141113.1240679-2-Jason@zx2c4.com/"];
|
||||
|
||||
fn ensure_safe_kernel_version() {
|
||||
let kernel_version = read_to_string("/proc/version").expect("/proc/version");
|
||||
let kernel_version =
|
||||
read_to_string("/proc/version").expect(bug!("Unable to open file: /proc/version"));
|
||||
let v = kernel_version
|
||||
.split(' ')
|
||||
.nth(2)
|
||||
.expect("Unable to parse kernel version")
|
||||
.expect(bug!("Unable to parse kernel version"))
|
||||
.split('.')
|
||||
.take(2)
|
||||
.map(str::parse)
|
||||
.map(|x| x.expect("Unable to parse kernel version number"))
|
||||
.map(|x| x.expect(bug!("Unable to parse kernel version number")))
|
||||
.collect::<Vec<u32>>();
|
||||
let [major, minor, ..] = v.as_slice() else {
|
||||
panic!("Unable to determine major and minor: {kernel_version}");
|
||||
|
@ -30,22 +33,23 @@ fn ensure_safe_kernel_version() {
|
|||
}
|
||||
|
||||
fn ensure_offline() {
|
||||
let paths = read_dir("/sys/class/net").expect("Unable to read network interfaces");
|
||||
let paths = read_dir("/sys/class/net").expect(bug!("Unable to read network interfaces"));
|
||||
for entry in paths {
|
||||
let mut path = entry.expect("Unable to read directory entry").path();
|
||||
let mut path = entry.expect(bug!("Unable to read directory entry")).path();
|
||||
if path
|
||||
.as_os_str()
|
||||
.to_str()
|
||||
.expect("Unable to decode UTF-8 filepath")
|
||||
.expect(bug!("Unable to decode UTF-8 filepath"))
|
||||
.split('/')
|
||||
.last()
|
||||
.expect("No data in file path")
|
||||
.expect(bug!("No data in file path"))
|
||||
== "lo"
|
||||
{
|
||||
continue;
|
||||
}
|
||||
path.push("operstate");
|
||||
let isup = read_to_string(&path).expect("Unable to read operstate of network interfaces");
|
||||
let isup =
|
||||
read_to_string(&path).expect(bug!("Unable to read operstate of network interfaces"));
|
||||
assert_ne!(isup.trim(), "up", "No network interfaces should be up");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@ sha2 = "0.10.7"
|
|||
hmac = "0.12.1"
|
||||
pbkdf2 = "0.12.2"
|
||||
smex = { version = "0.1.0", path = "../smex", optional = true }
|
||||
keyfork-bug = { version = "0.1.0", path = "../keyfork-bug" }
|
||||
|
||||
[dev-dependencies]
|
||||
bip39 = "2.0.0"
|
||||
|
|
|
@ -48,13 +48,9 @@
|
|||
//! let new_mnemonic = Mnemonic::from_str(&mnemonic_text).unwrap();
|
||||
//! ```
|
||||
|
||||
use std::{
|
||||
error::Error,
|
||||
fmt::Display,
|
||||
str::FromStr,
|
||||
sync::OnceLock,
|
||||
marker::PhantomData,
|
||||
};
|
||||
use std::{error::Error, fmt::Display, marker::PhantomData, str::FromStr, sync::OnceLock};
|
||||
|
||||
use keyfork_bug::bug;
|
||||
|
||||
use hmac::Hmac;
|
||||
use pbkdf2::pbkdf2;
|
||||
|
@ -115,12 +111,11 @@ impl Wordlist for English {
|
|||
fn get_singleton<'a>() -> &'a Self {
|
||||
ENGLISH.get_or_init(|| {
|
||||
let wordlist_file = include_str!("data/wordlist.txt");
|
||||
let mut words = wordlist_file
|
||||
.lines()
|
||||
.skip(1)
|
||||
.map(|x| x.trim().to_string());
|
||||
let mut words = wordlist_file.lines().skip(1).map(|x| x.trim().to_string());
|
||||
English {
|
||||
words: std::array::from_fn(|_| words.next().expect("wordlist has 2048 words")),
|
||||
words: std::array::from_fn(|_| {
|
||||
words.next().expect(bug!("wordlist {} should have 2048 words"))
|
||||
}),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -247,7 +242,10 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
Ok(MnemonicBase { data, marker: PhantomData })
|
||||
Ok(MnemonicBase {
|
||||
data,
|
||||
marker: PhantomData,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -390,7 +388,7 @@ where
|
|||
let mnemonic = self.to_string();
|
||||
let salt = ["mnemonic", passphrase.unwrap_or("")].join("");
|
||||
pbkdf2::<Hmac<Sha512>>(mnemonic.as_bytes(), salt.as_bytes(), 2048, &mut seed)
|
||||
.expect("HmacSha512 InvalidLength should be infallible");
|
||||
.expect(bug!("HmacSha512 InvalidLength should be infallible"));
|
||||
seed.to_vec()
|
||||
}
|
||||
|
||||
|
@ -415,13 +413,16 @@ where
|
|||
}
|
||||
|
||||
// TODO: find a way to not have to collect to vec
|
||||
bits.chunks_exact(11).peekable().map(|chunk| {
|
||||
bits.chunks_exact(11)
|
||||
.peekable()
|
||||
.map(|chunk| {
|
||||
let mut num = 0usize;
|
||||
for i in 0..11 {
|
||||
num += usize::from(chunk[10 - i]) << i;
|
||||
}
|
||||
num
|
||||
}).collect()
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@ default = ["mnemonic"]
|
|||
mnemonic = ["keyfork-mnemonic-util"]
|
||||
|
||||
[dependencies]
|
||||
keyfork-bug = { version = "0.1.0", path = "../keyfork-bug" }
|
||||
keyfork-crossterm = { version = "0.27.1", path = "../keyfork-crossterm", default-features = false, features = ["use-dev-tty", "events", "bracketed-paste"] }
|
||||
keyfork-mnemonic-util = { version = "0.1.0", path = "../keyfork-mnemonic-util", optional = true }
|
||||
thiserror = "1.0.51"
|
||||
|
|
|
@ -13,6 +13,8 @@ use keyfork_crossterm::{
|
|||
ExecutableCommand, QueueableCommand,
|
||||
};
|
||||
|
||||
use keyfork_bug::bug;
|
||||
|
||||
use crate::{Error, Message, PromptHandler, Wordlist};
|
||||
|
||||
#[allow(missing_docs)]
|
||||
|
@ -120,9 +122,9 @@ where
|
|||
W: Write + AsRawFd,
|
||||
{
|
||||
fn drop(&mut self) {
|
||||
self.write.execute(DisableBracketedPaste).unwrap();
|
||||
self.write.execute(LeaveAlternateScreen).unwrap();
|
||||
self.terminal.disable_raw_mode().unwrap();
|
||||
self.write.execute(DisableBracketedPaste).expect(bug!("can't restore bracketed paste"));
|
||||
self.write.execute(LeaveAlternateScreen).expect(bug!("can't leave alternate screen"));
|
||||
self.terminal.disable_raw_mode().expect(bug!("can't disable raw mode"));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -80,6 +80,7 @@ pub mod mnemonic {
|
|||
use super::Validator;
|
||||
|
||||
use keyfork_mnemonic_util::{Mnemonic, MnemonicFromStrError};
|
||||
use keyfork_bug::bug;
|
||||
|
||||
/// A mnemonic could not be validated from the given input.
|
||||
#[derive(thiserror::Error, Debug)]
|
||||
|
@ -237,7 +238,7 @@ pub mod mnemonic {
|
|||
|
||||
Ok(output
|
||||
.try_into()
|
||||
.expect("vec with capacity of const N was not filled"))
|
||||
.expect(bug!("vec with capacity of const N was not filled")))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue