/*
* Copyright © 2018 Endless Mobile, Inc.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see .
*
* Authors:
* Philip Withnall
*/
#include "config.h"
#include
#include
#include
#include "flatpak-parental-controls-private.h"
/*
* See https://www.freedesktop.org/software/appstream/docs/chap-Metadata.html#tag-content_rating
* for details of the appstream content rating specification.
*
* See https://hughsie.github.io/oars/ for details of OARS. Specifically,
* https://github.com/hughsie/oars/tree/master/specification/.
*/
/* Convert an appstream value to #MctAppFilterOarsValue.
* https://www.freedesktop.org/software/appstream/docs/chap-Metadata.html#tag-content_rating
*/
static MctAppFilterOarsValue
app_filter_oars_value_from_appdata (const gchar *appdata_value)
{
g_return_val_if_fail (appdata_value != NULL, MCT_APP_FILTER_OARS_VALUE_UNKNOWN);
if (g_str_equal (appdata_value, "intense"))
return MCT_APP_FILTER_OARS_VALUE_INTENSE;
else if (g_str_equal (appdata_value, "moderate"))
return MCT_APP_FILTER_OARS_VALUE_MODERATE;
else if (g_str_equal (appdata_value, "mild"))
return MCT_APP_FILTER_OARS_VALUE_MILD;
else if (g_str_equal (appdata_value, "none"))
return MCT_APP_FILTER_OARS_VALUE_NONE;
else if (g_str_equal (appdata_value, "unknown"))
return MCT_APP_FILTER_OARS_VALUE_UNKNOWN;
else
return MCT_APP_FILTER_OARS_VALUE_UNKNOWN;
}
static const gchar *
app_filter_oars_value_to_string (MctAppFilterOarsValue oars_value)
{
switch (oars_value)
{
case MCT_APP_FILTER_OARS_VALUE_UNKNOWN: return "unknown";
case MCT_APP_FILTER_OARS_VALUE_INTENSE: return "intense";
case MCT_APP_FILTER_OARS_VALUE_MODERATE: return "moderate";
case MCT_APP_FILTER_OARS_VALUE_MILD: return "mild";
case MCT_APP_FILTER_OARS_VALUE_NONE: return "none";
default: return "unknown";
}
}
/**
* flatpak_oars_check_rating:
* @content_rating: (nullable) (transfer none): OARS ratings for the app,
* or %NULL if none are known
* @content_rating_type: (nullable): scheme used in @content_rating, such as
* `oars-1.0` or `oars-1.1`, or %NULL if @content_rating is %NULL
* @filter: user’s parental controls settings
*
* Check whether the OARS rating in @content_rating is as, or less, extreme than
* the user’s preferences in @filter. If so (i.e. if the app is suitable for
* this user to use), return %TRUE; otherwise return %FALSE.
*
* @content_rating may be %NULL if no OARS ratings are provided for the app. If
* so, we have to assume the most restrictive ratings.
*
* Returns: %TRUE if the app is safe to install, %FALSE otherwise
*/
gboolean
flatpak_oars_check_rating (GHashTable *content_rating,
const gchar *content_rating_type,
MctAppFilter *filter)
{
const gchar * const supported_rating_types[] = { "oars-1.0", "oars-1.1", NULL };
g_autofree const gchar **oars_sections = mct_app_filter_get_oars_sections (filter);
MctAppFilterOarsValue default_rating_value;
if (content_rating_type != NULL &&
!g_strv_contains (supported_rating_types, content_rating_type))
return FALSE;
/* If the app has a element, even if it has no OARS sections
* in it, use a default value of `none` for any missing sections. Otherwise,
* if the app has no element, use `unknown`. */
if (content_rating != NULL)
default_rating_value = MCT_APP_FILTER_OARS_VALUE_NONE;
else
default_rating_value = MCT_APP_FILTER_OARS_VALUE_UNKNOWN;
for (gsize i = 0; oars_sections[i] != NULL; i++)
{
MctAppFilterOarsValue rating_value;
MctAppFilterOarsValue filter_value = mct_app_filter_get_oars_value (filter,
oars_sections[i]);
const gchar *appdata_value = NULL;
if (content_rating != NULL)
appdata_value = g_hash_table_lookup (content_rating, oars_sections[i]);
if (appdata_value != NULL)
rating_value = app_filter_oars_value_from_appdata (appdata_value);
else
rating_value = default_rating_value;
if (filter_value < rating_value ||
(rating_value == MCT_APP_FILTER_OARS_VALUE_UNKNOWN &&
filter_value != MCT_APP_FILTER_OARS_VALUE_UNKNOWN) ||
(rating_value != MCT_APP_FILTER_OARS_VALUE_UNKNOWN &&
filter_value == MCT_APP_FILTER_OARS_VALUE_UNKNOWN))
{
g_debug ("%s: Comparing rating ‘%s’: app has ‘%s’ but policy has ‘%s’ unknown: OARS check failed",
G_STRFUNC, oars_sections[i],
app_filter_oars_value_to_string (rating_value),
app_filter_oars_value_to_string (filter_value));
return FALSE;
}
}
return TRUE;
}