Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion crates/humanode-peer/src/cli/run.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use sc_service::PartialComponents;

use crate::service;

use super::{Root, Subcommand};
use super::{bioauth, Root, Subcommand};

/// Parse command line arguments and run the requested operation.
pub async fn run() -> sc_cli::Result<()> {
Expand Down Expand Up @@ -89,6 +89,15 @@ pub async fn run() -> sc_cli::Result<()> {
})
.await
}
Some(Subcommand::Bioauth(bioauth::BioauthCmd::Key(bioauth::key::KeyCmd::List(cmd)))) => {
let runner = root.create_humanode_runner(cmd)?;
runner
.async_run(|config| async move {
let (keystore_container, task_manager) = service::keystore_container(&config)?;
Ok((cmd.run(keystore_container), task_manager))
})
.await
}
Some(Subcommand::Benchmark(cmd)) => {
if cfg!(feature = "runtime-benchmarks") {
let runner = root.create_humanode_runner(cmd)?;
Expand Down
50 changes: 50 additions & 0 deletions crates/humanode-peer/src/cli/subcommand/bioauth/key.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
//! Bioauth key management subcommands.

use sc_cli::{CliConfiguration, KeystoreParams, SharedParams};
use sc_service::KeystoreContainer;
use structopt::StructOpt;

use crate::cli::CliConfigurationExt;

/// Subcommands for the `bioauth key` command.
#[derive(Debug, StructOpt)]
pub enum KeyCmd {
/// List the bioauth keys.
List(ListKeysCmd),
}

/// The `bioauth key list` command.
#[derive(Debug, StructOpt)]
pub struct ListKeysCmd {
#[allow(missing_docs, clippy::missing_docs_in_private_items)]
#[structopt(flatten)]
pub shared_params: SharedParams,

#[allow(missing_docs, clippy::missing_docs_in_private_items)]
#[structopt(flatten)]
pub keystore_params: KeystoreParams,
}

impl ListKeysCmd {
/// Run the list command.
pub async fn run(&self, keystore_container: KeystoreContainer) -> sc_cli::Result<()> {
let keystore = keystore_container.keystore();
let keys = crate::validator_key::AuraPublic::list(keystore.as_ref()).await;
for key in keys {
println!("{}", &key);
}
Ok(())
}
}

impl CliConfiguration for ListKeysCmd {
fn shared_params(&self) -> &SharedParams {
&self.shared_params
}

fn keystore_params(&self) -> Option<&KeystoreParams> {
Some(&self.keystore_params)
}
}

impl CliConfigurationExt for ListKeysCmd {}
12 changes: 12 additions & 0 deletions crates/humanode-peer/src/cli/subcommand/bioauth/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
//! Bioauth subcommands and related common utilities.

use structopt::StructOpt;

pub mod key;

/// Subcommands for the `bioauth` command.
#[derive(Debug, StructOpt)]
pub enum BioauthCmd {
/// Bioauth key utilities.
Key(key::KeyCmd),
}
5 changes: 5 additions & 0 deletions crates/humanode-peer/src/cli/subcommand/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ use structopt::StructOpt;

use super::CliConfigurationExt;

pub mod bioauth;

/// Humanode peer subcommands.
#[derive(Debug, StructOpt)]
pub enum Subcommand {
Expand Down Expand Up @@ -33,6 +35,9 @@ pub enum Subcommand {
/// Revert the chain to a previous state.
Revert(sc_cli::RevertCmd),

/// Biometric authentication related subcommands.
Bioauth(bioauth::BioauthCmd),

/// The custom benchmark subcommmand benchmarking runtime pallets.
#[structopt(name = "benchmark", about = "Benchmark runtime pallets.")]
Benchmark(frame_benchmarking_cli::BenchmarkCmd),
Expand Down
44 changes: 31 additions & 13 deletions crates/humanode-peer/src/service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use sc_client_api::ExecutorProvider;
use sc_consensus_aura::{ImportQueueParams, SlotDuration, SlotProportion, StartAuraParams};
use sc_executor::native_executor_instance;
pub use sc_executor::NativeExecutor;
use sc_service::{Error as ServiceError, PartialComponents, TaskManager};
use sc_service::{Error as ServiceError, KeystoreContainer, PartialComponents, TaskManager};
use sp_consensus::SlotData;
use sp_consensus_aura::sr25519::AuthorityPair as AuraPair;
use tracing::*;
Expand All @@ -30,6 +30,15 @@ type FullBackend = sc_service::TFullBackend<Block>;
/// Full node select chain type.
type FullSelectChain = sc_consensus::LongestChain<FullBackend, Block>;

/// Construct a bare keystore from the configuration.
pub fn keystore_container(
config: &Configuration,
) -> Result<(KeystoreContainer, TaskManager), ServiceError> {
let (_client, _backend, keystore_container, task_manager) =
sc_service::new_full_parts::<Block, RuntimeApi, Executor>(&config.substrate, None)?;
Ok((keystore_container, task_manager))
}

/// Extract substrate partial components.
pub fn new_partial(
config: &Configuration,
Expand Down Expand Up @@ -255,33 +264,42 @@ pub async fn new_full(config: Configuration) -> Result<TaskManager, ServiceError
let keystore = keystore_container.keystore();
let transaction_pool = Arc::clone(&transaction_pool);
Box::pin(async move {
info!("bioauth flow starting up");

let aura_public_key =
crate::validator_key::AuraPublic::from_keystore(keystore.as_ref())
.await
.expect("vector has to be of length 1 at this point");
crate::validator_key::AuraPublic::from_keystore(keystore.as_ref()).await;

let aura_public_key = match aura_public_key {
Some(key) => {
info!("Running bioauth flow for {}", key);
key
}
None => {
warn!("No validator key found, skipping bioauth");
return;
}
};

info!("Bioauth flow starting up");

if bioauth_perform_enroll {
info!("bioauth flow - enrolling in progress");
info!("Bioauth flow - enrolling in progress");

if let Some(qrcode) = webapp_qrcode.as_ref() {
qrcode.print()
} else {
info!("bioauth flow - waiting for enroll");
info!("Bioauth flow - waiting for enroll");
}

flow.enroll(&aura_public_key).await.expect("enroll failed");

info!("bioauth flow - enrolling complete");
info!("Bioauth flow - enrolling complete");
}

info!("bioauth flow - authentication in progress");
info!("Bioauth flow - authentication in progress");

if let Some(qrcode) = webapp_qrcode.as_ref() {
qrcode.print()
} else {
info!("bioauth flow - waiting for authentication");
info!("Bioauth flow - waiting for authentication");
}

let aura_signer = crate::validator_key::AuraSigner {
Expand All @@ -294,12 +312,12 @@ pub async fn new_full(config: Configuration) -> Result<TaskManager, ServiceError
match result {
Ok(v) => break v,
Err(error) => {
error!(message = "bioauth flow - authentication failure", ?error);
error!(message = "Bioauth flow - authentication failure", ?error);
}
};
};

info!("bioauth flow - authentication complete");
info!("Bioauth flow - authentication complete");

info!(message = "We've obtained an auth ticket", auth_ticket = ?authenticate_response.auth_ticket);

Expand Down
24 changes: 19 additions & 5 deletions crates/humanode-peer/src/validator_key.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//! The validator key integration logic.

use std::sync::Arc;
use std::{fmt::Display, sync::Arc};

use bioauth_flow::flow::Signer;
use sp_application_crypto::Public;
Expand Down Expand Up @@ -60,11 +60,25 @@ impl AsRef<[u8]> for AuraPublic {
impl AuraPublic {
/// Fetch the aura public key from the keystore.
pub async fn from_keystore(keystore: &dyn CryptoStore) -> Option<Self> {
let mut aura_public_keys = keystore
let mut list = Self::list(keystore).await;
assert!(
list.size_hint().0 <= 1,
"The list of aura public keys is larger than 1; please report this"
);
list.next()
}

/// List all [`AuraPublic`] keys in the keystore.
pub async fn list(keystore: &dyn CryptoStore) -> impl Iterator<Item = Self> {
let aura_public_keys = keystore
.sr25519_public_keys(sp_application_crypto::key_types::AURA)
.await;
assert_eq!(aura_public_keys.len(), 1);
let aura_public_key = aura_public_keys.drain(..).next()?;
Some(Self(aura_public_key))
aura_public_keys.into_iter().map(Self)
}
}

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