From e74749642f9efc12e3dc147fbfc0cac08eb804d3 Mon Sep 17 00:00:00 2001 From: Stefan Brand Date: Sun, 16 Feb 2014 16:27:28 +0100 Subject: [PATCH] Added first version of experimental QR-Code support --- harbour-sailotp.pro | 4 +- qml/lib/urldecoder.js | 23 +++++++++++ qml/pages/AddOTP.qml | 5 ++- qml/pages/MainView.qml | 5 +++ qml/pages/ScanOTP.qml | 90 ++++++++++++++++++++++++++++++++++++++++++ src/qzxing/QZXing.pri | 2 +- 6 files changed, 125 insertions(+), 4 deletions(-) create mode 100644 qml/lib/urldecoder.js create mode 100644 qml/pages/ScanOTP.qml diff --git a/harbour-sailotp.pro b/harbour-sailotp.pro index 85e6523..fbf18df 100644 --- a/harbour-sailotp.pro +++ b/harbour-sailotp.pro @@ -30,7 +30,9 @@ OTHER_FILES += qml/harbour-sailotp.qml \ qml/sailotp.png \ qml/pages/ExportPage.qml \ qml/lib/gibberish-aes.js \ - qml/components/NotifyBanner.qml + qml/components/NotifyBanner.qml \ + qml/pages/ScanOTP.qml \ + qml/lib/urldecoder.js HEADERS += \ src/fileio.h diff --git a/qml/lib/urldecoder.js b/qml/lib/urldecoder.js new file mode 100644 index 0000000..212c545 --- /dev/null +++ b/qml/lib/urldecoder.js @@ -0,0 +1,23 @@ + +function decode(url) { + // otpauth://totp/user@host.com?secret=JBSWY3DPEHPK3PXP + // otpauth://totp/user@host.com?secret=JBSWY3DPEHPK3PXP + + if (url.search(/^otpauth:\/\/[th]otp\/.*?.*/) != -1) { + var ret = {"type": "", "title": "", "secret": "", "counter": ""}; + ret.type = url.slice(10,14).toUpperCase(); + ret.title = url.slice(15, url.indexOf("?")); + var pstr = url.slice(url.indexOf("?")+1, url.length); + var params = pstr.split("&"); + + for (var i = 0; i < params.length; ++i) { + pstr = params[i]; + var tmp = pstr.split("="); + if (tmp[0] == "secret") ret.secret = tmp[1]; + if (tmp[0] == "counter") ret.counter = tmp[1]; + } + + return ret; + } +} + diff --git a/qml/pages/AddOTP.qml b/qml/pages/AddOTP.qml index 752715d..c28df00 100644 --- a/qml/pages/AddOTP.qml +++ b/qml/pages/AddOTP.qml @@ -44,6 +44,7 @@ Dialog { property string paramLabel: "" property string paramKey: "" property int paramCounter: 1 // New Counters start at 1 + property bool paramNew: false SilicaFlickable { id: addOtpList @@ -54,7 +55,7 @@ Dialog { Column { anchors.fill: parent DialogHeader { - acceptText: paramLabel != "" ? qsTr("Save") : qsTr("Add") + acceptText: paramNew ? qsTr("Add") : qsTr("Save") } ComboBox { @@ -116,7 +117,7 @@ Dialog { onDone: { if (result == DialogResult.Accepted) { // Save the entry to the Config DB - if (paramLabel != "" && paramKey != "") { + if (paramLabel != "" && paramKey != "" && !paramNew) { // Parameters where filled -> Change existing entry DB.changeOTP(otpLabel.text, otpSecret.text, paramType, otpCounter.text, paramLabel, paramKey) } else { diff --git a/qml/pages/MainView.qml b/qml/pages/MainView.qml index 4641347..d73454d 100644 --- a/qml/pages/MainView.qml +++ b/qml/pages/MainView.qml @@ -114,6 +114,11 @@ Page { text: qsTr("Add Token") onClicked: pageStack.push(Qt.resolvedUrl("AddOTP.qml"), {parentPage: mainPage}) } + + MenuItem { + text: qsTr("Scan Token") + onClicked: pageStack.push(Qt.resolvedUrl("ScanOTP.qml"), {parentPage: mainPage}) + } } ProgressBar { diff --git a/qml/pages/ScanOTP.qml b/qml/pages/ScanOTP.qml new file mode 100644 index 0000000..42c6a73 --- /dev/null +++ b/qml/pages/ScanOTP.qml @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2013, Stefan Brand + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this + * list of conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. The names of the contributors may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +import QtQuick 2.0 +import QtMultimedia 5.0 +import Sailfish.Silica 1.0 +import Sailfish.Media 1.0 // Not allowed in harbour, but normal VideoOutput doesn't work yet! +import harbour.sailotp.QZXing 2.2 +import "../lib/urldecoder.js" as URL + +Page { + id: scanPage + + property QtObject parentPage: null + + SilicaFlickable { + anchors.fill: parent + + Camera { + id: cam + + flash.mode: Camera.FlashOff + captureMode: Camera.CaptureStillImage + focus.focusMode: Camera.FocusContinuous + + imageCapture { + onImageSaved: { + decoder.decodeImageFromFile("/tmp/qrscan.jpg"); + } + } + } + + GStreamerVideoOutput { + id: videoPreview + anchors.centerIn: parent + source: cam + MouseArea { + anchors.fill: parent + onClicked: { + cam.imageCapture.captureToLocation("/tmp/qrscan.jpg"); + } + } + } + + QZXing{ + id: decoder + + enabledDecoders: QZXing.DecoderFormat_QR_CODE + onDecodingStarted: console.log("Decoding of image started...") + + onTagFound: { + console.log("Barcode data: " + tag) + var ret = URL.decode(tag); + if (ret.type != "" && ret.title != "" && ret.secret != "" && (ret.counter != "" || ret.type == "TOTP ")) { + pageStack.replace(Qt.resolvedUrl("AddOTP.qml"), {parentPage: parentPage, paramLabel: ret.title, paramKey: ret.secret, paramType: ret.type, paramCounter: ret.counter, paramNew: true}) + } else { + notify.show(qsTr("Error decoding QR-Code"), 3000); + } + } + + onDecodingFinished: console.log("Decoding finished " + (succeeded==true ? "successfully" : "unsuccessfully") ) + } + } +} diff --git a/src/qzxing/QZXing.pri b/src/qzxing/QZXing.pri index ca196dd..3f8e008 100644 --- a/src/qzxing/QZXing.pri +++ b/src/qzxing/QZXing.pri @@ -250,7 +250,7 @@ unix:!symbian { } DEFINES += NOFMAXL - INSTALLS += target +# INSTALLS += target } win32-msvc*{