mirror of
https://github.com/seiichiro0185/sailotp.git
synced 2024-11-22 07:39:42 +00:00
Preparations for version 0.6 release
Added possibility to cycle through the tokens from the cover
This commit is contained in:
parent
82ea4f182c
commit
dc02a1aa3f
5 changed files with 97 additions and 53 deletions
|
@ -38,28 +38,30 @@ CoverBackground {
|
||||||
|
|
||||||
property double lastUpdated: 0
|
property double lastUpdated: 0
|
||||||
|
|
||||||
|
function updateOTP() {
|
||||||
|
// get seconds from current Date
|
||||||
|
var curDate = new Date();
|
||||||
|
|
||||||
|
if (lOTP.text == "------" || curDate.getSeconds() == 30 || curDate.getSeconds() == 0 || (curDate.getTime() - lastUpdated > 2000)) {
|
||||||
|
appWin.coverOTP = OTP.calcOTP(appWin.coverSecret, "TOTP", 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Change color of the OTP to red if less than 5 seconds left
|
||||||
|
if (29 - (curDate.getSeconds() % 30) < 5) {
|
||||||
|
lOTP.color = "red"
|
||||||
|
} else {
|
||||||
|
lOTP.color = Theme.highlightColor
|
||||||
|
}
|
||||||
|
|
||||||
|
lastUpdated = curDate.getTime();
|
||||||
|
}
|
||||||
|
|
||||||
Timer {
|
Timer {
|
||||||
interval: 1000
|
interval: 1000
|
||||||
// Timer runs only when cover is visible and favourite is set
|
// Timer runs only when cover is visible and favourite is set
|
||||||
running: !Qt.application.active && appWin.coverSecret != "" && appWin.coverType == "TOTP"
|
running: !Qt.application.active && appWin.coverSecret != "" && appWin.coverType == "TOTP"
|
||||||
repeat: true
|
repeat: true
|
||||||
onTriggered: {
|
onTriggered: updateOTP();
|
||||||
// get seconds from current Date
|
|
||||||
var curDate = new Date();
|
|
||||||
|
|
||||||
if (lOTP.text == "------" || curDate.getSeconds() == 30 || curDate.getSeconds() == 0 || (curDate.getTime() - lastUpdated > 2000)) {
|
|
||||||
appWin.coverOTP = OTP.calcOTP(appWin.coverSecret, "TOTP", 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Change color of the OTP to red if less than 5 seconds left
|
|
||||||
if (29 - (curDate.getSeconds() % 30) < 5) {
|
|
||||||
lOTP.color = "red"
|
|
||||||
} else {
|
|
||||||
lOTP.color = Theme.highlightColor
|
|
||||||
}
|
|
||||||
|
|
||||||
lastUpdated = curDate.getTime();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Show the SailOTP Logo
|
// Show the SailOTP Logo
|
||||||
|
@ -79,7 +81,6 @@ CoverBackground {
|
||||||
Label {
|
Label {
|
||||||
text: appWin.coverTitle
|
text: appWin.coverTitle
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
color: Theme.secondaryColor
|
|
||||||
}
|
}
|
||||||
Label {
|
Label {
|
||||||
id: lOTP
|
id: lOTP
|
||||||
|
@ -91,11 +92,28 @@ CoverBackground {
|
||||||
}
|
}
|
||||||
// CoverAction to update a HOTP-Token, only visible for HOTP-Type Tokens
|
// CoverAction to update a HOTP-Token, only visible for HOTP-Type Tokens
|
||||||
CoverActionList {
|
CoverActionList {
|
||||||
enabled: appWin.coverType == "HOTP" ? true : false
|
|
||||||
CoverAction {
|
CoverAction {
|
||||||
iconSource: "image://theme/icon-m-refresh"
|
iconSource: appWin.coverType == "HOTP" ? "image://theme/icon-cover-refresh" : "image://theme/icon-cover-previous"
|
||||||
onTriggered: {
|
onTriggered: {
|
||||||
appWin.coverOTP = OTP.calcOTP(appWin.coverSecret, "HOTP", DB.getCounter(appWin.coverTitle, appWin.coverSecret, true));
|
if (appWin.coverType == "HOTP") {
|
||||||
|
appWin.coverOTP = OTP.calcOTP(appWin.coverSecret, "HOTP", DB.getCounter(appWin.coverTitle, appWin.coverSecret, true));
|
||||||
|
} else {
|
||||||
|
var index = appWin.coverIndex - 1
|
||||||
|
if (index < 0) index = appWin.listModel.count - 1
|
||||||
|
appWin.setCover(index);
|
||||||
|
DB.setFav(appWin.coverTitle, appWin.coverSecret)
|
||||||
|
if (appWin.coverType == "TOTP") updateOTP();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
CoverAction {
|
||||||
|
iconSource: "image://theme/icon-cover-next"
|
||||||
|
onTriggered: {
|
||||||
|
var index = appWin.coverIndex + 1
|
||||||
|
if (index >= appWin.listModel.count) index = 0
|
||||||
|
appWin.setCover(index);
|
||||||
|
DB.setFav(appWin.coverTitle, appWin.coverSecret)
|
||||||
|
if (appWin.coverType == "TOTP") updateOTP();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,15 +37,50 @@ ApplicationWindow
|
||||||
id: appWin
|
id: appWin
|
||||||
|
|
||||||
// Properties to pass values between MainPage and Cover
|
// Properties to pass values between MainPage and Cover
|
||||||
|
property alias listModel: otpListModel
|
||||||
property string coverTitle: "SailOTP"
|
property string coverTitle: "SailOTP"
|
||||||
property string coverSecret: ""
|
property string coverSecret: ""
|
||||||
property string coverType: ""
|
property string coverType: ""
|
||||||
property string coverOTP: "------"
|
property string coverOTP: "------"
|
||||||
|
property int coverIndex: 0
|
||||||
|
|
||||||
|
// Global Listmodel for Tokens
|
||||||
|
ListModel { id: otpListModel }
|
||||||
|
|
||||||
|
// Global Component for showing notification banners
|
||||||
NotifyBanner { id: notify }
|
NotifyBanner { id: notify }
|
||||||
|
|
||||||
|
// Add an entry to the list
|
||||||
|
function appendOTP(title, secret, type, counter, fav) {
|
||||||
|
listModel.append({"secret": secret, "title": title, "fav": fav, "type": type, "counter": counter, "otp": "------"});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the OTP shown on the Cover
|
||||||
|
function setCover(index) {
|
||||||
|
if (index >= 0 && index < listModel.count) {
|
||||||
|
coverTitle = listModel.get(index).title;
|
||||||
|
coverSecret = listModel.get(index).secret;
|
||||||
|
coverType = listModel.get(index).type;
|
||||||
|
coverIndex = index;
|
||||||
|
if (coverType == "TOTP") { coverOTP = "------"; } else { coverOTP = listModel.get(index).otp; }
|
||||||
|
for (var i=0; i<listModel.count; i++) {
|
||||||
|
if (i != index) {
|
||||||
|
listModel.setProperty(i, "fav", 0);
|
||||||
|
} else {
|
||||||
|
listModel.setProperty(i, "fav", 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
coverTitle = "SailOTP";
|
||||||
|
coverSecret = "";
|
||||||
|
coverType = "";
|
||||||
|
coverIndex = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
initialPage: Component { MainView { } }
|
initialPage: Component { MainView { } }
|
||||||
cover: Qt.resolvedUrl("cover/CoverPage.qml")
|
cover: Qt.resolvedUrl("cover/CoverPage.qml")
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -65,8 +65,8 @@ function getOTP() {
|
||||||
function(tx) {
|
function(tx) {
|
||||||
var res = tx.executeSql("select * from OTPStorage;");
|
var res = tx.executeSql("select * from OTPStorage;");
|
||||||
for (var i=0; i < res.rows.length; i++) {
|
for (var i=0; i < res.rows.length; i++) {
|
||||||
mainPage.appendOTP(res.rows.item(i).title, res.rows.item(i).secret, res.rows.item(i).type, res.rows.item(i).counter, res.rows.item(i).fav);
|
appWin.appendOTP(res.rows.item(i).title, res.rows.item(i).secret, res.rows.item(i).type, res.rows.item(i).counter, res.rows.item(i).fav);
|
||||||
if (res.rows.item(i).fav) mainPage.setCoverOTP(res.rows.item(i).title, res.rows.item(i).secret, res.rows.item(i).type);
|
if (res.rows.item(i).fav) appWin.setCover(i);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,18 +36,9 @@ import "../lib/crypto.js" as OTP
|
||||||
Page {
|
Page {
|
||||||
id: mainPage
|
id: mainPage
|
||||||
|
|
||||||
ListModel {
|
|
||||||
id: otpListModel
|
|
||||||
}
|
|
||||||
|
|
||||||
// This holds the time of the last update of the page as Unix Timestamp (in Milliseconds)
|
// This holds the time of the last update of the page as Unix Timestamp (in Milliseconds)
|
||||||
property double lastUpdated: 0
|
property double lastUpdated: 0
|
||||||
|
|
||||||
// Add an entry to the list
|
|
||||||
function appendOTP(title, secret, type, counter, fav) {
|
|
||||||
otpListModel.append({"secret": secret, "title": title, "fav": fav, "type": type, "counter": counter, "otp": "------"});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Hand favorite over to the cover
|
// Hand favorite over to the cover
|
||||||
function setCoverOTP(title, secret, type) {
|
function setCoverOTP(title, secret, type) {
|
||||||
appWin.coverTitle = title
|
appWin.coverTitle = title
|
||||||
|
@ -63,7 +54,7 @@ Page {
|
||||||
// Reload the List of OTPs from storage
|
// Reload the List of OTPs from storage
|
||||||
function refreshOTPList() {
|
function refreshOTPList() {
|
||||||
otpList.visible = false;
|
otpList.visible = false;
|
||||||
otpListModel.clear();
|
appWin.listModel.clear();
|
||||||
DB.getOTP();
|
DB.getOTP();
|
||||||
refreshOTPValues();
|
refreshOTPValues();
|
||||||
otpList.visible = true;
|
otpList.visible = true;
|
||||||
|
@ -76,16 +67,16 @@ Page {
|
||||||
var seconds = curDate.getSeconds();
|
var seconds = curDate.getSeconds();
|
||||||
|
|
||||||
// Iterate over all List entries
|
// Iterate over all List entries
|
||||||
for (var i=0; i<otpListModel.count; i++) {
|
for (var i=0; i<appWin.listModel.count; i++) {
|
||||||
if (otpListModel.get(i).type == "TOTP") {
|
if (appWin.listModel.get(i).type == "TOTP") {
|
||||||
// Only update on full 30 / 60 Seconds or if last run of the Functions is more than 2s in the past (e.g. app was in background)
|
// Only update on full 30 / 60 Seconds or if last run of the Functions is more than 2s in the past (e.g. app was in background)
|
||||||
if (otpListModel.get(i).otp == "------" || seconds == 30 || seconds == 0 || (curDate.getTime() - lastUpdated > 2000)) {
|
if (appWin.listModel.get(i).otp == "------" || seconds == 30 || seconds == 0 || (curDate.getTime() - lastUpdated > 2000)) {
|
||||||
var curOTP = OTP.calcOTP(otpListModel.get(i).secret, "TOTP")
|
var curOTP = OTP.calcOTP(appWin.listModel.get(i).secret, "TOTP")
|
||||||
otpListModel.setProperty(i, "otp", curOTP);
|
appWin.listModel.setProperty(i, "otp", curOTP);
|
||||||
}
|
}
|
||||||
} else if (appWin.coverType == "HOTP" && (curDate.getTime() - lastUpdated > 2000) && otpListModel.get(i).fav == 1) {
|
} else if (appWin.coverType == "HOTP" && (curDate.getTime() - lastUpdated > 2000) && appWin.listModel.get(i).fav == 1) {
|
||||||
// If we are coming back from the CoverPage update OTP value if current favourite is HOTP
|
// If we are coming back from the CoverPage update OTP value if current favourite is HOTP
|
||||||
otpListModel.setProperty(i, "otp", appWin.coverOTP);
|
appWin.listModel.setProperty(i, "otp", appWin.coverOTP);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -98,7 +89,7 @@ Page {
|
||||||
Timer {
|
Timer {
|
||||||
interval: 500
|
interval: 500
|
||||||
// Timer only runs when app is acitive and we have entries
|
// Timer only runs when app is acitive and we have entries
|
||||||
running: Qt.application.active && otpListModel.count
|
running: Qt.application.active && appWin.listModel.count
|
||||||
repeat: true
|
repeat: true
|
||||||
onTriggered: refreshOTPValues();
|
onTriggered: refreshOTPValues();
|
||||||
}
|
}
|
||||||
|
@ -132,7 +123,7 @@ Page {
|
||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
anchors.topMargin: 48
|
anchors.topMargin: 48
|
||||||
// Only show when there are enries
|
// Only show when there are enries
|
||||||
visible: otpListModel.count
|
visible: appWin.listModel.count
|
||||||
}
|
}
|
||||||
|
|
||||||
SilicaListView {
|
SilicaListView {
|
||||||
|
@ -141,7 +132,7 @@ Page {
|
||||||
title: "SailOTP"
|
title: "SailOTP"
|
||||||
}
|
}
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
model: otpListModel
|
model: appWin.listModel
|
||||||
width: parent.width
|
width: parent.width
|
||||||
|
|
||||||
ViewPlaceholder {
|
ViewPlaceholder {
|
||||||
|
@ -158,7 +149,7 @@ Page {
|
||||||
|
|
||||||
function remove() {
|
function remove() {
|
||||||
// Show 5s countdown, then delete from DB and List
|
// Show 5s countdown, then delete from DB and List
|
||||||
remorseAction(qsTr("Deleting"), function() { DB.removeOTP(title, secret); otpListModel.remove(index) })
|
remorseAction(qsTr("Deleting"), function() { DB.removeOTP(title, secret); appWin.listModel.remove(index) })
|
||||||
}
|
}
|
||||||
|
|
||||||
onClicked: {
|
onClicked: {
|
||||||
|
@ -178,19 +169,19 @@ Page {
|
||||||
onClicked: {
|
onClicked: {
|
||||||
if (fav == 0) {
|
if (fav == 0) {
|
||||||
DB.setFav(title, secret)
|
DB.setFav(title, secret)
|
||||||
setCoverOTP(title, secret, type)
|
appWin.setCover(index)
|
||||||
if (type == "HOTP") appWin.coverOTP = otp
|
if (type == "HOTP") appWin.coverOTP = otp
|
||||||
for (var i=0; i<otpListModel.count; i++) {
|
for (var i=0; i<appWin.listModel.count; i++) {
|
||||||
if (i != index) {
|
if (i != index) {
|
||||||
otpListModel.setProperty(i, "fav", 0);
|
appWin.listModel.setProperty(i, "fav", 0);
|
||||||
} else {
|
} else {
|
||||||
otpListModel.setProperty(i, "fav", 1);
|
appWin.listModel.setProperty(i, "fav", 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
DB.resetFav(title, secret)
|
DB.resetFav(title, secret)
|
||||||
setCoverOTP("SailOTP", "", "")
|
appWin.setCover(-1)
|
||||||
otpListModel.setProperty(index, "fav", 0);
|
appWin.listModel.setProperty(index, "fav", 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -221,8 +212,8 @@ Page {
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
visible: type == "HOTP" ? true : false
|
visible: type == "HOTP" ? true : false
|
||||||
onClicked: {
|
onClicked: {
|
||||||
otpListModel.setProperty(index, "counter", DB.getCounter(title, secret, true));
|
appWin.listModel.setProperty(index, "counter", DB.getCounter(title, secret, true));
|
||||||
otpListModel.setProperty(index, "otp", OTP.calcOTP(secret, "HOTP", counter));
|
appWin.listModel.setProperty(index, "otp", OTP.calcOTP(secret, "HOTP", counter));
|
||||||
if (fav == 1) appWin.coverOTP = otp;
|
if (fav == 1) appWin.coverOTP = otp;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
Name: harbour-sailotp
|
Name: harbour-sailotp
|
||||||
Summary: SailOTP
|
Summary: SailOTP
|
||||||
Version: 0.5
|
Version: 0.6
|
||||||
Release: 1
|
Release: 1
|
||||||
Group: Security
|
Group: Security
|
||||||
URL: https://github.com/seiichiro0185/sailotp/
|
URL: https://github.com/seiichiro0185/sailotp/
|
||||||
|
|
Loading…
Reference in a new issue