Expose wl_display_set_global_filter as a virtual method
Summary: This allows a server to filter which globals are visible and bindable by clients. Design rationale: Could be it's own class with Display as an arg, but we need the lifespan to exactly match Display, and the cardinality to match Display and it needs to be set after we're started but before clients connect. Better to enfore rules with code than with documentation. I'm filtering by interface name as there isn't any other good identifier of what a wl_global refers to, even if you could assume you can cast the userdata to a Server::Global. Test Plan: Attached unit test Reviewers: #plasma, graesslin, bcooksley Reviewed By: #plasma, graesslin Subscribers: bcooksley, graesslin, plasma-devel, #frameworks Tags: #frameworks, #plasma Differential Revision: https://phabricator.kde.org/D8050
This commit is contained in:
parent
6cf6a4c72c
commit
ec75361d1f
5 changed files with 317 additions and 0 deletions
|
@ -8,6 +8,7 @@ set(SERVER_LIB_SRCS
|
|||
datasource_interface.cpp
|
||||
display.cpp
|
||||
dpms_interface.cpp
|
||||
filtered_display.cpp
|
||||
global.cpp
|
||||
idle_interface.cpp
|
||||
idleinhibit_interface.cpp
|
||||
|
@ -202,6 +203,7 @@ set(SERVER_LIB_HEADERS
|
|||
datasource_interface.h
|
||||
display.h
|
||||
dpms_interface.h
|
||||
filtered_display.h
|
||||
fakeinput_interface.h
|
||||
global.h
|
||||
idle_interface.h
|
||||
|
|
|
@ -379,3 +379,15 @@ add_executable(testPointerConstraints test_pointer_constraints.cpp)
|
|||
target_link_libraries( testPointerConstraints Qt5::Test Qt5::Gui KF5::WaylandServer KF5::WaylandClient Wayland::Client)
|
||||
add_test(NAME kwayland-testPointerConstraints COMMAND testPointerConstraints)
|
||||
ecm_mark_as_test(testPointerConstraints)
|
||||
|
||||
|
||||
########################################################
|
||||
# Test Filter
|
||||
########################################################
|
||||
set( testFilter_SRCS
|
||||
test_wayland_filter.cpp
|
||||
)
|
||||
add_executable(testFilter ${testFilter_SRCS})
|
||||
target_link_libraries( testFilter Qt5::Test Qt5::Gui KF5::WaylandClient KF5::WaylandServer Wayland::Server)
|
||||
add_test(NAME kwayland-testFilter COMMAND testFilter)
|
||||
ecm_mark_as_test(testFilter)
|
||||
|
|
168
src/wayland/autotests/client/test_wayland_filter.cpp
Normal file
168
src/wayland/autotests/client/test_wayland_filter.cpp
Normal file
|
@ -0,0 +1,168 @@
|
|||
/********************************************************************
|
||||
Copyright 2017 David Edmundson <davidedmundson@kde.org>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) version 3, or any
|
||||
later version accepted by the membership of KDE e.V. (or its
|
||||
successor approved by the membership of KDE e.V.), which shall
|
||||
act as a proxy defined in Section 6 of version 3 of the license.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*********************************************************************/
|
||||
// Qt
|
||||
#include <QtTest/QtTest>
|
||||
// KWin
|
||||
#include "../../src/client/compositor.h"
|
||||
#include "../../src/client/connection_thread.h"
|
||||
#include "../../src/client/event_queue.h"
|
||||
#include "../../src/client/region.h"
|
||||
#include "../../src/client/registry.h"
|
||||
#include "../../src/client/surface.h"
|
||||
#include "../../src/client/blur.h"
|
||||
#include "../../src/server/display.h"
|
||||
#include "../../src/server/compositor_interface.h"
|
||||
#include "../../src/server/region_interface.h"
|
||||
#include "../../src/server/blur_interface.h"
|
||||
#include "../../src/server/filtered_display.h"
|
||||
|
||||
#include <wayland-server.h>
|
||||
|
||||
using namespace KWayland::Client;
|
||||
|
||||
class TestDisplay;
|
||||
|
||||
class TestFilter : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit TestFilter(QObject *parent = nullptr);
|
||||
private Q_SLOTS:
|
||||
void init();
|
||||
void cleanup();
|
||||
void testFilter_data();
|
||||
void testFilter();
|
||||
|
||||
private:
|
||||
TestDisplay *m_display;
|
||||
KWayland::Server::CompositorInterface *m_compositorInterface;
|
||||
KWayland::Server::BlurManagerInterface *m_blurManagerInterface;
|
||||
};
|
||||
|
||||
static const QString s_socketName = QStringLiteral("kwayland-test-wayland-blur-0");
|
||||
|
||||
//The following non-realistic class allows only clients in the m_allowedClients list to access the blur interface
|
||||
//all other interfaces are allowed
|
||||
class TestDisplay : public KWayland::Server::FilteredDisplay
|
||||
{
|
||||
public:
|
||||
TestDisplay(QObject *parent);
|
||||
bool allowInterface(KWayland::Server::ClientConnection * client, const QByteArray & interfaceName) override;
|
||||
QList<wl_client*> m_allowedClients;
|
||||
};
|
||||
|
||||
TestDisplay::TestDisplay(QObject *parent):
|
||||
KWayland::Server::FilteredDisplay(parent)
|
||||
{}
|
||||
|
||||
bool TestDisplay::allowInterface(KWayland::Server::ClientConnection* client, const QByteArray& interfaceName)
|
||||
{
|
||||
if (interfaceName == "org_kde_kwin_blur_manager") {
|
||||
return m_allowedClients.contains(*client);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
TestFilter::TestFilter(QObject *parent)
|
||||
: QObject(parent)
|
||||
, m_display(nullptr)
|
||||
, m_compositorInterface(nullptr)
|
||||
{}
|
||||
|
||||
void TestFilter::init()
|
||||
{
|
||||
using namespace KWayland::Server;
|
||||
delete m_display;
|
||||
m_display = new TestDisplay(this);
|
||||
m_display->setSocketName(s_socketName);
|
||||
m_display->start();
|
||||
QVERIFY(m_display->isRunning());
|
||||
|
||||
m_compositorInterface = m_display->createCompositor(m_display);
|
||||
m_compositorInterface->create();
|
||||
QVERIFY(m_compositorInterface->isValid());
|
||||
|
||||
m_blurManagerInterface = m_display->createBlurManager(m_display);
|
||||
m_blurManagerInterface->create();
|
||||
QVERIFY(m_blurManagerInterface->isValid());
|
||||
}
|
||||
|
||||
void TestFilter::cleanup()
|
||||
{
|
||||
}
|
||||
|
||||
void TestFilter::testFilter_data()
|
||||
{
|
||||
QTest::addColumn<bool>("accessAllowed");
|
||||
QTest::newRow("granted") << true;
|
||||
QTest::newRow("denied") << false;
|
||||
|
||||
}
|
||||
|
||||
void TestFilter::testFilter()
|
||||
{
|
||||
QFETCH(bool, accessAllowed);
|
||||
|
||||
// setup connection
|
||||
QScopedPointer<KWayland::Client::ConnectionThread> connection(new KWayland::Client::ConnectionThread());
|
||||
QSignalSpy connectedSpy(connection.data(), &ConnectionThread::connected);
|
||||
QVERIFY(connectedSpy.isValid());
|
||||
connection->setSocketName(s_socketName);
|
||||
|
||||
QScopedPointer<QThread> thread(new QThread(this));
|
||||
connection->moveToThread(thread.data());
|
||||
thread->start();
|
||||
|
||||
connection->initConnection();
|
||||
QVERIFY(connectedSpy.wait());
|
||||
|
||||
//use low level API as Server::Display::connections only lists connections which have
|
||||
//been previous fetched via getConnection()
|
||||
if (accessAllowed) {
|
||||
wl_client *clientConnection;
|
||||
wl_client_for_each(clientConnection, wl_display_get_client_list(*m_display)) {
|
||||
m_display->m_allowedClients << clientConnection;
|
||||
}
|
||||
}
|
||||
|
||||
KWayland::Client::EventQueue queue;
|
||||
queue.setup(connection.data());
|
||||
|
||||
Registry registry;
|
||||
QSignalSpy registryDoneSpy(®istry, &Registry::interfacesAnnounced);
|
||||
QSignalSpy compositorSpy(®istry, &Registry::compositorAnnounced);
|
||||
QSignalSpy blurSpy(®istry, &Registry::blurAnnounced);
|
||||
|
||||
registry.setEventQueue(&queue);
|
||||
registry.create(connection->display());
|
||||
QVERIFY(registry.isValid());
|
||||
registry.setup();
|
||||
|
||||
QVERIFY(registryDoneSpy.wait());
|
||||
QVERIFY(compositorSpy.count() == 1);
|
||||
QVERIFY(blurSpy.count() == accessAllowed ? 1 : 0);
|
||||
|
||||
thread->quit();
|
||||
thread->wait();
|
||||
}
|
||||
|
||||
|
||||
QTEST_GUILESS_MAIN(TestFilter)
|
||||
#include "test_wayland_filter.moc"
|
70
src/wayland/filtered_display.cpp
Normal file
70
src/wayland/filtered_display.cpp
Normal file
|
@ -0,0 +1,70 @@
|
|||
/********************************************************************
|
||||
Copyright 2017 David Edmundson <davidedmundson@kde.org>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) version 3, or any
|
||||
later version accepted by the membership of KDE e.V. (or its
|
||||
successor approved by the membership of KDE e.V.), which shall
|
||||
act as a proxy defined in Section 6 of version 3 of the license.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*********************************************************************/
|
||||
|
||||
#include "filtered_display.h"
|
||||
#include "display.h"
|
||||
|
||||
#include <wayland-server.h>
|
||||
|
||||
#include <QByteArray>
|
||||
|
||||
namespace KWayland
|
||||
{
|
||||
namespace Server
|
||||
{
|
||||
|
||||
class FilteredDisplay::Private
|
||||
{
|
||||
public:
|
||||
Private(FilteredDisplay *_q);
|
||||
FilteredDisplay *q;
|
||||
static bool globalFilterCallback(const wl_client *client, const wl_global *global, void *data)
|
||||
{
|
||||
auto t = static_cast<FilteredDisplay::Private*>(data);
|
||||
auto clientConnection = t->q->getConnection(const_cast<wl_client*>(client));
|
||||
auto interface = wl_global_get_interface(global);
|
||||
auto name = QByteArray::fromRawData(interface->name, strlen(interface->name));
|
||||
return t->q->allowInterface(clientConnection, name);
|
||||
};
|
||||
};
|
||||
|
||||
FilteredDisplay::Private::Private(FilteredDisplay *_q):
|
||||
q(_q)
|
||||
{}
|
||||
|
||||
|
||||
FilteredDisplay::FilteredDisplay(QObject *parent):
|
||||
Display(parent),
|
||||
d(new Private(this))
|
||||
{
|
||||
connect(this, &Display::runningChanged, [this](bool running) {
|
||||
if (!running) {
|
||||
return;
|
||||
}
|
||||
wl_display_set_global_filter(*this, Private::globalFilterCallback, d.data());
|
||||
});
|
||||
}
|
||||
|
||||
FilteredDisplay::~FilteredDisplay()
|
||||
{
|
||||
}
|
||||
|
||||
}
|
||||
}
|
65
src/wayland/filtered_display.h
Normal file
65
src/wayland/filtered_display.h
Normal file
|
@ -0,0 +1,65 @@
|
|||
/********************************************************************
|
||||
Copyright 2017 David Edmundson <davidedmundson@kde.org>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) version 3, or any
|
||||
later version accepted by the membership of KDE e.V. (or its
|
||||
successor approved by the membership of KDE e.V.), which shall
|
||||
act as a proxy defined in Section 6 of version 3 of the license.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*********************************************************************/
|
||||
|
||||
#ifndef KWAYLAND_SERVER_FILTERED_DISPLAY_H
|
||||
#define KWAYLAND_SERVER_FILTERED_DISPLAY_H
|
||||
|
||||
#include "global.h"
|
||||
#include "display.h"
|
||||
|
||||
#include <KWayland/Server/kwaylandserver_export.h>
|
||||
|
||||
namespace KWayland
|
||||
{
|
||||
namespace Server
|
||||
{
|
||||
|
||||
/**
|
||||
* Server Implementation that allows one to restrict which globals are available to which clients
|
||||
*
|
||||
* Users of this class must implement the virtual @method allowInterface method.
|
||||
*
|
||||
* @since 5.FIXME
|
||||
*/
|
||||
class KWAYLANDSERVER_EXPORT FilteredDisplay : public Display
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
FilteredDisplay(QObject *parent);
|
||||
~FilteredDisplay();
|
||||
|
||||
/**
|
||||
* Return whether the @arg client can see the interface with the given @arg interfaceName
|
||||
*
|
||||
* When false will not see these globals for a given interface in the registry,
|
||||
* and any manual attempts to bind will fail
|
||||
*
|
||||
* @return true if the client should be able to access the global with the following interfaceName
|
||||
*/
|
||||
virtual bool allowInterface(ClientConnection *client, const QByteArray &interfaceName) = 0;
|
||||
private:
|
||||
class Private;
|
||||
QScopedPointer<Private> d;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
Loading…
Reference in a new issue