Merge branch 'parental-controls-enabled' into 'master'

app-filter: Add mct_app_filter_is_enabled() API

See merge request pwithnall/malcontent!47
This commit is contained in:
Philip Withnall 2020-03-24 11:08:33 +00:00
commit 435515d9da
7 changed files with 159 additions and 11 deletions

View File

@ -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) */

View File

@ -108,6 +108,69 @@ 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_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 its 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 its 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
@ -477,16 +540,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);
}
/**

View File

@ -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,

View File

@ -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

View File

@ -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,

View File

@ -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': <true> }", FALSE },
{ "{ 'AllowUserInstallation': <false> }", TRUE },
{ "{ 'AllowSystemInstallation': <true> }", FALSE },
{ "{ 'AllowSystemInstallation': <false> }", 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);

View File

@ -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);