mirror of
https://github.com/Yubico/yubioath-flutter.git
synced 2024-11-25 23:14:18 +03:00
drop support for OTP mode
this commit drops support for OTP mode, where TOTP secrets could be stored on the YubiKey configuration slots
This commit is contained in:
parent
ccde2488ff
commit
89673b58eb
@ -128,10 +128,7 @@ def catch_error(f):
|
|||||||
return wrapped
|
return wrapped
|
||||||
|
|
||||||
|
|
||||||
def usb_selectable(dev, otp_mode):
|
def usb_selectable(dev):
|
||||||
if otp_mode:
|
|
||||||
return dev.mode.has_transport(TRANSPORT.OTP)
|
|
||||||
else:
|
|
||||||
return dev.mode.has_transport(TRANSPORT.CCID) and (
|
return dev.mode.has_transport(TRANSPORT.CCID) and (
|
||||||
dev.config.usb_enabled & APPLICATION.OATH)
|
dev.config.usb_enabled & APPLICATION.OATH)
|
||||||
|
|
||||||
@ -235,7 +232,7 @@ class Controller(object):
|
|||||||
return YubiKey(Descriptor.from_driver(drv), drv)
|
return YubiKey(Descriptor.from_driver(drv), drv)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def _get_devices(self, otp_mode=False):
|
def _get_devices(self):
|
||||||
res = []
|
res = []
|
||||||
descs_to_match = self._descs[:]
|
descs_to_match = self._descs[:]
|
||||||
handled_serials = set()
|
handled_serials = set()
|
||||||
@ -248,9 +245,9 @@ class Controller(object):
|
|||||||
return res
|
return res
|
||||||
|
|
||||||
serial = dev.serial
|
serial = dev.serial
|
||||||
selectable = usb_selectable(dev, otp_mode)
|
selectable = usb_selectable(dev)
|
||||||
|
|
||||||
if selectable and not otp_mode and transport == TRANSPORT.CCID:
|
if selectable and transport == TRANSPORT.CCID:
|
||||||
controller = OathController(dev.driver)
|
controller = OathController(dev.driver)
|
||||||
has_password = controller.locked
|
has_password = controller.locked
|
||||||
else:
|
else:
|
||||||
@ -279,17 +276,17 @@ class Controller(object):
|
|||||||
descs_to_match.remove(matching_descriptor)
|
descs_to_match.remove(matching_descriptor)
|
||||||
return res
|
return res
|
||||||
|
|
||||||
def refresh_devices(self, otp_mode=False, reader_filter=None):
|
def refresh_devices(self, reader_filter=None):
|
||||||
self._devices = []
|
self._devices = []
|
||||||
|
|
||||||
if not otp_mode and reader_filter:
|
if reader_filter:
|
||||||
self._reader_filter = reader_filter
|
self._reader_filter = reader_filter
|
||||||
dev = self._get_dev_from_reader()
|
dev = self._get_dev_from_reader()
|
||||||
if dev:
|
if dev:
|
||||||
if is_nfc(self._reader_filter):
|
if is_nfc(self._reader_filter):
|
||||||
selectable = nfc_selectable(dev)
|
selectable = nfc_selectable(dev)
|
||||||
else:
|
else:
|
||||||
selectable = usb_selectable(dev, otp_mode)
|
selectable = usb_selectable(dev)
|
||||||
if selectable:
|
if selectable:
|
||||||
controller = OathController(dev.driver)
|
controller = OathController(dev.driver)
|
||||||
has_password = controller.locked
|
has_password = controller.locked
|
||||||
@ -318,7 +315,7 @@ class Controller(object):
|
|||||||
self._current_derived_key = None
|
self._current_derived_key = None
|
||||||
return success({'devices': []})
|
return success({'devices': []})
|
||||||
|
|
||||||
self._devices = self._get_devices(otp_mode)
|
self._devices = self._get_devices()
|
||||||
|
|
||||||
# If no current serial, or current serial seems removed,
|
# If no current serial, or current serial seems removed,
|
||||||
# select the first serial found.
|
# select the first serial found.
|
||||||
@ -401,77 +398,10 @@ class Controller(object):
|
|||||||
if e.sw == SW.INCORRECT_PARAMETERS:
|
if e.sw == SW.INCORRECT_PARAMETERS:
|
||||||
return failure('validate_failed')
|
return failure('validate_failed')
|
||||||
|
|
||||||
def _otp_get_code_or_touch(
|
|
||||||
self, slot, digits, timestamp, wait_for_touch=False):
|
|
||||||
code = None
|
|
||||||
touch = False
|
|
||||||
with self._open_otp() as otp_controller:
|
|
||||||
try:
|
|
||||||
code = otp_controller.calculate(
|
|
||||||
slot, challenge=timestamp, totp=True,
|
|
||||||
digits=int(digits), wait_for_touch=wait_for_touch)
|
|
||||||
except YkpersError as e:
|
|
||||||
if e.errno == 11: # Operation would block, touch credential
|
|
||||||
touch = True
|
|
||||||
else:
|
|
||||||
raise
|
|
||||||
return code, touch
|
|
||||||
|
|
||||||
def otp_calculate_all(
|
|
||||||
self, slot1_digits, slot2_digits, timestamp):
|
|
||||||
valid_from = timestamp - (timestamp % 30)
|
|
||||||
valid_to = valid_from + 30
|
|
||||||
entries = []
|
|
||||||
|
|
||||||
def calc(slot, digits, label):
|
|
||||||
try:
|
|
||||||
code, touch = self._otp_get_code_or_touch(
|
|
||||||
slot, digits, timestamp)
|
|
||||||
entries.append({
|
|
||||||
'credential': cred_to_dict(
|
|
||||||
Credential(label.encode(), OATH_TYPE.TOTP, touch)),
|
|
||||||
'code': code_to_dict(
|
|
||||||
Code(code, valid_from, valid_to)) if code else None
|
|
||||||
})
|
|
||||||
except YkpersError as e:
|
|
||||||
if e.errno == 4:
|
|
||||||
pass
|
|
||||||
else:
|
|
||||||
raise
|
|
||||||
|
|
||||||
if slot1_digits:
|
|
||||||
calc(1, slot1_digits, "Slot 1")
|
|
||||||
|
|
||||||
if slot2_digits:
|
|
||||||
calc(2, slot2_digits, "Slot 2")
|
|
||||||
|
|
||||||
return success({'entries': entries})
|
|
||||||
|
|
||||||
def otp_calculate(self, slot, digits, credential, timestamp):
|
|
||||||
valid_from = timestamp - (timestamp % 30)
|
|
||||||
valid_to = valid_from + 30
|
|
||||||
code, _ = self._otp_get_code_or_touch(
|
|
||||||
slot, digits, timestamp, wait_for_touch=True)
|
|
||||||
return success({
|
|
||||||
'credential': credential,
|
|
||||||
'code': code_to_dict(Code(code, valid_from, valid_to))
|
|
||||||
})
|
|
||||||
|
|
||||||
def otp_slot_status(self):
|
def otp_slot_status(self):
|
||||||
with self._open_otp() as otp_controller:
|
with self._open_otp() as otp_controller:
|
||||||
return success({'status': otp_controller.slot_status})
|
return success({'status': otp_controller.slot_status})
|
||||||
|
|
||||||
def otp_add_credential(self, slot, key, touch):
|
|
||||||
key = parse_b32_key(key)
|
|
||||||
with self._open_otp() as otp_controller:
|
|
||||||
otp_controller.program_chalresp(int(slot), key, touch)
|
|
||||||
return success()
|
|
||||||
|
|
||||||
def otp_delete_credential(self, slot):
|
|
||||||
with self._open_otp() as otp_controller:
|
|
||||||
otp_controller.zap_slot(slot)
|
|
||||||
return success()
|
|
||||||
|
|
||||||
def _unlock(self, controller):
|
def _unlock(self, controller):
|
||||||
if controller.locked:
|
if controller.locked:
|
||||||
keys = self.settings.get('keys', {})
|
keys = self.settings.get('keys', {})
|
||||||
|
@ -86,20 +86,7 @@ Pane {
|
|||||||
hotpTouchTimer.start()
|
hotpTouchTimer.start()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (settings.otpMode) {
|
|
||||||
yubiKey.otpCalculate(credential, function (resp) {
|
|
||||||
if (resp.success) {
|
|
||||||
hotpTouchTimer.stop()
|
|
||||||
if (copy) {
|
|
||||||
copyCode(resp.code.value)
|
|
||||||
}
|
|
||||||
entries.updateEntry(resp)
|
|
||||||
} else {
|
|
||||||
navigator.snackBarError(resp.error_id)
|
|
||||||
console.log("calculate failed:", resp.error_id)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
yubiKey.calculate(credential, function (resp) {
|
yubiKey.calculate(credential, function (resp) {
|
||||||
if (resp.success) {
|
if (resp.success) {
|
||||||
hotpTouchTimer.stop()
|
hotpTouchTimer.stop()
|
||||||
@ -124,7 +111,7 @@ Pane {
|
|||||||
console.log("calculate failed:", resp.error_id)
|
console.log("calculate failed:", resp.error_id)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
copyCode(code.value)
|
copyCode(code.value)
|
||||||
}
|
}
|
||||||
@ -141,25 +128,7 @@ Pane {
|
|||||||
"message": qsTr("This will permanently delete the account from your YubiKey."),
|
"message": qsTr("This will permanently delete the account from your YubiKey."),
|
||||||
"description": qsTr("You will not be able to generate security codes for the account anymore. Make sure 2FA has been disabled before proceeding."),
|
"description": qsTr("You will not be able to generate security codes for the account anymore. Make sure 2FA has been disabled before proceeding."),
|
||||||
"acceptedCb": function () {
|
"acceptedCb": function () {
|
||||||
if (settings.otpMode) {
|
|
||||||
yubiKey.otpDeleteCredential(credential,
|
|
||||||
function (resp) {
|
|
||||||
if (resp.success) {
|
|
||||||
if (favorite)
|
|
||||||
{
|
|
||||||
toggleFavorite()
|
|
||||||
}
|
|
||||||
entries.deleteEntry(
|
|
||||||
credential.key)
|
|
||||||
navigator.snackBar(
|
|
||||||
qsTr("Account deleted"))
|
|
||||||
} else {
|
|
||||||
navigator.snackBarError(
|
|
||||||
resp.error_id)
|
|
||||||
console.log("delete failed:", resp.error_id)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
yubiKey.deleteCredential(credential,
|
yubiKey.deleteCredential(credential,
|
||||||
function (resp) {
|
function (resp) {
|
||||||
if (resp.success) {
|
if (resp.success) {
|
||||||
@ -181,7 +150,7 @@ Pane {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -32,15 +32,11 @@ Flickable {
|
|||||||
function acceptableInput() {
|
function acceptableInput() {
|
||||||
// trim spaces to accurately count length, parse_b32_key later trims them
|
// trim spaces to accurately count length, parse_b32_key later trims them
|
||||||
var secretKeyTrimmed = secretKeyLbl.text.replace(/ /g, "")
|
var secretKeyTrimmed = secretKeyLbl.text.replace(/ /g, "")
|
||||||
if (settings.otpMode) {
|
|
||||||
return secretKeyTrimmed.length > 0 && secretKeyTrimmed.length <= 32
|
|
||||||
} else {
|
|
||||||
var nameAndKey = nameLbl.text.length > 0
|
var nameAndKey = nameLbl.text.length > 0
|
||||||
&& secretKeyTrimmed.length > 0
|
&& secretKeyTrimmed.length > 0
|
||||||
var okTotalLength = (nameLbl.text.length + issuerLbl.text.length) < 60
|
var okTotalLength = (nameLbl.text.length + issuerLbl.text.length) < 60
|
||||||
return nameAndKey && okTotalLength
|
return nameAndKey && okTotalLength
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
function addCredentialNoCopy() {
|
function addCredentialNoCopy() {
|
||||||
addCredential(true)
|
addCredential(true)
|
||||||
@ -66,12 +62,6 @@ Flickable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function _otpAddCredential() {
|
|
||||||
yubiKey.otpAddCredential(otpSlotComboBox.currentText,
|
|
||||||
secretKeyLbl.text,
|
|
||||||
requireTouchCheckBox.checked, callback)
|
|
||||||
}
|
|
||||||
|
|
||||||
function _ccidAddCredential(overwrite) {
|
function _ccidAddCredential(overwrite) {
|
||||||
yubiKey.ccidAddCredential(nameLbl.text, secretKeyLbl.text,
|
yubiKey.ccidAddCredential(nameLbl.text, secretKeyLbl.text,
|
||||||
issuerLbl.text,
|
issuerLbl.text,
|
||||||
@ -93,27 +83,7 @@ Flickable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (acceptableInput()) {
|
if (acceptableInput()) {
|
||||||
if (settings.otpMode) {
|
|
||||||
yubiKey.otpSlotStatus(function (resp) {
|
|
||||||
if (resp.success) {
|
|
||||||
if (resp.status[parseInt(
|
|
||||||
otpSlotComboBox.currentText) - 1]) {
|
|
||||||
navigator.confirm({
|
|
||||||
"heading": qsTr("Overwrite?"),
|
|
||||||
"message": qsTr("This slot is already configured, do you want to overwrite it?"),
|
|
||||||
"acceptedCb": _otpAddCredential
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
_otpAddCredential()
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
navigator.snackBarError(navigator.getErrorMessage(
|
|
||||||
resp.error_id))
|
|
||||||
}
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
_ccidAddCredentialNoOverwrite()
|
_ccidAddCredentialNoOverwrite()
|
||||||
}
|
|
||||||
settings.requireTouch = requireTouchCheckBox.checked
|
settings.requireTouch = requireTouchCheckBox.checked
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -121,17 +91,6 @@ Flickable {
|
|||||||
|
|
||||||
Keys.onEscapePressed: navigator.home()
|
Keys.onEscapePressed: navigator.home()
|
||||||
|
|
||||||
function getEnabledOtpSlots() {
|
|
||||||
var res = []
|
|
||||||
if (settings.slot1digits) {
|
|
||||||
res.push(1)
|
|
||||||
}
|
|
||||||
if (settings.slot2digits) {
|
|
||||||
res.push(2)
|
|
||||||
}
|
|
||||||
return res
|
|
||||||
}
|
|
||||||
|
|
||||||
ColumnLayout {
|
ColumnLayout {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
Layout.fillHeight: true
|
Layout.fillHeight: true
|
||||||
@ -208,7 +167,7 @@ Flickable {
|
|||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
text: credential
|
text: credential
|
||||||
&& credential.issuer ? credential.issuer : ""
|
&& credential.issuer ? credential.issuer : ""
|
||||||
visible: !settings.otpMode
|
visible: true
|
||||||
onSubmit: addCredential()
|
onSubmit: addCredential()
|
||||||
}
|
}
|
||||||
StyledTextField {
|
StyledTextField {
|
||||||
@ -217,7 +176,7 @@ Flickable {
|
|||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
required: true
|
required: true
|
||||||
text: credential && credential.name ? credential.name : ""
|
text: credential && credential.name ? credential.name : ""
|
||||||
visible: !settings.otpMode
|
visible: true
|
||||||
onSubmit: addCredential()
|
onSubmit: addCredential()
|
||||||
}
|
}
|
||||||
StyledTextField {
|
StyledTextField {
|
||||||
@ -234,16 +193,6 @@ Flickable {
|
|||||||
onSubmit: addCredential()
|
onSubmit: addCredential()
|
||||||
}
|
}
|
||||||
|
|
||||||
RowLayout {
|
|
||||||
Layout.fillWidth: true
|
|
||||||
StyledComboBox {
|
|
||||||
label: qsTr("Slot")
|
|
||||||
id: otpSlotComboBox
|
|
||||||
model: getEnabledOtpSlots()
|
|
||||||
}
|
|
||||||
visible: settings.otpMode
|
|
||||||
}
|
|
||||||
|
|
||||||
RowLayout {
|
RowLayout {
|
||||||
CheckBox {
|
CheckBox {
|
||||||
id: requireTouchCheckBox
|
id: requireTouchCheckBox
|
||||||
@ -255,14 +204,13 @@ Flickable {
|
|||||||
font.pixelSize: 13
|
font.pixelSize: 13
|
||||||
}
|
}
|
||||||
visible: yubiKey.supportsTouchCredentials()
|
visible: yubiKey.supportsTouchCredentials()
|
||||||
|| settings.otpMode
|
|
||||||
}
|
}
|
||||||
|
|
||||||
StyledExpansionPanel {
|
StyledExpansionPanel {
|
||||||
id: advancedSettingsPanel
|
id: advancedSettingsPanel
|
||||||
label: qsTr("Advanced settings")
|
label: qsTr("Advanced settings")
|
||||||
description: qsTr("Changing these may result in unexpected behavior.")
|
description: qsTr("Changing these may result in unexpected behavior.")
|
||||||
visible: manualEntry && !settings.otpMode
|
visible: manualEntry
|
||||||
dropShadow: false
|
dropShadow: false
|
||||||
backgroundColor: "transparent"
|
backgroundColor: "transparent"
|
||||||
|
|
||||||
@ -326,7 +274,7 @@ Flickable {
|
|||||||
id: addBtn
|
id: addBtn
|
||||||
text: qsTr("Add")
|
text: qsTr("Add")
|
||||||
toolTipText: qsTr("Add account to YubiKey")
|
toolTipText: qsTr("Add account to YubiKey")
|
||||||
enabled: settings.otpMode ? secretKeyLbl.validated && acceptableInput() : secretKeyLbl.validated && acceptableInput() && nameLbl.validated
|
enabled: secretKeyLbl.validated && acceptableInput() && nameLbl.validated
|
||||||
Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter
|
Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter
|
||||||
onClicked: addCredential()
|
onClicked: addCredential()
|
||||||
Layout.bottomMargin: -16
|
Layout.bottomMargin: -16
|
||||||
|
@ -45,7 +45,7 @@ ColumnLayout {
|
|||||||
Label {
|
Label {
|
||||||
text: {
|
text: {
|
||||||
if (yubiKey.availableDevices.length > 0 && !yubiKey.availableDevices.some(dev => dev.selectable)) {
|
if (yubiKey.availableDevices.length > 0 && !yubiKey.availableDevices.some(dev => dev.selectable)) {
|
||||||
return qsTr("Yubico Authenticator requires a CCID/OTP enabled and compatible YubiKey.")
|
return qsTr("Yubico Authenticator requires a CCID enabled and compatible YubiKey.")
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return ""
|
return ""
|
||||||
@ -76,8 +76,8 @@ ColumnLayout {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Label {
|
Label {
|
||||||
text: settings.useCustomReader ? qsTr("Interface: CCID - Custom reader") : qsTr("Interface: OTP")
|
text: qsTr("Interface: CCID - Custom reader")
|
||||||
visible: settings.useCustomReader || settings.otpMode
|
visible: settings.useCustomReader
|
||||||
Layout.minimumWidth: 300
|
Layout.minimumWidth: 300
|
||||||
Layout.maximumWidth: app.width - dynamicMargin
|
Layout.maximumWidth: app.width - dynamicMargin
|
||||||
< dynamicWidth ? app.width - dynamicMargin : dynamicWidth
|
< dynamicWidth ? app.width - dynamicMargin : dynamicWidth
|
||||||
|
@ -145,26 +145,6 @@ Flickable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ListModel {
|
|
||||||
id: otpModeDigits
|
|
||||||
|
|
||||||
ListElement {
|
|
||||||
text: "Off"
|
|
||||||
value: 0
|
|
||||||
}
|
|
||||||
ListElement {
|
|
||||||
text: "6"
|
|
||||||
value: 6
|
|
||||||
}
|
|
||||||
ListElement {
|
|
||||||
text: "7"
|
|
||||||
value: 7
|
|
||||||
}
|
|
||||||
ListElement {
|
|
||||||
text: "8"
|
|
||||||
value: 8
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ColumnLayout {
|
ColumnLayout {
|
||||||
id: content
|
id: content
|
||||||
@ -248,7 +228,7 @@ Flickable {
|
|||||||
id: passwordManagementPanel
|
id: passwordManagementPanel
|
||||||
label: !!yubiKey.currentDevice && yubiKey.currentDevice.hasPassword ? qsTr("Change password") : qsTr("Set password")
|
label: !!yubiKey.currentDevice && yubiKey.currentDevice.hasPassword ? qsTr("Change password") : qsTr("Set password")
|
||||||
description: qsTr("For additional security the YubiKey may be protected with a password.")
|
description: qsTr("For additional security the YubiKey may be protected with a password.")
|
||||||
visible: !!yubiKey.currentDevice && !settings.otpMode
|
visible: !!yubiKey.currentDevice
|
||||||
|
|
||||||
ColumnLayout {
|
ColumnLayout {
|
||||||
|
|
||||||
@ -308,7 +288,7 @@ Flickable {
|
|||||||
label: qsTr("Reset")
|
label: qsTr("Reset")
|
||||||
description: qsTr("Warning: Reset will delete all accounts and restore factory defaults.")
|
description: qsTr("Warning: Reset will delete all accounts and restore factory defaults.")
|
||||||
isEnabled: false
|
isEnabled: false
|
||||||
visible: !!yubiKey.currentDevice && !settings.otpMode
|
visible: !!yubiKey.currentDevice
|
||||||
toolButtonIcon: "../images/reset.svg"
|
toolButtonIcon: "../images/reset.svg"
|
||||||
toolButtonToolTip: qsTr("Reset device")
|
toolButtonToolTip: qsTr("Reset device")
|
||||||
toolButton.onClicked: navigator.confirm({
|
toolButton.onClicked: navigator.confirm({
|
||||||
@ -382,32 +362,15 @@ Flickable {
|
|||||||
id: interfacePanel
|
id: interfacePanel
|
||||||
label: qsTr("Interface")
|
label: qsTr("Interface")
|
||||||
description: qsTr("Configure how to communicate with the YubiKey.")
|
description: qsTr("Configure how to communicate with the YubiKey.")
|
||||||
property bool otpModeSelected: interfaceCombobox.currentIndex === 2
|
|
||||||
property bool customReaderSelected: interfaceCombobox.currentIndex === 1
|
property bool customReaderSelected: interfaceCombobox.currentIndex === 1
|
||||||
property bool aboutToChange: (otpModeSelected !== settings.otpMode)
|
property bool aboutToChange: customReaderSelected !== settings.useCustomReader
|
||||||
|| (slot1DigitsComboBox.currentIndex
|
|
||||||
!== getComboBoxIndex(
|
|
||||||
settings.slot1digits))
|
|
||||||
|| (slot2DigitsComboBox.currentIndex
|
|
||||||
!== getComboBoxIndex(
|
|
||||||
settings.slot2digits))
|
|
||||||
|| customReaderSelected !== settings.useCustomReader
|
|
||||||
|| readerFilter.text !== settings.customReaderName && readerFilter.text.length > 0
|
|| readerFilter.text !== settings.customReaderName && readerFilter.text.length > 0
|
||||||
|
|
||||||
function isValidMode() {
|
function isValidMode() {
|
||||||
return aboutToChange
|
return aboutToChange
|
||||||
&& ((otpModeSelected
|
|
||||||
&& (slot1DigitsComboBox.currentIndex !== 0
|
|
||||||
|| slot2DigitsComboBox.currentIndex !== 0))
|
|
||||||
|| !otpModeSelected)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function setInterface() {
|
function setInterface() {
|
||||||
settings.slot1digits = otpModeDigits.get(
|
|
||||||
slot1DigitsComboBox.currentIndex).value
|
|
||||||
settings.slot2digits = otpModeDigits.get(
|
|
||||||
slot2DigitsComboBox.currentIndex).value
|
|
||||||
settings.otpMode = otpModeSelected
|
|
||||||
settings.useCustomReader = customReaderSelected
|
settings.useCustomReader = customReaderSelected
|
||||||
settings.customReaderName = readerFilter.text
|
settings.customReaderName = readerFilter.text
|
||||||
yubiKey.clearCurrentDeviceAndEntries()
|
yubiKey.clearCurrentDeviceAndEntries()
|
||||||
@ -440,14 +403,12 @@ Flickable {
|
|||||||
StyledComboBox {
|
StyledComboBox {
|
||||||
id: interfaceCombobox
|
id: interfaceCombobox
|
||||||
label: qsTr("Interface")
|
label: qsTr("Interface")
|
||||||
model: ["CCID (recommended)", "CCID with custom reader", "OTP"]
|
model: ["CCID (recommended)", "CCID with custom reader"]
|
||||||
currentIndex: getCurrentIndex()
|
currentIndex: getCurrentIndex()
|
||||||
|
|
||||||
function getCurrentIndex() {
|
function getCurrentIndex() {
|
||||||
if (settings.otpMode) {
|
|
||||||
return 2
|
if (settings.useCustomReader) {
|
||||||
}
|
|
||||||
if (settings.useCustomReader && !settings.otpMode) {
|
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
// default
|
// default
|
||||||
@ -457,46 +418,6 @@ Flickable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
RowLayout {
|
|
||||||
visible: interfacePanel.otpModeSelected
|
|
||||||
Label {
|
|
||||||
Layout.fillWidth: true
|
|
||||||
font.pixelSize: 12
|
|
||||||
color: primaryColor
|
|
||||||
opacity: lowEmphasis
|
|
||||||
text: qsTr("Using OTP slots should be considered for special cases only.")
|
|
||||||
wrapMode: Text.WordWrap
|
|
||||||
Layout.rowSpan: 1
|
|
||||||
bottomPadding: 8
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
RowLayout {
|
|
||||||
visible: interfacePanel.otpModeSelected
|
|
||||||
|
|
||||||
StyledComboBox {
|
|
||||||
id: slot1DigitsComboBox
|
|
||||||
label: qsTr("Slot 1 digits")
|
|
||||||
comboBox.textRole: "text"
|
|
||||||
model: otpModeDigits
|
|
||||||
currentIndex: interfacePanel.getComboBoxIndex(
|
|
||||||
settings.slot1digits)
|
|
||||||
}
|
|
||||||
|
|
||||||
Item {
|
|
||||||
width: 16
|
|
||||||
}
|
|
||||||
|
|
||||||
StyledComboBox {
|
|
||||||
id: slot2DigitsComboBox
|
|
||||||
label: qsTr("Slot 2 digits")
|
|
||||||
comboBox.textRole: "text"
|
|
||||||
model: otpModeDigits
|
|
||||||
currentIndex: interfacePanel.getComboBoxIndex(
|
|
||||||
settings.slot2digits)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ColumnLayout {
|
ColumnLayout {
|
||||||
visible: interfacePanel.customReaderSelected
|
visible: interfacePanel.customReaderSelected
|
||||||
|
|
||||||
|
@ -32,7 +32,7 @@ ToolBar {
|
|||||||
function shouldShowSearch() {
|
function shouldShowSearch() {
|
||||||
return !!(navigator.currentItem
|
return !!(navigator.currentItem
|
||||||
&& navigator.currentItem.objectName === 'credentialsView'
|
&& navigator.currentItem.objectName === 'credentialsView'
|
||||||
&& entries.count > 0 && !settings.otpMode)
|
&& entries.count > 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
function shouldShowSettings() {
|
function shouldShowSettings() {
|
||||||
|
@ -239,7 +239,7 @@ Python {
|
|||||||
function refreshDevicesDefault() {
|
function refreshDevicesDefault() {
|
||||||
poller.running = false
|
poller.running = false
|
||||||
let customReaderName = settings.useCustomReader ? settings.customReaderName : null
|
let customReaderName = settings.useCustomReader ? settings.customReaderName : null
|
||||||
refreshDevices(settings.otpMode, customReaderName, function (resp) {
|
refreshDevices(customReaderName, function (resp) {
|
||||||
if (resp.success) {
|
if (resp.success) {
|
||||||
availableDevices = resp.devices
|
availableDevices = resp.devices
|
||||||
// no current device, or current device is no longer available, pick a new one
|
// no current device, or current device is no longer available, pick a new one
|
||||||
@ -286,16 +286,13 @@ Python {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (settings.useCustomReader && !settings.otpMode) {
|
if (settings.useCustomReader) {
|
||||||
checkReaders(settings.customReaderName, callback)
|
checkReaders(settings.customReaderName, callback)
|
||||||
} else {
|
} else {
|
||||||
checkDescriptors(callback)
|
checkDescriptors(callback)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!settings.otpMode) {
|
|
||||||
refreshReaders()
|
refreshReaders()
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
function calculateAll(cb) {
|
function calculateAll(cb) {
|
||||||
|
|
||||||
@ -323,11 +320,9 @@ Python {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (settings.otpMode) {
|
|
||||||
otpCalculateAll(callback)
|
|
||||||
} else {
|
|
||||||
ccidCalculateAll(callback)
|
ccidCalculateAll(callback)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateNextCalculateAll() {
|
function updateNextCalculateAll() {
|
||||||
@ -380,14 +375,8 @@ Python {
|
|||||||
doCall('yubikey.controller.ccid_calculate_all', [now], cb)
|
doCall('yubikey.controller.ccid_calculate_all', [now], cb)
|
||||||
}
|
}
|
||||||
|
|
||||||
function otpCalculateAll(cb) {
|
function refreshDevices(customReader, cb) {
|
||||||
var now = Utils.getNow()
|
doCall('yubikey.controller.refresh_devices', [customReader], cb)
|
||||||
doCall('yubikey.controller.otp_calculate_all',
|
|
||||||
[settings.slot1digits, settings.slot2digits, now], cb)
|
|
||||||
}
|
|
||||||
|
|
||||||
function refreshDevices(otpMode, customReader, cb) {
|
|
||||||
doCall('yubikey.controller.refresh_devices', [otpMode, customReader], cb)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function selectCurrentSerial(serial, cb) {
|
function selectCurrentSerial(serial, cb) {
|
||||||
@ -401,23 +390,6 @@ Python {
|
|||||||
[credential, nowAndMargin], cb)
|
[credential, nowAndMargin], cb)
|
||||||
}
|
}
|
||||||
|
|
||||||
function otpCalculate(credential, cb) {
|
|
||||||
var margin = credential.touch ? 10 : 0
|
|
||||||
var nowAndMargin = Utils.getNow() + margin
|
|
||||||
var slot = (credential.key === "Slot 1") ? 1 : 2
|
|
||||||
var digits = (slot === 1) ? settings.slot1digits : settings.slot2digits
|
|
||||||
doCall('yubikey.controller.otp_calculate',
|
|
||||||
[slot, digits, credential, nowAndMargin], cb)
|
|
||||||
}
|
|
||||||
|
|
||||||
function otpDeleteCredential(credential, cb) {
|
|
||||||
var slot = (credential.key === "Slot 1") ? 1 : 2
|
|
||||||
doCall('yubikey.controller.otp_delete_credential', [slot], cb)
|
|
||||||
}
|
|
||||||
|
|
||||||
function otpAddCredential(slot, key, touch, cb) {
|
|
||||||
doCall('yubikey.controller.otp_add_credential', [slot, key, touch], cb)
|
|
||||||
}
|
|
||||||
|
|
||||||
function ccidAddCredential(name, key, issuer, oathType, algo, digits, period, touch, overwrite, cb) {
|
function ccidAddCredential(name, key, issuer, oathType, algo, digits, period, touch, overwrite, cb) {
|
||||||
doCall('yubikey.controller.ccid_add_credential',
|
doCall('yubikey.controller.ccid_add_credential',
|
||||||
|
24
qml/main.qml
24
qml/main.qml
@ -178,23 +178,6 @@ ApplicationWindow {
|
|||||||
qsTr("Touch your YubiKey now to generate security code."),
|
qsTr("Touch your YubiKey now to generate security code."),
|
||||||
SystemTrayIcon.NoIcon)
|
SystemTrayIcon.NoIcon)
|
||||||
}
|
}
|
||||||
if (settings.otpMode) {
|
|
||||||
yubiKey.otpCalculate(credential, function (resp) {
|
|
||||||
if (resp.success) {
|
|
||||||
clipBoard.push(resp.code.value)
|
|
||||||
sysTrayIcon.showMessage(
|
|
||||||
qsTr("Copied to clipboard"),
|
|
||||||
"The code for " + text + " is now in the clipboard.",
|
|
||||||
SystemTrayIcon.NoIcon)
|
|
||||||
} else {
|
|
||||||
sysTrayIcon.showMessage(
|
|
||||||
"Error",
|
|
||||||
"calculate failed: " + resp.error_id,
|
|
||||||
SystemTrayIcon.NoIcon)
|
|
||||||
console.log("calculate failed:", resp.error_id)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
yubiKey.calculate(credential, function (resp) {
|
yubiKey.calculate(credential, function (resp) {
|
||||||
if (resp.success) {
|
if (resp.success) {
|
||||||
clipBoard.push(resp.code.value)
|
clipBoard.push(resp.code.value)
|
||||||
@ -210,7 +193,7 @@ ApplicationWindow {
|
|||||||
console.log("calculate failed:", resp.error_id)
|
console.log("calculate failed:", resp.error_id)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function getFavoriteEntries() {
|
function getFavoriteEntries() {
|
||||||
@ -291,11 +274,6 @@ ApplicationWindow {
|
|||||||
Settings {
|
Settings {
|
||||||
id: settings
|
id: settings
|
||||||
|
|
||||||
// Can be 0 (off), 6, 7 or 8
|
|
||||||
property int slot1digits
|
|
||||||
property int slot2digits
|
|
||||||
|
|
||||||
property bool otpMode
|
|
||||||
property bool useCustomReader
|
property bool useCustomReader
|
||||||
property string customReaderName
|
property string customReaderName
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user