/* vi:set et sw=2 sts=2 cin cino=t0,f0,(0,{s,>2s,n-s,^-s,e-s: * 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_info ("%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; }