Lock wallet on inactivity

This commit is contained in:
dsc 2018-12-13 19:02:02 +01:00
parent bac833c1dd
commit 5bebf83d52
No known key found for this signature in database
GPG Key ID: 7BBC83D7A8810AAB
6 changed files with 135 additions and 8 deletions

View File

@ -38,6 +38,10 @@ filter::filter(QObject *parent) :
}
bool filter::eventFilter(QObject *obj, QEvent *ev) {
if(ev->type() == QEvent::KeyPress || ev->type() == QEvent::MouseButtonRelease){
emit userActivity();
}
switch(ev->type()) {
case QEvent::KeyPress: {
QKeyEvent *ke = static_cast<QKeyEvent*>(ev);

View File

@ -48,6 +48,7 @@ signals:
void sequenceReleased(const QVariant &o, const QVariant &seq);
void mousePressed(const QVariant &o, const QVariant &x, const QVariant &y);
void mouseReleased(const QVariant &o, const QVariant &x, const QVariant &y);
void userActivity();
};
#endif // FILTER_H

View File

@ -324,6 +324,6 @@ int main(int argc, char *argv[])
QObject::connect(eventFilter, SIGNAL(sequenceReleased(QVariant,QVariant)), rootObject, SLOT(sequenceReleased(QVariant,QVariant)));
QObject::connect(eventFilter, SIGNAL(mousePressed(QVariant,QVariant,QVariant)), rootObject, SLOT(mousePressed(QVariant,QVariant,QVariant)));
QObject::connect(eventFilter, SIGNAL(mouseReleased(QVariant,QVariant,QVariant)), rootObject, SLOT(mouseReleased(QVariant,QVariant,QVariant)));
QObject::connect(eventFilter, SIGNAL(userActivity()), rootObject, SLOT(userActivity()));
return app.exec();
}

View File

@ -75,6 +75,7 @@ ApplicationWindow {
property var cameraUi
property bool remoteNodeConnected: false
property bool androidCloseTapped: false;
property int userLastActive; // epoch
// Default daemon addresses
readonly property string localDaemonAddress : persistentSettings.nettype == NetworkType.MAINNET ? "localhost:18081" : persistentSettings.nettype == NetworkType.TESTNET ? "localhost:28081" : "localhost:38081"
property string currentDaemonAddress;
@ -219,6 +220,8 @@ ApplicationWindow {
// Local daemon settings
walletManager.setDaemonAddress(localDaemonAddress)
// enable user inactivity timer
userInActivityTimer.running = true;
// wallet already opened with wizard, we just need to initialize it
if (typeof wizard.m_wallet !== 'undefined') {
@ -932,6 +935,8 @@ ApplicationWindow {
rootItem.state = "wizard"
// reset balance
leftPanel.balanceText = leftPanel.unlockedBalanceText = walletManager.displayAmount(0);
// disable inactivity timer
userInActivityTimer.running = false;
}
function hideMenu() {
@ -1041,6 +1046,8 @@ ApplicationWindow {
property int segregationHeight: 0
property int kdfRounds: 1
property bool hideBalance: false
property bool lockOnUserInActivity: true
property int lockOnUserInActivityInterval: 10 // minutes
}
// Information dialog
@ -1696,6 +1703,12 @@ ApplicationWindow {
triggeredOnStart: false
}
Timer {
id: userInActivityTimer
interval: 2000; running: false; repeat: true
onTriggered: checkInUserActivity()
}
Rectangle {
id: statusMessage
z: 99
@ -1823,6 +1836,32 @@ ApplicationWindow {
leftPanel.balanceLabelText = qsTr("Balance")
}
function userActivity() {
// register user activity
var epoch = Math.floor((new Date).getTime()/1000);
appWindow.userLastActive = epoch;
}
function checkInUserActivity() {
if(!persistentSettings.lockOnUserInActivity) return;
// prompt password after X seconds of inactivity
var epoch = Math.floor((new Date).getTime() / 1000);
var inactivity = epoch - appWindow.userLastActive;
if(inactivity < (persistentSettings.lockOnUserInActivityInterval * 60)) return;
passwordDialog.onAcceptedCallback = function() {
if(walletPassword === passwordDialog.password){
passwordDialog.close();
} else {
passwordDialog.showError(qsTr("Wrong password"));
}
}
passwordDialog.onRejectedCallback = function() { appWindow.showWizard(); }
passwordDialog.open();
}
// Daemon console
DaemonConsole {
id: daemonConsolePopup

View File

@ -65,17 +65,16 @@ ColumnLayout {
onCurrentViewChanged: {
if (previousView) {
// if (typeof previousView.onPageClosed === "function") {
// previousView.onPageClosed();
// }
if (typeof previousView.onPageClosed === "function") {
previousView.onPageClosed();
}
}
previousView = currentView
if (currentView) {
stackView.replace(currentView)
// Component.onCompleted is called before wallet is initilized
// if (typeof currentView.onPageCompleted === "function") {
// currentView.onPageCompleted();
// }
if (typeof currentView.onPageCompleted === "function") {
currentView.onPageCompleted();
}
}
}

View File

@ -40,6 +40,14 @@ Rectangle {
height: 1400
Layout.fillWidth: true
function onPageCompleted() {
userInactivitySliderTimer.running = true;
}
function onPageClosed() {
userInactivitySliderTimer.running = false;
}
ColumnLayout {
id: settingsUI
property int itemHeight: 60 * scaleRatio
@ -70,6 +78,82 @@ Rectangle {
text: qsTr("Hide balance") + translationManager.emptyString
}
MoneroComponents.CheckBox {
visible: !isMobile
id: userInActivityCheckbox
checked: persistentSettings.lockOnUserInActivity
onClicked: persistentSettings.lockOnUserInActivity = !persistentSettings.lockOnUserInActivity
text: qsTr("Lock wallet on inactivity") + translationManager.emptyString
}
ColumnLayout {
visible: userInActivityCheckbox.checked
Layout.fillWidth: true
Layout.topMargin: 6 * scaleRatio
Layout.leftMargin: 42 * scaleRatio
spacing: 0
MoneroComponents.TextBlock {
font.pixelSize: 14 * scaleRatio
Layout.fillWidth: true
text: {
var val = userInactivitySlider.value;
var minutes = val > 1 ? qsTr("minutes") : qsTr("minute");
qsTr("After ") + val + " " + minutes + translationManager.emptyString;
}
}
Slider {
id: userInactivitySlider
from: 1
value: persistentSettings.lockOnUserInActivityInterval
to: 60
leftPadding: 0
stepSize: 1
snapMode: Slider.SnapAlways
background: Rectangle {
x: parent.leftPadding
y: parent.topPadding + parent.availableHeight / 2 - height / 2
implicitWidth: 200 * scaleRatio
implicitHeight: 4 * scaleRatio
width: parent.availableWidth
height: implicitHeight
radius: 2
color: MoneroComponents.Style.grey
Rectangle {
width: parent.visualPosition * parent.width
height: parent.height
color: MoneroComponents.Style.green
radius: 2
}
}
handle: Rectangle {
x: parent.leftPadding + parent.visualPosition * (parent.availableWidth - width)
y: parent.topPadding + parent.availableHeight / 2 - height / 2
implicitWidth: 18 * scaleRatio
implicitHeight: 18 * scaleRatio
radius: 8
color: parent.pressed ? "#f0f0f0" : "#f6f6f6"
border.color: MoneroComponents.Style.grey
}
}
Timer {
// @TODO: Slider.onMoved{} is available in Qt > 5.9, use a hacky timer for now
id: userInactivitySliderTimer
interval: 1000; running: false; repeat: true
onTriggered: {
if(persistentSettings.lockOnUserInActivityInterval != userInactivitySlider.value) {
persistentSettings.lockOnUserInActivityInterval = userInactivitySlider.value;
}
}
}
}
MoneroComponents.TextBlock {
visible: isMobile
font.pixelSize: 14