/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use crate::authenticatorservice::AuthenticatorTransport; use crate::authenticatorservice::{RegisterArgs, SignArgs}; use crate::errors::*; use crate::statecallback::StateCallback; use crate::statemachine::StateMachine; use crate::Pin; use runloop::RunLoop; use std::io; use std::sync::mpsc::{channel, RecvTimeoutError, Sender}; use std::time::Duration; enum QueueAction { Register { timeout: u64, register_args: RegisterArgs, status: Sender, callback: StateCallback>, }, Sign { timeout: u64, sign_args: SignArgs, status: Sender, callback: StateCallback>, }, Cancel, Reset { timeout: u64, status: Sender, callback: StateCallback>, }, SetPin { timeout: u64, new_pin: Pin, status: Sender, callback: StateCallback>, }, InteractiveManagement { timeout: u64, status: Sender, callback: StateCallback>, }, } pub struct Manager { queue: RunLoop, tx: Sender, } impl Manager { pub fn new() -> io::Result { let (tx, rx) = channel(); // Start a new work queue thread. let queue = RunLoop::new(move |alive| { let mut sm = StateMachine::new(); while alive() { match rx.recv_timeout(Duration::from_millis(50)) { Ok(QueueAction::Register { timeout, register_args, status, callback, }) => { // This must not block, otherwise we can't cancel. sm.register(timeout, register_args, status, callback); } Ok(QueueAction::Sign { timeout, sign_args, status, callback, }) => { // This must not block, otherwise we can't cancel. sm.sign(timeout, sign_args, status, callback); } Ok(QueueAction::Cancel) => { // Cancelling must block so that we don't start a new // polling thread before the old one has shut down. sm.cancel(); } Ok(QueueAction::Reset { timeout, status, callback, }) => { // Reset the token: Delete all keypairs, reset PIN sm.reset(timeout, status, callback); } Ok(QueueAction::SetPin { timeout, new_pin, status, callback, }) => { // This must not block, otherwise we can't cancel. sm.set_pin(timeout, new_pin, status, callback); } Ok(QueueAction::InteractiveManagement { timeout, status, callback, }) => { // Manage token interactively sm.manage(timeout, status, callback); } Err(RecvTimeoutError::Disconnected) => { break; } _ => { /* continue */ } } } // Cancel any ongoing activity. sm.cancel(); })?; Ok(Self { queue, tx }) } } impl Drop for Manager { fn drop(&mut self) { self.queue.cancel(); } } impl AuthenticatorTransport for Manager { fn register( &mut self, timeout: u64, register_args: RegisterArgs, status: Sender, callback: StateCallback>, ) -> Result<(), AuthenticatorError> { let action = QueueAction::Register { timeout, register_args, status, callback, }; Ok(self.tx.send(action)?) } fn sign( &mut self, timeout: u64, sign_args: SignArgs, status: Sender, callback: StateCallback>, ) -> crate::Result<()> { let action = QueueAction::Sign { timeout, sign_args, status, callback, }; self.tx.send(action)?; Ok(()) } fn cancel(&mut self) -> Result<(), AuthenticatorError> { Ok(self.tx.send(QueueAction::Cancel)?) } fn reset( &mut self, timeout: u64, status: Sender, callback: StateCallback>, ) -> Result<(), AuthenticatorError> { Ok(self.tx.send(QueueAction::Reset { timeout, status, callback, })?) } fn set_pin( &mut self, timeout: u64, new_pin: Pin, status: Sender, callback: StateCallback>, ) -> crate::Result<()> { Ok(self.tx.send(QueueAction::SetPin { timeout, new_pin, status, callback, })?) } fn manage( &mut self, timeout: u64, status: Sender, callback: StateCallback>, ) -> Result<(), AuthenticatorError> { Ok(self.tx.send(QueueAction::InteractiveManagement { timeout, status, callback, })?) } }