diff options
author | DexesTTP <dexes.ttp@gmail.com> | 2021-04-24 01:46:49 +0200 |
---|---|---|
committer | Linus Groh <mail@linusgroh.de> | 2021-04-25 19:04:34 +0200 |
commit | 62ed26164bd160387c80522dfee5db2891b4c0dc (patch) | |
tree | 0ac84f7e03d12e6aaf320698cb18c452d50b938f /Userland | |
parent | c11ca9df33c602a8c5d8efb89cb42a9986629c1d (diff) | |
download | serenity-62ed26164bd160387c80522dfee5db2891b4c0dc.zip |
Services: Add a WebSocket service
The WebSocket service isolates communication with a WebSocket to its
own isolated process. Similar to other isolating services, it has its
own user and group.
Diffstat (limited to 'Userland')
-rw-r--r-- | Userland/Libraries/LibProtocol/CMakeLists.txt | 4 | ||||
-rw-r--r-- | Userland/Libraries/LibProtocol/WebSocket.cpp | 70 | ||||
-rw-r--r-- | Userland/Libraries/LibProtocol/WebSocket.h | 78 | ||||
-rw-r--r-- | Userland/Libraries/LibProtocol/WebSocketClient.cpp | 100 | ||||
-rw-r--r-- | Userland/Libraries/LibProtocol/WebSocketClient.h | 45 | ||||
-rw-r--r-- | Userland/Libraries/LibWebSocket/WebSocket.cpp | 3 | ||||
-rw-r--r-- | Userland/Services/CMakeLists.txt | 1 | ||||
-rw-r--r-- | Userland/Services/WebSocket/CMakeLists.txt | 12 | ||||
-rw-r--r-- | Userland/Services/WebSocket/ClientConnection.cpp | 144 | ||||
-rw-r--r-- | Userland/Services/WebSocket/ClientConnection.h | 46 | ||||
-rw-r--r-- | Userland/Services/WebSocket/WebSocketClient.ipc | 11 | ||||
-rw-r--r-- | Userland/Services/WebSocket/WebSocketServer.ipc | 13 | ||||
-rw-r--r-- | Userland/Services/WebSocket/main.cpp | 42 |
13 files changed, 569 insertions, 0 deletions
diff --git a/Userland/Libraries/LibProtocol/CMakeLists.txt b/Userland/Libraries/LibProtocol/CMakeLists.txt index 7c2e59d45d..a17b5e728b 100644 --- a/Userland/Libraries/LibProtocol/CMakeLists.txt +++ b/Userland/Libraries/LibProtocol/CMakeLists.txt @@ -1,11 +1,15 @@ set(SOURCES Client.cpp Download.cpp + WebSocket.cpp + WebSocketClient.cpp ) set(GENERATED_SOURCES ../../Services/ProtocolServer/ProtocolClientEndpoint.h ../../Services/ProtocolServer/ProtocolServerEndpoint.h + ../../Services/WebSocket/WebSocketClientEndpoint.h + ../../Services/WebSocket/WebSocketServerEndpoint.h ) serenity_lib(LibProtocol protocol) diff --git a/Userland/Libraries/LibProtocol/WebSocket.cpp b/Userland/Libraries/LibProtocol/WebSocket.cpp new file mode 100644 index 0000000000..5d497e1a18 --- /dev/null +++ b/Userland/Libraries/LibProtocol/WebSocket.cpp @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2021, Dex♪ <dexes.ttp@gmail.com> + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include <LibProtocol/WebSocket.h> +#include <LibProtocol/WebSocketClient.h> + +namespace Protocol { + +WebSocket::WebSocket(WebSocketClient& client, i32 connection_id) + : m_client(client) + , m_connection_id(connection_id) +{ +} + +WebSocket::ReadyState WebSocket::ready_state() +{ + return (WebSocket::ReadyState)m_client->ready_state({}, *this); +} + +void WebSocket::send(ByteBuffer binary_or_text_message, bool is_text) +{ + m_client->send({}, *this, move(binary_or_text_message), is_text); +} + +void WebSocket::send(StringView text_message) +{ + send(ByteBuffer::copy(text_message.bytes()), true); +} + +void WebSocket::close(u16 code, String reason) +{ + m_client->close({}, *this, code, move(reason)); +} + +void WebSocket::did_open(Badge<WebSocketClient>) +{ + if (on_open) + on_open(); +} + +void WebSocket::did_receive(Badge<WebSocketClient>, ByteBuffer data, bool is_text) +{ + if (on_message) + on_message(WebSocket::Message { move(data), is_text }); +} + +void WebSocket::did_error(Badge<WebSocketClient>, i32 error_code) +{ + if (on_error) + on_error((WebSocket::Error)error_code); +} + +void WebSocket::did_close(Badge<WebSocketClient>, u16 code, String reason, bool was_clean) +{ + if (on_close) + on_close(code, move(reason), was_clean); +} + +void WebSocket::did_request_certificates(Badge<WebSocketClient>) +{ + if (on_certificate_requested) { + auto result = on_certificate_requested(); + if (!m_client->set_certificate({}, *this, result.certificate, result.key)) + dbgln("WebSocket: set_certificate failed"); + } +} +} diff --git a/Userland/Libraries/LibProtocol/WebSocket.h b/Userland/Libraries/LibProtocol/WebSocket.h new file mode 100644 index 0000000000..c0f079f5c1 --- /dev/null +++ b/Userland/Libraries/LibProtocol/WebSocket.h @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2021, Dex♪ <dexes.ttp@gmail.com> + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include <AK/Badge.h> +#include <AK/ByteBuffer.h> +#include <AK/Function.h> +#include <AK/RefCounted.h> +#include <AK/String.h> +#include <AK/WeakPtr.h> +#include <LibCore/Notifier.h> +#include <LibIPC/Forward.h> + +namespace Protocol { + +class WebSocketClient; + +class WebSocket : public RefCounted<WebSocket> { +public: + struct CertificateAndKey { + String certificate; + String key; + }; + + struct Message { + ByteBuffer data; + bool is_text { false }; + }; + + enum class Error { + CouldNotEstablishConnection, + ConnectionUpgradeFailed, + ServerClosedSocket, + }; + + enum class ReadyState { + Connecting = 0, + Open = 1, + Closing = 2, + Closed = 3, + }; + + static NonnullRefPtr<WebSocket> create_from_id(Badge<WebSocketClient>, WebSocketClient& client, i32 connection_id) + { + return adopt_ref(*new WebSocket(client, connection_id)); + } + + int id() const { return m_connection_id; } + + ReadyState ready_state(); + + void send(ByteBuffer binary_or_text_message, bool is_text); + void send(StringView text_message); + void close(u16 code = 1005, String reason = {}); + + Function<void()> on_open; + Function<void(Message)> on_message; + Function<void(Error)> on_error; + Function<void(u16 code, String reason, bool was_clean)> on_close; + Function<CertificateAndKey()> on_certificate_requested; + + void did_open(Badge<WebSocketClient>); + void did_receive(Badge<WebSocketClient>, ByteBuffer, bool); + void did_error(Badge<WebSocketClient>, i32); + void did_close(Badge<WebSocketClient>, u16, String, bool); + void did_request_certificates(Badge<WebSocketClient>); + +private: + explicit WebSocket(WebSocketClient&, i32 connection_id); + WeakPtr<WebSocketClient> m_client; + int m_connection_id { -1 }; +}; + +} diff --git a/Userland/Libraries/LibProtocol/WebSocketClient.cpp b/Userland/Libraries/LibProtocol/WebSocketClient.cpp new file mode 100644 index 0000000000..728f05a3a1 --- /dev/null +++ b/Userland/Libraries/LibProtocol/WebSocketClient.cpp @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2021, Dex♪ <dexes.ttp@gmail.com> + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include <LibProtocol/WebSocket.h> +#include <LibProtocol/WebSocketClient.h> + +namespace Protocol { + +WebSocketClient::WebSocketClient() + : IPC::ServerConnection<WebSocketClientEndpoint, WebSocketServerEndpoint>(*this, "/tmp/portal/websocket") +{ + handshake(); +} + +void WebSocketClient::handshake() +{ + send_sync<Messages::WebSocketServer::Greet>(); +} + +RefPtr<WebSocket> WebSocketClient::connect(const URL& url, const String& origin, const Vector<String>& protocols, const Vector<String>& extensions, const HashMap<String, String>& request_headers) +{ + IPC::Dictionary header_dictionary; + for (auto& it : request_headers) + header_dictionary.add(it.key, it.value); + auto response = send_sync<Messages::WebSocketServer::Connect>(url, origin, protocols, extensions, header_dictionary); + auto connection_id = response->connection_id(); + if (connection_id < 0) + return nullptr; + auto connection = WebSocket::create_from_id({}, *this, connection_id); + m_connections.set(connection_id, connection); + return connection; +} + +u32 WebSocketClient::ready_state(Badge<WebSocket>, WebSocket& connection) +{ + if (!m_connections.contains(connection.id())) + return (u32)WebSocket::ReadyState::Closed; + return send_sync<Messages::WebSocketServer::ReadyState>(connection.id())->ready_state(); +} + +void WebSocketClient::send(Badge<WebSocket>, WebSocket& connection, ByteBuffer data, bool is_text) +{ + if (!m_connections.contains(connection.id())) + return; + post_message(Messages::WebSocketServer::Send(connection.id(), is_text, move(data))); +} + +void WebSocketClient::close(Badge<WebSocket>, WebSocket& connection, u16 code, String message) +{ + if (!m_connections.contains(connection.id())) + return; + post_message(Messages::WebSocketServer::Close(connection.id(), code, move(message))); +} + +bool WebSocketClient::set_certificate(Badge<WebSocket>, WebSocket& connection, String certificate, String key) +{ + if (!m_connections.contains(connection.id())) + return false; + return send_sync<Messages::WebSocketServer::SetCertificate>(connection.id(), move(certificate), move(key))->success(); +} + +void WebSocketClient::handle(const Messages::WebSocketClient::Connected& message) +{ + auto maybe_connection = m_connections.get(message.connection_id()); + if (maybe_connection.has_value()) + maybe_connection.value()->did_open({}); +} + +void WebSocketClient::handle(const Messages::WebSocketClient::Received& message) +{ + auto maybe_connection = m_connections.get(message.connection_id()); + if (maybe_connection.has_value()) + maybe_connection.value()->did_receive({}, message.data(), message.is_text()); +} + +void WebSocketClient::handle(const Messages::WebSocketClient::Errored& message) +{ + auto maybe_connection = m_connections.get(message.connection_id()); + if (maybe_connection.has_value()) + maybe_connection.value()->did_error({}, message.message()); +} + +void WebSocketClient::handle(const Messages::WebSocketClient::Closed& message) +{ + auto maybe_connection = m_connections.get(message.connection_id()); + if (maybe_connection.has_value()) + maybe_connection.value()->did_close({}, message.code(), message.reason(), message.clean()); +} + +void WebSocketClient::handle(const Messages::WebSocketClient::CertificateRequested& message) +{ + auto maybe_connection = m_connections.get(message.connection_id()); + if (maybe_connection.has_value()) + maybe_connection.value()->did_request_certificates({}); +} + +} diff --git a/Userland/Libraries/LibProtocol/WebSocketClient.h b/Userland/Libraries/LibProtocol/WebSocketClient.h new file mode 100644 index 0000000000..07db4de425 --- /dev/null +++ b/Userland/Libraries/LibProtocol/WebSocketClient.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2021, Dex♪ <dexes.ttp@gmail.com> + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include <AK/HashMap.h> +#include <LibIPC/ServerConnection.h> +#include <WebSocket/WebSocketClientEndpoint.h> +#include <WebSocket/WebSocketServerEndpoint.h> + +namespace Protocol { + +class WebSocket; + +class WebSocketClient + : public IPC::ServerConnection<WebSocketClientEndpoint, WebSocketServerEndpoint> + , public WebSocketClientEndpoint { + C_OBJECT(WebSocketClient); + +public: + virtual void handshake() override; + + RefPtr<WebSocket> connect(const URL&, const String& origin = {}, const Vector<String>& protocols = {}, const Vector<String>& extensions = {}, const HashMap<String, String>& request_headers = {}); + + u32 ready_state(Badge<WebSocket>, WebSocket&); + void send(Badge<WebSocket>, WebSocket&, ByteBuffer, bool is_text); + void close(Badge<WebSocket>, WebSocket&, u16 code, String reason); + bool set_certificate(Badge<WebSocket>, WebSocket&, String, String); + +private: + WebSocketClient(); + + virtual void handle(const Messages::WebSocketClient::Connected&) override; + virtual void handle(const Messages::WebSocketClient::Received&) override; + virtual void handle(const Messages::WebSocketClient::Errored&) override; + virtual void handle(const Messages::WebSocketClient::Closed&) override; + virtual void handle(const Messages::WebSocketClient::CertificateRequested&) override; + + HashMap<i32, NonnullRefPtr<WebSocket>> m_connections; +}; + +} diff --git a/Userland/Libraries/LibWebSocket/WebSocket.cpp b/Userland/Libraries/LibWebSocket/WebSocket.cpp index 42351fc28a..03184aa503 100644 --- a/Userland/Libraries/LibWebSocket/WebSocket.cpp +++ b/Userland/Libraries/LibWebSocket/WebSocket.cpp @@ -559,6 +559,9 @@ void WebSocket::discard_connection() { VERIFY(m_impl); m_impl->discard_connection(); + m_impl->on_connection_error = nullptr; + m_impl->on_connected = nullptr; + m_impl->on_ready_to_read = nullptr; m_impl = nullptr; } diff --git a/Userland/Services/CMakeLists.txt b/Userland/Services/CMakeLists.txt index 6a40b4d5c2..55eec246f9 100644 --- a/Userland/Services/CMakeLists.txt +++ b/Userland/Services/CMakeLists.txt @@ -16,4 +16,5 @@ add_subdirectory(Taskbar) add_subdirectory(TelnetServer) add_subdirectory(WebContent) add_subdirectory(WebServer) +add_subdirectory(WebSocket) add_subdirectory(WindowServer) diff --git a/Userland/Services/WebSocket/CMakeLists.txt b/Userland/Services/WebSocket/CMakeLists.txt new file mode 100644 index 0000000000..2dc8971c2c --- /dev/null +++ b/Userland/Services/WebSocket/CMakeLists.txt @@ -0,0 +1,12 @@ +compile_ipc(WebSocketServer.ipc WebSocketServerEndpoint.h) +compile_ipc(WebSocketClient.ipc WebSocketClientEndpoint.h) + +set(SOURCES + ClientConnection.cpp + main.cpp + WebSocketClientEndpoint.h + WebSocketServerEndpoint.h +) + +serenity_bin(WebSocket) +target_link_libraries(WebSocket LibCore LibIPC LibWebSocket) diff --git a/Userland/Services/WebSocket/ClientConnection.cpp b/Userland/Services/WebSocket/ClientConnection.cpp new file mode 100644 index 0000000000..683749b409 --- /dev/null +++ b/Userland/Services/WebSocket/ClientConnection.cpp @@ -0,0 +1,144 @@ +/* + * Copyright (c) 2021, Dex♪ <dexes.ttp@gmail.com> + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include <AK/Badge.h> +#include <LibWebSocket/ConnectionInfo.h> +#include <LibWebSocket/Message.h> +#include <WebSocket/ClientConnection.h> +#include <WebSocket/WebSocketClientEndpoint.h> + +namespace WebSocket { + +static HashMap<int, RefPtr<ClientConnection>> s_connections; + +ClientConnection::ClientConnection(NonnullRefPtr<Core::LocalSocket> socket, int client_id) + : IPC::ClientConnection<WebSocketClientEndpoint, WebSocketServerEndpoint>(*this, move(socket), client_id) +{ + s_connections.set(client_id, *this); +} + +ClientConnection::~ClientConnection() +{ +} + +void ClientConnection::die() +{ + s_connections.remove(client_id()); + if (s_connections.is_empty()) + Core::EventLoop::current().quit(0); +} + +OwnPtr<Messages::WebSocketServer::GreetResponse> ClientConnection::handle(const Messages::WebSocketServer::Greet&) +{ + return make<Messages::WebSocketServer::GreetResponse>(); +} + +OwnPtr<Messages::WebSocketServer::ConnectResponse> ClientConnection::handle(const Messages::WebSocketServer::Connect& message) +{ + const auto& url = message.url(); + if (!url.is_valid()) { + dbgln("WebSocket::Connect: Invalid URL requested: '{}'", url); + return make<Messages::WebSocketServer::ConnectResponse>(-1); + } + + ConnectionInfo connection_info(url); + connection_info.set_origin(message.origin()); + connection_info.set_protocols(message.protocols()); + connection_info.set_extensions(message.extensions()); + + Vector<ConnectionInfo::Header> headers; + for (const auto& header : message.additional_request_headers().entries()) { + headers.append({ header.key, header.value }); + } + connection_info.set_headers(headers); + + VERIFY(m_connection_ids < NumericLimits<i32>::max()); + auto id = ++m_connection_ids; + auto connection = WebSocket::create(move(connection_info)); + connection->on_open = [this, id]() { + did_connect(id); + }; + connection->on_message = [this, id](auto message) { + did_receive_message(id, move(message)); + }; + connection->on_error = [this, id](auto message) { + did_error(id, (i32)message); + }; + connection->on_close = [this, id](u16 code, String reason, bool was_clean) { + did_close(id, code, move(reason), was_clean); + }; + + connection->start(); + m_connections.set(id, move(connection)); + return make<Messages::WebSocketServer::ConnectResponse>(id); +} + +OwnPtr<Messages::WebSocketServer::ReadyStateResponse> ClientConnection::handle(const Messages::WebSocketServer::ReadyState& message) +{ + RefPtr<WebSocket> connection = m_connections.get(message.connection_id()).value_or({}); + if (connection) { + return make<Messages::WebSocketServer::ReadyStateResponse>((u32)connection->ready_state()); + } + return make<Messages::WebSocketServer::ReadyStateResponse>((u32)ReadyState::Closed); +} + +void ClientConnection::handle(const Messages::WebSocketServer::Send& message) +{ + RefPtr<WebSocket> connection = m_connections.get(message.connection_id()).value_or({}); + if (connection && connection->ready_state() == ReadyState::Open) { + Message websocket_message(message.data(), message.is_text()); + connection->send(websocket_message); + } +} + +void ClientConnection::handle(const Messages::WebSocketServer::Close& message) +{ + RefPtr<WebSocket> connection = m_connections.get(message.connection_id()).value_or({}); + if (connection && connection->ready_state() == ReadyState::Open) + connection->close(message.code(), message.reason()); +} + +OwnPtr<Messages::WebSocketServer::SetCertificateResponse> ClientConnection::handle(const Messages::WebSocketServer::SetCertificate& message) +{ + RefPtr<WebSocket> connection = m_connections.get(message.connection_id()).value_or({}); + bool success = false; + if (connection) { + // NO OP here + // connection->set_certificate(message.certificate(), message.key()); + success = true; + } + return make<Messages::WebSocketServer::SetCertificateResponse>(success); +} + +void ClientConnection::did_connect(i32 connection_id) +{ + post_message(Messages::WebSocketClient::Connected(connection_id)); +} + +void ClientConnection::did_receive_message(i32 connection_id, Message message) +{ + post_message(Messages::WebSocketClient::Received(connection_id, message.is_text(), message.data())); +} + +void ClientConnection::did_error(i32 connection_id, i32 message) +{ + post_message(Messages::WebSocketClient::Errored(connection_id, message)); +} + +void ClientConnection::did_close(i32 connection_id, u16 code, String reason, bool was_clean) +{ + post_message(Messages::WebSocketClient::Closed(connection_id, code, reason, was_clean)); + deferred_invoke([this, connection_id] { + m_connections.remove(connection_id); + }); +} + +void ClientConnection::did_request_certificates(i32 connection_id) +{ + post_message(Messages::WebSocketClient::CertificateRequested(connection_id)); +} + +} diff --git a/Userland/Services/WebSocket/ClientConnection.h b/Userland/Services/WebSocket/ClientConnection.h new file mode 100644 index 0000000000..83f7ab5e9d --- /dev/null +++ b/Userland/Services/WebSocket/ClientConnection.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2021, Dex♪ <dexes.ttp@gmail.com> + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include <AK/HashMap.h> +#include <LibIPC/ClientConnection.h> +#include <LibWebSocket/WebSocket.h> +#include <WebSocket/WebSocketClientEndpoint.h> +#include <WebSocket/WebSocketServerEndpoint.h> + +namespace WebSocket { + +class ClientConnection final + : public IPC::ClientConnection<WebSocketClientEndpoint, WebSocketServerEndpoint> + , public WebSocketServerEndpoint { + C_OBJECT(ClientConnection); + +public: + explicit ClientConnection(NonnullRefPtr<Core::LocalSocket>, int client_id); + ~ClientConnection() override; + + virtual void die() override; + +private: + virtual OwnPtr<Messages::WebSocketServer::GreetResponse> handle(const Messages::WebSocketServer::Greet&) override; + virtual OwnPtr<Messages::WebSocketServer::ConnectResponse> handle(const Messages::WebSocketServer::Connect&) override; + virtual OwnPtr<Messages::WebSocketServer::ReadyStateResponse> handle(const Messages::WebSocketServer::ReadyState&) override; + virtual void handle(const Messages::WebSocketServer::Send&) override; + virtual void handle(const Messages::WebSocketServer::Close&) override; + virtual OwnPtr<Messages::WebSocketServer::SetCertificateResponse> handle(const Messages::WebSocketServer::SetCertificate&) override; + + void did_connect(i32); + void did_receive_message(i32, Message); + void did_error(i32, i32 message); + void did_close(i32, u16 code, String reason, bool was_clean); + void did_request_certificates(i32); + + i32 m_connection_ids { 0 }; + HashMap<i32, RefPtr<WebSocket>> m_connections; +}; + +} diff --git a/Userland/Services/WebSocket/WebSocketClient.ipc b/Userland/Services/WebSocket/WebSocketClient.ipc new file mode 100644 index 0000000000..edcd43b1a1 --- /dev/null +++ b/Userland/Services/WebSocket/WebSocketClient.ipc @@ -0,0 +1,11 @@ +endpoint WebSocketClient +{ + // Connection API + Connected(i32 connection_id) =| + Received(i32 connection_id, bool is_text, ByteBuffer data) =| + Errored(i32 connection_id, i32 message) =| + Closed(i32 connection_id, u16 code, String reason, bool clean) =| + + // Certificate requests + CertificateRequested(i32 connection_id) =| +} diff --git a/Userland/Services/WebSocket/WebSocketServer.ipc b/Userland/Services/WebSocket/WebSocketServer.ipc new file mode 100644 index 0000000000..d2fc01884c --- /dev/null +++ b/Userland/Services/WebSocket/WebSocketServer.ipc @@ -0,0 +1,13 @@ +endpoint WebSocketServer +{ + // Basic protocol + Greet() => () + + // Connection API + Connect(URL url, String origin, Vector<String> protocols, Vector<String> extensions, IPC::Dictionary additional_request_headers) => (i32 connection_id) + ReadyState(i32 connection_id) => (u32 ready_state) + Send(i32 connection_id, bool is_text, ByteBuffer data) =| + Close(i32 connection_id, u16 code, String reason) =| + + SetCertificate(i32 connection_id, String certificate, String key) => (bool success) +} diff --git a/Userland/Services/WebSocket/main.cpp b/Userland/Services/WebSocket/main.cpp new file mode 100644 index 0000000000..3541b7e5af --- /dev/null +++ b/Userland/Services/WebSocket/main.cpp @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2021, Dex♪ <dexes.ttp@gmail.com> + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include <LibCore/EventLoop.h> +#include <LibCore/LocalServer.h> +#include <LibIPC/ClientConnection.h> +#include <LibTLS/Certificate.h> +#include <WebSocket/ClientConnection.h> + +int main(int, char**) +{ + if (pledge("stdio inet accept unix rpath cpath fattr sendfd recvfd", nullptr) < 0) { + perror("pledge"); + return 1; + } + + // Ensure the certificates are read out here. + [[maybe_unused]] auto& certs = DefaultRootCACertificates::the(); + + Core::EventLoop event_loop; + // FIXME: Establish a connection to LookupServer and then drop "unix"? + if (pledge("stdio inet accept unix sendfd recvfd", nullptr) < 0) { + perror("pledge"); + return 1; + } + if (unveil("/tmp/portal/lookup", "rw") < 0) { + perror("unveil"); + return 1; + } + if (unveil(nullptr, nullptr) < 0) { + perror("unveil"); + return 1; + } + + auto socket = Core::LocalSocket::take_over_accepted_socket_from_system_server(); + VERIFY(socket); + IPC::new_client_connection<WebSocket::ClientConnection>(socket.release_nonnull(), 1); + return event_loop.exec(); +} |