diff --git a/qml/cover/CoverPage.qml b/qml/cover/CoverPage.qml index 6a31e98..2aa4247 100644 --- a/qml/cover/CoverPage.qml +++ b/qml/cover/CoverPage.qml @@ -41,9 +41,15 @@ CoverBackground { function updateOTP() { // get seconds from current Date var curDate = new Date(); + var type; if (lOTP.text == "------" || curDate.getSeconds() == 30 || curDate.getSeconds() == 0 || (curDate.getTime() - lastUpdated > 2000)) { - appWin.coverOTP = OTP.calcOTP(appWin.coverSecret, "TOTP", 0); + if (appWin.coverTitle.substr(0,6) == "Steam:") { + type = "TOTP_STEAM" + } else { + type = "TOTP" + } + appWin.coverOTP = OTP.calcOTP(appWin.coverSecret, type, 0); } // Change color of the OTP to red if less than 5 seconds left diff --git a/qml/lib/crypto.js b/qml/lib/crypto.js index 9cba4f0..bff4a58 100644 --- a/qml/lib/crypto.js +++ b/qml/lib/crypto.js @@ -63,6 +63,11 @@ function leftpad(str, len, pad) { return str; } +// characters steam uses to generate the final code +var steamChars = ['2', '3', '4', '5', '6', '7', '8', '9', 'B', 'C', + 'D', 'F', 'G', 'H', 'J', 'K', 'M', 'N', 'P', 'Q', + 'R', 'T', 'V', 'W', 'X', 'Y'] + // *** Main Function *** // // Calculate an OTP-Value from the given secret @@ -75,7 +80,7 @@ function calcOTP(secret, type, counter) { var key = base32tohex(secret); var factor = ""; - if (type == "TOTP") { + if (type.substr(0, 4) == "TOTP") { // Get current Time in UNIX Timestamp format (Seconds since 01.01.1970 00:00 UTC) var epoch = Math.round(new Date().getTime() / 1000.0); // Get last full 30 / 60 Seconds and convert to HEX @@ -92,8 +97,19 @@ function calcOTP(secret, type, counter) { // 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 code = hex2dec(hmac.substr(offset * 2, 8)) & hex2dec('7fffffff'); + var otp = ''; + + // Steam has it's own way of creating the code from the result + if (type == "TOTP_STEAM") { + for (var i = 0; i < 5; i++) { + otp += steamChars[code % steamChars.length]; + code = Math.floor(code/steamChars.length); + } + } else { + otp = code + ''; + otp = (otp).substr(otp.length - 6, 6); + } } catch (e) { otp = "Invalid Secret!" } diff --git a/qml/pages/MainView.qml b/qml/pages/MainView.qml index 43f7272..8a82e61 100644 --- a/qml/pages/MainView.qml +++ b/qml/pages/MainView.qml @@ -69,13 +69,20 @@ Page { // get seconds from current Date var curDate = new Date(); var seconds = curDate.getSeconds(); + var type; // Iterate over all List entries for (var i=0; i 2000)) { - var curOTP = OTP.calcOTP(appWin.listModel.get(i).secret, "TOTP") + if (appWin.listModel.get(i).title.substr(0,6) == "Steam:") { + type = "TOTP_STEAM" + } else { + type = "TOTP" + } + + var curOTP = OTP.calcOTP(appWin.listModel.get(i).secret, type) appWin.listModel.setProperty(i, "otp", curOTP); } } else if (appWin.coverType == "HOTP" && (curDate.getTime() - lastUpdated > 2000) && appWin.listModel.get(i).fav == 1) {