From 9fbcef0fb8a8834be8d32c3addf50ac86fa6cb20 Mon Sep 17 00:00:00 2001 From: Philip Withnall Date: Fri, 20 Mar 2020 14:54:42 +0000 Subject: [PATCH 1/4] libmalcontent: Add a clarifying comment about nullability This introduces no functional changes. Signed-off-by: Philip Withnall --- libmalcontent/app-filter-private.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libmalcontent/app-filter-private.h b/libmalcontent/app-filter-private.h index 42e97b3..c4f9b31 100644 --- a/libmalcontent/app-filter-private.h +++ b/libmalcontent/app-filter-private.h @@ -52,7 +52,7 @@ struct _MctAppFilter uid_t user_id; - gchar **app_list; /* (owned) (array zero-terminated=1) */ + gchar **app_list; /* (not nullable) (owned) (array zero-terminated=1) */ MctAppFilterListType app_list_type; GVariant *oars_ratings; /* (type a{ss}) (owned non-floating) */ From faa0b9a3eb90b455b5fe2ba9c322c2c9fee5895d Mon Sep 17 00:00:00 2001 From: Philip Withnall Date: Fri, 20 Mar 2020 14:55:36 +0000 Subject: [PATCH 2/4] app-filter: Factor out a helper function This introduces no functional changes, but will make an upcoming change a little simpler. Signed-off-by: Philip Withnall --- libmalcontent/app-filter.c | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/libmalcontent/app-filter.c b/libmalcontent/app-filter.c index a9d9683..9340caf 100644 --- a/libmalcontent/app-filter.c +++ b/libmalcontent/app-filter.c @@ -108,6 +108,21 @@ mct_app_filter_get_user_id (MctAppFilter *filter) return filter->user_id; } +static MctAppFilterOarsValue +oars_str_to_enum (const gchar *value_str) +{ + if (g_str_equal (value_str, "none")) + return MCT_APP_FILTER_OARS_VALUE_NONE; + else if (g_str_equal (value_str, "mild")) + return MCT_APP_FILTER_OARS_VALUE_MILD; + else if (g_str_equal (value_str, "moderate")) + return MCT_APP_FILTER_OARS_VALUE_MODERATE; + else if (g_str_equal (value_str, "intense")) + return MCT_APP_FILTER_OARS_VALUE_INTENSE; + else + return MCT_APP_FILTER_OARS_VALUE_UNKNOWN; +} + /** * mct_app_filter_is_path_allowed: * @filter: an #MctAppFilter @@ -477,16 +492,7 @@ mct_app_filter_get_oars_value (MctAppFilter *filter, if (!g_variant_lookup (filter->oars_ratings, oars_section, "&s", &value_str)) return MCT_APP_FILTER_OARS_VALUE_UNKNOWN; - if (g_str_equal (value_str, "none")) - return MCT_APP_FILTER_OARS_VALUE_NONE; - else if (g_str_equal (value_str, "mild")) - return MCT_APP_FILTER_OARS_VALUE_MILD; - else if (g_str_equal (value_str, "moderate")) - return MCT_APP_FILTER_OARS_VALUE_MODERATE; - else if (g_str_equal (value_str, "intense")) - return MCT_APP_FILTER_OARS_VALUE_INTENSE; - else - return MCT_APP_FILTER_OARS_VALUE_UNKNOWN; + return oars_str_to_enum (value_str); } /** From f106319fdd15aa54a3e1edd29ab1ebd50250edba Mon Sep 17 00:00:00 2001 From: Philip Withnall Date: Fri, 20 Mar 2020 14:56:36 +0000 Subject: [PATCH 3/4] app-filter: Add mct_app_filter_is_enabled() API MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is a high-level API to indicate whether parental controls are ‘enabled’ for the given user. Specifically, whether any of the properties of the `MctAppFilter` differ from their default value. Includes tests. Signed-off-by: Philip Withnall --- libmalcontent/app-filter.c | 48 +++++++++++++++++++++++++ libmalcontent/app-filter.h | 3 ++ libmalcontent/tests/app-filter.c | 61 ++++++++++++++++++++++++++++++++ 3 files changed, 112 insertions(+) diff --git a/libmalcontent/app-filter.c b/libmalcontent/app-filter.c index 9340caf..3fdc1e9 100644 --- a/libmalcontent/app-filter.c +++ b/libmalcontent/app-filter.c @@ -123,6 +123,54 @@ oars_str_to_enum (const gchar *value_str) return MCT_APP_FILTER_OARS_VALUE_UNKNOWN; } +/** + * mct_app_filter_is_enabled: + * @filter: an #MctAppFilter + * + * Check whether the app filter is enabled and is going to impose at least one + * restriction on the user. This gives a high level view of whether app filter + * parental controls are ‘enabled’ for the given user. + * + * Returns: %TRUE if the app filter contains at least one non-default value, + * %FALSE if it’s entirely default + * Since: 0.7.0 + */ +gboolean +mct_app_filter_is_enabled (MctAppFilter *filter) +{ + gboolean oars_ratings_all_intense_or_unknown; + GVariantIter iter; + const gchar *oars_value; + + g_return_val_if_fail (filter != NULL, FALSE); + g_return_val_if_fail (filter->ref_count >= 1, FALSE); + + /* The least restrictive OARS filter has all values as intense, or unknown. */ + oars_ratings_all_intense_or_unknown = TRUE; + g_variant_iter_init (&iter, filter->oars_ratings); + + while (g_variant_iter_loop (&iter, "{&s&s}", NULL, &oars_value)) + { + MctAppFilterOarsValue value = oars_str_to_enum (oars_value); + + if (value != MCT_APP_FILTER_OARS_VALUE_UNKNOWN && + value != MCT_APP_FILTER_OARS_VALUE_INTENSE) + { + oars_ratings_all_intense_or_unknown = FALSE; + break; + } + } + + /* Check all fields against their default values. Ignore + * `allow_system_installation` since it’s false by default, so the default + * value is already the most restrictive. */ + return ((filter->app_list_type == MCT_APP_FILTER_LIST_BLACKLIST && + filter->app_list[0] != NULL) || + filter->app_list_type == MCT_APP_FILTER_LIST_WHITELIST || + !oars_ratings_all_intense_or_unknown || + !filter->allow_user_installation); +} + /** * mct_app_filter_is_path_allowed: * @filter: an #MctAppFilter diff --git a/libmalcontent/app-filter.h b/libmalcontent/app-filter.h index b5d8fb9..3902f87 100644 --- a/libmalcontent/app-filter.h +++ b/libmalcontent/app-filter.h @@ -78,6 +78,9 @@ void mct_app_filter_unref (MctAppFilter *filter); G_DEFINE_AUTOPTR_CLEANUP_FUNC (MctAppFilter, mct_app_filter_unref) uid_t mct_app_filter_get_user_id (MctAppFilter *filter); + +gboolean mct_app_filter_is_enabled (MctAppFilter *filter); + gboolean mct_app_filter_is_path_allowed (MctAppFilter *filter, const gchar *path); gboolean mct_app_filter_is_flatpak_ref_allowed (MctAppFilter *filter, diff --git a/libmalcontent/tests/app-filter.c b/libmalcontent/tests/app-filter.c index f5f9eca..00c6d43 100644 --- a/libmalcontent/tests/app-filter.c +++ b/libmalcontent/tests/app-filter.c @@ -162,6 +162,55 @@ test_app_filter_deserialize_invalid (void) } } +/* Test that mct_app_filter_is_enabled() returns the correct results on various + * app filters. */ +static void +test_app_filter_is_enabled (void) +{ + const struct + { + const gchar *serialized; + gboolean is_enabled; + } + app_filters[] = + { + { "@a{sv} {}", FALSE }, + { "{ 'AppFilter': <(true, @as [])> }", TRUE }, + { "{ 'AppFilter': <(false, @as [])> }", FALSE }, + { "{ 'AppFilter': <(false, @as [ '/usr/bin/gnome-software' ])> }", TRUE }, + { "{ 'OarsFilter': <('oars-1.1', @a{ss} {})> }", FALSE }, + { "{ 'OarsFilter': <('oars-1.1', { 'violence-cartoon': 'mild' })> }", TRUE }, + { "{ 'OarsFilter': <('oars-1.1', { 'violence-cartoon': 'intense' })> }", FALSE }, + { "{ 'OarsFilter': <('oars-1.1', { 'violence-cartoon': '' })> }", FALSE }, /* technically an invalid serialisation */ + { "{ 'OarsFilter': <('oars-1.1', { 'violence-cartoon': 'none' })> }", TRUE }, + { "{ 'OarsFilter': <('oars-1.1', { 'violence-cartoon': 'mild', 'violence-realistic': 'intense' })> }", TRUE }, + { "{ 'OarsFilter': <('oars-1.1', { 'violence-cartoon': 'mild', 'violence-realistic': 'none' })> }", TRUE }, + { "{ 'AllowUserInstallation': }", FALSE }, + { "{ 'AllowUserInstallation': }", TRUE }, + { "{ 'AllowSystemInstallation': }", FALSE }, + { "{ 'AllowSystemInstallation': }", FALSE }, + }; + + for (gsize i = 0; i < G_N_ELEMENTS (app_filters); i++) + { + g_autoptr(GVariant) variant = NULL; + g_autoptr(MctAppFilter) filter = NULL; + + g_test_message ("%" G_GSIZE_FORMAT ": %s", i, app_filters[i].serialized); + + variant = g_variant_parse (NULL, app_filters[i].serialized, NULL, NULL, NULL); + g_assert (variant != NULL); + + filter = mct_app_filter_deserialize (variant, 1, NULL); + g_assert (filter != NULL); + + if (app_filters[i].is_enabled) + g_assert_true (mct_app_filter_is_enabled (filter)); + else + g_assert_false (mct_app_filter_is_enabled (filter)); + } +} + /* Fixture for tests which use an #MctAppFilterBuilder. The builder can either * be heap- or stack-allocated. @builder will always be a valid pointer to it. */ @@ -244,6 +293,8 @@ test_app_filter_builder_non_empty (BuilderFixture *fixture, filter = mct_app_filter_builder_end (fixture->builder); + g_assert_true (mct_app_filter_is_enabled (filter)); + g_assert_true (mct_app_filter_is_path_allowed (filter, "/bin/false")); g_assert_false (mct_app_filter_is_path_allowed (filter, "/usr/bin/gnome-software")); @@ -285,6 +336,8 @@ test_app_filter_builder_empty (BuilderFixture *fixture, filter = mct_app_filter_builder_end (fixture->builder); + g_assert_false (mct_app_filter_is_enabled (filter)); + g_assert_true (mct_app_filter_is_path_allowed (filter, "/bin/false")); g_assert_true (mct_app_filter_is_path_allowed (filter, "/usr/bin/gnome-software")); @@ -332,6 +385,7 @@ test_app_filter_builder_copy_empty (void) "x-scheme-handler/http"); filter = mct_app_filter_builder_end (builder_copy); + g_assert_true (mct_app_filter_is_enabled (filter)); g_assert_true (mct_app_filter_is_path_allowed (filter, "/bin/false")); g_assert_false (mct_app_filter_is_path_allowed (filter, "/bin/true")); g_assert_true (mct_app_filter_is_content_type_allowed (filter, @@ -359,6 +413,7 @@ test_app_filter_builder_copy_full (void) builder_copy = mct_app_filter_builder_copy (builder); filter = mct_app_filter_builder_end (builder_copy); + g_assert_true (mct_app_filter_is_enabled (filter)); g_assert_true (mct_app_filter_is_path_allowed (filter, "/bin/false")); g_assert_false (mct_app_filter_is_path_allowed (filter, "/bin/true")); g_assert_true (mct_app_filter_is_content_type_allowed (filter, @@ -691,6 +746,7 @@ test_app_filter_bus_get (BusFixture *fixture, /* Check the app filter properties. */ g_assert_cmpuint (mct_app_filter_get_user_id (app_filter), ==, fixture->valid_uid); + g_assert_true (mct_app_filter_is_enabled (app_filter)); g_assert_false (mct_app_filter_is_flatpak_app_allowed (app_filter, "org.gnome.Builder")); g_assert_true (mct_app_filter_is_flatpak_app_allowed (app_filter, "org.gnome.Chess")); } @@ -736,6 +792,7 @@ test_app_filter_bus_get_whitelist (BusFixture *fixture, /* Check the app filter properties. The returned filter is a whitelist, * whereas typically a blacklist is returned. */ g_assert_cmpuint (mct_app_filter_get_user_id (app_filter), ==, fixture->valid_uid); + g_assert_true (mct_app_filter_is_enabled (app_filter)); g_assert_false (mct_app_filter_is_flatpak_app_allowed (app_filter, "org.gnome.Builder")); g_assert_true (mct_app_filter_is_flatpak_app_allowed (app_filter, "org.gnome.Whitelisted1")); g_assert_true (mct_app_filter_is_flatpak_app_allowed (app_filter, "org.gnome.Whitelisted2")); @@ -791,6 +848,7 @@ test_app_filter_bus_get_all_oars_values (BusFixture *fixture, /* Check the OARS filter properties. Each OARS value should have been parsed * correctly, except for the unknown `other` one. */ g_assert_cmpuint (mct_app_filter_get_user_id (app_filter), ==, fixture->valid_uid); + g_assert_true (mct_app_filter_is_enabled (app_filter)); g_assert_cmpint (mct_app_filter_get_oars_value (app_filter, "violence-bloodshed"), ==, MCT_APP_FILTER_OARS_VALUE_NONE); g_assert_cmpint (mct_app_filter_get_oars_value (app_filter, "violence-sexual"), ==, @@ -838,6 +896,7 @@ test_app_filter_bus_get_defaults (BusFixture *fixture, /* Check the default values for the properties. */ g_assert_cmpuint (mct_app_filter_get_user_id (app_filter), ==, fixture->valid_uid); + g_assert_false (mct_app_filter_is_enabled (app_filter)); oars_sections = mct_app_filter_get_oars_sections (app_filter); g_assert_cmpuint (g_strv_length ((gchar **) oars_sections), ==, 0); g_assert_cmpint (mct_app_filter_get_oars_value (app_filter, "violence-bloodshed"), ==, @@ -1462,6 +1521,8 @@ main (int argc, g_test_add_func ("/app-filter/deserialize", test_app_filter_deserialize); g_test_add_func ("/app-filter/deserialize/invalid", test_app_filter_deserialize_invalid); + g_test_add_func ("/app-filter/is-enabled", test_app_filter_is_enabled); + g_test_add ("/app-filter/builder/stack/non-empty", BuilderFixture, NULL, builder_set_up_stack, test_app_filter_builder_non_empty, builder_tear_down_stack); From 04705c079a0c7a4ef01b8385a7666a2012707411 Mon Sep 17 00:00:00 2001 From: Philip Withnall Date: Fri, 20 Mar 2020 15:06:34 +0000 Subject: [PATCH 4/4] session-limits: Add mct_session_limits_is_enabled() API MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is a high-level API to indicate whether parental controls are ‘enabled’ for the given user. It’s a mirror of `mct_app_filter_is_enabled()`, and exposes the existing `time_limit_enabled_out` argument of `mct_session_limits_check_time_remaining()` more conveniently. Includes tests. Signed-off-by: Philip Withnall --- libmalcontent/session-limits.c | 25 +++++++++++++++++++++++++ libmalcontent/session-limits.h | 3 +++ libmalcontent/tests/session-limits.c | 2 ++ 3 files changed, 30 insertions(+) diff --git a/libmalcontent/session-limits.c b/libmalcontent/session-limits.c index dbe07ce..f02c52f 100644 --- a/libmalcontent/session-limits.c +++ b/libmalcontent/session-limits.c @@ -98,6 +98,31 @@ mct_session_limits_get_user_id (MctSessionLimits *limits) return limits->user_id; } +/** + * mct_session_limits_is_enabled: + * @limits: an #MctSessionLimits + * + * Check whether any session limits are enabled and are going to impose at least + * one restriction on the user. This gives a high level view of whether session + * limit parental controls are ‘enabled’ for the given user. + * + * This function is equivalent to the value returned by the + * `time_limit_enabled_out` argument of + * mct_session_limits_check_time_remaining(). + * + * Returns: %TRUE if the session limits object contains at least one restrictive + * session limit, %FALSE if there are no limits in place + * Since: 0.7.0 + */ +gboolean +mct_session_limits_is_enabled (MctSessionLimits *limits) +{ + g_return_val_if_fail (limits != NULL, FALSE); + g_return_val_if_fail (limits->ref_count >= 1, FALSE); + + return (limits->limit_type != MCT_SESSION_LIMITS_TYPE_NONE); +} + /** * mct_session_limits_check_time_remaining: * @limits: an #MctSessionLimits diff --git a/libmalcontent/session-limits.h b/libmalcontent/session-limits.h index dd5e9e9..5b6e43a 100644 --- a/libmalcontent/session-limits.h +++ b/libmalcontent/session-limits.h @@ -52,6 +52,9 @@ void mct_session_limits_unref (MctSessionLimits *limits); G_DEFINE_AUTOPTR_CLEANUP_FUNC (MctSessionLimits, mct_session_limits_unref) uid_t mct_session_limits_get_user_id (MctSessionLimits *limits); + +gboolean mct_session_limits_is_enabled (MctSessionLimits *limits); + gboolean mct_session_limits_check_time_remaining (MctSessionLimits *limits, guint64 now_usecs, guint64 *time_remaining_secs_out, diff --git a/libmalcontent/tests/session-limits.c b/libmalcontent/tests/session-limits.c index 2a3e8bf..bc4b70a 100644 --- a/libmalcontent/tests/session-limits.c +++ b/libmalcontent/tests/session-limits.c @@ -518,6 +518,7 @@ test_session_limits_bus_get (BusFixture *fixture, /* Check the session limits properties. */ g_assert_cmpuint (mct_session_limits_get_user_id (session_limits), ==, fixture->valid_uid); + g_assert_true (mct_session_limits_is_enabled (session_limits)); g_assert_false (mct_session_limits_check_time_remaining (session_limits, usec (0), &time_remaining_secs, &time_limit_enabled)); g_assert_true (time_limit_enabled); @@ -580,6 +581,7 @@ test_session_limits_bus_get_none (BusFixture *fixture, /* Check the session limits properties. */ g_assert_cmpuint (mct_session_limits_get_user_id (session_limits), ==, fixture->valid_uid); + g_assert_false (mct_session_limits_is_enabled (session_limits)); g_assert_true (mct_session_limits_check_time_remaining (session_limits, usec (0), &time_remaining_secs, &time_limit_enabled)); g_assert_false (time_limit_enabled);