diff --git a/qml/lib/crypto.js b/qml/lib/crypto.js index 56f1a8a..d518466 100644 --- a/qml/lib/crypto.js +++ b/qml/lib/crypto.js @@ -75,15 +75,19 @@ function calcOTP(secret) { // Get last full 30 / 60 Seconds and convert to HEX var time = leftpad(dec2hex(Math.floor(epoch / 30)), 16, '0'); - // Calculate the SHA-1 HMAC Value from time and key - var hmacObj = new SHA.jsSHA(time, 'HEX'); - var hmac = hmacObj.getHMAC(key, 'HEX', 'SHA-1', "HEX"); + try { + // Calculate the SHA-1 HMAC Value from time and key + var hmacObj = new SHA.jsSHA(time, 'HEX'); + var hmac = hmacObj.getHMAC(key, 'HEX', 'SHA-1', "HEX"); - // Finally convert the HMAC-Value to the corresponding 6-digit token - var offset = hex2dec(hmac.substring(hmac.length - 1)); + // Finally convert the HMAC-Value to the corresponding 6-digit token + var offset = hex2dec(hmac.substring(hmac.length - 1)); - var otp = (hex2dec(hmac.substr(offset * 2, 8)) & hex2dec('7fffffff')) + ''; - otp = (otp).substr(otp.length - 6, 6); + var otp = (hex2dec(hmac.substr(offset * 2, 8)) & hex2dec('7fffffff')) + ''; + otp = (otp).substr(otp.length - 6, 6); + } catch (e) { + otp = "Invalid Secret!" + } // return the calculated token return otp; diff --git a/qml/lib/storage.js b/qml/lib/storage.js index 7ec2108..a616ad8 100644 --- a/qml/lib/storage.js +++ b/qml/lib/storage.js @@ -80,3 +80,14 @@ function removeOTP(title, secret) { } ) } + +// Change an existing OTP +function changeOTP(title, secret, oldtitle, oldsecret) { + var db = getDB(); + + db.transaction( + function(tx) { + tx.executeSql("UPDATE OTPStorage SET title=?, secret=? WHERE title=? and secret=?;", [title, secret, oldtitle, oldsecret]); + } + ) +} diff --git a/qml/pages/AddOTP.qml b/qml/pages/AddOTP.qml index ebeddf2..c68afae 100644 --- a/qml/pages/AddOTP.qml +++ b/qml/pages/AddOTP.qml @@ -39,6 +39,10 @@ Dialog { // We get the Object of the parent page on call to refresh it after adding a new Entry property QtObject parentPage: null + // If we want to edit a Key we get title and key from the calling page + property string paramLabel: "" + property string paramKey: "" + SilicaFlickable { id: addOtpList anchors.fill: parent @@ -48,20 +52,22 @@ Dialog { Column { anchors.fill: parent DialogHeader { - acceptText: "Add" + acceptText: paramLabel != "" ? "Save" : "Add" } TextField { id: otpLabel width: parent.width label: "Title" placeholderText: "Title for the OTP" + text: paramLabel != "" ? paramLabel : "" focus: true horizontalAlignment: TextInput.AlignLeft } TextField { id: otpSecret width: parent.width - label: "Secret" + label: "Secret (at least 16 characters)" + text: paramKey != "" ? paramKey : "" placeholderText: "Secret OTP Key" focus: true horizontalAlignment: TextInput.AlignLeft @@ -69,12 +75,20 @@ Dialog { } } - // Save if page is Left with Add + // Check if we can Save + canAccept: otpLabel.text.length > 0 && otpSecret.text.length >= 16 ? true : false + + // Save if page is Left with Add onDone: { - // Some basic Input Check, we need both Values to work - if (otpLabel.text != "" && otpSecret.text != "") { + if (result == DialogResult.Accepted) { // Save the entry to the Config DB - DB.addOTP(otpLabel.text, otpSecret.text); + if (paramLabel != "" && paramKey != "") { + // Parameters where filled -> Change existing entry + DB.changeOTP(otpLabel.text, otpSecret.text, paramLabel, paramKey) + } else { + // There were no parameters -> Add new entry + DB.addOTP(otpLabel.text, otpSecret.text); + } // Refresh the main Page parentPage.refreshOTPList(); } diff --git a/qml/pages/MainView.qml b/qml/pages/MainView.qml index e9fea04..e5aadb2 100644 --- a/qml/pages/MainView.qml +++ b/qml/pages/MainView.qml @@ -158,6 +158,12 @@ Page { Component { id: otpContextMenu ContextMenu { + MenuItem { + text: "Edit" + onClicked: { + pageStack.push(Qt.resolvedUrl("AddOTP.qml"), {parentPage: mainPage, paramLabel: title, paramKey: secret}) + } + } MenuItem { text: "Delete" onClicked: remove()