2019-09-09 15:12:58 +03:00
|
|
|
import QtQuick 2.9
|
|
|
|
import QtQuick.Controls 2.2
|
|
|
|
import QtQuick.Layouts 1.3
|
|
|
|
import QtQuick.Controls.Material 2.2
|
2017-02-20 15:47:39 +03:00
|
|
|
import Qt.labs.settings 1.0
|
2019-09-09 15:12:58 +03:00
|
|
|
import Qt.labs.platform 1.1
|
|
|
|
import QtQuick.Window 2.2
|
|
|
|
import QtQml 2.12
|
2017-01-27 15:55:38 +03:00
|
|
|
|
|
|
|
ApplicationWindow {
|
2017-02-20 15:47:39 +03:00
|
|
|
|
2019-09-09 15:12:58 +03:00
|
|
|
id: app
|
2017-09-12 17:21:38 +03:00
|
|
|
|
2019-09-09 15:12:58 +03:00
|
|
|
width: 360
|
|
|
|
height: 620
|
|
|
|
minimumWidth: 360
|
|
|
|
minimumHeight: 208
|
|
|
|
visible: false
|
2017-03-22 14:24:02 +03:00
|
|
|
|
2019-09-09 15:12:58 +03:00
|
|
|
flags: Qt.Window | Qt.WindowFullscreenButtonHint | Qt.WindowTitleHint
|
|
|
|
| Qt.WindowSystemMenuHint | Qt.WindowMinMaxButtonsHint
|
|
|
|
| Qt.WindowCloseButtonHint | Qt.WindowFullscreenButtonHint
|
2017-03-30 14:14:24 +03:00
|
|
|
|
2019-09-09 15:12:58 +03:00
|
|
|
readonly property string yubicoGreen: "#9aca3c"
|
|
|
|
readonly property string yubicoBlue: "#284c61"
|
|
|
|
readonly property string yubicoWhite: "#ffffff"
|
|
|
|
readonly property string yubicoGrey: "#939598"
|
|
|
|
readonly property string yubicoRed: "#fd5552"
|
2017-01-27 15:55:38 +03:00
|
|
|
|
2019-09-09 15:12:58 +03:00
|
|
|
readonly property string defaultDark: "#303030"
|
|
|
|
readonly property string defaultDarkLighter: "#383838"
|
|
|
|
readonly property string defaultDarkOverlay: "#4a4a4a"
|
|
|
|
readonly property string defaultDarkForeground: "#fafafa"
|
2017-02-03 11:58:17 +03:00
|
|
|
|
2019-09-09 15:12:58 +03:00
|
|
|
readonly property string defaultLight: "#fafafa"
|
|
|
|
readonly property string defaultLightDarker: "#ffffff"
|
|
|
|
readonly property string defaultLightOverlay: "#dddddd"
|
|
|
|
readonly property string defaultLightForeground: "#565656"
|
2017-02-20 14:27:10 +03:00
|
|
|
|
2019-09-09 15:12:58 +03:00
|
|
|
readonly property string defaultBackground: isDark() ? "#303030" : "#f7f8f9"
|
2017-02-16 17:22:20 +03:00
|
|
|
|
2019-09-09 15:12:58 +03:00
|
|
|
property string formUnderline: isDark() ? "#737373" : "#d8d8d8"
|
|
|
|
property string formLabel: isDark() ? "#c0c0c0" : "#a0a0a0"
|
|
|
|
property string formText: isDark() ? "#f0f0f0" : "#767676"
|
|
|
|
property string formPlaceholderText: isDark() ? "#808080" : "#b0b0b0"
|
|
|
|
property string formDropShdaow: isDark() ? "#1f1f1f" : "#cbcbcb"
|
|
|
|
property string formImageOverlay: isDark() ? "#d8d8d8" : "#727272"
|
|
|
|
property string formTitleUnderline: isDark() ? "#424242" : "#ffffff"
|
|
|
|
property string formStepBackground: isDark() ? "#565656" : "#bbbbbb"
|
2017-02-10 16:01:49 +03:00
|
|
|
|
2019-09-09 15:12:58 +03:00
|
|
|
property string credentialCardCurrentItem: isDark() ? "#4a4a4a" : "#e5e5e5"
|
|
|
|
property string credentialCardHovered: isDark() ? "#3e3e3e" : "#efefef"
|
|
|
|
property string credentialCardNormal: isDark() ? "#363636" : "#ffffff"
|
2017-02-17 10:52:34 +03:00
|
|
|
|
2019-09-09 15:12:58 +03:00
|
|
|
property string iconButtonNormal: isDark() ? "#B7B7B7" : "#767676"
|
|
|
|
property string iconButtonHovered: isDark() ? "#ffffff" : "#202020"
|
2017-03-18 20:43:11 +03:00
|
|
|
|
2019-09-09 15:12:58 +03:00
|
|
|
property string toolTipForeground: app.isDark() ? "#fafafa" : "#fbfbfb"
|
|
|
|
property string toolTipBackground: app.isDark() ? "#4a4a4a" : "#7f7f7f"
|
2017-03-01 13:57:40 +03:00
|
|
|
|
2019-09-09 15:12:58 +03:00
|
|
|
property var currentCredentialCard
|
2017-01-27 15:55:38 +03:00
|
|
|
|
2019-09-09 15:12:58 +03:00
|
|
|
Material.theme: settings.theme
|
|
|
|
Material.primary: yubicoGreen
|
|
|
|
Material.accent: yubicoGreen
|
|
|
|
Material.foreground: isDark(
|
|
|
|
) ? defaultDarkForeground : defaultLightForeground
|
|
|
|
Material.background: defaultBackground
|
|
|
|
header: StyledToolBar {
|
|
|
|
id: toolBar
|
2017-01-27 15:55:38 +03:00
|
|
|
}
|
|
|
|
|
2019-09-09 15:12:58 +03:00
|
|
|
// Don't refresh credentials when window is minimized or hidden
|
|
|
|
// See http://doc.qt.io/qt-5/qwindow.html#Visibility-enum
|
|
|
|
property bool isInForeground: visibility != 3 && visibility != 0
|
|
|
|
onIsInForegroundChanged: {
|
|
|
|
(poller.running = isInForeground || settings.closeToTray)
|
2017-02-17 16:09:55 +03:00
|
|
|
}
|
2019-09-09 15:12:58 +03:00
|
|
|
Component.onCompleted: {
|
|
|
|
updateTrayVisibility()
|
|
|
|
ensureMinimumWindowSize()
|
|
|
|
ensureValidWindowPosition()
|
|
|
|
app.visible = !(settings.closeToTray && settings.hideOnLaunch)
|
2017-01-27 15:55:38 +03:00
|
|
|
}
|
|
|
|
|
2019-09-09 15:12:58 +03:00
|
|
|
Component.onDestruction: saveScreenLayout()
|
2017-09-12 17:21:38 +03:00
|
|
|
|
2019-09-09 15:12:58 +03:00
|
|
|
function enableLogging(logLevel) {
|
|
|
|
yubiKey.enableLogging(logLevel, null)
|
2017-11-21 18:06:04 +03:00
|
|
|
}
|
2019-09-09 15:12:58 +03:00
|
|
|
function enableLoggingToFile(logLevellogFile) {
|
|
|
|
yubiKey.enableLogging(logLevel, logFile)
|
2017-11-29 16:45:53 +03:00
|
|
|
}
|
2019-09-09 15:12:58 +03:00
|
|
|
function disableLogging() {
|
|
|
|
yubiKey.disableLogging()
|
2017-08-15 10:25:10 +03:00
|
|
|
}
|
|
|
|
|
2019-09-09 15:12:58 +03:00
|
|
|
function isDark() {
|
|
|
|
return app.Material.theme === Material.Dark
|
2017-11-29 13:53:50 +03:00
|
|
|
}
|
|
|
|
|
2017-05-11 16:25:50 +03:00
|
|
|
function saveScreenLayout() {
|
|
|
|
settings.desktopAvailableWidth = Screen.desktopAvailableWidth
|
|
|
|
settings.desktopAvailableHeight = Screen.desktopAvailableHeight
|
|
|
|
}
|
|
|
|
|
2019-09-09 15:12:58 +03:00
|
|
|
function ensureMinimumWindowSize() {
|
|
|
|
app.width = width < minimumWidth ? minimumWidth : width
|
|
|
|
app.height = height < minimumHeight ? minimumHeight : height
|
|
|
|
}
|
|
|
|
|
2017-05-12 11:02:13 +03:00
|
|
|
function ensureValidWindowPosition() {
|
|
|
|
// If we have the same desktop dimensions as last time, use the saved position.
|
2017-05-11 16:25:50 +03:00
|
|
|
// If not, put the window in the middle of the screen.
|
|
|
|
var savedScreenLayout = (settings.desktopAvailableWidth === Screen.desktopAvailableWidth)
|
|
|
|
&& (settings.desktopAvailableHeight === Screen.desktopAvailableHeight)
|
2019-09-09 15:12:58 +03:00
|
|
|
app.x = (savedScreenLayout) ? settings.x : Screen.width / 2 - app.width / 2
|
|
|
|
app.y = (savedScreenLayout) ? settings.y : Screen.height / 2 - app.height / 2
|
2017-05-11 16:25:50 +03:00
|
|
|
}
|
|
|
|
|
2019-09-09 15:12:58 +03:00
|
|
|
function updateTrayVisibility() {
|
|
|
|
// When the tray option is enabled, closing the last window
|
|
|
|
// doesn't actually close the application.
|
|
|
|
application.quitOnLastWindowClosed = !settings.closeToTray
|
2017-03-17 15:52:13 +03:00
|
|
|
}
|
|
|
|
|
2019-09-09 15:12:58 +03:00
|
|
|
function calculateFavorite(credential, text) {
|
|
|
|
if (credential && credential.touch) {
|
|
|
|
sysTrayIcon.showMessage(
|
2019-09-09 17:59:30 +03:00
|
|
|
qsTr("Touch required"),
|
|
|
|
qsTr("Touch your YubiKey now to generate code for protected credential."),
|
2019-09-09 15:12:58 +03:00
|
|
|
SystemTrayIcon.NoIcon)
|
|
|
|
}
|
|
|
|
if (settings.otpMode) {
|
|
|
|
yubiKey.otpCalculate(credential, function (resp) {
|
|
|
|
if (resp.success) {
|
|
|
|
clipBoard.push(resp.code.value)
|
|
|
|
sysTrayIcon.showMessage(
|
2019-09-09 17:59:30 +03:00
|
|
|
qsTr("Copied to clipboard"),
|
2019-09-09 15:12:58 +03:00
|
|
|
"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) {
|
|
|
|
if (resp.success) {
|
|
|
|
clipBoard.push(resp.code.value)
|
|
|
|
sysTrayIcon.showMessage(
|
2019-09-09 17:59:30 +03:00
|
|
|
qsTr("Copied to clipboard"),
|
2019-09-09 15:12:58 +03:00
|
|
|
"The code for " + text + " is now in the clipboard.",
|
|
|
|
SystemTrayIcon.NoIcon)
|
|
|
|
} else {
|
|
|
|
sysTrayIcon.showMessage(
|
2019-09-09 17:59:30 +03:00
|
|
|
qsTr("Error"),
|
2019-09-09 15:12:58 +03:00
|
|
|
"calculate failed: " + resp.error_id,
|
|
|
|
SystemTrayIcon.NoIcon)
|
|
|
|
console.log("calculate failed:", resp.error_id)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
2017-03-09 12:49:42 +03:00
|
|
|
}
|
|
|
|
|
2019-09-09 15:12:58 +03:00
|
|
|
function getFavoriteEntries() {
|
|
|
|
var favs = entriesComponent.createObject(app, {
|
|
|
|
})
|
|
|
|
for (var i = 0; i < entries.count; i++) {
|
|
|
|
var entry = entries.get(i)
|
|
|
|
if (!!entry.credential && settings.favorites.includes(entry.credential.key)) {
|
|
|
|
favs.append(entry)
|
2017-03-17 13:01:59 +03:00
|
|
|
}
|
2017-03-09 12:49:42 +03:00
|
|
|
}
|
2019-09-09 15:12:58 +03:00
|
|
|
return favs
|
2017-03-09 12:49:42 +03:00
|
|
|
}
|
|
|
|
|
2019-09-09 15:12:58 +03:00
|
|
|
Shortcut {
|
|
|
|
sequence: StandardKey.Copy
|
|
|
|
enabled: !!currentCredentialCard
|
|
|
|
onActivated: app.currentCredentialCard.calculateCard(true)
|
2017-03-08 15:58:42 +03:00
|
|
|
}
|
|
|
|
|
2019-09-09 15:12:58 +03:00
|
|
|
Shortcut {
|
|
|
|
sequence: StandardKey.Delete
|
|
|
|
enabled: !!currentCredentialCard
|
|
|
|
onActivated: app.currentCredentialCard.deleteCard()
|
2017-02-23 14:18:20 +03:00
|
|
|
}
|
|
|
|
|
2019-09-09 15:12:58 +03:00
|
|
|
Shortcut {
|
|
|
|
sequence: StandardKey.Open
|
|
|
|
enabled: !!yubiKey.currentDevice && yubiKey.currentDeviceValidated
|
|
|
|
onActivated: yubiKey.scanQr()
|
2017-02-23 14:18:20 +03:00
|
|
|
}
|
|
|
|
|
2019-09-09 15:12:58 +03:00
|
|
|
Shortcut {
|
|
|
|
sequence: StandardKey.Preferences
|
|
|
|
onActivated: navigator.goToSettings()
|
|
|
|
}
|
2017-03-28 12:02:27 +03:00
|
|
|
|
2019-09-09 15:12:58 +03:00
|
|
|
Shortcut {
|
|
|
|
sequence: StandardKey.Quit
|
|
|
|
context: Qt.ApplicationShortcut
|
|
|
|
onActivated: Qt.quit()
|
2017-02-06 17:57:32 +03:00
|
|
|
}
|
|
|
|
|
2019-09-09 15:12:58 +03:00
|
|
|
Shortcut {
|
|
|
|
sequence: StandardKey.Close
|
|
|
|
onActivated: app.close()
|
|
|
|
context: Qt.ApplicationShortcut
|
2017-11-29 15:45:27 +03:00
|
|
|
}
|
|
|
|
|
2019-09-09 15:12:58 +03:00
|
|
|
Shortcut {
|
|
|
|
sequence: StandardKey.FullScreen
|
|
|
|
onActivated: visibility = visibility
|
|
|
|
=== Window.FullScreen ? Window.Windowed : Window.FullScreen
|
|
|
|
context: Qt.ApplicationShortcut
|
2017-02-17 12:14:37 +03:00
|
|
|
}
|
2017-03-09 12:49:42 +03:00
|
|
|
|
2019-09-09 15:12:58 +03:00
|
|
|
// This information is stored in the system registry on Windows,
|
|
|
|
// and in XML preferences files on macOS. On other Unix systems,
|
|
|
|
// in the absence of a standard, INI text files are used.
|
|
|
|
// See http://doc.qt.io/qt-5/qml-qt-labs-settings-settings.html#details
|
|
|
|
Settings {
|
|
|
|
id: settings
|
2017-03-30 10:48:59 +03:00
|
|
|
|
2019-09-09 15:12:58 +03:00
|
|
|
// Can be 0 (off), 6, 7 or 8
|
|
|
|
property int slot1digits
|
|
|
|
property int slot2digits
|
2017-02-02 16:16:52 +03:00
|
|
|
|
2019-09-09 15:12:58 +03:00
|
|
|
property bool otpMode
|
|
|
|
property bool useCustomReader
|
|
|
|
property string customReaderName
|
2017-02-23 15:51:44 +03:00
|
|
|
|
2019-09-09 15:12:58 +03:00
|
|
|
property bool closeToTray
|
|
|
|
property bool hideOnLaunch
|
|
|
|
property bool requireTouch: true
|
2017-03-16 16:59:30 +03:00
|
|
|
|
2019-09-09 15:12:58 +03:00
|
|
|
property int theme: Material.System
|
2017-03-16 17:10:15 +03:00
|
|
|
|
2019-09-09 15:12:58 +03:00
|
|
|
// Keep track of window and desktop dimensions.
|
|
|
|
property alias width: app.width
|
|
|
|
property alias height: app.height
|
|
|
|
property alias x: app.x
|
|
|
|
property alias y: app.y
|
2017-03-16 18:34:00 +03:00
|
|
|
|
2019-09-09 15:12:58 +03:00
|
|
|
property int desktopAvailableWidth
|
|
|
|
property int desktopAvailableHeight
|
2017-03-16 18:34:00 +03:00
|
|
|
|
2019-09-09 15:12:58 +03:00
|
|
|
property var favorites: []
|
|
|
|
property string favoriteDefault
|
2017-03-17 11:07:41 +03:00
|
|
|
|
2019-09-09 15:12:58 +03:00
|
|
|
onCloseToTrayChanged: updateTrayVisibility()
|
|
|
|
onThemeChanged: {
|
|
|
|
app.Material.theme = theme
|
2017-03-17 11:07:41 +03:00
|
|
|
}
|
|
|
|
}
|
2017-03-17 13:01:59 +03:00
|
|
|
|
2019-09-09 15:12:58 +03:00
|
|
|
Component {
|
|
|
|
id: entriesComponent
|
|
|
|
EntriesModel {
|
2017-03-17 13:01:59 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-09-09 15:12:58 +03:00
|
|
|
EntriesModel {
|
|
|
|
id: entries
|
2017-03-17 13:01:59 +03:00
|
|
|
}
|
2017-03-17 13:13:14 +03:00
|
|
|
|
2019-09-09 15:12:58 +03:00
|
|
|
ClipBoard {
|
|
|
|
id: clipBoard
|
2017-03-17 13:13:14 +03:00
|
|
|
}
|
2017-03-17 14:52:34 +03:00
|
|
|
|
2019-09-09 15:12:58 +03:00
|
|
|
Timer {
|
|
|
|
id: poller
|
|
|
|
triggeredOnStart: true
|
|
|
|
interval: 1000
|
|
|
|
repeat: true
|
|
|
|
running: app.isInForeground || settings.closeToTray
|
|
|
|
onTriggered: yubiKey.poll()
|
2017-07-07 11:03:50 +03:00
|
|
|
}
|
|
|
|
|
2019-09-09 15:12:58 +03:00
|
|
|
YubiKey {
|
|
|
|
id: yubiKey
|
2017-03-31 12:14:22 +03:00
|
|
|
}
|
2017-04-10 10:17:27 +03:00
|
|
|
|
2019-09-09 15:12:58 +03:00
|
|
|
SystemTray {
|
|
|
|
id: sysTrayIcon
|
2017-09-12 17:21:38 +03:00
|
|
|
}
|
2017-12-01 17:38:08 +03:00
|
|
|
|
2019-09-09 15:12:58 +03:00
|
|
|
Navigator {
|
|
|
|
id: navigator
|
|
|
|
anchors.fill: parent
|
|
|
|
focus: true
|
|
|
|
Keys.forwardTo: toolBar.searchField
|
2018-01-31 15:53:50 +03:00
|
|
|
}
|
2017-01-27 15:55:38 +03:00
|
|
|
}
|