diff --git a/accounts-service/com.endlessm.ParentalControls.AppFilter.xml b/accounts-service/com.endlessm.ParentalControls.AppFilter.xml index 8d4d554..ab88092 100644 --- a/accounts-service/com.endlessm.ParentalControls.AppFilter.xml +++ b/accounts-service/com.endlessm.ParentalControls.AppFilter.xml @@ -61,16 +61,33 @@ - + + + + + + diff --git a/eos-parental-controls-client/eos-parental-controls-client.py b/eos-parental-controls-client/eos-parental-controls-client.py index 5e6ca4f..fc3d238 100644 --- a/eos-parental-controls-client/eos-parental-controls-client.py +++ b/eos-parental-controls-client/eos-parental-controls-client.py @@ -138,10 +138,15 @@ def command_get(user, quiet=False, interactive=True): if not sections: print(' (No OARS values)') - if app_filter.is_app_installation_allowed(): - print('App installation is allowed') + if app_filter.is_user_installation_allowed(): + print('App installation is allowed to user repository') else: - print('App installation is disallowed') + print('App installation is disallowed to user repository') + + if app_filter.is_system_installation_allowed(): + print('App installation is allowed to system repository') + else: + print('App installation is disallowed to system repository') def command_check(user, path, quiet=False, interactive=True): @@ -186,12 +191,14 @@ def command_oars_section(user, section, quiet=False, interactive=True): section, user_id, __oars_value_to_string(value))) -def command_set(user, allow_app_installation=True, app_filter_args=None, +def command_set(user, allow_user_installation=True, + allow_system_installation=False, app_filter_args=None, quiet=False, interactive=True): """Set the app filter for the given user.""" user_id = __lookup_user_id_or_error(user) builder = EosParentalControls.AppFilterBuilder.new() - builder.set_allow_app_installation(allow_app_installation) + builder.set_allow_user_installation(allow_user_installation) + builder.set_allow_system_installation(allow_system_installation) for arg in app_filter_args: if '=' in arg: @@ -277,17 +284,31 @@ def main(): parser_set.add_argument('user', default='', nargs='?', help='user ID or username to get the app filter ' 'for (default: current user)') - parser_set.add_argument('--allow-app-installation', - dest='allow_app_installation', action='store_true', - help='allow app installation in general') - parser_set.add_argument('--disallow-app-installation', - dest='allow_app_installation', + parser_set.add_argument('--allow-user-installation', + dest='allow_user_installation', + action='store_true', + help='allow installation to the user flatpak ' + 'repo in general') + parser_set.add_argument('--disallow-user-installation', + dest='allow_user_installation', action='store_false', - help='unconditionally disallow app installation') + help='unconditionally disallow installation to ' + 'the user flatpak repo') + parser_set.add_argument('--allow-system-installation', + dest='allow_system_installation', + action='store_true', + help='allow installation to the system flatpak ' + 'repo in general') + parser_set.add_argument('--disallow-system-installation', + dest='allow_system_installation', + action='store_false', + help='unconditionally disallow installation to ' + 'the system flatpak repo') parser_set.add_argument('app_filter_args', nargs='*', help='paths to blacklist and OARS section=value ' 'pairs to store') - parser_set.set_defaults(allow_app_installation=True) + parser_set.set_defaults(allow_user_installation=True, + allow_system_installation=False) # Parse the command line arguments and run the subcommand. args = parser.parse_args() diff --git a/libeos-parental-controls/app-filter.c b/libeos-parental-controls/app-filter.c index 43a939e..33ee9d7 100644 --- a/libeos-parental-controls/app-filter.c +++ b/libeos-parental-controls/app-filter.c @@ -59,7 +59,8 @@ struct _EpcAppFilter EpcAppFilterListType app_list_type; GVariant *oars_ratings; /* (type a{ss}) (owned non-floating) */ - gboolean allow_app_installation; + gboolean allow_user_installation; + gboolean allow_system_installation; }; G_DEFINE_BOXED_TYPE (EpcAppFilter, epc_app_filter, @@ -376,7 +377,7 @@ epc_app_filter_get_oars_sections (EpcAppFilter *filter) * section, inclusive. Any app with a more intense value for this section must * be hidden from the user whose @filter this is. * - * This does not factor in epc_app_filter_is_app_installation_allowed(). + * This does not factor in epc_app_filter_is_system_installation_allowed(). * * Returns: an #EpcAppFilterOarsValue * Since: 0.1.0 @@ -409,25 +410,47 @@ epc_app_filter_get_oars_value (EpcAppFilter *filter, } /** - * epc_app_filter_is_app_installation_allowed: + * epc_app_filter_is_user_installation_allowed: * @filter: an #EpcAppFilter * - * Get whether app installation is allowed at all for the user. This should be - * queried in addition to the OARS values (epc_app_filter_get_oars_value()) — if - * it returns %FALSE, the OARS values should be ignored and app installation - * should be unconditionally disallowed. + * Get whether the user is allowed to install to their flatpak user repository. + * This should be queried in addition to the OARS values + * (epc_app_filter_get_oars_value()) — if it returns %FALSE, the OARS values + * should be ignored and app installation should be unconditionally disallowed. * - * Returns: %TRUE if app installation is allowed in general for this user; - * %FALSE if it is unconditionally disallowed for this user + * Returns: %TRUE if app installation is allowed to the user repository for + * this user; %FALSE if it is unconditionally disallowed for this user * Since: 0.1.0 */ gboolean -epc_app_filter_is_app_installation_allowed (EpcAppFilter *filter) +epc_app_filter_is_user_installation_allowed (EpcAppFilter *filter) { g_return_val_if_fail (filter != NULL, FALSE); g_return_val_if_fail (filter->ref_count >= 1, FALSE); - return filter->allow_app_installation; + return filter->allow_user_installation; +} + +/** + * epc_app_filter_is_system_installation_allowed: + * @filter: an #EpcAppFilter + * + * Get whether the user is allowed to install to the flatpak system repository. + * This should be queried in addition to the OARS values + * (epc_app_filter_get_oars_value()) — if it returns %FALSE, the OARS values + * should be ignored and app installation should be unconditionally disallowed. + * + * Returns: %TRUE if app installation is allowed to the system repository for + * this user; %FALSE if it is unconditionally disallowed for this user + * Since: 0.1.0 + */ +gboolean +epc_app_filter_is_system_installation_allowed (EpcAppFilter *filter) +{ + g_return_val_if_fail (filter != NULL, FALSE); + g_return_val_if_fail (filter->ref_count >= 1, FALSE); + + return filter->allow_system_installation; } /** @@ -566,7 +589,8 @@ epc_get_app_filter (GDBusConnection *connection, const gchar *content_rating_kind; g_autoptr(GVariant) oars_variant = NULL; g_autoptr(GHashTable) oars_map = NULL; - gboolean allow_app_installation; + gboolean allow_user_installation; + gboolean allow_system_installation; g_return_val_if_fail (connection == NULL || G_IS_DBUS_CONNECTION (connection), NULL); g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); @@ -638,11 +662,18 @@ epc_get_app_filter (GDBusConnection *connection, return NULL; } - if (!g_variant_lookup (properties, "allow-app-installation", "b", - &allow_app_installation)) + if (!g_variant_lookup (properties, "allow-user-installation", "b", + &allow_user_installation)) { /* Default value. */ - allow_app_installation = TRUE; + allow_user_installation = TRUE; + } + + if (!g_variant_lookup (properties, "allow-system-installation", "b", + &allow_system_installation)) + { + /* Default value. */ + allow_system_installation = FALSE; } /* Success. Create an #EpcAppFilter object to contain the results. */ @@ -653,7 +684,8 @@ epc_get_app_filter (GDBusConnection *connection, app_filter->app_list_type = is_whitelist ? EPC_APP_FILTER_LIST_WHITELIST : EPC_APP_FILTER_LIST_BLACKLIST; app_filter->oars_ratings = g_steal_pointer (&oars_variant); - app_filter->allow_app_installation = allow_app_installation; + app_filter->allow_user_installation = allow_user_installation; + app_filter->allow_system_installation = allow_system_installation; return g_steal_pointer (&app_filter); } @@ -798,10 +830,12 @@ epc_set_app_filter (GDBusConnection *connection, g_autofree gchar *object_path = NULL; g_autoptr(GVariant) app_filter_variant = NULL; g_autoptr(GVariant) oars_filter_variant = NULL; - g_autoptr(GVariant) allow_app_installation_variant = NULL; + g_autoptr(GVariant) allow_user_installation_variant = NULL; + g_autoptr(GVariant) allow_system_installation_variant = NULL; g_autoptr(GVariant) app_filter_result_variant = NULL; g_autoptr(GVariant) oars_filter_result_variant = NULL; - g_autoptr(GVariant) allow_app_installation_result_variant = NULL; + g_autoptr(GVariant) allow_user_installation_result_variant = NULL; + g_autoptr(GVariant) allow_system_installation_result_variant = NULL; g_autoptr(GError) local_error = NULL; g_return_val_if_fail (connection == NULL || G_IS_DBUS_CONNECTION (connection), FALSE); @@ -824,7 +858,8 @@ epc_set_app_filter (GDBusConnection *connection, app_filter_variant = _epc_app_filter_build_app_filter_variant (app_filter); oars_filter_variant = g_variant_new ("(s@a{ss})", "oars-1.1", app_filter->oars_ratings); - allow_app_installation_variant = g_variant_new_boolean (app_filter->allow_app_installation); + allow_user_installation_variant = g_variant_new_boolean (app_filter->allow_user_installation); + allow_system_installation_variant = g_variant_new_boolean (app_filter->allow_system_installation); app_filter_result_variant = g_dbus_connection_call_sync (connection, @@ -872,7 +907,7 @@ epc_set_app_filter (GDBusConnection *connection, return FALSE; } - allow_app_installation_result_variant = + allow_user_installation_result_variant = g_dbus_connection_call_sync (connection, "org.freedesktop.Accounts", object_path, @@ -880,8 +915,31 @@ epc_set_app_filter (GDBusConnection *connection, "Set", g_variant_new ("(ssv)", "com.endlessm.ParentalControls.AppFilter", - "allow-app-installation", - g_steal_pointer (&allow_app_installation_variant)), + "allow-user-installation", + g_steal_pointer (&allow_user_installation_variant)), + G_VARIANT_TYPE ("()"), + allow_interactive_authorization + ? G_DBUS_CALL_FLAGS_ALLOW_INTERACTIVE_AUTHORIZATION + : G_DBUS_CALL_FLAGS_NONE, + -1, /* timeout, ms */ + cancellable, + &local_error); + if (local_error != NULL) + { + g_propagate_error (error, bus_error_to_app_filter_error (local_error, user_id)); + return FALSE; + } + + allow_system_installation_result_variant = + g_dbus_connection_call_sync (connection, + "org.freedesktop.Accounts", + object_path, + "org.freedesktop.DBus.Properties", + "Set", + g_variant_new ("(ssv)", + "com.endlessm.ParentalControls.AppFilter", + "allow-system-installation", + g_steal_pointer (&allow_system_installation_variant)), G_VARIANT_TYPE ("()"), allow_interactive_authorization ? G_DBUS_CALL_FLAGS_ALLOW_INTERACTIVE_AUTHORIZATION @@ -1026,7 +1084,8 @@ typedef struct { GPtrArray *paths_blacklist; /* (nullable) (owned) (element-type filename) */ GHashTable *oars; /* (nullable) (owned) (element-type utf8 EpcAppFilterOarsValue) */ - gboolean allow_app_installation; + gboolean allow_user_installation; + gboolean allow_system_installation; /*< private >*/ gpointer padding[2]; @@ -1141,7 +1200,8 @@ epc_app_filter_builder_copy (EpcAppFilterBuilder *builder) _copy->paths_blacklist = g_ptr_array_ref (_builder->paths_blacklist); if (_builder->oars != NULL) _copy->oars = g_hash_table_ref (_builder->oars); - _copy->allow_app_installation = _builder->allow_app_installation; + _copy->allow_user_installation = _builder->allow_user_installation; + _copy->allow_system_installation = _builder->allow_system_installation; return g_steal_pointer (©); } @@ -1225,7 +1285,8 @@ epc_app_filter_builder_end (EpcAppFilterBuilder *builder) app_filter->app_list = (gchar **) g_ptr_array_free (g_steal_pointer (&_builder->paths_blacklist), FALSE); app_filter->app_list_type = EPC_APP_FILTER_LIST_BLACKLIST; app_filter->oars_ratings = g_steal_pointer (&oars_variant); - app_filter->allow_app_installation = _builder->allow_app_installation; + app_filter->allow_user_installation = _builder->allow_user_installation; + app_filter->allow_system_installation = _builder->allow_system_installation; epc_app_filter_builder_clear (builder); @@ -1316,25 +1377,49 @@ epc_app_filter_builder_set_oars_value (EpcAppFilterBuilder *builder, } /** - * epc_app_filter_builder_set_allow_app_installation: + * epc_app_filter_builder_set_allow_user_installation: * @builder: an initialised #EpcAppFilterBuilder - * @allow_app_installation: %TRUE to allow app installation; %FALSE to + * @allow_user_installation: %TRUE to allow app installation; %FALSE to * unconditionally disallow it * - * Set whether app installation is allowed in general for the user. If this is - * %TRUE, app installation is still subject to the OARS values + * Set whether the user is allowed to install to their flatpak user repository. + * If this is %TRUE, app installation is still subject to the OARS values * (epc_app_filter_builder_set_oars_value()). If it is %FALSE, app installation * is unconditionally disallowed for this user. * * Since: 0.1.0 */ void -epc_app_filter_builder_set_allow_app_installation (EpcAppFilterBuilder *builder, - gboolean allow_app_installation) +epc_app_filter_builder_set_allow_user_installation (EpcAppFilterBuilder *builder, + gboolean allow_user_installation) { EpcAppFilterBuilderReal *_builder = (EpcAppFilterBuilderReal *) builder; g_return_if_fail (_builder != NULL); - _builder->allow_app_installation = allow_app_installation; + _builder->allow_user_installation = allow_user_installation; +} + +/** + * epc_app_filter_builder_set_allow_system_installation: + * @builder: an initialised #EpcAppFilterBuilder + * @allow_system_installation: %TRUE to allow app installation; %FALSE to + * unconditionally disallow it + * + * Set whether the user is allowed to install to the flatpak system repository. + * If this is %TRUE, app installation is still subject to the OARS values + * (epc_app_filter_builder_set_oars_value()). If it is %FALSE, app installation + * is unconditionally disallowed for this user. + * + * Since: 0.1.0 + */ +void +epc_app_filter_builder_set_allow_system_installation (EpcAppFilterBuilder *builder, + gboolean allow_system_installation) +{ + EpcAppFilterBuilderReal *_builder = (EpcAppFilterBuilderReal *) builder; + + g_return_if_fail (_builder != NULL); + + _builder->allow_system_installation = allow_system_installation; } diff --git a/libeos-parental-controls/app-filter.h b/libeos-parental-controls/app-filter.h index 1f952ff..5cc0a60 100644 --- a/libeos-parental-controls/app-filter.h +++ b/libeos-parental-controls/app-filter.h @@ -111,7 +111,8 @@ const gchar **epc_app_filter_get_oars_sections (EpcAppFilter *filter); EpcAppFilterOarsValue epc_app_filter_get_oars_value (EpcAppFilter *filter, const gchar *oars_section); -gboolean epc_app_filter_is_app_installation_allowed (EpcAppFilter *filter); +gboolean epc_app_filter_is_user_installation_allowed (EpcAppFilter *filter); +gboolean epc_app_filter_is_system_installation_allowed (EpcAppFilter *filter); EpcAppFilter *epc_get_app_filter (GDBusConnection *connection, uid_t user_id, @@ -159,6 +160,7 @@ typedef struct gpointer p0; gpointer p1; gboolean b0; + gboolean b1; gpointer p2; gpointer p3; } EpcAppFilterBuilder; @@ -183,6 +185,7 @@ GType epc_app_filter_builder_get_type (void); g_ptr_array_new_with_free_func (g_free), \ g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL), \ TRUE, \ + FALSE, \ } void epc_app_filter_builder_init (EpcAppFilterBuilder *builder); @@ -207,7 +210,9 @@ void epc_app_filter_builder_set_oars_value (EpcAppFilterBuilder *builde const gchar *oars_section, EpcAppFilterOarsValue value); -void epc_app_filter_builder_set_allow_app_installation (EpcAppFilterBuilder *builder, - gboolean allow_app_installation); +void epc_app_filter_builder_set_allow_user_installation (EpcAppFilterBuilder *builder, + gboolean allow_user_installation); +void epc_app_filter_builder_set_allow_system_installation (EpcAppFilterBuilder *builder, + gboolean allow_system_installation); G_END_DECLS diff --git a/libeos-parental-controls/tests/app-filter.c b/libeos-parental-controls/tests/app-filter.c index 7fb4e5e..a7e491b 100644 --- a/libeos-parental-controls/tests/app-filter.c +++ b/libeos-parental-controls/tests/app-filter.c @@ -125,7 +125,8 @@ test_app_filter_builder_non_empty (BuilderFixture *fixture, EPC_APP_FILTER_OARS_VALUE_MILD); epc_app_filter_builder_set_oars_value (fixture->builder, "language-humor", EPC_APP_FILTER_OARS_VALUE_MODERATE); - epc_app_filter_builder_set_allow_app_installation (fixture->builder, FALSE); + epc_app_filter_builder_set_allow_user_installation (fixture->builder, TRUE); + epc_app_filter_builder_set_allow_system_installation (fixture->builder, FALSE); filter = epc_app_filter_builder_end (fixture->builder); @@ -151,7 +152,8 @@ test_app_filter_builder_non_empty (BuilderFixture *fixture, const gchar * const expected_sections[] = { "drugs-alcohol", "language-humor", NULL }; assert_strv_equal ((const gchar * const *) sections, expected_sections); - g_assert_false (epc_app_filter_is_app_installation_allowed (filter)); + g_assert_true (epc_app_filter_is_user_installation_allowed (filter)); + g_assert_false (epc_app_filter_is_system_installation_allowed (filter)); } /* Test building an empty #EpcAppFilter using an #EpcAppFilterBuilder. */ @@ -186,7 +188,8 @@ test_app_filter_builder_empty (BuilderFixture *fixture, const gchar * const expected_sections[] = { NULL }; assert_strv_equal ((const gchar * const *) sections, expected_sections); - g_assert_true (epc_app_filter_is_app_installation_allowed (filter)); + g_assert_true (epc_app_filter_is_user_installation_allowed (filter)); + g_assert_false (epc_app_filter_is_system_installation_allowed (filter)); } /* Check that copying a cleared #EpcAppFilterBuilder works, and the copy can @@ -208,7 +211,8 @@ test_app_filter_builder_copy_empty (void) g_assert_true (epc_app_filter_is_path_allowed (filter, "/bin/false")); g_assert_false (epc_app_filter_is_path_allowed (filter, "/bin/true")); - g_assert_true (epc_app_filter_is_app_installation_allowed (filter)); + g_assert_true (epc_app_filter_is_user_installation_allowed (filter)); + g_assert_false (epc_app_filter_is_system_installation_allowed (filter)); } /* Check that copying a filled #EpcAppFilterBuilder works, and the copy can be @@ -221,13 +225,15 @@ test_app_filter_builder_copy_full (void) g_autoptr(EpcAppFilter) filter = NULL; epc_app_filter_builder_blacklist_path (builder, "/bin/true"); - epc_app_filter_builder_set_allow_app_installation (builder, FALSE); + epc_app_filter_builder_set_allow_user_installation (builder, FALSE); + epc_app_filter_builder_set_allow_system_installation (builder, TRUE); builder_copy = epc_app_filter_builder_copy (builder); filter = epc_app_filter_builder_end (builder_copy); g_assert_true (epc_app_filter_is_path_allowed (filter, "/bin/false")); g_assert_false (epc_app_filter_is_path_allowed (filter, "/bin/true")); - g_assert_false (epc_app_filter_is_app_installation_allowed (filter)); + g_assert_false (epc_app_filter_is_user_installation_allowed (filter)); + g_assert_true (epc_app_filter_is_system_installation_allowed (filter)); } int