libmalcontent: Add support for filtering by content type
This is useful for example if blacklisting all apps that can handle certain content types is desired. Signed-off-by: Andre Moreira Magalhaes <andre@endlessm.com>
This commit is contained in:
parent
bbd1b2bdff
commit
da0e63fe99
|
@ -1,6 +1,6 @@
|
||||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
|
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
|
||||||
*
|
*
|
||||||
* Copyright © 2018 Endless Mobile, Inc.
|
* Copyright © 2018-2019 Endless Mobile, Inc.
|
||||||
*
|
*
|
||||||
* This library is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
@ -18,6 +18,7 @@
|
||||||
*
|
*
|
||||||
* Authors:
|
* Authors:
|
||||||
* - Philip Withnall <withnall@endlessm.com>
|
* - Philip Withnall <withnall@endlessm.com>
|
||||||
|
* - Andre Moreira Magalhaes <andre@endlessm.com>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
@ -142,6 +143,34 @@ mct_app_filter_is_path_allowed (MctAppFilter *filter,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Check whether a given @ref is a valid flatpak ref.
|
||||||
|
*
|
||||||
|
* For simplicity and to avoid duplicating the whole logic behind
|
||||||
|
* flatpak_ref_parse() this method will only check whether:
|
||||||
|
* - the @ref contains exactly 3 slash chars
|
||||||
|
* - the @ref starts with either app/ or runtime/
|
||||||
|
* - the name, arch and branch components of the @ref are not empty
|
||||||
|
*
|
||||||
|
* We avoid using flatpak_ref_parse() to allow for libflatpak
|
||||||
|
* to depend on malcontent without causing a cyclic dependency.
|
||||||
|
*/
|
||||||
|
static gboolean
|
||||||
|
is_valid_flatpak_ref (const gchar *ref)
|
||||||
|
{
|
||||||
|
g_auto(GStrv) parts = NULL;
|
||||||
|
|
||||||
|
if (ref == NULL)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
parts = g_strsplit (ref, "/", 0);
|
||||||
|
return (g_strv_length (parts) == 4 &&
|
||||||
|
(strcmp (parts[0], "app") == 0 ||
|
||||||
|
strcmp (parts[0], "runtime") == 0) &&
|
||||||
|
*parts[1] != '\0' &&
|
||||||
|
*parts[2] != '\0' &&
|
||||||
|
*parts[3] != '\0');
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* mct_app_filter_is_flatpak_ref_allowed:
|
* mct_app_filter_is_flatpak_ref_allowed:
|
||||||
* @filter: an #MctAppFilter
|
* @filter: an #MctAppFilter
|
||||||
|
@ -161,6 +190,7 @@ mct_app_filter_is_flatpak_ref_allowed (MctAppFilter *filter,
|
||||||
g_return_val_if_fail (filter != NULL, FALSE);
|
g_return_val_if_fail (filter != NULL, FALSE);
|
||||||
g_return_val_if_fail (filter->ref_count >= 1, FALSE);
|
g_return_val_if_fail (filter->ref_count >= 1, FALSE);
|
||||||
g_return_val_if_fail (app_ref != NULL, FALSE);
|
g_return_val_if_fail (app_ref != NULL, FALSE);
|
||||||
|
g_return_val_if_fail (is_valid_flatpak_ref (app_ref), FALSE);
|
||||||
|
|
||||||
gboolean ref_in_list = g_strv_contains ((const gchar * const *) filter->app_list,
|
gboolean ref_in_list = g_strv_contains ((const gchar * const *) filter->app_list,
|
||||||
app_ref);
|
app_ref);
|
||||||
|
@ -205,9 +235,8 @@ mct_app_filter_is_flatpak_app_allowed (MctAppFilter *filter,
|
||||||
gboolean id_in_list = FALSE;
|
gboolean id_in_list = FALSE;
|
||||||
for (gsize i = 0; filter->app_list[i] != NULL; i++)
|
for (gsize i = 0; filter->app_list[i] != NULL; i++)
|
||||||
{
|
{
|
||||||
/* Avoid using flatpak_ref_parse() to avoid a dependency on libflatpak
|
if (is_valid_flatpak_ref (filter->app_list[i]) &&
|
||||||
* just for that one function. */
|
g_str_has_prefix (filter->app_list[i], "app/") &&
|
||||||
if (g_str_has_prefix (filter->app_list[i], "app/") &&
|
|
||||||
strncmp (filter->app_list[i] + strlen ("app/"), app_id, app_id_len) == 0 &&
|
strncmp (filter->app_list[i] + strlen ("app/"), app_id, app_id_len) == 0 &&
|
||||||
filter->app_list[i][strlen ("app/") + app_id_len] == '/')
|
filter->app_list[i][strlen ("app/") + app_id_len] == '/')
|
||||||
{
|
{
|
||||||
|
@ -246,6 +275,7 @@ mct_app_filter_is_appinfo_allowed (MctAppFilter *filter,
|
||||||
GAppInfo *app_info)
|
GAppInfo *app_info)
|
||||||
{
|
{
|
||||||
g_autofree gchar *abs_path = NULL;
|
g_autofree gchar *abs_path = NULL;
|
||||||
|
const gchar * const *types = NULL;
|
||||||
|
|
||||||
g_return_val_if_fail (filter != NULL, FALSE);
|
g_return_val_if_fail (filter != NULL, FALSE);
|
||||||
g_return_val_if_fail (filter->ref_count >= 1, FALSE);
|
g_return_val_if_fail (filter->ref_count >= 1, FALSE);
|
||||||
|
@ -257,6 +287,13 @@ mct_app_filter_is_appinfo_allowed (MctAppFilter *filter,
|
||||||
!mct_app_filter_is_path_allowed (filter, abs_path))
|
!mct_app_filter_is_path_allowed (filter, abs_path))
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
|
types = g_app_info_get_supported_types (app_info);
|
||||||
|
for (gsize i = 0; types != NULL && types[i] != NULL; i++)
|
||||||
|
{
|
||||||
|
if (!mct_app_filter_is_content_type_allowed (filter, types[i]))
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
if (G_IS_DESKTOP_APP_INFO (app_info))
|
if (G_IS_DESKTOP_APP_INFO (app_info))
|
||||||
{
|
{
|
||||||
g_autofree gchar *flatpak_app = NULL;
|
g_autofree gchar *flatpak_app = NULL;
|
||||||
|
@ -296,6 +333,67 @@ mct_app_filter_is_appinfo_allowed (MctAppFilter *filter,
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Check whether a given @content_type is valid.
|
||||||
|
*
|
||||||
|
* For simplicity this method will only check whether:
|
||||||
|
* - the @content_type contains exactly 1 slash char
|
||||||
|
* - the @content_type does not start with a slash char
|
||||||
|
* - the type and subtype components of the @content_type are not empty
|
||||||
|
*/
|
||||||
|
static gboolean
|
||||||
|
is_valid_content_type (const gchar *content_type)
|
||||||
|
{
|
||||||
|
g_auto(GStrv) parts = NULL;
|
||||||
|
|
||||||
|
if (content_type == NULL)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
parts = g_strsplit (content_type, "/", 0);
|
||||||
|
return (g_strv_length (parts) == 2 &&
|
||||||
|
*parts[0] != '\0' &&
|
||||||
|
*parts[1] != '\0');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* mct_app_filter_is_content_type_allowed:
|
||||||
|
* @filter: an #MctAppFilter
|
||||||
|
* @content_type: content type to check
|
||||||
|
*
|
||||||
|
* Check whether apps handling the given @content_type are allowed to be run
|
||||||
|
* according to this app filter.
|
||||||
|
*
|
||||||
|
* Note that this method doesn’t match content subtypes. For example, if
|
||||||
|
* `application/xml` is added to the blacklist but `application/xspf+xml` is not,
|
||||||
|
* a check for whether `application/xspf+xml` is blacklisted would return false.
|
||||||
|
*
|
||||||
|
* Returns: %TRUE if the user this @filter corresponds to is allowed to run
|
||||||
|
* programs handling @content_type according to the @filter policy;
|
||||||
|
* %FALSE otherwise
|
||||||
|
* Since: 0.4.0
|
||||||
|
*/
|
||||||
|
gboolean
|
||||||
|
mct_app_filter_is_content_type_allowed (MctAppFilter *filter,
|
||||||
|
const gchar *content_type)
|
||||||
|
{
|
||||||
|
g_return_val_if_fail (filter != NULL, FALSE);
|
||||||
|
g_return_val_if_fail (filter->ref_count >= 1, FALSE);
|
||||||
|
g_return_val_if_fail (content_type != NULL, FALSE);
|
||||||
|
g_return_val_if_fail (is_valid_content_type (content_type), FALSE);
|
||||||
|
|
||||||
|
gboolean ref_in_list = g_strv_contains ((const gchar * const *) filter->app_list,
|
||||||
|
content_type);
|
||||||
|
|
||||||
|
switch (filter->app_list_type)
|
||||||
|
{
|
||||||
|
case MCT_APP_FILTER_LIST_BLACKLIST:
|
||||||
|
return !ref_in_list;
|
||||||
|
case MCT_APP_FILTER_LIST_WHITELIST:
|
||||||
|
return ref_in_list;
|
||||||
|
default:
|
||||||
|
g_assert_not_reached ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static gint
|
static gint
|
||||||
strcmp_cb (gconstpointer a,
|
strcmp_cb (gconstpointer a,
|
||||||
gconstpointer b)
|
gconstpointer b)
|
||||||
|
@ -700,12 +798,44 @@ mct_app_filter_builder_blacklist_flatpak_ref (MctAppFilterBuilder *builder,
|
||||||
g_return_if_fail (_builder != NULL);
|
g_return_if_fail (_builder != NULL);
|
||||||
g_return_if_fail (_builder->blacklist != NULL);
|
g_return_if_fail (_builder->blacklist != NULL);
|
||||||
g_return_if_fail (app_ref != NULL);
|
g_return_if_fail (app_ref != NULL);
|
||||||
|
g_return_if_fail (is_valid_flatpak_ref (app_ref));
|
||||||
|
|
||||||
if (!g_ptr_array_find_with_equal_func (_builder->blacklist,
|
if (!g_ptr_array_find_with_equal_func (_builder->blacklist,
|
||||||
app_ref, g_str_equal, NULL))
|
app_ref, g_str_equal, NULL))
|
||||||
g_ptr_array_add (_builder->blacklist, g_strdup (app_ref));
|
g_ptr_array_add (_builder->blacklist, g_strdup (app_ref));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* mct_app_filter_builder_blacklist_content_type:
|
||||||
|
* @builder: an initialised #MctAppFilterBuilder
|
||||||
|
* @content_type: a content type to blacklist
|
||||||
|
*
|
||||||
|
* Add @content_type to the blacklist of content types in the filter under
|
||||||
|
* construction. The @content_type will not be added again if it’s already been
|
||||||
|
* added.
|
||||||
|
*
|
||||||
|
* Note that this method doesn’t handle content subtypes. For example, if
|
||||||
|
* `application/xml` is added to the blacklist but `application/xspf+xml` is not,
|
||||||
|
* a check for whether `application/xspf+xml` is blacklisted would return false.
|
||||||
|
*
|
||||||
|
* Since: 0.4.0
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
mct_app_filter_builder_blacklist_content_type (MctAppFilterBuilder *builder,
|
||||||
|
const gchar *content_type)
|
||||||
|
{
|
||||||
|
MctAppFilterBuilderReal *_builder = (MctAppFilterBuilderReal *) builder;
|
||||||
|
|
||||||
|
g_return_if_fail (_builder != NULL);
|
||||||
|
g_return_if_fail (_builder->blacklist != NULL);
|
||||||
|
g_return_if_fail (content_type != NULL);
|
||||||
|
g_return_if_fail (is_valid_content_type (content_type));
|
||||||
|
|
||||||
|
if (!g_ptr_array_find_with_equal_func (_builder->blacklist,
|
||||||
|
content_type, g_str_equal, NULL))
|
||||||
|
g_ptr_array_add (_builder->blacklist, g_strdup (content_type));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* mct_app_filter_builder_set_oars_value:
|
* mct_app_filter_builder_set_oars_value:
|
||||||
* @builder: an initialised #MctAppFilterBuilder
|
* @builder: an initialised #MctAppFilterBuilder
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
|
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
|
||||||
*
|
*
|
||||||
* Copyright © 2018 Endless Mobile, Inc.
|
* Copyright © 2018-2019 Endless Mobile, Inc.
|
||||||
*
|
*
|
||||||
* This library is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
@ -18,6 +18,7 @@
|
||||||
*
|
*
|
||||||
* Authors:
|
* Authors:
|
||||||
* - Philip Withnall <withnall@endlessm.com>
|
* - Philip Withnall <withnall@endlessm.com>
|
||||||
|
* - Andre Moreira Magalhaes <andre@endlessm.com>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
@ -109,6 +110,8 @@ gboolean mct_app_filter_is_flatpak_app_allowed (MctAppFilter *filter,
|
||||||
const gchar *app_id);
|
const gchar *app_id);
|
||||||
gboolean mct_app_filter_is_appinfo_allowed (MctAppFilter *filter,
|
gboolean mct_app_filter_is_appinfo_allowed (MctAppFilter *filter,
|
||||||
GAppInfo *app_info);
|
GAppInfo *app_info);
|
||||||
|
gboolean mct_app_filter_is_content_type_allowed (MctAppFilter *filter,
|
||||||
|
const gchar *content_type);
|
||||||
|
|
||||||
const gchar **mct_app_filter_get_oars_sections (MctAppFilter *filter);
|
const gchar **mct_app_filter_get_oars_sections (MctAppFilter *filter);
|
||||||
MctAppFilterOarsValue mct_app_filter_get_oars_value (MctAppFilter *filter,
|
MctAppFilterOarsValue mct_app_filter_get_oars_value (MctAppFilter *filter,
|
||||||
|
@ -182,6 +185,9 @@ void mct_app_filter_builder_blacklist_path (MctAppFilterBuilder *builde
|
||||||
const gchar *path);
|
const gchar *path);
|
||||||
void mct_app_filter_builder_blacklist_flatpak_ref (MctAppFilterBuilder *builder,
|
void mct_app_filter_builder_blacklist_flatpak_ref (MctAppFilterBuilder *builder,
|
||||||
const gchar *app_ref);
|
const gchar *app_ref);
|
||||||
|
void mct_app_filter_builder_blacklist_content_type (MctAppFilterBuilder *builder,
|
||||||
|
const gchar *content_type);
|
||||||
|
|
||||||
void mct_app_filter_builder_set_oars_value (MctAppFilterBuilder *builder,
|
void mct_app_filter_builder_set_oars_value (MctAppFilterBuilder *builder,
|
||||||
const gchar *oars_section,
|
const gchar *oars_section,
|
||||||
MctAppFilterOarsValue value);
|
MctAppFilterOarsValue value);
|
||||||
|
|
Loading…
Reference in New Issue