From b0f5b1d97a6502d5e87da617e719c859ea6867e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javier=20S=C3=A1nchez=20Parra?= Date: Wed, 27 Jan 2021 19:27:12 +0100 Subject: [PATCH] tui: add WireGuard support to nmtui https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/736 --- Makefile.am | 6 + po/POTFILES.in | 3 + src/libnm-core-impl/nm-connection.c | 2 + src/nmtui/meson.build | 3 + src/nmtui/nm-editor-bindings.c | 223 ++++++++++++ src/nmtui/nm-editor-bindings.h | 50 +++ src/nmtui/nm-editor-utils.c | 25 ++ src/nmtui/nmt-connect-connection-list.c | 1 + src/nmtui/nmt-editor.c | 3 + src/nmtui/nmt-page-wireguard.c | 125 +++++++ src/nmtui/nmt-page-wireguard.h | 34 ++ src/nmtui/nmt-wireguard-peer-editor.c | 247 +++++++++++++ src/nmtui/nmt-wireguard-peer-editor.h | 35 ++ src/nmtui/nmt-wireguard-peer-list.c | 451 ++++++++++++++++++++++++ src/nmtui/nmt-wireguard-peer-list.h | 42 +++ 15 files changed, 1250 insertions(+) create mode 100644 src/nmtui/nmt-page-wireguard.c create mode 100644 src/nmtui/nmt-page-wireguard.h create mode 100644 src/nmtui/nmt-wireguard-peer-editor.c create mode 100644 src/nmtui/nmt-wireguard-peer-editor.h create mode 100644 src/nmtui/nmt-wireguard-peer-list.c create mode 100644 src/nmtui/nmt-wireguard-peer-list.h diff --git a/Makefile.am b/Makefile.am index 8f658b52c0..a86bf9029d 100644 --- a/Makefile.am +++ b/Makefile.am @@ -5112,6 +5112,8 @@ src_nmtui_nmtui_SOURCES = \ src/nmtui/nmt-page-vlan.h \ src/nmtui/nmt-page-wifi.c \ src/nmtui/nmt-page-wifi.h \ + src/nmtui/nmt-page-wireguard.c \ + src/nmtui/nmt-page-wireguard.h \ src/nmtui/nmt-password-dialog.c \ src/nmtui/nmt-password-dialog.h \ src/nmtui/nmt-password-fields.c \ @@ -5124,6 +5126,10 @@ src_nmtui_nmtui_SOURCES = \ src/nmtui/nmt-route-table.h \ src/nmtui/nmt-slave-list.c \ src/nmtui/nmt-slave-list.h \ + src/nmtui/nmt-wireguard-peer-list.c \ + src/nmtui/nmt-wireguard-peer-list.h \ + src/nmtui/nmt-wireguard-peer-editor.c \ + src/nmtui/nmt-wireguard-peer-editor.h \ src/nmtui/nmt-utils.c \ src/nmtui/nmt-utils.h \ src/nmtui/nmt-widget-list.c \ diff --git a/po/POTFILES.in b/po/POTFILES.in index ac1bd52b67..597035e6f6 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -173,11 +173,14 @@ src/nmtui/nmt-page-team-port.c src/nmtui/nmt-page-team.c src/nmtui/nmt-page-vlan.c src/nmtui/nmt-page-wifi.c +src/nmtui/nmt-page-wireguard.c src/nmtui/nmt-password-dialog.c src/nmtui/nmt-password-fields.c src/nmtui/nmt-route-editor.c src/nmtui/nmt-route-table.c src/nmtui/nmt-slave-list.c +src/nmtui/nmt-wireguard-peer-list.c +src/nmtui/nmt-wireguard-peer-editor.c src/nmtui/nmt-widget-list.c src/nmtui/nmtui-connect.c src/nmtui/nmtui-edit.c diff --git a/src/libnm-core-impl/nm-connection.c b/src/libnm-core-impl/nm-connection.c index a811b799c8..03fde1f9cf 100644 --- a/src/libnm-core-impl/nm-connection.c +++ b/src/libnm-core-impl/nm-connection.c @@ -3116,6 +3116,8 @@ nm_connection_get_virtual_device_description(NMConnection *connection) nm_connection_get_setting_infiniband(connection)); } else if (!strcmp(type, NM_SETTING_IP_TUNNEL_SETTING_NAME)) display_type = _("IP Tunnel"); + else if (!strcmp(type, NM_SETTING_WIREGUARD_SETTING_NAME)) + display_type = _("WireGuard"); if (!iface || !display_type) return NULL; diff --git a/src/nmtui/meson.build b/src/nmtui/meson.build index fe4401751c..b4ac068b5b 100644 --- a/src/nmtui/meson.build +++ b/src/nmtui/meson.build @@ -31,12 +31,15 @@ executable( 'nmt-page-team-port.c', 'nmt-page-vlan.c', 'nmt-page-wifi.c', + 'nmt-page-wireguard.c', 'nmt-password-dialog.c', 'nmt-password-fields.c', 'nmt-route-editor.c', 'nmt-route-entry.c', 'nmt-route-table.c', 'nmt-slave-list.c', + 'nmt-wireguard-peer-list.c', + 'nmt-wireguard-peer-editor.c', 'nmtui.c', 'nmtui-connect.c', 'nmtui-edit.c', diff --git a/src/nmtui/nm-editor-bindings.c b/src/nmtui/nm-editor-bindings.c index 2b1c474847..59474fba42 100644 --- a/src/nmtui/nm-editor-bindings.c +++ b/src/nmtui/nm-editor-bindings.c @@ -576,6 +576,229 @@ nm_editor_bind_ip_route_to_strings(int addr_family, NULL); } +gboolean +peer_transform_to_public_key_string(GBinding * binding, + const GValue *source_value, + GValue * target_value, + gpointer user_data) +{ + NMWireGuardPeer *peer; + char * string; + + peer = g_value_get_boxed(source_value); + if (peer && nm_wireguard_peer_get_public_key(peer)) { + string = g_strdup(nm_wireguard_peer_get_public_key(peer)); + g_value_take_string(target_value, string); + } else + g_value_set_string(target_value, ""); + return TRUE; +} + +gboolean +peer_transform_to_allowed_ips_string(GBinding * binding, + const GValue *source_value, + GValue * target_value, + gpointer user_data) +{ + NMWireGuardPeer *peer; + GString * string = NULL; + guint i, len; + + peer = g_value_get_boxed(source_value); + if (!peer) + return TRUE; + + len = nm_wireguard_peer_get_allowed_ips_len(peer); + for (i = 0; i < len; i++) { + if (!string) + string = g_string_new(""); + else + g_string_append_c(string, ','); + g_string_append(string, nm_wireguard_peer_get_allowed_ip(peer, i, NULL)); + } + if (string) + g_value_take_string(target_value, g_string_free(string, FALSE)); + + return TRUE; +} + +gboolean +peer_transform_to_endpoint_string(GBinding * binding, + const GValue *source_value, + GValue * target_value, + gpointer user_data) +{ + NMWireGuardPeer *peer; + char * string; + + peer = g_value_get_boxed(source_value); + if (peer && nm_wireguard_peer_get_endpoint(peer)) { + string = g_strdup_printf("%s", nm_wireguard_peer_get_endpoint(peer)); + g_value_take_string(target_value, string); + } else + g_value_set_string(target_value, ""); + return TRUE; +} + +gboolean +peer_transform_to_preshared_key_string(GBinding * binding, + const GValue *source_value, + GValue * target_value, + gpointer user_data) +{ + NMWireGuardPeer *peer; + char * string; + + peer = g_value_get_boxed(source_value); + if (peer && nm_wireguard_peer_get_preshared_key(peer)) { + string = g_strdup_printf("%s", nm_wireguard_peer_get_preshared_key(peer)); + g_value_take_string(target_value, string); + } else + g_value_set_string(target_value, ""); + return TRUE; +} + +gboolean +peer_transform_to_persistent_keepalive_string(GBinding * binding, + const GValue *source_value, + GValue * target_value, + gpointer user_data) +{ + NMWireGuardPeer *peer; + char * string; + + peer = g_value_get_boxed(source_value); + if (peer && nm_wireguard_peer_get_persistent_keepalive(peer)) { + string = g_strdup_printf("%d", nm_wireguard_peer_get_persistent_keepalive(peer)); + g_value_take_string(target_value, string); + } else + g_value_set_string(target_value, ""); + return TRUE; +} + +gboolean +peer_transform_from_public_key_string(GBinding * binding, + const GValue *source_value, + GValue * target_value, + gpointer user_data) +{ + NMWireGuardPeer *peer; + const char * text; + + text = g_value_get_string(source_value); + + /* Fetch the original property value */ + g_object_get(g_binding_get_source(binding), + g_binding_get_source_property(binding), + &peer, + NULL); + + nm_wireguard_peer_set_public_key(peer, text, TRUE); + + g_value_take_boxed(target_value, peer); + return TRUE; +} + +gboolean +peer_transform_from_allowed_ips_string(GBinding * binding, + const GValue *source_value, + GValue * target_value, + gpointer user_data) +{ + NMWireGuardPeer *peer; + const char * text; + char ** strv; + guint i; + + text = g_value_get_string(source_value); + + /* Fetch the original property value */ + g_object_get(g_binding_get_source(binding), + g_binding_get_source_property(binding), + &peer, + NULL); + + nm_wireguard_peer_clear_allowed_ips(peer); + + strv = g_strsplit(text, ",", -1); + for (i = 0; strv && strv[i]; i++) + nm_wireguard_peer_append_allowed_ip(peer, g_strstrip(strv[i]), TRUE); + g_strfreev(strv); + + g_value_take_boxed(target_value, peer); + return TRUE; +} + +gboolean +peer_transform_from_endpoint_string(GBinding * binding, + const GValue *source_value, + GValue * target_value, + gpointer user_data) +{ + NMWireGuardPeer *peer; + const char * text; + + text = g_value_get_string(source_value); + + /* Fetch the original property value */ + g_object_get(g_binding_get_source(binding), + g_binding_get_source_property(binding), + &peer, + NULL); + + nm_wireguard_peer_set_endpoint(peer, text, TRUE); + + g_value_take_boxed(target_value, peer); + return TRUE; +} + +gboolean +peer_transform_from_preshared_key_string(GBinding * binding, + const GValue *source_value, + GValue * target_value, + gpointer user_data) +{ + NMWireGuardPeer *peer; + const char * text; + + text = g_value_get_string(source_value); + + /* Fetch the original property value */ + g_object_get(g_binding_get_source(binding), + g_binding_get_source_property(binding), + &peer, + NULL); + + nm_wireguard_peer_set_preshared_key(peer, text && text[0] ? text : NULL, TRUE); + nm_wireguard_peer_set_preshared_key_flags(peer, NM_SETTING_SECRET_FLAG_NONE); + + g_value_take_boxed(target_value, peer); + return TRUE; +} + +gboolean +peer_transform_from_persistent_keepalive_string(GBinding * binding, + const GValue *source_value, + GValue * target_value, + gpointer user_data) +{ + NMWireGuardPeer *peer; + const char * text; + + text = g_value_get_string(source_value); + + /* Fetch the original property value */ + g_object_get(g_binding_get_source(binding), + g_binding_get_source_property(binding), + &peer, + NULL); + + nm_wireguard_peer_set_persistent_keepalive(peer, atoi(text)); + + g_value_take_boxed(target_value, peer); + return TRUE; +} + /* Wireless security method binding */ typedef struct { NMConnection * connection; diff --git a/src/nmtui/nm-editor-bindings.h b/src/nmtui/nm-editor-bindings.h index 027a59a9bd..a9bf51ed0f 100644 --- a/src/nmtui/nm-editor-bindings.h +++ b/src/nmtui/nm-editor-bindings.h @@ -53,4 +53,54 @@ void nm_editor_bind_wireless_security_wep_key(NMSettingWirelessSecurity *s_wsec, void nm_editor_bind_vlan_name(NMSettingVlan *s_vlan, NMSettingConnection *s_con); +gboolean peer_transform_to_public_key_string(GBinding * binding, + const GValue *source_value, + GValue * target_value, + gpointer user_data); + +gboolean peer_transform_to_allowed_ips_string(GBinding * binding, + const GValue *source_value, + GValue * target_value, + gpointer user_data); + +gboolean peer_transform_to_endpoint_string(GBinding * binding, + const GValue *source_value, + GValue * target_value, + gpointer user_data); + +gboolean peer_transform_to_preshared_key_string(GBinding * binding, + const GValue *source_value, + GValue * target_value, + gpointer user_data); + +gboolean peer_transform_to_persistent_keepalive_string(GBinding * binding, + const GValue *source_value, + GValue * target_value, + gpointer user_data); + +gboolean peer_transform_from_public_key_string(GBinding * binding, + const GValue *source_value, + GValue * target_value, + gpointer user_data); + +gboolean peer_transform_from_allowed_ips_string(GBinding * binding, + const GValue *source_value, + GValue * target_value, + gpointer user_data); + +gboolean peer_transform_from_endpoint_string(GBinding * binding, + const GValue *source_value, + GValue * target_value, + gpointer user_data); + +gboolean peer_transform_from_preshared_key_string(GBinding * binding, + const GValue *source_value, + GValue * target_value, + gpointer user_data); + +gboolean peer_transform_from_persistent_keepalive_string(GBinding * binding, + const GValue *source_value, + GValue * target_value, + gpointer user_data); + #endif /* NM_EDITOR_BINDINGS_H */ diff --git a/src/nmtui/nm-editor-utils.c b/src/nmtui/nm-editor-utils.c index 02d7d6b263..2b6acbbe24 100644 --- a/src/nmtui/nm-editor-utils.c +++ b/src/nmtui/nm-editor-utils.c @@ -66,6 +66,22 @@ bond_connection_setup_func(NMConnection *connection, NMSettingConnection *s_con, } } +static void +wireguard_connection_setup_func(NMConnection * connection, + NMSettingConnection *s_con, + NMSetting * s_hw) +{ + NMSettingIPConfig *s_ip; + + s_ip = (NMSettingIPConfig *) nm_setting_ip4_config_new(); + g_object_set(s_ip, NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_DISABLED, NULL); + nm_connection_add_setting(connection, (NMSetting *) s_ip); + + s_ip = (NMSettingIPConfig *) nm_setting_ip6_config_new(); + g_object_set(s_ip, NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP6_CONFIG_METHOD_DISABLED, NULL); + nm_connection_add_setting(connection, (NMSetting *) s_ip); +} + typedef void (*NMEditorNewConnectionSetupFunc)(NMConnection * connection, NMSettingConnection *s_con, NMSetting * s_hw); @@ -243,6 +259,15 @@ nm_editor_utils_get_connection_type_list(void) } #endif + item = g_new0(NMEditorConnectionTypeDataReal, 1); + item->data.name = _("WireGuard"); + item->data.setting_type = NM_TYPE_SETTING_WIREGUARD; + item->data.device_type = NM_TYPE_DEVICE_WIREGUARD; + item->data.virtual = TRUE; + item->id_format = _("WireGuard connection %d"); + item->connection_setup_func = wireguard_connection_setup_func; + g_ptr_array_add(array, item); + g_ptr_array_sort(array, sort_types); g_ptr_array_add(array, NULL); diff --git a/src/nmtui/nmt-connect-connection-list.c b/src/nmtui/nmt-connect-connection-list.c index 4503dc924b..486e14004f 100644 --- a/src/nmtui/nmt-connect-connection-list.c +++ b/src/nmtui/nmt-connect-connection-list.c @@ -100,6 +100,7 @@ static const char *device_sort_order[] = {"NMDeviceEthernet", NM_SETTING_TEAM_SETTING_NAME, NM_SETTING_BRIDGE_SETTING_NAME, NM_SETTING_IP_TUNNEL_SETTING_NAME, + NM_SETTING_WIREGUARD_SETTING_NAME, "NMDeviceModem", "NMDeviceBt"}; static const int device_sort_order_len = G_N_ELEMENTS(device_sort_order); diff --git a/src/nmtui/nmt-editor.c b/src/nmtui/nmt-editor.c index 0ef236938f..baca5b3cf3 100644 --- a/src/nmtui/nmt-editor.c +++ b/src/nmtui/nmt-editor.c @@ -39,6 +39,7 @@ #include "nmt-page-team-port.h" #include "nmt-page-vlan.h" #include "nmt-page-wifi.h" +#include "nmt-page-wireguard.h" #include "libnmc-setting/nm-meta-setting-access.h" @@ -372,6 +373,8 @@ nmt_editor_constructed(GObject *object) page = nmt_page_wifi_new(priv->edit_connection, deventry); else if (nm_connection_is_type(priv->edit_connection, NM_SETTING_IP_TUNNEL_SETTING_NAME)) page = nmt_page_ip_tunnel_new(priv->edit_connection, deventry); + else if (nm_connection_is_type(priv->edit_connection, NM_SETTING_WIREGUARD_SETTING_NAME)) + page = nmt_page_wireguard_new(priv->edit_connection, deventry); else g_assert_not_reached(); diff --git a/src/nmtui/nmt-page-wireguard.c b/src/nmtui/nmt-page-wireguard.c new file mode 100644 index 0000000000..8b797d33c7 --- /dev/null +++ b/src/nmtui/nmt-page-wireguard.c @@ -0,0 +1,125 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2021 Red Hat, Inc. + */ +/** + * SECTION:nmt-page-wireguard + * @short_description: The editor page for WireGuard connections + */ + +#include "libnm-client-aux-extern/nm-default-client.h" + +#include "nmt-page-wireguard.h" + +#include "nmt-device-entry.h" +#include "nmt-mtu-entry.h" +#include "nmt-wireguard-peer-list.h" + +G_DEFINE_TYPE(NmtPageWireGuard, nmt_page_wireguard, NMT_TYPE_EDITOR_PAGE_DEVICE) + +#define NMT_PAGE_WIREGUARD_GET_PRIVATE(o) \ + (G_TYPE_INSTANCE_GET_PRIVATE((o), NMT_TYPE_PAGE_WIREGUARD, NmtPageWireGuardPrivate)) + +typedef struct { + NmtWireguardPeerList *peers; +} NmtPageWireGuardPrivate; + +NmtEditorPage * +nmt_page_wireguard_new(NMConnection *conn, NmtDeviceEntry *deventry) +{ + return g_object_new(NMT_TYPE_PAGE_WIREGUARD, + "connection", + conn, + "device-entry", + deventry, + NULL); +} + +static void +nmt_page_wireguard_init(NmtPageWireGuard *wireguard) +{} + +static void +nmt_page_wireguard_constructed(GObject *object) +{ + NmtPageWireGuard * wireguard = NMT_PAGE_WIREGUARD(object); + NmtPageWireGuardPrivate *priv = NMT_PAGE_WIREGUARD_GET_PRIVATE(wireguard); + NmtEditorSection * section; + NmtEditorGrid * grid; + NMSettingWireGuard * s_wireguard; + NmtNewtWidget * widget; + NMConnection * conn; + + conn = nmt_editor_page_get_connection(NMT_EDITOR_PAGE(wireguard)); + s_wireguard = NM_SETTING_WIREGUARD(nm_connection_get_setting(conn, NM_TYPE_SETTING_WIREGUARD)); + if (!s_wireguard) { + nm_connection_add_setting(conn, nm_setting_wireguard_new()); + s_wireguard = + NM_SETTING_WIREGUARD(nm_connection_get_setting(conn, NM_TYPE_SETTING_WIREGUARD)); + } + + section = nmt_editor_section_new(_("WireGuard"), NULL, TRUE); + grid = nmt_editor_section_get_body(section); + + widget = nmt_newt_entry_new(40, 0); + nmt_editor_grid_append(grid, _("Private key"), widget, NULL); + g_object_bind_property(s_wireguard, + NM_SETTING_WIREGUARD_PRIVATE_KEY, + widget, + "text", + G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL); + + widget = nmt_newt_entry_new(40, 0); + nmt_editor_grid_append(grid, _("Listen port"), widget, NULL); + g_object_bind_property(s_wireguard, + NM_SETTING_WIREGUARD_LISTEN_PORT, + widget, + "text", + G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL); + + widget = nmt_newt_entry_new(40, 0); + nmt_editor_grid_append(grid, _("Fwmark"), widget, NULL); + g_object_bind_property(s_wireguard, + NM_SETTING_WIREGUARD_FWMARK, + widget, + "text", + G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL); + + widget = nmt_mtu_entry_new(); + nmt_editor_grid_append(grid, _("MTU"), widget, NULL); + g_object_bind_property(s_wireguard, + NM_SETTING_WIREGUARD_MTU, + widget, + "mtu", + G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL); + + widget = nmt_newt_checkbox_new(_("Add peer routes")); + nmt_editor_grid_append(grid, NULL, widget, NULL); + g_object_bind_property(s_wireguard, + NM_SETTING_WIREGUARD_PEER_ROUTES, + widget, + "active", + G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL); + + widget = nmt_newt_separator_new(); + nmt_editor_grid_append(grid, _("Peers"), widget, NULL); + nmt_editor_grid_set_row_flags(grid, widget, NMT_EDITOR_GRID_ROW_LABEL_ALIGN_LEFT); + + widget = nmt_wireguard_peer_list_new(s_wireguard); + nmt_editor_grid_append(grid, NULL, widget, NULL); + priv->peers = NMT_WIREGUARD_PEER_LIST(widget); + + nmt_editor_page_add_section(NMT_EDITOR_PAGE(wireguard), section); + + G_OBJECT_CLASS(nmt_page_wireguard_parent_class)->constructed(object); +} + +static void +nmt_page_wireguard_class_init(NmtPageWireGuardClass *wireguard_class) +{ + GObjectClass *object_class = G_OBJECT_CLASS(wireguard_class); + + g_type_class_add_private(wireguard_class, sizeof(NmtPageWireGuardPrivate)); + + object_class->constructed = nmt_page_wireguard_constructed; +} diff --git a/src/nmtui/nmt-page-wireguard.h b/src/nmtui/nmt-page-wireguard.h new file mode 100644 index 0000000000..8e39139c80 --- /dev/null +++ b/src/nmtui/nmt-page-wireguard.h @@ -0,0 +1,34 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2021 Red Hat, Inc. + */ + +#ifndef NMT_PAGE_WIREGUARD_H +#define NMT_PAGE_WIREGUARD_H + +#include "nmt-editor-page-device.h" + +#define NMT_TYPE_PAGE_WIREGUARD (nmt_page_wireguard_get_type()) +#define NMT_PAGE_WIREGUARD(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj), NMT_TYPE_PAGE_WIREGUARD, NmtPageWireGuard)) +#define NMT_PAGE_WIREGUARD_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass), NMT_TYPE_PAGE_WIREGUARD, NmtPageWireGuardClass)) +#define NMT_IS_PAGE_WIREGUARD(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NMT_TYPE_PAGE_WIREGUARD)) +#define NMT_IS_PAGE_WIREGUARD_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass), NMT_TYPE_PAGE_WIREGUARD)) +#define NMT_PAGE_WIREGUARD_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS((obj), NMT_TYPE_PAGE_WIREGUARD, NmtPageWireGuardClass)) + +typedef struct { + NmtEditorPageDevice parent; +} NmtPageWireGuard; + +typedef struct { + NmtEditorPageDeviceClass parent; +} NmtPageWireGuardClass; + +GType nmt_page_wireguard_get_type(void); + +NmtEditorPage *nmt_page_wireguard_new(NMConnection *conn, NmtDeviceEntry *deventry); + +#endif /* NMT_PAGE_WIREGUARD_H */ diff --git a/src/nmtui/nmt-wireguard-peer-editor.c b/src/nmtui/nmt-wireguard-peer-editor.c new file mode 100644 index 0000000000..810bdf6966 --- /dev/null +++ b/src/nmtui/nmt-wireguard-peer-editor.c @@ -0,0 +1,247 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2021 Red Hat, Inc. + */ +/** + * SECTION:nmt-wireguard-peer-editor + * @short_description: The editor page for Peer connections + */ + +#include "libnm-client-aux-extern/nm-default-client.h" + +#include "nmt-wireguard-peer-editor.h" +#include "nmt-page-wireguard.h" + +#include "nmt-device-entry.h" +#include "nmt-mtu-entry.h" +#include "nmt-wireguard-peer-list.h" + +#include "nm-editor-bindings.h" + +G_DEFINE_TYPE(NmtWireguardPeerEditor, nmt_wireguard_peer_editor, NMT_TYPE_NEWT_FORM) + +#define NMT_WIREGUARD_PEER_EDITOR_GET_PRIVATE(o) \ + (G_TYPE_INSTANCE_GET_PRIVATE((o), \ + NMT_TYPE_WIREGUARD_PEER_EDITOR, \ + NmtWireguardPeerEditorPrivate)) + +typedef struct { + NMSettingWireGuard *orig_setting; + NMSettingWireGuard *edit_setting; + NMWireGuardPeer * peer; + NmtNewtEntry * private_key; +} NmtWireguardPeerEditorPrivate; + +enum { + PROP_0, + + PROP_SETTING, + PROP_PEER, + PROP_PUBLIC_KEY, + + LAST_PROP +}; + +NmtNewtForm * +nmt_wireguard_peer_editor_new(NMSettingWireGuard *setting, NMWireGuardPeer *peer) +{ + return g_object_new(NMT_TYPE_WIREGUARD_PEER_EDITOR, "setting", setting, "peer", peer, NULL); +} + +static void +nmt_wireguard_peer_editor_init(NmtWireguardPeerEditor *peer) +{} + +static void +save_peer_and_exit(NmtNewtButton *button, gpointer user_data) +{ + NmtWireguardPeerEditor * editor = user_data; + NmtWireguardPeerEditorPrivate *priv = NMT_WIREGUARD_PEER_EDITOR_GET_PRIVATE(editor); + + nm_setting_wireguard_append_peer(priv->orig_setting, priv->peer); + + nmt_newt_form_quit(NMT_NEWT_FORM(editor)); +} + +static void +nmt_wireguard_peer_editor_constructed(GObject *object) +{ + NmtWireguardPeerEditor *peer = NMT_WIREGUARD_PEER_EDITOR(object); + NmtEditorSection * section; + NmtEditorGrid * grid; + NmtNewtWidget * widget, *label; + NmtNewtWidget * buttons, *ok, *cancel; + + if (G_OBJECT_CLASS(nmt_wireguard_peer_editor_parent_class)->constructed) + G_OBJECT_CLASS(nmt_wireguard_peer_editor_parent_class)->constructed(object); + + section = nmt_editor_section_new(_("Peer"), NULL, TRUE); + grid = nmt_editor_section_get_body(section); + + widget = nmt_newt_entry_new(40, 0); + nmt_editor_grid_append(grid, _("Public key"), widget, NULL); + g_object_bind_property_full(object, + "peer", + widget, + "text", + G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL, + peer_transform_to_public_key_string, + peer_transform_from_public_key_string, + NULL, + NULL); + + widget = nmt_newt_entry_new(40, 0); + nmt_editor_grid_append(grid, _("Allowed IPs"), widget, NULL); + g_object_bind_property_full(peer, + "peer", + widget, + "text", + G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL, + peer_transform_to_allowed_ips_string, + peer_transform_from_allowed_ips_string, + NULL, + NULL); + + widget = nmt_newt_entry_new(40, 0); + nmt_editor_grid_append(grid, _("Endpoint"), widget, NULL); + g_object_bind_property_full(peer, + "peer", + widget, + "text", + G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL, + peer_transform_to_endpoint_string, + peer_transform_from_endpoint_string, + NULL, + NULL); + + widget = nmt_newt_entry_new(40, 0); + nmt_editor_grid_append(grid, _("Preshared key"), widget, NULL); + g_object_bind_property_full(peer, + "peer", + widget, + "text", + G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL, + peer_transform_to_preshared_key_string, + peer_transform_from_preshared_key_string, + NULL, + NULL); + + widget = nmt_newt_entry_numeric_new(10, 0, G_MAXINT); + label = nmt_newt_label_new(C_("seconds", "seconds")); + nmt_editor_grid_append(grid, _("Persistent keepalive"), widget, label); + g_object_bind_property_full(peer, + "peer", + widget, + "text", + G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL, + peer_transform_to_persistent_keepalive_string, + peer_transform_from_persistent_keepalive_string, + NULL, + NULL); + + buttons = nmt_newt_grid_new(); + nmt_editor_grid_append(grid, NULL, buttons, NULL); + nmt_newt_widget_set_padding(buttons, 0, 1, 0, 0); + + cancel = g_object_ref_sink(nmt_newt_button_new(_("Cancel"))); + nmt_newt_widget_set_exit_on_activate(cancel, TRUE); + nmt_newt_grid_add(NMT_NEWT_GRID(buttons), cancel, 0, 0); + nmt_newt_grid_set_flags(NMT_NEWT_GRID(buttons), + cancel, + NMT_NEWT_GRID_EXPAND_X | NMT_NEWT_GRID_ANCHOR_RIGHT + | NMT_NEWT_GRID_FILL_Y); + + ok = g_object_ref_sink(nmt_newt_button_new(_("OK"))); + g_signal_connect(ok, "clicked", G_CALLBACK(save_peer_and_exit), peer); + nmt_newt_grid_add(NMT_NEWT_GRID(buttons), ok, 1, 0); + nmt_newt_widget_set_padding(ok, 1, 0, 0, 0); + g_object_bind_property(NMT_NEWT_GRID(buttons), "valid", ok, "sensitive", G_BINDING_SYNC_CREATE); + + nmt_newt_form_set_content(NMT_NEWT_FORM(peer), NMT_NEWT_WIDGET(section)); +} + +static void +nmt_wireguard_peer_editor_set_property(GObject * object, + guint prop_id, + const GValue *value, + GParamSpec * pspec) +{ + NmtWireguardPeerEditorPrivate *priv = NMT_WIREGUARD_PEER_EDITOR_GET_PRIVATE(object); + + switch (prop_id) { + case PROP_SETTING: + priv->orig_setting = g_value_dup_object(value); + priv->edit_setting = + NM_SETTING_WIREGUARD(nm_setting_duplicate(NM_SETTING(priv->orig_setting))); + break; + case PROP_PEER: + priv->peer = g_value_dup_boxed(value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); + break; + } +} + +static void +nmt_wireguard_peer_editor_get_property(GObject * object, + guint prop_id, + GValue * value, + GParamSpec *pspec) +{ + NmtWireguardPeerEditorPrivate *priv = NMT_WIREGUARD_PEER_EDITOR_GET_PRIVATE(object); + + switch (prop_id) { + case PROP_SETTING: + g_value_set_object(value, priv->edit_setting); + break; + case PROP_PEER: + g_value_set_boxed(value, priv->peer); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); + break; + } +} + +static void +nmt_wireguard_peer_editor_class_init(NmtWireguardPeerEditorClass *peer_class) +{ + GObjectClass *object_class = G_OBJECT_CLASS(peer_class); + + g_type_class_add_private(peer_class, sizeof(NmtWireguardPeerEditorPrivate)); + + /* virtual methods */ + object_class->constructed = nmt_wireguard_peer_editor_constructed; + object_class->set_property = nmt_wireguard_peer_editor_set_property; + object_class->get_property = nmt_wireguard_peer_editor_get_property; + + /* properties */ + + /** + * NmtPeerPage:setting: + * + * The page's #NMSettingWireGuard. + */ + g_object_class_install_property( + object_class, + PROP_SETTING, + g_param_spec_object("setting", + "", + "", + NM_TYPE_SETTING_WIREGUARD, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); + + /** + * NmtPeerPage:peer: + * + * The page's #NMWireGuardPeer. + */ + g_object_class_install_property(object_class, + PROP_PEER, + g_param_spec_boxed("peer", + "", + "", + nm_wireguard_peer_get_type(), + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); +} diff --git a/src/nmtui/nmt-wireguard-peer-editor.h b/src/nmtui/nmt-wireguard-peer-editor.h new file mode 100644 index 0000000000..ffe76c8cf9 --- /dev/null +++ b/src/nmtui/nmt-wireguard-peer-editor.h @@ -0,0 +1,35 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2021 Red Hat, Inc. + */ + +#ifndef NMT_WIREGUARD_PEER_EDITOR_H +#define NMT_WIREGUARD_PEER_EDITOR_H + +#include "libnmt-newt/nmt-newt.h" + +#define NMT_TYPE_WIREGUARD_PEER_EDITOR (nmt_wireguard_peer_editor_get_type()) +#define NMT_WIREGUARD_PEER_EDITOR(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj), NMT_TYPE_WIREGUARD_PEER_EDITOR, NmtWireguardPeerEditor)) +#define NMT_WIREGUARD_PEER_EDITOR_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass), NMT_TYPE_WIREGUARD_PEER_EDITOR, NmtWireguardPeerEditorClass)) +#define NMT_IS_WIREGUARD_PEER_EDITOR(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj), NMT_TYPE_WIREGUARD_PEER_EDITOR)) +#define NMT_IS_WIREGUARD_PEER_EDITOR_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass), NMT_TYPE_WIREGUARD_PEER_EDITOR)) +#define NMT_WIREGUARD_PEER_EDITOR_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS((obj), NMT_TYPE_WIREGUARD_PEER_EDITOR, NmtWireguardPeerEditorClass)) + +typedef struct { + NmtNewtForm parent; +} NmtWireguardPeerEditor; + +typedef struct { + NmtNewtFormClass parent; +} NmtWireguardPeerEditorClass; + +GType nmt_wireguard_peer_editor_get_type(void); + +NmtNewtForm *nmt_wireguard_peer_editor_new(NMSettingWireGuard *setting, NMWireGuardPeer *peer); + +#endif /* NMT_WIREGUARD_PEER_EDITOR_H */ diff --git a/src/nmtui/nmt-wireguard-peer-list.c b/src/nmtui/nmt-wireguard-peer-list.c new file mode 100644 index 0000000000..03f3ef9aaa --- /dev/null +++ b/src/nmtui/nmt-wireguard-peer-list.c @@ -0,0 +1,451 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2021 Red Hat, Inc. + */ + +/** + * SECTION:nmt-wireguard-peer-list: + * @short_description: An editable list of a connection's peers + * + * #NmtWireguardPeerList implements an #NmtNewtGrid for the + * peers of a connection. + */ + +#include "libnm-client-aux-extern/nm-default-client.h" + +#include "nmtui.h" +#include "nmt-wireguard-peer-list.h" +#include "nmt-wireguard-peer-editor.h" + +G_DEFINE_TYPE(NmtWireguardPeerList, nmt_wireguard_peer_list, NMT_TYPE_NEWT_GRID) + +#define NMT_WIREGUARD_PEER_LIST_GET_PRIVATE(o) \ + (G_TYPE_INSTANCE_GET_PRIVATE((o), NMT_TYPE_WIREGUARD_PEER_LIST, NmtWireguardPeerListPrivate)) + +typedef struct { + NMSettingWireGuard *setting; + GSList * peers; + + NmtNewtListbox * listbox; + NmtNewtButtonBox *buttons; + + NmtNewtWidget *add; + NmtNewtWidget *edit; + NmtNewtWidget *delete; +} NmtWireguardPeerListPrivate; + +enum { + PROP_0, + + PROP_SETTING, + PROP_PEERS, + PROP_NUM_PEERS, + + LAST_PROP +}; + +enum { + ADD_PEER, + EDIT_PEER, + REMOVE_PEER, + + LAST_SIGNAL +}; + +static guint signals[LAST_SIGNAL] = {0}; + +/** + * nmt_wireguard_peer_list_new: + * @master: the master #NMSettingWireGuard whose peers are being listed + * + * Creates a new #NmtWireguardPeerList. + * + * Returns: a new #NmtWireguardPeerList. + */ +NmtNewtWidget * +nmt_wireguard_peer_list_new(NMSettingWireGuard *setting) +{ + return g_object_new(NMT_TYPE_WIREGUARD_PEER_LIST, "setting", setting, NULL); +} + +static void +add_clicked(NmtNewtButton *button, gpointer list) +{ + g_signal_emit(list, signals[ADD_PEER], 0); +} + +static void +edit_clicked(NmtNewtButton *button, gpointer list) +{ + g_signal_emit(list, signals[EDIT_PEER], 0); +} + +static void +delete_clicked(NmtNewtButton *button, gpointer list) +{ + g_signal_emit(list, signals[REMOVE_PEER], 0); +} + +static void +listbox_activated(NmtNewtWidget *listbox, gpointer list) +{ + NmtWireguardPeerListPrivate *priv = NMT_WIREGUARD_PEER_LIST_GET_PRIVATE(list); + + edit_clicked(NMT_NEWT_BUTTON(priv->edit), list); +} + +static void +nmt_wireguard_peer_list_init(NmtWireguardPeerList *list) +{ + NmtWireguardPeerListPrivate *priv = NMT_WIREGUARD_PEER_LIST_GET_PRIVATE(list); + NmtNewtWidget * listbox, *buttons; + NmtNewtGrid * grid = NMT_NEWT_GRID(list); + + listbox = g_object_new(NMT_TYPE_NEWT_LISTBOX, + "flags", + NMT_NEWT_LISTBOX_SCROLL | NMT_NEWT_LISTBOX_BORDER, + "skip-null-keys", + TRUE, + NULL); + priv->listbox = NMT_NEWT_LISTBOX(listbox); + nmt_newt_grid_add(grid, listbox, 0, 0); + nmt_newt_grid_set_flags(grid, + listbox, + NMT_NEWT_GRID_FILL_X | NMT_NEWT_GRID_FILL_Y | NMT_NEWT_GRID_EXPAND_X + | NMT_NEWT_GRID_EXPAND_Y); + g_signal_connect(priv->listbox, "activated", G_CALLBACK(listbox_activated), list); + + buttons = nmt_newt_button_box_new(NMT_NEWT_BUTTON_BOX_VERTICAL); + priv->buttons = NMT_NEWT_BUTTON_BOX(buttons); + nmt_newt_grid_add(grid, buttons, 1, 0); + nmt_newt_widget_set_padding(buttons, 1, 1, 0, 1); + nmt_newt_grid_set_flags(grid, + buttons, + NMT_NEWT_GRID_FILL_X | NMT_NEWT_GRID_FILL_Y | NMT_NEWT_GRID_EXPAND_Y); + + priv->add = nmt_newt_button_box_add_start(priv->buttons, _("Add")); + g_signal_connect(priv->add, "clicked", G_CALLBACK(add_clicked), list); + + priv->edit = nmt_newt_button_box_add_start(priv->buttons, _("Edit...")); + g_signal_connect(priv->edit, "clicked", G_CALLBACK(edit_clicked), list); + + priv->delete = nmt_newt_button_box_add_start(priv->buttons, _("Delete")); + g_signal_connect(priv->delete, "clicked", G_CALLBACK(delete_clicked), list); +} + +static void nmt_wireguard_peer_list_rebuild(NmtWireguardPeerList *list); + +static void +rebuild_on_peer_changed(gpointer list) +{ + nmt_wireguard_peer_list_rebuild(list); +} + +static void +free_peers(NmtWireguardPeerList *list) +{ + NmtWireguardPeerListPrivate *priv = NMT_WIREGUARD_PEER_LIST_GET_PRIVATE(list); + + g_slist_free(priv->peers); + priv->peers = NULL; +} + +static void +nmt_wireguard_peer_list_finalize(GObject *object) +{ + NmtWireguardPeerListPrivate *priv = NMT_WIREGUARD_PEER_LIST_GET_PRIVATE(object); + + free_peers(NMT_WIREGUARD_PEER_LIST(object)); + g_object_unref(priv->setting); + g_object_unref(priv->peers); + + G_OBJECT_CLASS(nmt_wireguard_peer_list_parent_class)->finalize(object); +} + +static void +nmt_wireguard_peer_list_add_peer(NmtWireguardPeerList *list) +{ + NmtWireguardPeerListPrivate *priv = NMT_WIREGUARD_PEER_LIST_GET_PRIVATE(list); + NMWireGuardPeer * peer = nm_wireguard_peer_new(); + NmtNewtForm * editor; + + editor = nmt_wireguard_peer_editor_new(priv->setting, peer); + + if (!editor) + return; + + nmt_newt_form_run_sync(editor); + g_object_unref(editor); + rebuild_on_peer_changed(list); +} + +static void +nmt_wireguard_peer_list_edit_peer(NmtWireguardPeerList *list) +{ + NmtWireguardPeerListPrivate *priv = NMT_WIREGUARD_PEER_LIST_GET_PRIVATE(list); + NMWireGuardPeer * orig_peer, *edit_peer; + NmtNewtForm * editor; + int selected_row; + + selected_row = nmt_newt_listbox_get_active(priv->listbox); + + if (selected_row >= 0) { + orig_peer = nm_setting_wireguard_get_peer(priv->setting, (guint) selected_row); + edit_peer = nm_wireguard_peer_new_clone(orig_peer, TRUE); + editor = nmt_wireguard_peer_editor_new(priv->setting, edit_peer); + if (!editor) + return; + nmt_newt_form_run_sync(editor); + g_object_unref(editor); + rebuild_on_peer_changed(list); + } +} + +static void +nmt_wireguard_peer_list_remove_peer(NmtWireguardPeerList *list) +{ + NmtWireguardPeerListPrivate *priv = NMT_WIREGUARD_PEER_LIST_GET_PRIVATE(list); + int selected_row; + + selected_row = nmt_newt_listbox_get_active(priv->listbox); + + if (selected_row >= 0) { + nm_setting_wireguard_remove_peer(priv->setting, (guint) selected_row); + rebuild_on_peer_changed(list); + } +} + +static void +nmt_wireguard_peer_list_set_property(GObject * object, + guint prop_id, + const GValue *value, + GParamSpec * pspec) +{ + NmtWireguardPeerListPrivate *priv = NMT_WIREGUARD_PEER_LIST_GET_PRIVATE(object); + + switch (prop_id) { + case PROP_SETTING: + priv->setting = g_value_get_pointer(value); + break; + case PROP_PEERS: + priv->peers = g_value_get_pointer(value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); + break; + } +} + +static void +nmt_wireguard_peer_list_get_property(GObject * object, + guint prop_id, + GValue * value, + GParamSpec *pspec) +{ + NmtWireguardPeerListPrivate *priv = NMT_WIREGUARD_PEER_LIST_GET_PRIVATE(object); + GPtrArray * peers; + GSList * iter; + + switch (prop_id) { + case PROP_SETTING: + g_value_set_pointer(value, priv->setting); + break; + case PROP_PEERS: + peers = g_ptr_array_new_with_free_func(g_object_unref); + for (iter = priv->peers; iter; iter = iter->next) + g_ptr_array_add(peers, g_object_ref(iter->data)); + g_value_take_boxed(value, peers); + break; + case PROP_NUM_PEERS: + g_value_set_int(value, g_slist_length(priv->peers)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); + break; + } +} + +static void +nmt_wireguard_peer_list_rebuild(NmtWireguardPeerList *list) +{ + NmtWireguardPeerListPrivate *priv = NMT_WIREGUARD_PEER_LIST_GET_PRIVATE(list); + GSList * iter; + NMWireGuardPeer * peer, *selected_peer; + int i, row, selected_row, num; + NMSettingWireGuard * setting = priv->setting; + + selected_row = nmt_newt_listbox_get_active(priv->listbox); + selected_peer = nmt_newt_listbox_get_active_key(priv->listbox); + + free_peers(list); + num = nm_setting_wireguard_get_peers_len(setting); + for (i = 0; i < num; i++) { + peer = nm_setting_wireguard_get_peer(setting, i); + priv->peers = g_slist_append(priv->peers, peer); + } + g_object_notify(G_OBJECT(list), "peers"); + g_object_notify(G_OBJECT(list), "num-peers"); + + nmt_newt_component_set_sensitive(NMT_NEWT_COMPONENT(priv->edit), priv->peers != NULL); + nmt_newt_component_set_sensitive(NMT_NEWT_COMPONENT(priv->delete), priv->peers != NULL); + + nmt_newt_listbox_clear(priv->listbox); + + for (iter = priv->peers, row = 0; iter; iter = iter->next, row++) { + peer = iter->data; + nmt_newt_listbox_append(priv->listbox, nm_wireguard_peer_get_public_key(peer), peer); + if (peer == selected_peer) + selected_row = row; + } + if (selected_row >= row) + selected_row = row - 1; + nmt_newt_listbox_set_active(priv->listbox, selected_row); +} + +static void +rebuild_on_peers_changed(GObject *object, GParamSpec *pspec, gpointer list) +{ + nmt_wireguard_peer_list_rebuild(list); +} + +static void +nmt_wireguard_peer_list_constructed(GObject *object) +{ + NmtWireguardPeerList *list = NMT_WIREGUARD_PEER_LIST(object); + + g_signal_connect(nm_client, + "notify::" NM_CLIENT_CONNECTIONS, + G_CALLBACK(rebuild_on_peers_changed), + list); + + nmt_wireguard_peer_list_rebuild(list); + + G_OBJECT_CLASS(nmt_wireguard_peer_list_parent_class)->constructed(object); +} + +static void +nmt_wireguard_peer_list_class_init(NmtWireguardPeerListClass *list_class) +{ + GObjectClass *object_class = G_OBJECT_CLASS(list_class); + + g_type_class_add_private(list_class, sizeof(NmtWireguardPeerListPrivate)); + + /* virtual methods */ + object_class->constructed = nmt_wireguard_peer_list_constructed; + object_class->set_property = nmt_wireguard_peer_list_set_property; + object_class->get_property = nmt_wireguard_peer_list_get_property; + object_class->finalize = nmt_wireguard_peer_list_finalize; + + list_class->add_peer = nmt_wireguard_peer_list_add_peer; + list_class->edit_peer = nmt_wireguard_peer_list_edit_peer; + list_class->remove_peer = nmt_wireguard_peer_list_remove_peer; + + /* signals */ + + /** + * NmtWireguardPeerList::add-connection: + * @list: the #NmtWireguardPeerList + * + * Emitted when the user clicks the list's "Add" button. + */ + signals[ADD_PEER] = g_signal_new("add-peer", + G_OBJECT_CLASS_TYPE(object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET(NmtWireguardPeerListClass, add_peer), + NULL, + NULL, + NULL, + G_TYPE_NONE, + 0); + + /** + * NmtWireguardPeerList::edit-connection: + * @list: the #NmtWireguardPeerList + * @connection: the connection to edit + * + * Emitted when the user clicks the list's "Edit" button, or + * hits "Return" on the listbox. + */ + signals[EDIT_PEER] = g_signal_new("edit-peer", + G_OBJECT_CLASS_TYPE(object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET(NmtWireguardPeerListClass, edit_peer), + NULL, + NULL, + NULL, + G_TYPE_NONE, + 0); + + /** + * NmtWireguardPeerList::remove-connection: + * @list: the #NmtWireguardPeerList + * @connection: the connection to remove + * + * Emitted when the user clicks the list's "Delete" button. + */ + signals[REMOVE_PEER] = g_signal_new("remove-peer", + G_OBJECT_CLASS_TYPE(object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET(NmtWireguardPeerListClass, remove_peer), + NULL, + NULL, + NULL, + G_TYPE_NONE, + 0); + + /* properties */ + + /** + * NmtWireguardPeerListFilter: + * @list: the #NmtWireguardPeerList + * @connection: an #NMConnection + * @user_data: the user data + * + * Decides whether @connection should be displayed in @list. + * + * Returns: %TRUE or %FALSE + */ + /** + * NmtWireguardPeerList:connection-filter: + * + * A callback function for filtering which connections appear in + * the list. + */ + g_object_class_install_property( + object_class, + PROP_SETTING, + g_param_spec_pointer("setting", + "", + "", + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); + + /** + * NmtWireguardPeerList:connections: + * + * The list of connections in the widget. + * + * Element-Type: #NMConnection + */ + g_object_class_install_property(object_class, + PROP_PEERS, + g_param_spec_boxed("peers", + "", + "", + G_TYPE_PTR_ARRAY, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + /** + * NmtWireguardPeerList:num-connections: + * + * The number of connections in the widget. + */ + g_object_class_install_property(object_class, + PROP_NUM_PEERS, + g_param_spec_int("num-peers", + "", + "", + 0, + G_MAXINT, + 0, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); +} diff --git a/src/nmtui/nmt-wireguard-peer-list.h b/src/nmtui/nmt-wireguard-peer-list.h new file mode 100644 index 0000000000..de3faf1206 --- /dev/null +++ b/src/nmtui/nmt-wireguard-peer-list.h @@ -0,0 +1,42 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2021 Red Hat, Inc. + */ + +#ifndef NMT_WIREGUARD_PEER_LIST_H +#define NMT_WIREGUARD_PEER_LIST_H + +#include "libnmt-newt/nmt-newt.h" +#include "nmtui-edit.h" + +#define NMT_TYPE_WIREGUARD_PEER_LIST (nmt_wireguard_peer_list_get_type()) +#define NMT_WIREGUARD_PEER_LIST(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj), NMT_TYPE_WIREGUARD_PEER_LIST, NmtWireguardPeerList)) +#define NMT_WIREGUARD_PEER_LIST_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass), NMT_TYPE_WIREGUARD_PEER_LIST, NmtWireguardPeerListClass)) +#define NMT_IS_WIREGUARD_PEER_LIST(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj), NMT_TYPE_WIREGUARD_PEER_LIST)) +#define NMT_IS_WIREGUARD_PEER_LIST_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass), NMT_TYPE_WIREGUARD_PEER_LIST)) +#define NMT_WIREGUARD_PEER_LIST_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS((obj), NMT_TYPE_WIREGUARD_PEER_LIST, NmtWireguardPeerListClass)) + +typedef struct { + NmtNewtGrid parent; + +} NmtWireguardPeerList; + +typedef struct { + NmtNewtGridClass parent; + + /* signals */ + void (*add_peer)(NmtWireguardPeerList *list); + void (*edit_peer)(NmtWireguardPeerList *list); + void (*remove_peer)(NmtWireguardPeerList *list); +} NmtWireguardPeerListClass; + +GType nmt_wireguard_peer_list_get_type(void); + +NmtNewtWidget *nmt_wireguard_peer_list_new(NMSettingWireGuard *setting); + +#endif /* NMT_WIREGUARD_PEER_LIST_H */