Skip to content

Commit

Permalink
Refactor connection handling
Browse files Browse the repository at this point in the history
This patch introduces two new functions, find_device and connect, to
connect to a Nitrokey device.  find_device queries the attached Nitrokey
devices, applies the filters (currently only the --model option) and
returns the first match.  connect calls find_device and connects to the
returned device.
This refactoring allows us to add more device filters, for example a
--serial-number option, without code duplication.
  • Loading branch information
robinkrahl authored and d-e-s-o committed Jan 11, 2021
1 parent 0cc4371 commit 0f16347
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 17 deletions.
61 changes: 50 additions & 11 deletions src/commands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
use std::convert::TryFrom as _;
use std::fmt;
use std::mem;
use std::ops::Deref as _;
use std::thread;
use std::time;
use std::u8;
Expand All @@ -20,6 +21,7 @@ use nitrokey::GenerateOtp;
use nitrokey::GetPasswordSafe;

use crate::args;
use crate::config;
use crate::pinentry;
use crate::Context;

Expand All @@ -39,6 +41,45 @@ fn set_log_level(ctx: &mut Context<'_>) {
nitrokey::set_log_level(log_lvl);
}

/// Create a filter string from the program configuration.
fn format_filter(config: &config::Config) -> String {
if let Some(model) = config.model {
format!(" (filter: model={})", model.as_ref())
} else {
String::new()
}
}

/// Find a Nitrokey device that matches the given requirements
fn find_device(config: &config::Config) -> anyhow::Result<nitrokey::DeviceInfo> {
let devices = nitrokey::list_devices().context("Failed to enumerate Nitrokey devices")?;
let nkmodel = config.model.map(nitrokey::Model::from);
let mut iter = devices
.into_iter()
.filter(|device| nkmodel.is_none() || device.model == nkmodel);

let device = iter
.next()
.with_context(|| format!("Nitrokey device not found{}", format_filter(config)))?;
Ok(device)
}

/// Connect to a Nitrokey device that matches the given requirements
fn connect<'mgr>(
manager: &'mgr mut nitrokey::Manager,
config: &config::Config,
) -> anyhow::Result<nitrokey::DeviceWrapper<'mgr>> {
let device_info = find_device(config)?;
manager
.connect_path(device_info.path.deref())
.with_context(|| {
format!(
"Failed to connect to Nitrokey device at path {}",
device_info.path
)
})
}

/// Connect to any Nitrokey device and do something with it.
fn with_device<F>(ctx: &mut Context<'_>, op: F) -> anyhow::Result<()>
where
Expand All @@ -49,13 +90,7 @@ where

set_log_level(ctx);

let device = match ctx.config.model {
Some(model) => manager.connect_model(model.into()).with_context(|| {
anyhow::anyhow!("Nitrokey {} device not found", model.as_user_facing_str())
})?,
None => manager.connect().context("Nitrokey device not found")?,
};

let device = connect(&mut manager, &ctx.config)?;
op(ctx, device)
}

Expand All @@ -73,12 +108,16 @@ where
if model != args::DeviceModel::Storage {
anyhow::bail!("This command is only available on the Nitrokey Storage");
}
} else {
ctx.config.model = Some(args::DeviceModel::Storage);
}

let device = manager
.connect_storage()
.context("Nitrokey Storage device not found")?;
op(ctx, device)
let device = connect(&mut manager, &ctx.config)?;
if let nitrokey::DeviceWrapper::Storage(storage) = device {
op(ctx, storage)
} else {
panic!("connect returned a wrong model: {}", device.get_model())
}
}

/// Connect to any Nitrokey device, retrieve a password safe handle, and
Expand Down
1 change: 1 addition & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
// Copyright (C) 2017-2020 The Nitrocli Developers
// SPDX-License-Identifier: GPL-3.0-or-later

#![allow(clippy::trivially_copy_pass_by_ref)]
#![warn(
bad_style,
dead_code,
Expand Down
7 changes: 1 addition & 6 deletions src/tests/status.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,7 @@ fn not_found_raw() {

assert_ne!(rc, 0);
assert_eq!(out, b"");
let expected = r#"Nitrokey device not found
Caused by:
Communication error: Could not connect to a Nitrokey device
"#;
assert_eq!(err, expected.as_bytes());
assert_eq!(err, b"Nitrokey device not found\n");
}

#[test_device]
Expand Down

0 comments on commit 0f16347

Please sign in to comment.