Exemple #1
0
static inline bool httpOnlyCookieExists(const GSList* cookies, const gchar* name, const gchar* path)
{
    for (const GSList* iter = cookies; iter; iter = g_slist_next(iter)) {
        SoupCookie* cookie = static_cast<SoupCookie*>(iter->data);
        if (!strcmp(soup_cookie_get_name(cookie), name)
            && !g_strcmp0(soup_cookie_get_path(cookie), path)) {
            if (soup_cookie_get_http_only(cookie))
                return true;
            break;
        }
    }
    return false;
}
Exemple #2
0
void setCookiesFromDOM(const NetworkStorageSession& session, const URL& firstParty, const URL& url, const String& value)
{
    SoupCookieJar* jar = cookieJarForSession(session);
    if (!jar)
        return;

    GUniquePtr<SoupURI> origin = url.createSoupURI();
    GUniquePtr<SoupURI> firstPartyURI = firstParty.createSoupURI();

    // Get existing cookies for this origin.
    GSList* existingCookies = soup_cookie_jar_get_cookie_list(jar, origin.get(), TRUE);

    Vector<String> cookies;
    value.split('\n', cookies);
    const size_t cookiesCount = cookies.size();
    for (size_t i = 0; i < cookiesCount; ++i) {
        GUniquePtr<SoupCookie> cookie(soup_cookie_parse(cookies[i].utf8().data(), origin.get()));
        if (!cookie)
            continue;

        // Make sure the cookie is not httpOnly since such cookies should not be set from JavaScript.
        if (soup_cookie_get_http_only(cookie.get()))
            continue;

        // Make sure we do not overwrite httpOnly cookies from JavaScript.
        if (httpOnlyCookieExists(existingCookies, soup_cookie_get_name(cookie.get()), soup_cookie_get_path(cookie.get())))
            continue;

        soup_cookie_jar_add_cookie_with_first_party(jar, firstPartyURI.get(), cookie.release());
    }

    soup_cookies_free(existingCookies);
}
static gint _cookie_permission_manager_ask_for_policy(CookiePermissionManager *self,
														MidoriView *inView,
														SoupMessage *inMessage,
														GSList *inUnknownCookies)
{
	/* Ask user for policy of unkndown domains in an undistracting way.
	 * The idea is to put the message not in a modal window but into midori's info bar.
	 * Then we'll set up our own GMainLoop to simulate a modal info bar. We need to
	 * connect to all possible signals of info bar, web view and so on to handle user's
	 * decision and to get out of our own GMainLoop. After that webkit resumes processing
	 * data.
	 */
	CookiePermissionManagerPrivate			*priv=self->priv;
	GtkWidget								*infobar;
/* FIXME: Find a way to add "details" widget */
#ifndef NO_INFOBAR_DETAILS
	GtkWidget								*widget;
	GtkWidget								*contentArea;
	GtkWidget								*vbox, *hbox;
	GtkWidget								*expander;
	GtkListStore							*listStore;
	GtkTreeIter								listIter;
	GtkWidget								*scrolled;
	GtkWidget								*list;
	GtkCellRenderer							*renderer;
	GtkTreeViewColumn						*column;
#endif
	gchar									*text;
	gint									numberDomains, numberCookies;
	GSList									*sortedCookies, *cookies;
	WebKitWebView							*webkitView;
	CookiePermissionManagerModalInfobar		*modalInfo;

	/* Get webkit view of midori view */
	webkitView=WEBKIT_WEB_VIEW(midori_view_get_web_view(inView));
	modalInfo=g_new0(CookiePermissionManagerModalInfobar, 1);

	/* Create a copy of cookies and sort them */
	sortedCookies=_cookie_permission_manager_get_number_domains_and_cookies(self,
																			inUnknownCookies,
																			&numberDomains,
																			&numberCookies);

/* FIXME: Find a way to add "details" widget */
#ifndef NO_INFOBAR_DETAILS
	/* Create list model and fill in data */
	listStore=gtk_list_store_new(N_COLUMN,
									G_TYPE_STRING,	/* DOMAIN_COLUMN */
									G_TYPE_STRING,	/* PATH_COLUMN */
									G_TYPE_STRING,	/* NAME_COLUMN */
									G_TYPE_STRING,	/* VALUE_COLUMN */
									G_TYPE_STRING	/* EXPIRE_DATE_COLUMN */);

	for(cookies=sortedCookies; cookies; cookies=cookies->next)
	{
		SoupCookie				*cookie=(SoupCookie*)cookies->data;
		SoupDate				*cookieDate=soup_cookie_get_expires(cookie);

		if(cookieDate) text=soup_date_to_string(cookieDate, SOUP_DATE_HTTP);
			else text=g_strdup(_("Till session end"));

		gtk_list_store_append(listStore, &listIter);
		gtk_list_store_set(listStore,
							&listIter,
							DOMAIN_COLUMN, soup_cookie_get_domain(cookie),
							PATH_COLUMN, soup_cookie_get_path(cookie),
							NAME_COLUMN, soup_cookie_get_name(cookie),
							VALUE_COLUMN, soup_cookie_get_value(cookie),
							EXPIRE_DATE_COLUMN, text,
							-1);

		g_free(text);
	}
#endif

	/* Create description text */
	if(numberDomains==1)
	{
		const gchar					*cookieDomain=soup_cookie_get_domain((SoupCookie*)sortedCookies->data);

		if(*cookieDomain=='.') cookieDomain++;
		
		if(numberCookies>1)
			text=g_strdup_printf(_("The website %s wants to store %d cookies."), cookieDomain, numberCookies);
		else
			text=g_strdup_printf(_("The website %s wants to store a cookie."), cookieDomain);
	}
		else
		{
			text=g_strdup_printf(_("Multiple websites want to store %d cookies in total."), numberCookies);
		}

	/* Create info bar message and buttons */
	infobar=midori_view_add_info_bar(inView,
										GTK_MESSAGE_QUESTION,
										text,
										G_CALLBACK(_cookie_permission_manager_on_infobar_policy_decision),
										NULL,
										_("_Accept"), COOKIE_PERMISSION_MANAGER_POLICY_ACCEPT,
										_("Accept for this _session"), COOKIE_PERMISSION_MANAGER_POLICY_ACCEPT_FOR_SESSION,
										_("De_ny"), COOKIE_PERMISSION_MANAGER_POLICY_BLOCK,
										_("Deny _this time"), COOKIE_PERMISSION_MANAGER_POLICY_UNDETERMINED,
										NULL);
	g_free(text);

	/* midori_view_add_info_bar() in version 0.4.8 expects a GObject as user data
	 * but I don't want to create an GObject just for a simple struct. So set object
	 * data by our own
	 */
	g_object_set_data_full(G_OBJECT(infobar), "cookie-permission-manager-infobar-data", modalInfo, (GDestroyNotify)g_free);

/* FIXME: Find a way to add "details" widget */
#ifndef NO_INFOBAR_DETAILS
	/* Get content area of infobar */
	contentArea=gtk_info_bar_get_content_area(GTK_INFO_BAR(infobar));

	/* Create list and set up columns of list */
	list=gtk_tree_view_new_with_model(GTK_TREE_MODEL(listStore));
#ifndef HAVE_GTK3
	gtk_widget_set_size_request(list, -1, 100);
#endif

	renderer=gtk_cell_renderer_text_new();
	column=gtk_tree_view_column_new_with_attributes(_("Domain"),
													renderer,
													"text", DOMAIN_COLUMN,
													NULL);
	gtk_tree_view_append_column(GTK_TREE_VIEW(list), column);

	renderer=gtk_cell_renderer_text_new();
	column=gtk_tree_view_column_new_with_attributes(_("Path"),
													renderer,
													"text", PATH_COLUMN,
													NULL);
	gtk_tree_view_append_column(GTK_TREE_VIEW(list), column);

	renderer=gtk_cell_renderer_text_new();
	column=gtk_tree_view_column_new_with_attributes(_("Name"),
													renderer,
													"text", NAME_COLUMN,
													NULL);
	gtk_tree_view_append_column(GTK_TREE_VIEW(list), column);

	renderer=gtk_cell_renderer_text_new();
	column=gtk_tree_view_column_new_with_attributes(_("Value"),
													renderer,
													"text", VALUE_COLUMN,
													NULL);
	g_object_set(G_OBJECT(renderer),
					"ellipsize", PANGO_ELLIPSIZE_END,
					"width-chars", 30,
					NULL);
	gtk_tree_view_append_column(GTK_TREE_VIEW(list), column);

	renderer=gtk_cell_renderer_text_new();
	column=gtk_tree_view_column_new_with_attributes(_("Expire date"),
													renderer,
													"text", EXPIRE_DATE_COLUMN,
													NULL);
	gtk_tree_view_append_column(GTK_TREE_VIEW(list), column);

	scrolled=gtk_scrolled_window_new(NULL, NULL);
#ifdef HAVE_GTK3
	gtk_scrolled_window_set_min_content_height(GTK_SCROLLED_WINDOW(scrolled), 100);
#endif
	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
	gtk_container_add(GTK_CONTAINER(scrolled), list);
	gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled), GTK_SHADOW_IN);
	gtk_container_add(GTK_CONTAINER(expander), scrolled);

	gtk_widget_show_all(vbox);
	gtk_container_add(GTK_CONTAINER(contentArea), vbox);

	/* Set state of expander based on config 'show-details-when-ask' */
	gtk_expander_set_expanded(GTK_EXPANDER(expander),
								midori_extension_get_boolean(priv->extension, "show-details-when-ask"));
	g_signal_connect_swapped(expander, "notify::expanded", G_CALLBACK(_cookie_permission_manager_when_ask_expander_changed), self);
#endif

	/* Show all widgets of info bar */
	gtk_widget_show_all(infobar);

	/* Connect signals to quit main loop */
	g_signal_connect(webkitView, "navigation-policy-decision-requested", G_CALLBACK(_cookie_permission_manager_on_infobar_webview_navigate), infobar);
	g_signal_connect(infobar, "destroy", G_CALLBACK(_cookie_permission_manager_on_infobar_destroy), modalInfo);

	/* Let info bar be modal and set response to default */
	modalInfo->response=COOKIE_PERMISSION_MANAGER_POLICY_UNDETERMINED;
	modalInfo->mainLoop=g_main_loop_new(NULL, FALSE);

	GDK_THREADS_LEAVE();
	g_main_loop_run(modalInfo->mainLoop);
	GDK_THREADS_ENTER();

	g_main_loop_unref(modalInfo->mainLoop);

	modalInfo->mainLoop=NULL;

	/* Disconnect signal handler to webkit's web view  */
	g_signal_handlers_disconnect_by_func(webkitView, G_CALLBACK(_cookie_permission_manager_on_infobar_webview_navigate), infobar);

	/* Store user's decision in database if it is not a temporary block.
	 * We use the already sorted list of cookies to prevent multiple
	 * updates of database for the same domain. This sorted list is a copy
	 * to avoid a reorder of cookies
	 */
	if(modalInfo->response!=COOKIE_PERMISSION_MANAGER_POLICY_UNDETERMINED)
	{
		const gchar					*lastDomain=NULL;

		/* Iterate through cookies and store decision for each domain once */
		for(cookies=sortedCookies; cookies; cookies=cookies->next)
		{
			SoupCookie				*cookie=(SoupCookie*)cookies->data;
			const gchar				*cookieDomain=soup_cookie_get_domain(cookie);

			if(*cookieDomain=='.') cookieDomain++;

			/* Store decision if new domain found while iterating through cookies */
			if(!lastDomain || g_ascii_strcasecmp(lastDomain, cookieDomain)!=0)
			{
				gchar	*sql;
				gchar	*error=NULL;
				gint	success;

				sql=sqlite3_mprintf("INSERT OR REPLACE INTO policies (domain, value) VALUES ('%q', %d);",
										cookieDomain,
										modalInfo->response);
				success=sqlite3_exec(priv->database, sql, NULL, NULL, &error);
				if(success!=SQLITE_OK) g_warning(_("SQL fails: %s"), error);
				if(error) sqlite3_free(error);
				sqlite3_free(sql);

				lastDomain=cookieDomain;
			}
		}
	}

	/* Free up allocated resources */
	g_slist_free(sortedCookies);

	/* Return response */
	return(modalInfo->response==COOKIE_PERMISSION_MANAGER_POLICY_UNDETERMINED ?
			COOKIE_PERMISSION_MANAGER_POLICY_BLOCK : modalInfo->response);
}