/* This Source Code Form is subject to the terms of the Mozilla Public *License,v.2.0.IfacopyoftheMPLwasnotdistributedwiththis
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
fn init_device(
info: DeviceBuildParameters,
selector: &Sender<DeviceSelectorEvent>,
) -> Option<Device> { // Create a new device. letmut dev = match Device::new(info) {
Ok(dev) => dev,
Err((e, id)) => {
info!("error happened with device: {}", e); let _ = selector.send(DeviceSelectorEvent::NotAToken(id)); return None;
}
};
// Try initializing it. iflet Err(e) = dev.init() {
warn!("error while initializing device: {}", e); let _ = selector.send(DeviceSelectorEvent::NotAToken(dev.id())); return None;
}
Some(dev)
}
fn wait_for_device_selector(
dev: &mut Device,
selector: &Sender<DeviceSelectorEvent>,
status: &Sender<crate::StatusUpdate>,
keep_alive: &dynFn() -> bool,
) -> bool { let (tx, rx) = channel(); if selector
.send(DeviceSelectorEvent::ImAToken((dev.id(), tx)))
.is_err()
{ // If we fail to register with the device selector, then we're not going // to be selected. returnfalse;
}
// We can be cancelled from the user (through keep_alive()) or from the device selector // (through a DeviceCommand::Cancel on rx). We'll combine those signals into a single // predicate to pass to Device::block_and_blink. let keep_blinking = || keep_alive() && !matches!(rx.try_recv(), Ok(DeviceCommand::Cancel));
// Blocking recv. DeviceSelector will tell us what to do match rx.recv() {
Ok(DeviceCommand::Blink) => { // The caller wants the user to choose a device. Send a status update and blink // this device. NOTE: We send one status update per device, so the recipient should be // prepared to receive the message multiple times.
send_status(status, crate::StatusUpdate::SelectDeviceNotice); match dev.block_and_blink(&keep_blinking) {
BlinkResult::DeviceSelected => { // User selected us. Let DeviceSelector know, so it can cancel all other // outstanding open blink-requests. If we fail to send the SelectedToken // message to the device selector, then don't consider this token as having // been selected.
selector
.send(DeviceSelectorEvent::SelectedToken(dev.id()))
.is_ok()
}
BlinkResult::Cancelled => {
info!("Device {:?} was not selected", dev.id()); false
}
}
}
Ok(DeviceCommand::Cancel) => {
info!("Device {:?} was not selected", dev.id()); false
}
Ok(DeviceCommand::Removed) => {
info!("Device {:?} was removed", dev.id()); false
}
Ok(DeviceCommand::Continue) => true,
Err(_) => {
warn!("Error when trying to receive messages from DeviceSelector! Exiting."); false
}
}
}
if args.use_ctap1_fallback {
dev.downgrade_to_ctap1();
}
info!("Device {:?} continues with the register process", dev.id()); if ctap2::register(&mut dev, args.clone(), status, callback.clone(), alive) { // ctap2::register returns true if it called the callback with Ok(..). Cancel // all other tokens in case we skipped the "blinking"-action and went straight // for the actual request. let _ = selector.send(DeviceSelectorEvent::SelectedToken(dev.id()));
}
},
);
if args.use_ctap1_fallback {
dev.downgrade_to_ctap1();
}
info!("Device {:?} continues with the signing process", dev.id()); if ctap2::sign(&mut dev, args.clone(), status, callback.clone(), alive) { // ctap2::sign returns true if it called the callback with Ok(..). Cancel all // other tokens in case we skipped the "blinking"-action and went straight for // the actual request. let _ = selector.send(DeviceSelectorEvent::SelectedToken(dev.id()));
}
},
);
if dev.get_protocol() != FidoProtocol::CTAP2 {
info!("Device does not support CTAP2"); let _ = selector.send(DeviceSelectorEvent::NotAToken(dev.id())); return;
}
if dev.get_protocol() != FidoProtocol::CTAP2 {
info!("Device does not support CTAP2"); let _ = selector.send(DeviceSelectorEvent::NotAToken(dev.id())); return;
}
if !Self::wait_for_device_selector(&mut dev, &selector, &status, alive) { return;
};
// Function to interactively manage a specific token. // Difference to register/sign: These want to do something and don't care // with which token they do it. // This function wants to manipulate a specific token. For this, we first // have to select one and then do something with it, based on what it // supports (Set PIN, Change PIN, Reset, etc.). // Hence, we first go through the discovery-phase, then provide the user // with the AuthenticatorInfo and then let them interactively decide what to do pubfn manage(
&mutself,
timeout: u64,
status: Sender<crate::StatusUpdate>,
callback: StateCallback<crate::Result<crate::ManageResult>>,
) { // Abort any prior register/sign calls. self.cancel(); let cbc = callback.clone();
if dev.get_protocol() != FidoProtocol::CTAP2 {
info!("Device does not support CTAP2"); let _ = selector.send(DeviceSelectorEvent::NotAToken(dev.id())); return;
}
if !Self::wait_for_device_selector(&mut dev, &selector, &status, alive) { return;
};
info!("Device {:?} selected for interactive management.", dev.id());
// Sending the user the info about the token let (tx, rx) = channel();
send_status(
&status, crate::StatusUpdate::InteractiveManagement(InteractiveUpdate::StartManagement(
(tx, dev.get_authenticator_info().cloned()),
)),
); while alive() { match rx.recv_timeout(Duration::from_millis(400)) {
Ok(InteractiveRequest::Quit) => {
callback.call(Ok(ManageResult::Success)); break;
}
Ok(InteractiveRequest::Reset) => {
ctap2::reset_helper(
&mut dev,
selector,
status,
callback.clone(),
alive,
);
}
Ok(InteractiveRequest::ChangePIN(curr_pin, new_pin)) => {
ctap2::set_or_change_pin_helper(
&mut dev,
Some(curr_pin),
new_pin,
status,
callback.clone(),
alive,
);
}
Ok(InteractiveRequest::SetPIN(pin)) => {
ctap2::set_or_change_pin_helper(
&mut dev,
None,
pin,
status,
callback.clone(),
alive,
);
}
Ok(InteractiveRequest::ChangeConfig(authcfg, puat)) => {
ctap2::configure_authenticator(
&mut dev,
puat,
authcfg,
status.clone(),
callback.clone(),
alive,
); continue;
}
Ok(InteractiveRequest::CredentialManagement(cred_management, puat)) => {
ctap2::credential_management(
&mut dev,
puat,
cred_management,
status.clone(),
callback.clone(),
alive,
); continue;
}
Ok(InteractiveRequest::BioEnrollment(bio_enrollment, puat)) => {
ctap2::bio_enrollment(
&mut dev,
puat,
bio_enrollment,
status.clone(),
callback.clone(),
alive,
); continue;
}
Err(RecvTimeoutError::Timeout) => { if !alive() { // We got stopped at some point
callback.call(Err(AuthenticatorError::CancelledByUser)); break;
} continue;
}
Err(RecvTimeoutError::Disconnected) => { // recv() failed, because the other side is dropping the Sender.
info!( "Callback dropped the channel, so we abort the interactive session"
);
callback.call(Err(AuthenticatorError::CancelledByUser));
}
} break;
}
},
);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.