Commit d048aafb authored by Charlie Turner's avatar Charlie Turner

Allow per-site autoplay policies.

Denying autoplay can break websites that use it for stylistic
effects. On the other hand, it can be increadibly annoying to be
spammed with videos autoplaying.

By default, videos can autoplay so long as they have no audio (or the
audio is muted). Alternatively, users can allow all videos to autoplay
even with audio, or to deny all attempts to autoplay video. Users can
make these decisions using the security pop-over on a
per security-origin basis.
parent f87996ef
Pipeline #192287 failed with stages
in 15 minutes and 40 seconds
......@@ -429,5 +429,10 @@
<summary>Decision to apply when advertisement permission is requested for this host</summary>
<description>This option is used to save whether a given host has been given permission to allow advertisements. The “undecided” default means the browser global setting is used, while “allow” and “deny” tell it to automatically make the decision upon request.</description>
</key>
<key name="autoplay-permission" enum="org.gnome.Epiphany.Permission">
<default>'undecided'</default>
<summary>Decision to apply when an autoplay policy is requested for this host</summary>
<description>This option is used to save whether a given host has been given permission to autoplay. The “undecided” default means to allow autoplay of muted media, while “allow” and “deny” tell it to allow / deny all requests to autoplay media respectively.</description>
</key>
</schema>
</schemalist>
......@@ -812,10 +812,46 @@ process_terminated_cb (EphyWebView *web_view,
}
static gboolean
decide_policy_cb (WebKitWebView *web_view,
WebKitPolicyDecision *decision,
WebKitPolicyDecisionType decision_type,
gpointer user_data)
decide_navigation (WebKitWebView *web_view,
WebKitPolicyDecision *decision,
gpointer user_data)
{
EphyEmbedShell *shell = ephy_embed_shell_get_default ();
WebKitWebsitePolicies *website_policies = NULL;
g_autofree gchar *origin = NULL;
WebKitNavigationPolicyDecision *navigation_policy_decision = WEBKIT_NAVIGATION_POLICY_DECISION (decision);
WebKitNavigationAction *navigation_action = webkit_navigation_policy_decision_get_navigation_action (navigation_policy_decision);
WebKitURIRequest *request = webkit_navigation_action_get_request (navigation_action);
const gchar *navigation_uri = webkit_uri_request_get_uri (request);
EphyPermission permission = EPHY_PERMISSION_UNDECIDED;
origin = ephy_uri_to_security_origin (navigation_uri);
if (origin)
permission = ephy_permissions_manager_get_permission (ephy_embed_shell_get_permissions_manager (shell),
EPHY_PERMISSION_TYPE_AUTOPLAY_POLICY,
origin);
switch (permission) {
case EPHY_PERMISSION_UNDECIDED:
website_policies = webkit_website_policies_new_with_policies ("autoplay", WEBKIT_AUTOPLAY_ALLOW_WITHOUT_SOUND, NULL);
break;
case EPHY_PERMISSION_PERMIT:
website_policies = webkit_website_policies_new_with_policies ("autoplay", WEBKIT_AUTOPLAY_ALLOW, NULL);
break;
case EPHY_PERMISSION_DENY:
website_policies = webkit_website_policies_new_with_policies ("autoplay", WEBKIT_AUTOPLAY_DENY, NULL);
break;
}
webkit_policy_decision_use_with_policies (decision, website_policies);
g_object_unref (website_policies);
return TRUE;
}
static gboolean
decide_resource (WebKitWebView *web_view,
WebKitPolicyDecision *decision,
gpointer user_data)
{
WebKitResponsePolicyDecision *response_decision;
WebKitURIResponse *response;
......@@ -826,9 +862,6 @@ decide_policy_cb (WebKitWebView *web_view,
const char *request_uri;
gboolean is_main_resource;
if (decision_type != WEBKIT_POLICY_DECISION_TYPE_RESPONSE)
return FALSE;
/* If WebKit can handle the MIME type, let it.
* Otherwise, we'll start a download.
*/
......@@ -881,6 +914,25 @@ decide_policy_cb (WebKitWebView *web_view,
return TRUE;
}
static gboolean
decide_policy_cb (WebKitWebView *web_view,
WebKitPolicyDecision *decision,
WebKitPolicyDecisionType decision_type,
gpointer user_data)
{
switch (decision_type) {
case WEBKIT_POLICY_DECISION_TYPE_NAVIGATION_ACTION:
return decide_navigation (web_view, decision, user_data);
case WEBKIT_POLICY_DECISION_TYPE_RESPONSE:
return decide_resource (web_view, decision, user_data);
case WEBKIT_POLICY_DECISION_TYPE_NEW_WINDOW_ACTION:
/* not handled */
break;
}
return TRUE;
}
typedef struct {
EphyWebView *web_view;
WebKitPermissionRequest *request;
......
......@@ -167,6 +167,8 @@ permission_type_to_string (EphyPermissionType type)
return "video-device-permission";
case EPHY_PERMISSION_TYPE_SHOW_ADS:
return "advertisement-permission";
case EPHY_PERMISSION_TYPE_AUTOPLAY_POLICY:
return "autoplay-permission";
default:
g_assert_not_reached ();
}
......
......@@ -43,6 +43,7 @@ typedef enum {
EPHY_PERMISSION_TYPE_ACCESS_MICROPHONE,
EPHY_PERMISSION_TYPE_ACCESS_WEBCAM,
EPHY_PERMISSION_TYPE_SHOW_ADS,
EPHY_PERMISSION_TYPE_AUTOPLAY_POLICY,
} EphyPermissionType;
EphyPermissionsManager *ephy_permissions_manager_new (void);
......
......@@ -65,6 +65,7 @@ struct _EphySecurityPopover {
GtkWidget *access_location_combobox;
GtkWidget *access_microphone_combobox;
GtkWidget *access_webcam_combobox;
GtkWidget *autoplay_combobox;
GtkWidget *grid;
GTlsCertificate *certificate;
GTlsCertificateFlags tls_errors;
......@@ -155,6 +156,7 @@ ephy_security_popover_set_address (EphySecurityPopover *popover,
set_permission_combobox_state (permissions_manager, EPHY_PERMISSION_TYPE_ACCESS_LOCATION, origin, popover->access_location_combobox);
set_permission_combobox_state (permissions_manager, EPHY_PERMISSION_TYPE_ACCESS_MICROPHONE, origin, popover->access_microphone_combobox);
set_permission_combobox_state (permissions_manager, EPHY_PERMISSION_TYPE_ACCESS_WEBCAM, origin, popover->access_webcam_combobox);
set_permission_combobox_state (permissions_manager, EPHY_PERMISSION_TYPE_AUTOPLAY_POLICY, origin, popover->autoplay_combobox);
}
static void
......@@ -482,11 +484,20 @@ on_access_webcam_combobox_changed (GtkComboBox *box,
handle_permission_combobox_changed (popover, gtk_combo_box_get_active (box), EPHY_PERMISSION_TYPE_ACCESS_WEBCAM);
}
static void
on_autoplay_policy_combobox_changed (GtkComboBox *box,
EphySecurityPopover *popover)
{
handle_permission_combobox_changed (popover, gtk_combo_box_get_active (box), EPHY_PERMISSION_TYPE_AUTOPLAY_POLICY);
}
static GtkWidget *
add_permission_combobox (EphySecurityPopover *popover,
const gchar *name,
gpointer callback,
gboolean no_ask)
GtkSizeGroup *size_group,
gboolean no_ask,
const gchar *third_option_name)
{
GtkWidget *widget;
GtkWidget *hbox;
......@@ -503,11 +514,14 @@ add_permission_combobox (EphySecurityPopover *popover,
gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (widget), _("Allow"));
gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (widget), _("Deny"));
if (!no_ask)
gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (widget), _("Ask"));
if (!no_ask) {
const gchar *name = third_option_name == NULL ? _("Ask") : third_option_name;
gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (widget), _(name));
}
gtk_box_pack_start (GTK_BOX (hbox), widget, FALSE, FALSE, 6);
g_signal_connect (widget, "changed", G_CALLBACK (callback), popover);
gtk_size_group_add_widget (size_group, widget);
return widget;
}
......@@ -517,6 +531,7 @@ ephy_security_popover_init (EphySecurityPopover *popover)
{
GtkWidget *permissions;
GtkWidget *box;
g_autoptr (GtkSizeGroup) combo_box_size_group = NULL;
g_autofree char *label = g_strdup_printf ("<b>%s</b>", _("Permissions"));
popover->grid = gtk_grid_new ();
......@@ -553,12 +568,15 @@ ephy_security_popover_init (EphySecurityPopover *popover)
gtk_grid_attach (GTK_GRID (popover->grid), permissions, 0, 4, 2, 1);
popover->permission_pos = 5;
popover->ad_combobox = add_permission_combobox (popover, _("Advertisements"), on_ad_combobox_changed, TRUE);
popover->notification_combobox = add_permission_combobox (popover, _("Notifications"), on_notification_combobox_changed, FALSE);
popover->save_password_combobox = add_permission_combobox (popover, _("Password saving"), on_save_password_combobox_changed, FALSE);
popover->access_location_combobox = add_permission_combobox (popover, _("Location access"), on_access_location_combobox_changed, FALSE);
popover->access_microphone_combobox = add_permission_combobox (popover, _("Microphone access"), on_access_microphone_combobox_changed, FALSE);
popover->access_webcam_combobox = add_permission_combobox (popover, _("Webcam access"), on_access_webcam_combobox_changed, FALSE);
combo_box_size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
popover->ad_combobox = add_permission_combobox (popover, _("Advertisements"), on_ad_combobox_changed, combo_box_size_group, TRUE, NULL);
popover->notification_combobox = add_permission_combobox (popover, _("Notifications"), on_notification_combobox_changed, combo_box_size_group, FALSE, NULL);
popover->save_password_combobox = add_permission_combobox (popover, _("Password saving"), on_save_password_combobox_changed, combo_box_size_group, FALSE, NULL);
popover->access_location_combobox = add_permission_combobox (popover, _("Location access"), on_access_location_combobox_changed, combo_box_size_group, FALSE, NULL);
popover->access_microphone_combobox = add_permission_combobox (popover, _("Microphone access"), on_access_microphone_combobox_changed, combo_box_size_group, FALSE, NULL);
popover->access_webcam_combobox = add_permission_combobox (popover, _("Webcam access"), on_access_webcam_combobox_changed, combo_box_size_group, FALSE, NULL);
popover->autoplay_combobox = add_permission_combobox (popover, _("Media autoplay"), on_autoplay_policy_combobox_changed, combo_box_size_group, FALSE, "Without Sound");
gtk_container_add (GTK_CONTAINER (popover), popover->grid);
gtk_widget_show_all (popover->grid);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment