OSDN Git Service

kdirshare: implement authentication
authorIvailo Monev <xakepa10@gmail.com>
Wed, 11 May 2022 19:30:27 +0000 (22:30 +0300)
committerIvailo Monev <xakepa10@gmail.com>
Wed, 11 May 2022 20:08:24 +0000 (23:08 +0300)
requires:
https://github.com/fluxer/kdelibs/commit/a48d4cbb28d301194a247b10f0b3214e537ec082

Signed-off-by: Ivailo Monev <xakepa10@gmail.com>
kdirshare/filepropertiesplugin/kdirshareplugin.cpp
kdirshare/filepropertiesplugin/kdirshareplugin.h
kdirshare/filepropertiesplugin/kdirshareplugin.ui
kdirshare/kded/CMakeLists.txt
kdirshare/kded/kded_kdirshare.cpp
kdirshare/kded/kded_kdirshare.h
kdirshare/kded/kdirshareimpl.cpp
kdirshare/kded/kdirshareimpl.h
kdirshare/kdirshare.notifyrc

index 6f1139c..4be8e45 100644 (file)
@@ -60,9 +60,11 @@ KDirSharePlugin::KDirSharePlugin(QObject *parent, const QList<QVariant> &args)
             kWarning() << "Invalid kdirshare module reply for isShared()";
             m_ui.sharebox->setChecked(false);
             m_ui.portgroup->setEnabled(false);
+            m_ui.authgroup->setEnabled(false);
         } else {
             m_ui.sharebox->setChecked(kdirsharereply.value());
             m_ui.portgroup->setEnabled(kdirsharereply.value());
+            m_ui.authgroup->setEnabled(kdirsharereply.value());
         }
 
         QDBusReply<quint16> kdirsharereply2 = m_kdirshareiface.call("getPortMin", m_url);
@@ -82,16 +84,40 @@ KDirSharePlugin::KDirSharePlugin(QObject *parent, const QList<QVariant> &args)
         const bool randomport = (m_ui.portmininput->value() != m_ui.portmaxinput->value());
         m_ui.randombox->setChecked(randomport);
         m_ui.portmininput->setVisible(randomport);
+
+        QDBusReply<QString> kdirsharereply3 = m_kdirshareiface.call("getUser", m_url);
+        if (!kdirsharereply3.isValid()) {
+            kWarning() << "Invalid kdirshare module reply for getUser()";
+            m_ui.useredit->setText(QString());
+        } else {
+            m_ui.useredit->setText(kdirsharereply3.value());
+        }
+        kdirsharereply3 = m_kdirshareiface.call("getPassword", m_url);
+        if (!kdirsharereply3.isValid()) {
+            kWarning() << "Invalid kdirshare module reply for getPassword()";
+            m_ui.passwordedit->setText(QString());
+        } else {
+            m_ui.passwordedit->setText(kdirsharereply3.value());
+        }
+        if (!m_ui.useredit->text().isEmpty() || !m_ui.passwordedit->text().isEmpty()) {
+            m_ui.authbox->setChecked(true);
+        }
+        m_ui.useredit->setEnabled(m_ui.authbox->isChecked());
+        m_ui.passwordedit->setEnabled(m_ui.authbox->isChecked());
     } else {
         kWarning() << "kdirshare module interface is not valid";
         m_ui.sharebox->setEnabled(false);
         m_ui.portgroup->setEnabled(false);
+        m_ui.authgroup->setEnabled(false);
     }
 
     connect(m_ui.sharebox, SIGNAL(toggled(bool)), this, SLOT(slotShare(bool)));
     connect(m_ui.randombox, SIGNAL(toggled(bool)), this, SLOT(slotRandomPort(bool)));
     connect(m_ui.portmininput, SIGNAL(valueChanged(int)), this, SLOT(slotPortMin(int)));
     connect(m_ui.portmaxinput, SIGNAL(valueChanged(int)), this, SLOT(slotPortMax(int)));
+    connect(m_ui.authbox, SIGNAL(toggled(bool)), this, SLOT(slotAuthorization(bool)));
+    connect(m_ui.useredit, SIGNAL(textEdited(QString)), this, SLOT(slotUserEdited(QString)));
+    connect(m_ui.passwordedit, SIGNAL(textEdited(QString)), this, SLOT(slotPasswordEdited(QString)));
 }
 
 KDirSharePlugin::~KDirSharePlugin()
@@ -106,7 +132,8 @@ void KDirSharePlugin::applyChanges()
         if (m_ui.sharebox->isChecked()) {
             kdirsharereply = m_kdirshareiface.call("share",
                 m_url,
-                uint(m_ui.portmininput->value()), uint(m_ui.portmaxinput->value())
+                uint(m_ui.portmininput->value()), uint(m_ui.portmaxinput->value()),
+                m_ui.useredit->text(), m_ui.passwordedit->text()
             );
         } else {
             kdirsharereply = m_kdirshareiface.call("unshare", m_url);
@@ -126,6 +153,7 @@ void KDirSharePlugin::slotShare(const bool value)
 {
     // qDebug() << Q_FUNC_INFO << value;
     m_ui.portgroup->setEnabled(value);
+    m_ui.authgroup->setEnabled(value);
     emit changed();
 }
 
@@ -157,4 +185,28 @@ void KDirSharePlugin::slotPortMax(const int value)
     emit changed();
 }
 
+void KDirSharePlugin::slotAuthorization(const bool value)
+{
+    // qDebug() << Q_FUNC_INFO << value;
+    m_ui.useredit->setEnabled(value);
+    m_ui.passwordedit->setEnabled(value);
+    if (!value) {
+        m_ui.useredit->clear();
+        m_ui.passwordedit->clear();
+    }
+    emit changed();
+}
+
+void KDirSharePlugin::slotUserEdited(const QString &value)
+{
+    // qDebug() << Q_FUNC_INFO << value;
+    emit changed();
+}
+
+void KDirSharePlugin::slotPasswordEdited(const QString &value)
+{
+    // qDebug() << Q_FUNC_INFO << value;
+    emit changed();
+}
+
 #include "moc_kdirshareplugin.cpp"
index 56906f9..a57a925 100644 (file)
@@ -38,6 +38,9 @@ private Q_SLOTS:
     void slotRandomPort(const bool value);
     void slotPortMin(const int value);
     void slotPortMax(const int value);
+    void slotAuthorization(const bool value);
+    void slotUserEdited(const QString &value);
+    void slotPasswordEdited(const QString &value);
 
 private:
     Ui_KDirShareUI m_ui;
index 682451a..8f28b3c 100644 (file)
     </widget>
    </item>
    <item>
+    <widget class="QGroupBox" name="authgroup">
+     <property name="title">
+      <string>Authentication</string>
+     </property>
+     <layout class="QGridLayout" name="gridLayout_2">
+      <item row="3" column="0">
+       <widget class="QLabel" name="label_2">
+        <property name="text">
+         <string>Password:</string>
+        </property>
+       </widget>
+      </item>
+      <item row="1" column="0">
+       <widget class="QLabel" name="label">
+        <property name="text">
+         <string>User:</string>
+        </property>
+       </widget>
+      </item>
+      <item row="1" column="1">
+       <widget class="QLineEdit" name="useredit"/>
+      </item>
+      <item row="3" column="1">
+       <widget class="QLineEdit" name="passwordedit">
+        <property name="echoMode">
+         <enum>QLineEdit::Password</enum>
+        </property>
+       </widget>
+      </item>
+      <item row="0" column="0">
+       <widget class="QCheckBox" name="authbox">
+        <property name="text">
+         <string>Require authentication</string>
+        </property>
+       </widget>
+      </item>
+     </layout>
+    </widget>
+   </item>
+   <item>
     <spacer name="verticalSpacer">
      <property name="orientation">
       <enum>Qt::Vertical</enum>
index a103e08..cac8be5 100644 (file)
@@ -14,6 +14,7 @@ target_link_libraries(kded_kdirshare PRIVATE
     ${KDE4_KDEUI_LIBS}
     ${KDE4_KHTTP_LIBS}
     ${KDE4_KDNSSD_LIBS}
+    ${KDE4_KPASSWDSTORE_LIBS}
 )
 
 if(OPENSSL_FOUND)
index f6b4ca6..d86a71f 100644 (file)
@@ -21,6 +21,7 @@
 
 #include <QThread>
 #include <QCoreApplication>
+#include <QTimer>
 #include <klocale.h>
 #include <kconfiggroup.h>
 #include <knotification.h>
@@ -52,10 +53,14 @@ public:
     KDirShareThread(QObject *parent = nullptr);
     ~KDirShareThread();
 
-    QString serve(const QString &dirpath, const quint16 portmin, const quint16 portmax);
+    QString serve(const QString &dirpath,
+                  const quint16 portmin, const quint16 portmax,
+                  const QString &username, const QString &password);
     QString directory() const;
     quint16 portMin() const;
     quint16 portMax() const;
+    QString user() const;
+    QString password() const;
 
 Q_SIGNALS:
     void unblock();
@@ -75,6 +80,8 @@ private:
     quint16 m_port;
     quint16 m_portmin;
     quint16 m_portmax;
+    QString m_user;
+    QString m_password;
     QString m_error;
 };
 
@@ -119,6 +126,16 @@ quint16 KDirShareThread::portMax() const
     return m_portmax;
 }
 
+QString KDirShareThread::user() const
+{
+    return m_user;
+}
+
+QString KDirShareThread::password() const
+{
+    return m_password;
+}
+
 void KDirShareThread::run()
 {
     if (!m_kdirshareimpl->setDirectory(m_directory)) {
@@ -126,6 +143,13 @@ void KDirShareThread::run()
         emit unblock();
         return;
     }
+    if (!m_user.isEmpty() && !m_password.isEmpty()) {
+        if (!m_kdirshareimpl->setAuthenticate(m_user.toUtf8(), m_password.toUtf8(), i18n("Not authorized"))) {
+            emit serveError(i18n("Could not set authentication: %1", m_kdirshareimpl->errorString()));
+            emit unblock();
+            return;
+        }
+    }
     if (!m_kdirshareimpl->serve(QHostAddress(QHostAddress::Any), m_port)) {
         emit serveError(i18n("Could not serve: %1", m_kdirshareimpl->errorString()));
         emit unblock();
@@ -140,13 +164,17 @@ void KDirShareThread::run()
     emit unblock();
 }
 
-QString KDirShareThread::serve(const QString &dirpath, const quint16 portmin, const quint16 portmax)
+QString KDirShareThread::serve(const QString &dirpath,
+                               const quint16 portmin, const quint16 portmax,
+                               const QString &username, const QString &password)
 {
     // qDebug() << Q_FUNC_INFO << dirpath << port;
     m_directory = dirpath;
     m_port = getPort(portmin, portmax);
     m_portmin = portmin;
     m_portmax = portmax;
+    m_user = username;
+    m_password = password;
     m_starting = true;
     m_error.clear();
     start();
@@ -174,35 +202,9 @@ K_EXPORT_PLUGIN(KDirShareModuleFactory("kdirshare"))
 KDirShareModule::KDirShareModule(QObject *parent, const QList<QVariant>&)
     : KDEDModule(parent)
 {
-    bool shareerror = false;
-    KConfig kdirshareconfig("kdirsharerc", KConfig::SimpleConfig);
-    foreach (const QString &kdirsharekey, kdirshareconfig.groupList()) {
-        // qDebug() << Q_FUNC_INFO << kdirsharekey;
-        KConfigGroup kdirsharegroup = kdirshareconfig.group(kdirsharekey);
-        const QString kdirsharedirpath = kdirsharegroup.readEntry("dirpath", QString());
-        if (kdirsharedirpath.isEmpty()) {
-            continue;
-        }
-        const uint kdirshareportmin = kdirsharegroup.readEntry("portmin", uint(s_kdirshareportmin));
-        const uint kdirshareportmax = kdirsharegroup.readEntry("portmax", uint(s_kdirshareportmax));
-        // qDebug() << Q_FUNC_INFO << kdirsharekey << kdirsharedirpath << kdirshareportmin << kdirshareportmax;
-        const QString kdirshareerror = share(
-            kdirsharedirpath,
-            quint16(kdirshareportmin), quint16(kdirshareportmax)
-        );
-        if (!kdirshareerror.isEmpty()) {
-            kWarning() << kdirshareerror;
-            shareerror = true;
-        }
-    }
-
-    if (shareerror) {
-        KNotification *knotification = new KNotification("ShareError");
-        knotification->setComponentData(KComponentData("kdirshare"));
-        knotification->setTitle(i18n("Directory share"));
-        knotification->setText(i18n("Unable to share one or more directories"));
-        knotification->sendEvent();
-    }
+    m_passwdstore.setStoreID("KDirShare");
+    // HACK: kpasswdstore uses on-demand service so doing delayed restore
+    QTimer::singleShot(2000, this, SLOT(slotDelayedRestore()));
 }
 
 KDirShareModule::~KDirShareModule()
@@ -215,12 +217,15 @@ KDirShareModule::~KDirShareModule()
         kdirsharegroup.writeEntry("dirpath", kdirsharethread->directory());
         kdirsharegroup.writeEntry("portmin", uint(kdirsharethread->portMin()));
         kdirsharegroup.writeEntry("portmax", uint(kdirsharethread->portMax()));
+        kdirsharegroup.writeEntry("user", kdirsharethread->user());
     }
     qDeleteAll(m_dirshares);
     m_dirshares.clear();
 }
 
-QString KDirShareModule::share(const QString &dirpath, const uint portmin, const uint portmax)
+QString KDirShareModule::share(const QString &dirpath,
+                               const uint portmin, const uint portmax,
+                               const QString &username, const QString &password)
 {
     if (isShared(dirpath)) {
         const QString unshareerror = unshare(dirpath);
@@ -231,7 +236,14 @@ QString KDirShareModule::share(const QString &dirpath, const uint portmin, const
 
     KDirShareThread *kdirsharethread = new KDirShareThread(this);
     // qDebug() << Q_FUNC_INFO << dirpath << portmin << portmax;
-    const QString serveerror = kdirsharethread->serve(dirpath, portmin, portmax);
+    const QString serveerror = kdirsharethread->serve(
+        dirpath,
+        portmin, portmax,
+        username, password
+    );
+    if (!username.isEmpty() && !password.isEmpty()) {
+        m_passwdstore.storePasswd(KPasswdStore::makeKey(dirpath), password);
+    }
     if (!serveerror.isEmpty()) {
         delete kdirsharethread;
         return serveerror;
@@ -287,4 +299,84 @@ quint16 KDirShareModule::getPortMax(const QString &dirpath) const
     return s_kdirshareportmax;
 }
 
+QString KDirShareModule::getUser(const QString &dirpath) const
+{
+    foreach (const KDirShareThread *kdirsharethread, m_dirshares) {
+        if (kdirsharethread->directory() == dirpath) {
+            return kdirsharethread->user();
+        }
+    }
+    return QString();
+}
+
+QString KDirShareModule::getPassword(const QString &dirpath) const
+{
+    foreach (const KDirShareThread *kdirsharethread, m_dirshares) {
+        if (kdirsharethread->directory() == dirpath) {
+            return kdirsharethread->password();
+        }
+    }
+    return QString();
+}
+
+void KDirShareModule::slotDelayedRestore()
+{
+    bool requiresauth = false;
+    KConfig kdirshareconfig("kdirsharerc", KConfig::SimpleConfig);
+    foreach (const QString &kdirsharekey, kdirshareconfig.groupList()) {
+        // qDebug() << Q_FUNC_INFO << kdirsharekey;
+        KConfigGroup kdirsharegroup = kdirshareconfig.group(kdirsharekey);
+        const QString kdirsharedirpath = kdirsharegroup.readEntry("dirpath", QString());
+        if (kdirsharedirpath.isEmpty()) {
+            continue;
+        }
+        const QString kdirshareuser = kdirsharegroup.readEntry("user", QString());
+        if (!kdirshareuser.isEmpty()) {
+            requiresauth = true;
+            break;
+        }
+    }
+    if (requiresauth) {
+        if (!m_passwdstore.openStore()) {
+            KNotification *knotification = new KNotification("AuthError");
+            knotification->setComponentData(KComponentData("kdirshare"));
+            knotification->setTitle(i18n("Directory share"));
+            knotification->setText(i18n("Authorization is required but could not open password store"));
+            knotification->sendEvent();
+            return;
+        }
+    }
+
+    bool shareerror = false;
+    foreach (const QString &kdirsharekey, kdirshareconfig.groupList()) {
+        // qDebug() << Q_FUNC_INFO << kdirsharekey;
+        KConfigGroup kdirsharegroup = kdirshareconfig.group(kdirsharekey);
+        const QString kdirsharedirpath = kdirsharegroup.readEntry("dirpath", QString());
+        if (kdirsharedirpath.isEmpty()) {
+            continue;
+        }
+        const uint kdirshareportmin = kdirsharegroup.readEntry("portmin", uint(s_kdirshareportmin));
+        const uint kdirshareportmax = kdirsharegroup.readEntry("portmax", uint(s_kdirshareportmax));
+        const QString kdirshareuser = kdirsharegroup.readEntry("user", QString());
+        const QString kdirsharepassword = m_passwdstore.getPasswd(KPasswdStore::makeKey(kdirsharedirpath));
+        // qDebug() << Q_FUNC_INFO << kdirsharekey << kdirsharedirpath << kdirshareportmin << kdirshareportmax;
+        const QString kdirshareerror = share(
+            kdirsharedirpath,
+            quint16(kdirshareportmin), quint16(kdirshareportmax),
+            kdirshareuser, kdirsharepassword
+        );
+        if (!kdirshareerror.isEmpty()) {
+            kWarning() << kdirshareerror;
+            shareerror = true;
+        }
+    }
+    if (shareerror) {
+        KNotification *knotification = new KNotification("ShareError");
+        knotification->setComponentData(KComponentData("kdirshare"));
+        knotification->setTitle(i18n("Directory share"));
+        knotification->setText(i18n("Unable to share one or more directories"));
+        knotification->sendEvent();
+    }
+}
+
 #include "kded_kdirshare.moc"
index 10692b0..7e52a94 100644 (file)
@@ -23,6 +23,7 @@
 
 #include <QList>
 #include <kdedmodule.h>
+#include <kpasswdstore.h>
 
 class KDirShareThread;
 
@@ -36,16 +37,24 @@ public:
     ~KDirShareModule();
 
 public Q_SLOTS:
-    Q_SCRIPTABLE QString share(const QString &dirpath, const uint portmin, const uint portmax);
+    Q_SCRIPTABLE QString share(const QString &dirpath,
+                               const uint portmin, const uint portmax,
+                               const QString &username, const QString &password);
     Q_SCRIPTABLE QString unshare(const QString &dirpath);
 
     Q_SCRIPTABLE bool isShared(const QString &dirpath) const;
 
     Q_SCRIPTABLE quint16 getPortMin(const QString &dirpath) const;
     Q_SCRIPTABLE quint16 getPortMax(const QString &dirpath) const;
+    Q_SCRIPTABLE QString getUser(const QString &dirpath) const;
+    Q_SCRIPTABLE QString getPassword(const QString &dirpath) const;
+
+private Q_SLOTS:
+    void slotDelayedRestore();
 
 private:
     QList<KDirShareThread*> m_dirshares;
+    KPasswdStore m_passwdstore;
 };
 
 #endif // KDIRSHARE_KDED_H
index d32301d..db0a0b3 100644 (file)
@@ -148,11 +148,6 @@ KDirShareImpl::~KDirShareImpl()
     stop();
 }
 
-QString KDirShareImpl::directory() const
-{
-    return m_directory;
-}
-
 bool KDirShareImpl::setDirectory(const QString &dirpath)
 {
     if (!QDir(dirpath).exists()) {
index c5b10d9..6f2dc6b 100644 (file)
@@ -29,7 +29,6 @@ public:
     KDirShareImpl(QObject *parent = nullptr);
     ~KDirShareImpl();
 
-    QString directory() const;
     bool setDirectory(const QString &dirpath);
     bool serve(const QHostAddress &address, const quint16 port);
     bool publish();
index c901f79..7d527bd 100644 (file)
@@ -3,6 +3,12 @@ Name=kdirshare
 Comment=Directory share
 IconName=network-server
 
+[Event/AuthError]
+Name=Authorization is required but could not open password store
+Action=Sound|Popup
+Sound=KDE-Sys-App-Error-Serious.ogg
+IconName=dialog-error
+
 [Event/ShareError]
 Name=Unable to share one or more directories
 Action=Sound|Popup