File indexing completed on 2024-04-28 05:34:16

0001 // SPDX-FileCopyrightText: 2021 Daniel Vrátil <dvratil@kde.org>
0002 //
0003 // SPDX-License-Identifier: LGPL-2.1-or-later
0004 
0005 #include "otpprovider.h"
0006 
0007 #include <QUrl>
0008 #include <QUrlQuery>
0009 #include <QDebug>
0010 #include <QDateTime>
0011 
0012 #include <KLocalizedString>
0013 
0014 #include <chrono>
0015 
0016 #include <liboath/oath.h>
0017 
0018 using namespace PlasmaPass;
0019 using namespace std::chrono_literals;
0020 
0021 namespace {
0022 
0023 static const QString otpAuthSchema = QStringLiteral("otpauth://");
0024 static const QString secretQueryItem = QStringLiteral("secret");
0025 
0026 QString parseOtpType(const QUrl &url)
0027 {
0028     return url.host();
0029 }
0030 
0031 } // namespace
0032 
0033 OTPProvider::OTPProvider(const QString &path, QObject *parent)
0034     : ProviderBase(path, parent)
0035 {
0036     setSecretTimeout(30s);
0037 }
0038 
0039 ProviderBase::HandlingResult OTPProvider::handleSecret(QStringView secret)
0040 {
0041     if (!secret.startsWith(otpAuthSchema)) {
0042         return HandlingResult::Continue;
0043     }
0044 
0045     QUrl url(secret.toString());
0046     const auto otpType = parseOtpType(url);
0047     if (otpType == QLatin1String("totp")) {
0048         handleTOTP(url);
0049     } else {
0050         setError(i18n("Unsupported OTP type %1", otpType));
0051         return HandlingResult::Stop;
0052     }
0053 
0054     return HandlingResult::Stop;
0055 }
0056 
0057 
0058 void OTPProvider::handleTOTP(const QUrl &url)
0059 {
0060     const QUrlQuery query(url.query());
0061     const auto secret = query.queryItemValue(secretQueryItem).toUtf8();
0062 
0063     char *decodedSecret = {};
0064     size_t decodedSecretLen = 0;
0065     oath_base32_decode(secret.data(), secret.size(), &decodedSecret, &decodedSecretLen);
0066 
0067     char output_otp[6] = {};
0068     oath_totp_generate(decodedSecret, decodedSecretLen,
0069             QDateTime::currentDateTime().toSecsSinceEpoch(),
0070             OATH_TOTP_DEFAULT_TIME_STEP_SIZE,
0071             OATH_TOTP_DEFAULT_START_TIME,
0072             6,
0073             output_otp);
0074 
0075     setSecret(QString::fromLatin1(output_otp, sizeof(output_otp)));
0076 }
0077 
0078 #include "moc_otpprovider.cpp"