File indexing completed on 2024-05-19 04:44:47

0001 /*
0002  * SPDX-FileCopyrightText: 2010 Kare Sars <kare dot sars at iki dot fi>
0003  * SPDX-FileCopyrightText: 2014 Gregor Mitsch : port to KDE5 frameworks
0004  *
0005  * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
0006  */
0007 
0008 #include "authentication.h"
0009 
0010 // Qt includes
0011 #include <QMutex>
0012 #include <QMutexLocker>
0013 #include <QList>
0014 
0015 #include <ksanecore_debug.h>
0016 
0017 namespace KSaneCore
0018 {
0019 
0020 static Authentication *s_instance = nullptr;
0021 Q_GLOBAL_STATIC(QMutex, s_mutex)
0022 
0023 struct Authentication::Private {
0024     struct AuthStruct {
0025         QString resource;
0026         QString username;
0027         QString password;
0028     };
0029 
0030     QList<AuthStruct> authList;
0031 };
0032 
0033 Authentication *Authentication::getInstance()
0034 {
0035 #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
0036     QMutexLocker<QMutex> locker(s_mutex);
0037 #else
0038     QMutexLocker locker(s_mutex);
0039 #endif
0040 
0041     if (s_instance == nullptr) {
0042         s_instance = new Authentication();
0043     }
0044     return s_instance;
0045 }
0046 
0047 Authentication::Authentication() : d(new Private) {}
0048 
0049 Authentication::~Authentication()
0050 {
0051 #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
0052     QMutexLocker<QMutex> locker(s_mutex);
0053 #else
0054     QMutexLocker locker(s_mutex);
0055 #endif
0056     d->authList.clear();
0057     delete d;
0058 }
0059 
0060 void Authentication::setDeviceAuth(const QString &resource, const QString &username, const QString &password)
0061 {
0062     // This is a short list so we do not need a QMap...
0063     int i;
0064     for (i = 0; i < d->authList.size(); i++) {
0065         if (resource == d->authList.at(i).resource) {
0066             // update the existing node
0067             d->authList[i].username = username;
0068             d->authList[i].password = password;
0069             break;
0070         }
0071     }
0072     if (i == d->authList.size()) {
0073         // Add a new list node
0074         Private::AuthStruct tmp;
0075         tmp.resource = resource;
0076         tmp.username = username;
0077         tmp.password = password;
0078         d->authList << tmp;
0079     }
0080 }
0081 
0082 void Authentication::clearDeviceAuth(const QString &resource)
0083 {
0084     // This is a short list so we do not need a QMap...
0085     for (int i = 0; i < d->authList.size(); i++) {
0086         if (resource == d->authList.at(i).resource) {
0087             d->authList.removeAt(i);
0088             return;
0089         }
0090     }
0091 }
0092 
0093 /** static function called by sane_open to get authorization from user */
0094 void Authentication::authorization(SANE_String_Const resource, SANE_Char *username, SANE_Char *password)
0095 {
0096     qCDebug(KSANECORE_LOG) << resource;
0097     // This is vague in the standard... what can I find in the resource string?
0098     // I have found that "resource contains the backend name + "$MD5$....."
0099     // it does not contain unique identifiers like ":libusb:001:004"
0100     // -> remove $MD5 and later before comparison...
0101     QString res = QString::fromUtf8(resource);
0102     int end = res.indexOf(QStringLiteral("$MD5$"));
0103     res = res.left(end);
0104     qCDebug(KSANECORE_LOG) << res;
0105 
0106     const QList<Private::AuthStruct> list = getInstance()->d->authList;
0107     for (const auto &authItem : list) {
0108         qCDebug(KSANECORE_LOG) << res << authItem.resource;
0109         if (authItem.resource.contains(res)) {
0110             qstrncpy(username, authItem.username.toLocal8Bit().constData(), SANE_MAX_USERNAME_LEN);
0111             qstrncpy(password, authItem.password.toLocal8Bit().constData(), SANE_MAX_PASSWORD_LEN);
0112             break;
0113         }
0114     }
0115 }
0116 
0117 } // namespace KSaneCore