Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pass XDG_ACTIVATION_TOKEN to apps launched via launch_app_env #3703

Merged
merged 22 commits into from
Jan 28, 2025
Merged
Show file tree
Hide file tree
Changes from 17 commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
84d9d8a
Add `TokenAuthority`, expose it via `Server::get_activation_token`
tarek-y-ismail Jan 23, 2025
c1ca68f
Modify `XdgActivationV1` to use `TokenAuthority`
tarek-y-ismail Jan 23, 2025
abf3192
Hook up `SessionListener`.
tarek-y-ismail Jan 23, 2025
96f53bd
Minor cleanups of xdg_activation.cpp
tarek-y-ismail Jan 23, 2025
d63b6e3
Pass `XDG_ACTIVATION_TOKEN` and `DESKTOP_STARTUP_ID` to launched apps
tarek-y-ismail Jan 23, 2025
6bf63b8
Ctrl+Alt+{t,T,x,X} now prevent other event filters from running.
tarek-y-ismail Jan 23, 2025
2f2c2b4
Ctrl+Alt+{t,T,x,X} now prevent other event filters from running. (#3726)
tarek-y-ismail Jan 23, 2025
f5ec4bd
PR feedback
tarek-y-ismail Jan 23, 2025
e28f18d
Don't let bogus tokens slide
tarek-y-ismail Jan 24, 2025
55da801
Use the old token-double-usage checking code
tarek-y-ismail Jan 24, 2025
cf43f17
Actually remove triggered token revocation alarms
tarek-y-ismail Jan 24, 2025
6cb3b96
Remove `TokenAuthority::is_token_valid`
tarek-y-ismail Jan 24, 2025
02ff4b5
Move token issuance to `XdgActivationTokenV1::commit`
tarek-y-ismail Jan 24, 2025
efa54ef
Merge `revocation_alarms` into `issued_tokens`
tarek-y-ismail Jan 24, 2025
61b984e
Pass `token_authority` as `const&` instead of copying the shared pointer
tarek-y-ismail Jan 27, 2025
e4d92be
Make `TokenAuthority::TokenAuthority` explicit
tarek-y-ismail Jan 27, 2025
167f78a
Copy the main loop shared ptr instead of moving out of it
tarek-y-ismail Jan 27, 2025
11b3fe0
Add a basic test suite for `TokenAuthority`
tarek-y-ismail Jan 27, 2025
d273459
Remove redundant const from `XdgActivationV1::create_token`'s return
tarek-y-ismail Jan 27, 2025
94556f0
PR feedback
tarek-y-ismail Jan 28, 2025
6b06163
Merge branch 'test-token-authority' into pass-xdg-activation-token-wh…
tarek-y-ismail Jan 28, 2025
45c2f00
Fix faulty main loop moving due to missing const correctness
tarek-y-ismail Jan 28, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)

set(MIR_VERSION_MAJOR 2)
set(MIR_VERSION_MINOR 19)
set(MIR_VERSION_PATCH 3)
set(MIR_VERSION_MINOR 20)
set(MIR_VERSION_PATCH 0)

add_compile_definitions(MIR_VERSION_MAJOR=${MIR_VERSION_MAJOR})
add_compile_definitions(MIR_VERSION_MINOR=${MIR_VERSION_MINOR})
Expand Down
4 changes: 2 additions & 2 deletions examples/miral-shell/shell_main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -110,12 +110,12 @@ int main(int argc, char const* argv[])
case XKB_KEY_t:
case XKB_KEY_T:
external_client_launcher.launch({terminal_cmd});
return false;
return true;

case XKB_KEY_x:
case XKB_KEY_X:
external_client_launcher.launch_using_x11({"xterm"});
return false;
return true;

default:
return false;
Expand Down
2 changes: 2 additions & 0 deletions src/include/server/mir/default_server_configuration.h
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,7 @@ class DefaultServerConfiguration : public virtual ServerConfiguration
std::shared_ptr<scene::TextInputHub> the_text_input_hub() override;
std::shared_ptr<scene::IdleHub> the_idle_hub() override;
std::shared_ptr<shell::IdleHandler> the_idle_handler() override;
std::shared_ptr<shell::TokenAuthority> the_token_authority() override;
std::function<void()> the_stop_callback() override;
std::shared_ptr<scene::SessionLock> the_session_lock() override;
void add_wayland_extension(
Expand Down Expand Up @@ -407,6 +408,7 @@ class DefaultServerConfiguration : public virtual ServerConfiguration
CachedPtr<scene::TextInputHub> text_input_hub;
CachedPtr<scene::IdleHub> idle_hub;
CachedPtr<shell::IdleHandler> idle_handler;
CachedPtr<shell::TokenAuthority> token_authority;
CachedPtr<shell::DisplayLayout> shell_display_layout;
CachedPtr<compositor::DisplayBufferCompositorFactory> display_buffer_compositor_factory;
CachedPtr<compositor::Compositor> compositor;
Expand Down
4 changes: 2 additions & 2 deletions src/include/server/mir/frontend/connector.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@
#ifndef MIR_FRONTEND_CONNECTOR_H_
#define MIR_FRONTEND_CONNECTOR_H_

#include <mir/optional_value.h>
#include <functional>
#include <memory>
#include <optional>
#include <string>

namespace mir
Expand All @@ -41,7 +41,7 @@ class Connector

virtual int client_socket_fd(std::function<void(std::shared_ptr<scene::Session> const& session)> const& connect_handler) const = 0;

virtual auto socket_name() const -> optional_value<std::string> = 0;
virtual auto socket_name() const -> std::optional<std::string> = 0;

protected:
Connector() = default;
Expand Down
11 changes: 8 additions & 3 deletions src/include/server/mir/server.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,11 @@
#define MIR_SERVER_H_

#include "mir/shell/window_manager_builder.h"
#include "mir/optional_value.h"
#include "mir_toolkit/common.h"

#include <functional>
#include <memory>
#include <optional>
#include <vector>

struct wl_display;
Expand All @@ -47,6 +47,7 @@ class DisplayLayout;
class DisplayConfigurationController;
class FocusController;
class IdleHandler;
class TokenAuthority;
class InputTargeter;
class PersistentSurfaceStore;
class Shell;
Expand Down Expand Up @@ -435,6 +436,8 @@ class Server
auto the_idle_handler() const ->
std::shared_ptr<shell::IdleHandler>;

auto the_token_authority() const ->
std::shared_ptr<shell::TokenAuthority>;
/** @} */

/** @name Client side support
Expand Down Expand Up @@ -468,10 +471,12 @@ class Server
std::function<bool(std::shared_ptr<scene::Session> const&, char const*)> const& extension_filter);

/// Get the name of the Wayland endpoint (if any) usable as a $WAYLAND_DISPLAY value
auto wayland_display() const -> optional_value<std::string>;
auto wayland_display() const -> std::optional<std::string>;

/// Get the name of the X11 display usable as a $DISPLAY value
auto x11_display() const -> optional_value<std::string>;
auto x11_display() const -> std::optional<std::string>;

auto get_activation_token() const -> std::string;

/// Overrides the standard set of Wayland extensions (mir::frontend::get_standard_extensions()) with a new list
void set_enabled_wayland_extensions(std::vector<std::string> const& extensions);
Expand Down
2 changes: 2 additions & 0 deletions src/include/server/mir/server_configuration.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ namespace shell
class SessionContainer;
class Shell;
class IdleHandler;
class TokenAuthority;
}
namespace graphics
{
Expand Down Expand Up @@ -100,6 +101,7 @@ class ServerConfiguration
virtual std::shared_ptr<scene::TextInputHub> the_text_input_hub() = 0;
virtual std::shared_ptr<scene::IdleHub> the_idle_hub() = 0;
virtual std::shared_ptr<shell::IdleHandler> the_idle_handler() = 0;
virtual std::shared_ptr<shell::TokenAuthority> the_token_authority() = 0;
virtual std::function<void()> the_stop_callback() = 0;
virtual void add_wayland_extension(
std::string const& name,
Expand Down
80 changes: 80 additions & 0 deletions src/include/server/mir/shell/token_authority.h
tarek-y-ismail marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
/*
* Copyright © Canonical Ltd.
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 or 3,
* as published by the Free Software Foundation.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

#ifndef MIR_SHELL_TOKEN_AUTHORITY_H_
#define MIR_SHELL_TOKEN_AUTHORITY_H_

#include <chrono>
#include <functional>
#include <memory>
#include <unordered_set>

namespace mir
{
class MainLoop;
namespace time { class Alarm; }
namespace shell
{
class TokenAuthority
mattkae marked this conversation as resolved.
Show resolved Hide resolved
{
public:
class Token
{
public:
using RevocationListener = std::function<void(Token const& token)>;

bool operator==(Token const& token) const;
explicit operator std::string() const;

private:
friend TokenAuthority;
mattkae marked this conversation as resolved.
Show resolved Hide resolved

Token(std::string token, std::optional<RevocationListener> revocation_listener);

std::string token;
std::optional<RevocationListener> revocation_listener;
};

explicit TokenAuthority(std::shared_ptr<MainLoop>&& main_loop);

auto issue_token(std::optional<Token::RevocationListener> revocation_listener) -> Token;
auto get_token_for_string(std::string const& string_token) const -> std::optional<Token>;
auto get_bogus_token() const -> Token;

void revoke_token(Token to_remove);
void revoke_all_tokens();

private:
static auto generate_token() -> std::string;

using TimedToken = std::pair<Token, std::unique_ptr<time::Alarm>>;
mattkae marked this conversation as resolved.
Show resolved Hide resolved
struct TimedTokenHash
{
std::size_t operator()(TimedToken const& s) const noexcept;
};
struct TimedTokenEq
{
bool operator()(TimedToken const& s1, TimedToken const& s2) const noexcept;
};
std::mutex mutable mutex;
AlanGriffiths marked this conversation as resolved.
Show resolved Hide resolved
std::unordered_set<TimedToken, TimedTokenHash, TimedTokenEq> issued_tokens;

std::shared_ptr<MainLoop> const main_loop;
};
}
}

#endif
7 changes: 5 additions & 2 deletions src/miral/external_client.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@

#include <mir/options/option.h>
#include <mir/server.h>
#include <mir/log.h>

#include <algorithm>
#include <stdexcept>
Expand Down Expand Up @@ -117,8 +118,9 @@ auto miral::ExternalClientLauncher::launch(std::vector<std::string> const& comma

auto const wayland_display = self->server->wayland_display();
auto const x11_display = self->server->x11_display();
auto const activation_token = self->server->get_activation_token();

return launch_app_env(command_line, wayland_display, x11_display, self->env);
return launch_app_env(command_line, wayland_display, x11_display, activation_token, self->env);
}

miral::ExternalClientLauncher::ExternalClientLauncher() : self{std::make_shared<Self>()} {}
Expand All @@ -133,7 +135,8 @@ auto miral::ExternalClientLauncher::launch_using_x11(std::vector<std::string> c
if (auto const x11_display = self->server->x11_display())
{
auto const wayland_display = self->server->wayland_display();
return launch_app_env(command_line, wayland_display, x11_display, self->x11_env);
return launch_app_env(
command_line, wayland_display, x11_display, self->server->get_activation_token(), self->x11_env);
}

return -1;
Expand Down
68 changes: 33 additions & 35 deletions src/miral/launch_app.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,11 @@

#include <boost/throw_exception.hpp>

#include <string>
#include <unistd.h>
#include <signal.h>

#include <cstring>
#include <stdexcept>
#include <system_error>
#include <vector>

Expand Down Expand Up @@ -93,46 +93,21 @@ auto Environment::exec_env() const & -> std::vector<char const*>
result.push_back(nullptr);
return result;
}
} // namespace

auto miral::launch_app_env(
std::vector<std::string> const& app,
mir::optional_value<std::string> const& wayland_display,
mir::optional_value<std::string> const& x11_display,
miral::AppEnvironment const& app_env) -> pid_t
void assign_or_unset(Environment& env, std::string const& key, auto optional_value)
tarek-y-ismail marked this conversation as resolved.
Show resolved Hide resolved
{
Environment application_environment;

for (auto const& [key, value]: app_env)
{
if (value)
{
application_environment.setenv(key, value.value());
}
else
{
application_environment.unsetenv(key);
}
}

if (wayland_display)
if (optional_value)
{
application_environment.setenv("WAYLAND_DISPLAY", wayland_display.value()); // configure Wayland socket
env.setenv(key, optional_value.value());
}
else
{
application_environment.unsetenv("WAYLAND_DISPLAY");
}

if (x11_display)
{
application_environment.setenv("DISPLAY", x11_display.value()); // configure X11 socket
}
else
{
application_environment.unsetenv("DISPLAY");
env.unsetenv(key);
}
}

auto execute_with_environment(std::vector<std::string> const app, Environment& application_environment) -> pid_t
{
auto const exec_env = application_environment.exec_env();

std::vector<char const*> exec_args;
Expand All @@ -155,12 +130,35 @@ auto miral::launch_app_env(
sigfillset(&all_signals);
pthread_sigmask(SIG_UNBLOCK, &all_signals, nullptr);

// execvpe() isn't listed as being async-signal-safe, but the implementation looks fine and rewriting seems unnecessary
execvpe(exec_args[0], const_cast<char*const*>(exec_args.data()), const_cast<char*const*>(exec_env.data()));
// execvpe() isn't listed as being async-signal-safe, but the implementation looks fine and rewriting seems
// unnecessary
execvpe(exec_args[0], const_cast<char* const*>(exec_args.data()), const_cast<char* const*>(exec_env.data()));

mir::log_warning("Failed to execute client (\"%s\") error: %s", exec_args[0], strerror(errno));
exit(EXIT_FAILURE);
}

return pid;
}
} // namespace


auto miral::launch_app_env(
std::vector<std::string> const& app,
std::optional<std::string> const& wayland_display,
std::optional<std::string> const& x11_display,
std::optional<std::string> const& xdg_activation_token,
miral::AppEnvironment const& app_env) -> pid_t
{
Environment application_environment;

for (auto const& [key, value]: app_env)
assign_or_unset(application_environment, key, value);

assign_or_unset(application_environment, "WAYLAND_DISPLAY", wayland_display); // configure Wayland socket
assign_or_unset(application_environment, "DISPLAY", x11_display); // configure X11 socket
assign_or_unset(application_environment, "XDG_ACTIVATION_TOKEN", xdg_activation_token);
assign_or_unset(application_environment, "DESKTOP_STARTUP_ID", xdg_activation_token);

return execute_with_environment(app, application_environment);
}
5 changes: 3 additions & 2 deletions src/miral/launch_app.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,9 @@ namespace miral
using AppEnvironment = std::map<std::string, std::optional<std::string>>;

auto launch_app_env(std::vector<std::string> const& app,
mir::optional_value<std::string> const& wayland_display,
mir::optional_value<std::string> const& x11_display,
std::optional<std::string> const& wayland_display,
std::optional<std::string> const& x11_display,
std::optional<std::string> const& xdg_activation_token,
AppEnvironment const& app_env) -> pid_t;
}

Expand Down
14 changes: 12 additions & 2 deletions src/miral/runner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -274,13 +274,23 @@ auto miral::MirRunner::display_config_file() const -> std::string
return self->display_config_file;
}

namespace
{
auto optional_to_mir_optional(std::optional<std::string> const& opt) -> mir::optional_value<std::string>
{
if (!opt)
return {};
return mir::optional_value{*opt};
}
}

auto miral::MirRunner::wayland_display() const -> mir::optional_value<std::string>
{
std::lock_guard lock{self->mutex};

if (auto const server = self->weak_server.lock())
{
return server->wayland_display();
return optional_to_mir_optional(server->wayland_display());
}

return {};
Expand All @@ -292,7 +302,7 @@ auto miral::MirRunner::x11_display() const -> mir::optional_value<std::string>

if (auto const server = self->weak_server.lock())
{
return server->x11_display();
return optional_to_mir_optional(server->x11_display());
}

return {};
Expand Down
1 change: 1 addition & 0 deletions src/miral/x11_support.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include <mir/options/configuration.h>
#include <mir/main_loop.h>
#include <mir/fd.h>
#include <mir/fatal.h>
AlanGriffiths marked this conversation as resolved.
Show resolved Hide resolved

namespace mo = mir::options;

Expand Down
1 change: 0 additions & 1 deletion src/server/frontend_wayland/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,5 @@ target_link_libraries(mirfrontend-wayland
mircore
PRIVATE
PkgConfig::GIOUnix
PkgConfig::UUID
)

Loading
Loading