kdirshare: implement authentication

requires:
a48d4cbb28

Signed-off-by: Ivailo Monev <xakepa10@gmail.com>
This commit is contained in:
Ivailo Monev 2022-05-11 22:30:27 +03:00
parent 19ed9f7462
commit 0b0a9bdfe8
9 changed files with 238 additions and 41 deletions

View file

@ -60,9 +60,11 @@ KDirSharePlugin::KDirSharePlugin(QObject *parent, const QList<QVariant> &args)
kWarning() << "Invalid kdirshare module reply for isShared()"; kWarning() << "Invalid kdirshare module reply for isShared()";
m_ui.sharebox->setChecked(false); m_ui.sharebox->setChecked(false);
m_ui.portgroup->setEnabled(false); m_ui.portgroup->setEnabled(false);
m_ui.authgroup->setEnabled(false);
} else { } else {
m_ui.sharebox->setChecked(kdirsharereply.value()); m_ui.sharebox->setChecked(kdirsharereply.value());
m_ui.portgroup->setEnabled(kdirsharereply.value()); m_ui.portgroup->setEnabled(kdirsharereply.value());
m_ui.authgroup->setEnabled(kdirsharereply.value());
} }
QDBusReply<quint16> kdirsharereply2 = m_kdirshareiface.call("getPortMin", m_url); 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()); const bool randomport = (m_ui.portmininput->value() != m_ui.portmaxinput->value());
m_ui.randombox->setChecked(randomport); m_ui.randombox->setChecked(randomport);
m_ui.portmininput->setVisible(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 { } else {
kWarning() << "kdirshare module interface is not valid"; kWarning() << "kdirshare module interface is not valid";
m_ui.sharebox->setEnabled(false); m_ui.sharebox->setEnabled(false);
m_ui.portgroup->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.sharebox, SIGNAL(toggled(bool)), this, SLOT(slotShare(bool)));
connect(m_ui.randombox, SIGNAL(toggled(bool)), this, SLOT(slotRandomPort(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.portmininput, SIGNAL(valueChanged(int)), this, SLOT(slotPortMin(int)));
connect(m_ui.portmaxinput, SIGNAL(valueChanged(int)), this, SLOT(slotPortMax(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() KDirSharePlugin::~KDirSharePlugin()
@ -106,7 +132,8 @@ void KDirSharePlugin::applyChanges()
if (m_ui.sharebox->isChecked()) { if (m_ui.sharebox->isChecked()) {
kdirsharereply = m_kdirshareiface.call("share", kdirsharereply = m_kdirshareiface.call("share",
m_url, 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 { } else {
kdirsharereply = m_kdirshareiface.call("unshare", m_url); kdirsharereply = m_kdirshareiface.call("unshare", m_url);
@ -126,6 +153,7 @@ void KDirSharePlugin::slotShare(const bool value)
{ {
// qDebug() << Q_FUNC_INFO << value; // qDebug() << Q_FUNC_INFO << value;
m_ui.portgroup->setEnabled(value); m_ui.portgroup->setEnabled(value);
m_ui.authgroup->setEnabled(value);
emit changed(); emit changed();
} }
@ -157,4 +185,28 @@ void KDirSharePlugin::slotPortMax(const int value)
emit changed(); 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" #include "moc_kdirshareplugin.cpp"

View file

@ -38,6 +38,9 @@ private Q_SLOTS:
void slotRandomPort(const bool value); void slotRandomPort(const bool value);
void slotPortMin(const int value); void slotPortMin(const int value);
void slotPortMax(const int value); void slotPortMax(const int value);
void slotAuthorization(const bool value);
void slotUserEdited(const QString &value);
void slotPasswordEdited(const QString &value);
private: private:
Ui_KDirShareUI m_ui; Ui_KDirShareUI m_ui;

View file

@ -71,6 +71,46 @@
</layout> </layout>
</widget> </widget>
</item> </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> <item>
<spacer name="verticalSpacer"> <spacer name="verticalSpacer">
<property name="orientation"> <property name="orientation">

View file

@ -14,6 +14,7 @@ target_link_libraries(kded_kdirshare PRIVATE
${KDE4_KDEUI_LIBS} ${KDE4_KDEUI_LIBS}
${KDE4_KHTTP_LIBS} ${KDE4_KHTTP_LIBS}
${KDE4_KDNSSD_LIBS} ${KDE4_KDNSSD_LIBS}
${KDE4_KPASSWDSTORE_LIBS}
) )
if(OPENSSL_FOUND) if(OPENSSL_FOUND)

View file

@ -21,6 +21,7 @@
#include <QThread> #include <QThread>
#include <QCoreApplication> #include <QCoreApplication>
#include <QTimer>
#include <klocale.h> #include <klocale.h>
#include <kconfiggroup.h> #include <kconfiggroup.h>
#include <knotification.h> #include <knotification.h>
@ -52,10 +53,14 @@ public:
KDirShareThread(QObject *parent = nullptr); KDirShareThread(QObject *parent = nullptr);
~KDirShareThread(); ~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; QString directory() const;
quint16 portMin() const; quint16 portMin() const;
quint16 portMax() const; quint16 portMax() const;
QString user() const;
QString password() const;
Q_SIGNALS: Q_SIGNALS:
void unblock(); void unblock();
@ -75,6 +80,8 @@ private:
quint16 m_port; quint16 m_port;
quint16 m_portmin; quint16 m_portmin;
quint16 m_portmax; quint16 m_portmax;
QString m_user;
QString m_password;
QString m_error; QString m_error;
}; };
@ -119,6 +126,16 @@ quint16 KDirShareThread::portMax() const
return m_portmax; return m_portmax;
} }
QString KDirShareThread::user() const
{
return m_user;
}
QString KDirShareThread::password() const
{
return m_password;
}
void KDirShareThread::run() void KDirShareThread::run()
{ {
if (!m_kdirshareimpl->setDirectory(m_directory)) { if (!m_kdirshareimpl->setDirectory(m_directory)) {
@ -126,6 +143,13 @@ void KDirShareThread::run()
emit unblock(); emit unblock();
return; 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)) { if (!m_kdirshareimpl->serve(QHostAddress(QHostAddress::Any), m_port)) {
emit serveError(i18n("Could not serve: %1", m_kdirshareimpl->errorString())); emit serveError(i18n("Could not serve: %1", m_kdirshareimpl->errorString()));
emit unblock(); emit unblock();
@ -140,13 +164,17 @@ void KDirShareThread::run()
emit unblock(); 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; // qDebug() << Q_FUNC_INFO << dirpath << port;
m_directory = dirpath; m_directory = dirpath;
m_port = getPort(portmin, portmax); m_port = getPort(portmin, portmax);
m_portmin = portmin; m_portmin = portmin;
m_portmax = portmax; m_portmax = portmax;
m_user = username;
m_password = password;
m_starting = true; m_starting = true;
m_error.clear(); m_error.clear();
start(); start();
@ -174,35 +202,9 @@ K_EXPORT_PLUGIN(KDirShareModuleFactory("kdirshare"))
KDirShareModule::KDirShareModule(QObject *parent, const QList<QVariant>&) KDirShareModule::KDirShareModule(QObject *parent, const QList<QVariant>&)
: KDEDModule(parent) : KDEDModule(parent)
{ {
bool shareerror = false; m_passwdstore.setStoreID("KDirShare");
KConfig kdirshareconfig("kdirsharerc", KConfig::SimpleConfig); // HACK: kpasswdstore uses on-demand service so doing delayed restore
foreach (const QString &kdirsharekey, kdirshareconfig.groupList()) { QTimer::singleShot(2000, this, SLOT(slotDelayedRestore()));
// 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();
}
} }
KDirShareModule::~KDirShareModule() KDirShareModule::~KDirShareModule()
@ -215,12 +217,15 @@ KDirShareModule::~KDirShareModule()
kdirsharegroup.writeEntry("dirpath", kdirsharethread->directory()); kdirsharegroup.writeEntry("dirpath", kdirsharethread->directory());
kdirsharegroup.writeEntry("portmin", uint(kdirsharethread->portMin())); kdirsharegroup.writeEntry("portmin", uint(kdirsharethread->portMin()));
kdirsharegroup.writeEntry("portmax", uint(kdirsharethread->portMax())); kdirsharegroup.writeEntry("portmax", uint(kdirsharethread->portMax()));
kdirsharegroup.writeEntry("user", kdirsharethread->user());
} }
qDeleteAll(m_dirshares); qDeleteAll(m_dirshares);
m_dirshares.clear(); 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)) { if (isShared(dirpath)) {
const QString unshareerror = unshare(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); KDirShareThread *kdirsharethread = new KDirShareThread(this);
// qDebug() << Q_FUNC_INFO << dirpath << portmin << portmax; // 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()) { if (!serveerror.isEmpty()) {
delete kdirsharethread; delete kdirsharethread;
return serveerror; return serveerror;
@ -287,4 +299,84 @@ quint16 KDirShareModule::getPortMax(const QString &dirpath) const
return s_kdirshareportmax; 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" #include "kded_kdirshare.moc"

View file

@ -23,6 +23,7 @@
#include <QList> #include <QList>
#include <kdedmodule.h> #include <kdedmodule.h>
#include <kpasswdstore.h>
class KDirShareThread; class KDirShareThread;
@ -36,16 +37,24 @@ public:
~KDirShareModule(); ~KDirShareModule();
public Q_SLOTS: 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 QString unshare(const QString &dirpath);
Q_SCRIPTABLE bool isShared(const QString &dirpath) const; Q_SCRIPTABLE bool isShared(const QString &dirpath) const;
Q_SCRIPTABLE quint16 getPortMin(const QString &dirpath) const; Q_SCRIPTABLE quint16 getPortMin(const QString &dirpath) const;
Q_SCRIPTABLE quint16 getPortMax(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: private:
QList<KDirShareThread*> m_dirshares; QList<KDirShareThread*> m_dirshares;
KPasswdStore m_passwdstore;
}; };
#endif // KDIRSHARE_KDED_H #endif // KDIRSHARE_KDED_H

View file

@ -148,11 +148,6 @@ KDirShareImpl::~KDirShareImpl()
stop(); stop();
} }
QString KDirShareImpl::directory() const
{
return m_directory;
}
bool KDirShareImpl::setDirectory(const QString &dirpath) bool KDirShareImpl::setDirectory(const QString &dirpath)
{ {
if (!QDir(dirpath).exists()) { if (!QDir(dirpath).exists()) {

View file

@ -29,7 +29,6 @@ public:
KDirShareImpl(QObject *parent = nullptr); KDirShareImpl(QObject *parent = nullptr);
~KDirShareImpl(); ~KDirShareImpl();
QString directory() const;
bool setDirectory(const QString &dirpath); bool setDirectory(const QString &dirpath);
bool serve(const QHostAddress &address, const quint16 port); bool serve(const QHostAddress &address, const quint16 port);
bool publish(); bool publish();

View file

@ -3,6 +3,12 @@ Name=kdirshare
Comment=Directory share Comment=Directory share
IconName=network-server 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] [Event/ShareError]
Name=Unable to share one or more directories Name=Unable to share one or more directories
Action=Sound|Popup Action=Sound|Popup