コード例 #1
0
        async Task TryUnlockWorkstation(IDevice device, string flowId, Action <WorkstationUnlockResult> onUnlockAttempt)
        {
            var result = new WorkstationUnlockResult();

            await _ui.SendNotification(TranslationSource.Instance["ConnectionFlow.Unlock.ReadingCredentials"], device.Mac);

            var credentials = await GetCredentials(device);

            // send credentials to the Credential Provider to unlock the PC
            await _ui.SendNotification(TranslationSource.Instance["ConnectionFlow.Unlock.Unlocking"], device.Mac);

            result.IsSuccessful = await _workstationUnlocker
                                  .SendLogonRequest(credentials.Login, credentials.Password, credentials.PreviousPassword);

            result.AccountName  = credentials.Name;
            result.AccountLogin = credentials.Login;
            result.DeviceMac    = device.Mac;
            result.FlowId       = flowId;

            onUnlockAttempt?.Invoke(result);

            if (!result.IsSuccessful)
            {
                throw new WorkstationUnlockFailedException(); // Abort connection flow
            }
        }
コード例 #2
0
        async Task UnlockByRfid(string rfid)
        {
            if (!isRunning)
            {
                return;
            }

            if (!_rfidSettingsManager.Settings.IsRfidEnabled)
            {
                return;
            }

            if (Interlocked.CompareExchange(ref _isConnecting, 1, 1) == 1)
            {
                return;
            }

            HwVaultShortInfoFromHesDto info = null;

            try
            {
                _screenActivator?.ActivateScreen();

                if (_hesConnection == null)
                {
                    throw new Exception(TranslationSource.Instance["ConnectionFlow.RfidConnection.Error.NotConnectedToHes"]);
                }


                // get MAC address from the HES
                info = await _hesConnection.GetHwVaultInfoByRfid(rfid);

                await _clientUiManager.SendNotification(TranslationSource.Instance["ConnectionFlow.RfidConnection.ContactingHesMessage"], info.VaultMac);

                if (Interlocked.CompareExchange(ref _isConnecting, 1, 0) == 0)
                {
                    try
                    {
                        await _connectionFlowProcessor.ConnectAndUnlock(info.VaultMac, OnUnlockAttempt);
                    }
                    catch (Exception)
                    {
                        // Silent handling. Log is already printed inside of _connectionFlowProcessor.ConnectAndUnlock()
                    }
                    finally
                    {
                        // this delay allows a user to move away the device from the rfid
                        // and prevents the repeated call of this method
                        await Task.Delay(SdkConfig.DelayAfterMainWorkflow);

                        Interlocked.Exchange(ref _isConnecting, 0);
                    }
                }
            }
            catch (Exception ex)
            {
                WriteLine(ex);
                await _clientUiManager.SendError(HideezExceptionLocalization.GetErrorAsString(ex), info?.VaultMac);
            }
        }
コード例 #3
0
        public async Task AuthVault(IDevice device, CancellationToken ct)
        {
            ct.ThrowIfCancellationRequested();

            if (device.AccessLevel.IsMasterKeyRequired && _hesConnection.State == HesConnectionState.Connected)
            {
                await _ui.SendNotification(TranslationSource.Instance["ConnectionFlow.MasterKey.AwaitingHESAuth"], device.Mac);

                await _hesConnection.AuthHwVault(device.SerialNo);

                await device.RefreshDeviceInfo();
            }

            if (device.AccessLevel.IsMasterKeyRequired)
            {
                if (_hesConnection.State == HesConnectionState.Connected)
                {
                    throw new WorkflowException(TranslationSource.Instance["ConnectionFlow.MasterKey.Error.AuthFailed"]);
                }
                else
                {
                    throw new WorkflowException(TranslationSource.Instance["ConnectionFlow.MasterKey.Error.AuthFailedNoNetwork"]);
                }
            }
        }
コード例 #4
0
        async Task <bool> ButtonWorkflow(IDevice device, int timeout, CancellationToken ct)
        {
            if (!device.AccessLevel.IsButtonRequired)
            {
                return(true);
            }

            await _ui.SendNotification(TranslationSource.Instance["ConnectionFlow.Button.PressButtonMessage"], device.Mac);

            await _ui.ShowButtonConfirmUi(device.Id);

            var res = await device.WaitButtonConfirmation(timeout, ct);

            ct.ThrowIfCancellationRequested();

            return(res);
        }
コード例 #5
0
        async Task MainWorkflow(string mac, bool rebondOnConnectionFail, bool tryUnlock, Action <WorkstationUnlockResult> onUnlockAttempt, CancellationToken ct)
        {
            // Ignore MainFlow requests for devices that are already connected
            // IsConnected-true indicates that device already finished main flow or is in progress
            var existingDevice = _deviceManager.Find(mac, (int)DefaultDeviceChannel.Main);

            if (existingDevice != null && existingDevice.IsConnected && !WorkstationHelper.IsActiveSessionLocked())
            {
                return;
            }

            WriteLine($"Started main workflow ({mac})");

            var flowId = Guid.NewGuid().ToString();

            Started?.Invoke(this, flowId);

            bool    workflowFinishedSuccessfully = false;
            bool    deleteVaultBond = false;
            string  errorMessage    = null;
            IDevice device          = null;

            try
            {
                await _ui.SendNotification(string.Empty, mac);

                _subp.PermissionsCheckProcessor.CheckPermissions();

                // Start periodic screen activator to raise the "curtain"
                if (WorkstationHelper.IsActiveSessionLocked())
                {
                    _screenActivator?.ActivateScreen();
                    _screenActivator?.StartPeriodicScreenActivation(0);

                    await new WaitWorkstationUnlockerConnectProc(_workstationUnlocker)
                    .Run(SdkConfig.WorkstationUnlockerConnectTimeout, ct);
                }

                device = await _subp.VaultConnectionProcessor.ConnectVault(mac, rebondOnConnectionFail, ct);

                device.Disconnected       += OnVaultDisconnectedDuringFlow;
                device.OperationCancelled += OnCancelledByVaultButton;

                await _subp.VaultConnectionProcessor.WaitVaultInitialization(mac, device, ct);

                if (device.IsBoot)
                {
                    throw new WorkflowException(TranslationSource.Instance["ConnectionFlow.Error.VaultInBootloaderMode"]);
                }

                device.SetUserProperty(CustomProperties.HW_CONNECTION_STATE_PROP, HwVaultConnectionState.Initializing);

                HwVaultInfoFromHesDto vaultInfo = new HwVaultInfoFromHesDto(); // Initializes with default values for when HES is not connected
                if (_hesConnection.State == HesConnectionState.Connected)
                {
                    vaultInfo = await _hesConnection.UpdateHwVaultProperties(new HwVaultInfoFromClientDto(device), true);
                }

                _subp.CacheVaultInfoProcessor.CacheAndUpdateVaultOwner(ref device, vaultInfo, ct);

                await _subp.LicensingProcessor.CheckLicense(device, vaultInfo, ct);

                vaultInfo = await _subp.StateUpdateProcessor.UpdateVaultStatus(device, vaultInfo, ct);

                vaultInfo = await _subp.ActivationProcessor.ActivateVault(device, vaultInfo, ct);

                await _subp.MasterkeyProcessor.AuthVault(device, ct);

                var osAccUpdateTask = _subp.AccountsUpdateProcessor.UpdateAccounts(device, vaultInfo, true);
                if (_workstationUnlocker.IsConnected && WorkstationHelper.IsActiveSessionLocked() && tryUnlock)
                {
                    await Task.WhenAll(_subp.UserAuthorizationProcessor.AuthorizeUser(device, ct), osAccUpdateTask);

                    _screenActivator?.StopPeriodicScreenActivation();
                    await _subp.UnlockProcessor.UnlockWorkstation(device, flowId, onUnlockAttempt, ct);
                }
                else
                {
                    await osAccUpdateTask;
                }

                device.SetUserProperty(CustomProperties.HW_CONNECTION_STATE_PROP, HwVaultConnectionState.Finalizing);
                WriteLine($"Finalizing main workflow: ({device.Id})");
                DeviceFinilizingMainFlow?.Invoke(this, device);

                await _subp.AccountsUpdateProcessor.UpdateAccounts(device, vaultInfo, false);

                device.SetUserProperty(CustomProperties.HW_CONNECTION_STATE_PROP, HwVaultConnectionState.Online);

                if (_hesConnection.State == HesConnectionState.Connected)
                {
                    await _hesConnection.UpdateHwVaultProperties(new HwVaultInfoFromClientDto(device), false);
                }

                workflowFinishedSuccessfully = true;
            }
            catch (HideezException ex)
            {
                switch (ex.ErrorCode)
                {
                case HideezErrorCode.DeviceIsLocked:
                case HideezErrorCode.DeviceNotAssignedToUser:
                case HideezErrorCode.HesDeviceNotFound:
                case HideezErrorCode.HesDeviceCompromised:
                case HideezErrorCode.DeviceHasBeenWiped:
                    // There errors require bond removal
                    deleteVaultBond = true;
                    errorMessage    = HideezExceptionLocalization.GetErrorAsString(ex);
                    break;

                case HideezErrorCode.ButtonConfirmationTimeout:
                case HideezErrorCode.GetPinTimeout:
                case HideezErrorCode.GetActivationCodeTimeout:
                    // Silent handling
                    WriteLine(ex);
                    break;

                case HideezErrorCode.HesNotConnected:
                    // We need to display an error message which is different from one that is usually shown for that error code.
                    errorMessage = TranslationSource.Instance["ConnectionFlow.Error.UnexpectedlyLostNetworkConnection"];
                    break;

                default:
                    errorMessage = HideezExceptionLocalization.GetErrorAsString(ex);
                    break;
                }
            }
            catch (VaultFailedToAuthorizeException ex)
            {
                // User should never receive this error unless there is a bug in algorithm
                errorMessage = HideezExceptionLocalization.GetErrorAsString(ex);
            }
            catch (WorkstationUnlockFailedException ex)
            {
                // Silent handling of failed workstation unlock
                // The actual message will be displayed by credential provider
                WriteLine(ex);
            }
            catch (OperationCanceledException ex)
            {
                // Silent cancelation handling
                WriteLine(ex);
            }
            catch (TimeoutException ex)
            {
                // Silent timeout handling
                WriteLine(ex);
            }
            catch (WebSocketException ex)
            {
                // Retrieve the most inner WebSocketException to retrieve the error code
                if (ex.WebSocketErrorCode != 0)
                {
                    errorMessage = string.Format(TranslationSource.Instance["ConnectionFlow.Error.UnexpectedNetworkError"], ex.WebSocketErrorCode);
                }
                else if (ex.ErrorCode != 0)
                {
                    errorMessage = string.Format(TranslationSource.Instance["ConnectionFlow.Error.UnexpectedNetworkError"], ex.ErrorCode);
                }
                else if (ex.InnerException is Win32Exception)
                {
                    errorMessage = string.Format(TranslationSource.Instance["ConnectionFlow.Error.UnexpectedNetworkError"], "native " + (ex.InnerException as Win32Exception).NativeErrorCode);
                }
            }
            catch (Exception ex)
            {
                errorMessage = HideezExceptionLocalization.GetErrorAsString(ex);
            }
            finally
            {
                if (device != null)
                {
                    device.Disconnected       -= OnVaultDisconnectedDuringFlow;
                    device.OperationCancelled -= OnCancelledByVaultButton;
                }
                _screenActivator?.StopPeriodicScreenActivation();
            }

            await WorkflowCleanup(errorMessage, mac, device, workflowFinishedSuccessfully, deleteVaultBond);

            Finished?.Invoke(this, flowId);

            WriteLine($"Main workflow end {mac}");
        }
コード例 #6
0
        public async Task <HwVaultInfoFromHesDto> ActivateVault(IDevice device, HwVaultInfoFromHesDto vaultInfo, CancellationToken ct)
        {
            HwVaultInfoFromHesDto newVaultInfo = null;

            if (device.IsLocked && device.IsCanUnlock)
            {
                try
                {
                    do
                    {
                        ct.ThrowIfCancellationRequested();

                        var code = await _ui.GetActivationCode(device.Id, 30_000, ct); // Todo: activation timeout should not be a magic number

                        ct.ThrowIfCancellationRequested();

                        if (code.Length < 6)
                        {
                            await _ui.SendError(TranslationSource.Instance["ConnectionFlow.ActivationCode.Error.CodeToShort"], device.Mac);

                            continue;
                        }

                        if (code.Length > 8)
                        {
                            await _ui.SendError(TranslationSource.Instance["ConnectionFlow.ActivationCode.Error.CodeToLong"], device.Mac);

                            continue;
                        }

                        try
                        {
                            await device.UnlockDeviceCode(code);
                        }
                        catch (HideezException ex) when(ex.ErrorCode == HideezErrorCode.ERR_PIN_WRONG)  // Entered invalid activation code
                        {
                        }
                        catch (HideezException ex) when(ex.ErrorCode == HideezErrorCode.ERR_DEVICE_LOCKED_BY_CODE)  // Unlock attempts == 0
                        {
                            throw new WorkflowException(TranslationSource.Instance["ConnectionFlow.ActivationCode.Error.LockedByInvalidAttempts"]);
                        }

                        ct.ThrowIfCancellationRequested();

                        await device.RefreshDeviceInfo();

                        ct.ThrowIfCancellationRequested();

                        if (!device.IsLocked)
                        {
                            WriteLine($"({device.SerialNo}) unlocked with activation code");
                        }
                        else if (device.UnlockAttemptsRemain > 0)
                        {
                            await _ui.SendNotification(TranslationSource.Instance.Format("ConnectionFlow.ActivationCode.Error.InvalidCode", device.UnlockAttemptsRemain), device.Mac);
                        }
                        else
                        {
                            // We won't reach this line, but will leave it just in case
                            throw new WorkflowException(TranslationSource.Instance["ConnectionFlow.ActivationCode.Error.LockedByInvalidAttempts"]);
                        }
                    }while (device.IsLocked);
                }
                catch
                {
                    if (_hesConnection.State == HesConnectionState.Connected)
                    {
                        await _hesConnection.UpdateHwVaultStatus(new HwVaultInfoFromClientDto(device), ct);
                    }

                    throw;
                }
                finally
                {
                    await _ui.HideActivationCodeUi();
                }

                if (_hesConnection.State == HesConnectionState.Connected)
                {
                    newVaultInfo = await _hesConnection.UpdateHwVaultStatus(new HwVaultInfoFromClientDto(device), ct);
                }
            }

            if (device.IsLocked)
            {
                if (_hesConnection.State == HesConnectionState.Connected)
                {
                    throw new WorkflowException(TranslationSource.Instance["ConnectionFlow.ActivationCode.Error.VaultIsLocked"]);
                }
                else
                {
                    throw new WorkflowException(TranslationSource.Instance["ConnectionFlow.ActivationCode.Error.VaultIsLockedNoNetwork"]);
                }
            }

            return(newVaultInfo ?? vaultInfo);
        }
コード例 #7
0
        public async Task <IDevice> ConnectVault(string mac, bool rebondOnFail, CancellationToken ct)
        {
            ct.ThrowIfCancellationRequested();
            if (_bondManager.Exists(mac))
            {
                await _ui.SendNotification(TranslationSource.Instance["ConnectionFlow.Connection.Stage1"], mac);
            }
            else
            {
                await _ui.SendNotification(TranslationSource.Instance["ConnectionFlow.Connection.Stage1.PressButton"], mac);
            }

            bool    ltkErrorOccured = false;
            IDevice device          = null;

            try
            {
                device = await _deviceManager.ConnectDevice(mac, SdkConfig.ConnectDeviceTimeout);
            }
            catch (Exception ex) // Thrown when LTK error occurs in csr
            {
                WriteLine(ex);
                ltkErrorOccured = true;
            }

            if (device == null)
            {
                ct.ThrowIfCancellationRequested();

                string ltk = "";
                if (ltkErrorOccured)
                {
                    ltk             = "LTK error.";
                    ltkErrorOccured = false;
                }
                if (_bondManager.Exists(mac))
                {
                    await _ui.SendNotification(ltk + TranslationSource.Instance["ConnectionFlow.Connection.Stage2"], mac);
                }
                else
                {
                    await _ui.SendNotification(ltk + TranslationSource.Instance["ConnectionFlow.Connection.Stage2.PressButton"], mac);
                }

                try
                {
                    device = await _deviceManager.ConnectDevice(mac, SdkConfig.ConnectDeviceTimeout / 2);
                }
                catch (Exception ex) // Thrown when LTK error occurs in csr
                {
                    WriteLine(ex);
                    ltkErrorOccured = true;
                }

                if (device == null && rebondOnFail)
                {
                    ct.ThrowIfCancellationRequested();

                    // remove the bond and try one more time
                    await _deviceManager.RemoveByMac(mac);

                    if (ltkErrorOccured)
                    {
                        await _ui.SendNotification(TranslationSource.Instance["ConnectionFlow.Connection.Stage3.LtkError.PressButton"], mac); // TODO: Fix LTK error in CSR
                    }
                    else
                    {
                        await _ui.SendNotification(TranslationSource.Instance["ConnectionFlow.Connection.Stage3.PressButton"], mac);
                    }

                    device = await _deviceManager.ConnectDevice(mac, SdkConfig.ConnectDeviceTimeout);
                }
            }

            if (device == null)
            {
                throw new WorkflowException(TranslationSource.Instance.Format("ConnectionFlow.Connection.ConnectionFailed", mac));
            }

            return(device);
        }
コード例 #8
0
        public async Task CheckLicense(IDevice device, HwVaultInfoFromHesDto vaultInfo, CancellationToken ct)
        {
            if ((device.AccessLevel.IsLinkRequired || vaultInfo.NeedUpdateLicense) && _hesConnection.State == HesConnectionState.Connected)
            {
                await _ui.SendNotification(TranslationSource.Instance["ConnectionFlow.License.UpdatingLicenseMessage"], device.Mac);

                IList <HwVaultLicenseDto> licenses;
                if (device.AccessLevel.IsLinkRequired)
                {
                    licenses = await _hesConnection.GetHwVaultLicenses(device.SerialNo, ct);

                    WriteLine($"Received {licenses.Count} TOTAL licenses from HES");
                }
                else
                {
                    licenses = await _hesConnection.GetNewHwVaultLicenses(device.SerialNo, ct);

                    WriteLine($"Received {licenses.Count} NEW licenses from HES");
                }

                ct.ThrowIfCancellationRequested();

                if (licenses.Count > 0)
                {
                    for (int i = 0; i < licenses.Count; i++)
                    {
                        var license = licenses[i];

                        ct.ThrowIfCancellationRequested();

                        if (license.Data == null)
                        {
                            throw new WorkflowException(TranslationSource.Instance.Format("ConnectionFlow.License.Error.EmptyLicenseData", device.SerialNo));
                        }

                        if (license.Id == null)
                        {
                            throw new WorkflowException(TranslationSource.Instance.Format("ConnectionFlow.License.Error.EmptyLicenseId", device.SerialNo));
                        }

                        try
                        {
                            await device.LoadLicense(license.Data, SdkConfig.DefaultCommandTimeout);

                            WriteLine($"Loaded license ({license.Id}) into vault ({device.SerialNo}) in available slot");
                        }
                        catch (HideezException ex) when(ex.ErrorCode == HideezErrorCode.ERR_DEVICE_LOCKED_BY_CODE || ex.ErrorCode == HideezErrorCode.ERR_DEVICE_LOCKED_BY_PIN)
                        {
                            await device.LoadLicense(i, license.Data, SdkConfig.DefaultCommandTimeout);

                            WriteLine($"Loaded license ({license.Id}) into vault ({device.SerialNo}) into slot {i}");
                        }

                        await _hesConnection.OnHwVaultLicenseApplied(device.SerialNo, license.Id);
                    }
                }

                await device.RefreshDeviceInfo();

                ct.ThrowIfCancellationRequested();
            }

            if (device.LicenseInfo == 0)
            {
                if (_hesConnection.State == HesConnectionState.Connected)
                {
                    throw new WorkflowException(TranslationSource.Instance["ConnectionFlow.License.Error.NoLicensesAvailable"]);
                }
                else
                {
                    throw new WorkflowException(TranslationSource.Instance["ConnectionFlow.License.Error.CannotDownloadLicense"]);
                }
            }
        }