about summary refs log blame commit diff stats
path: root/whitelist.c
blob: 48c29094e99762ee534aeab7d3fa5331ce63ba89 (plain) (tree)
1
2
3
4
5
6
7
8






                                                                     
                                                   













                                                                           
                     

       
                                      








                                         
                        
                              



                                            
 
                                     
                                                                      
                                              
            

                              



                                                





                           

                                           
 
                                   
 
                                                      

                              




                                                

         
                      





                                                                
                                          
                                                               


                                        
                                   








                                        


                                       


                                   


                                   
                      


                                  





                                                          
                                        





                                                                           









                                                          


                                                            


                                                          
                          

         
                                                                              



                                                   
 















                                                            

                                         
                                                   
                                                 




                                 

                                        
                                                       
                                                
















                                                                                     

                                         
                                                   
                                                 


                                 
                         

                                               
                                                         
                                                       


                                          


                                           

                             







                            

                          



                   
   
                                                                          
 
                                   








                                                                      

                                             

                                         
                                                                          








                                                                   

                                             

                                         
                                                                          






                                                
                                                                 
                             
                                                                     
                              
                                                                     
                                    
                                                                  



                    
    
                                                      
 




                                                         





                                                         




                                   




































                                                                              
 


                                                      
 
               




                                              




                                                                     





                                          




                                                                      





                                          




                                                                      





                                            
                                   







                                            
                                        





                                                                           
                                
 
                      










                                                      
                 
                                               


                                             
                                                




                                                      














                                              
                                   
















                                                      
                                        







                                                                             
                                                                           

                                             
                





                                                       
                                                                           



                                                
                                                                                                      














                                                         
                                   
















                                                      
                                        






                                                                           



                                             





                                                       












                                                         




                                                    
                                   












                                                                           
                                       
 
                      










                                                      


                                                   



                                                     








                                              
/*
 * Copyright (c) 2010, 2011 Marco Peereboom <marco@peereboom.us>
 * Copyright (c) 2011 Stevan Andjelkovic <stevan@student.chalmers.se>
 * Copyright (c) 2010, 2011 Edd Barrett <vext01@gmail.com>
 * Copyright (c) 2011 Todd T. Fries <todd@fries.net>
 * Copyright (c) 2011 Raphael Graf <r@undefined.ch>
 * Copyright (c) 2011 Michal Mazurek <akfaew@jasminek.net>
 * Copyright (c) 2012 Josh Rickmar <jrick@devio.us>
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#include <xombrero.h>

gchar *
find_domain(const gchar *s, int flags)
{
	SoupURI			*uri;
	gchar			*ret, *p;

	if (s == NULL)
		return (NULL);

	uri = soup_uri_new(s);

	if (uri == NULL)
		return (NULL);
	if (!SOUP_URI_VALID_FOR_HTTP(uri)) {
		soup_uri_free(uri);
		return (NULL);
	}

	if (flags & XT_WL_TOPLEVEL &&
	    !isdigit((unsigned char)uri->host[strlen(uri->host) - 1]))
		p = tld_get_suffix(uri->host);
	else
		p = uri->host;

	if (flags & XT_WL_TOPLEVEL)
		ret = g_strdup_printf(".%s", p);
	else	/* assume FQDN */
		ret = g_strdup(p);

	soup_uri_free(uri);

	return (ret);
}

struct wl_entry *
wl_find(const gchar *s, struct wl_list *wl)
{
	struct wl_entry		*w;

	if (s == NULL || strlen(s) == 0 || wl == NULL)
		return (NULL);

	TAILQ_FOREACH(w, wl, entry) {
		if (w->re == NULL)
			continue;
		if (!regexec(w->re, s, 0, 0, 0))
			return (w);
	}

	return (NULL);
}

int
wl_save(struct tab *t, struct karg *args, int list)
{
	char			file[PATH_MAX], *lst_str = NULL;
	FILE			*f = NULL;
	char			*line = NULL, *lt = NULL, *dom;
	size_t			linelen;
	const gchar		*uri;
	struct karg		a;
	struct wl_entry		*w;
	GSList			*cf;
	SoupCookie		*ci, *c;

	if (t == NULL || args == NULL)
		return (1);

	if (runtime_settings[0] == '\0')
		return (1);

	switch (list) {
	case XT_WL_JAVASCRIPT:
		lst_str = "JavaScript";
		break;
	case XT_WL_COOKIE:
		lst_str = "Cookie";
		break;
	case XT_WL_PLUGIN:
		lst_str = "Plugin";
		break;
	case XT_WL_HTTPS:
		lst_str = "HTTPS";
		break;
	default:
		show_oops(t, "Invalid list id: %d", list);
		return (1);
	}

	uri = get_uri(t);
	dom = find_domain(uri, args->i);
	if (uri == NULL || dom == NULL ||
	    webkit_web_view_get_load_status(t->wv) == WEBKIT_LOAD_FAILED) {
		show_oops(t, "Can't add domain to %s white list", lst_str);
		goto done;
	}

	switch (list) {
	case XT_WL_JAVASCRIPT:
		lt = g_strdup_printf("js_wl=%s", dom);
		break;
	case XT_WL_COOKIE:
		lt = g_strdup_printf("cookie_wl=%s", dom);
		break;
	case XT_WL_PLUGIN:
		lt = g_strdup_printf("pl_wl=%s", dom);
		break;
	case XT_WL_HTTPS:
		lt = g_strdup_printf("force_https=%s", dom);
		break;
	default:
		/* can't happen */
		show_oops(t, "Invalid list id: %d", list);
		goto done;
	}

	snprintf(file, sizeof file, "%s" PS "%s", work_dir, runtime_settings);
	if ((f = fopen(file, "r+")) == NULL) {
		show_oops(t, "can't open file %s");
		goto done;
	}

	while (!feof(f)) {
		line = fparseln(f, &linelen, NULL, NULL, 0);
		if (line == NULL)
			continue;
		if (!strcmp(line, lt))
			goto done;
		free(line);
		line = NULL;
	}

	fprintf(f, "%s\n", lt);

	a.i = XT_WL_ENABLE;
	a.i |= args->i;
	switch (list) {
	case XT_WL_JAVASCRIPT:
		w = wl_find(dom, &js_wl);
		if (w == NULL) {
			settings_add("js_wl", dom);
			w = wl_find(dom, &js_wl);
		}
		toggle_js(t, &a);
		break;

	case XT_WL_COOKIE:
		w = wl_find(dom, &c_wl);
		if (w == NULL) {
			settings_add("cookie_wl", dom);
			w = wl_find(dom, &c_wl);
		}
		toggle_cwl(t, &a);

		/* find and add to persistent jar */
		cf = soup_cookie_jar_all_cookies(s_cookiejar);
		for (;cf; cf = cf->next) {
			ci = cf->data;
			if (!strcmp(dom, ci->domain) ||
			    !strcmp(&dom[1], ci->domain)) /* deal with leading . */ {
				c = soup_cookie_copy(ci);
				_soup_cookie_jar_add_cookie(p_cookiejar, c);
			}
		}
		soup_cookies_free(cf);
		break;

	case XT_WL_PLUGIN:
		w = wl_find(dom, &pl_wl);
		if (w == NULL) {
			settings_add("pl_wl", dom);
			w = wl_find(dom, &pl_wl);
		}
		toggle_pl(t, &a);
		break;
	case XT_WL_HTTPS:
		w = wl_find(dom, &force_https);
		if (w == NULL) {
			settings_add("force_https", dom);
			w = wl_find(dom, &force_https);
		}
		toggle_force_https(t, &a);
		break;
	default:
		abort(); /* can't happen */
	}
	if (w != NULL)
		w->handy = 1;

done:
	if (line)
		free(line);
	if (dom)
		g_free(dom);
	if (lt)
		g_free(lt);
	if (f)
		fclose(f);

	return (0);
}

int
wl_show(struct tab *t, struct karg *args, char *title, struct wl_list *wl)
{
	struct wl_entry		*w;
	char			*tmp, *body;

	body = g_strdup("");

	/* p list */
	if (args->i & XT_WL_PERSISTENT) {
		tmp = body;
		body = g_strdup_printf("%s<h2>Persistent</h2>", body);
		g_free(tmp);
		TAILQ_FOREACH(w, wl, entry) {
			if (w->handy == 0)
				continue;
			tmp = body;
			body = g_strdup_printf("%s%s<br/>", body, w->pat);
			g_free(tmp);
		}
	}

	/* s list */
	if (args->i & XT_WL_SESSION) {
		tmp = body;
		body = g_strdup_printf("%s<h2>Session</h2>", body);
		g_free(tmp);
		TAILQ_FOREACH(w, wl, entry) {
			if (w->handy == 1)
				continue;
			tmp = body;
			body = g_strdup_printf("%s%s<br/>", body, w->pat);
			g_free(tmp);
		}
	}

	tmp = get_html_page(title, body, "", 0);
	g_free(body);
	if (wl == &js_wl)
		load_webkit_string(t, tmp, XT_URI_ABOUT_JSWL, 0);
	else if (wl == &c_wl)
		load_webkit_string(t, tmp, XT_URI_ABOUT_COOKIEWL, 0);
	else if (wl == &pl_wl)
		load_webkit_string(t, tmp, XT_URI_ABOUT_PLUGINWL, 0);
	else if (wl == &force_https)
		load_webkit_string(t, tmp, XT_URI_ABOUT_HTTPS, 0);
	g_free(tmp);
	return (0);
}

void
wl_add(const char *str, struct wl_list *wl, int flags)
{
	struct wl_entry		*w;
	int			add_dot = 0, chopped = 0;
	const char		*s = str;
	char			*escstr, *p, *pat;
	char			**sv;

	if (str == NULL || wl == NULL || strlen(str) < 2)
		return;

	DNPRINTF(XT_D_COOKIE, "wl_add in: %s\n", str);

	/* slice off port number */
	p = g_strrstr(str, ":");
	if (p)
		*p = '\0';

	w = g_malloc(sizeof *w);
	w->re = g_malloc(sizeof *w->re);
	if (flags & XT_WL_REGEX) {
		w->pat = g_strdup_printf("re:%s", str);
		regcomp(w->re, str, REG_EXTENDED | REG_NOSUB);
		DNPRINTF(XT_D_COOKIE, "wl_add: %s\n", str);
	} else {
		/* treat *.moo.com the same as .moo.com */
		if (s[0] == '*' && s[1] == '.')
			s = &s[1];
		else if (s[0] != '.' && (flags & XT_WL_TOPLEVEL))
			add_dot = 1;

		if (s[0] == '.') {
			s = &s[1];
			chopped = 1;
		}
		sv = g_strsplit(s, ".", 0);
		escstr = g_strjoinv("\\.", sv);
		g_strfreev(sv);

		if (add_dot) {
			w->pat = g_strdup_printf(".%s", str);
			pat = g_strdup_printf("^(.*\\.)*%s$", escstr);
			regcomp(w->re, pat, REG_EXTENDED | REG_NOSUB);
		} else {
			w->pat = g_strdup(str);
			if (chopped)
				pat = g_strdup_printf("^(.*\\.)*%s$", escstr);
			else
				pat = g_strdup_printf("^%s$", escstr);
			regcomp(w->re, pat, REG_EXTENDED | REG_NOSUB);
		}
		DNPRINTF(XT_D_COOKIE, "wl_add: %s\n", pat);
		g_free(escstr);
		g_free(pat);
	}

	w->handy = (flags & XT_WL_PERSISTENT) ? 1 : 0;

	TAILQ_INSERT_HEAD(wl, w, entry);

	return;
}

int
add_cookie_wl(struct settings *s, char *entry)
{
	if (g_str_has_prefix(entry, "re:")) {
		entry = &entry[3];
		wl_add(entry, &c_wl, XT_WL_PERSISTENT | XT_WL_REGEX);
	} else
		wl_add(entry, &c_wl, XT_WL_PERSISTENT);
	return (0);
}

int
add_js_wl(struct settings *s, char *entry)
{
	if (g_str_has_prefix(entry, "re:")) {
		entry = &entry[3];
		wl_add(entry, &js_wl, XT_WL_PERSISTENT | XT_WL_REGEX);
	} else
		wl_add(entry, &js_wl, XT_WL_PERSISTENT);
	return (0);
}

int
add_pl_wl(struct settings *s, char *entry)
{
	if (g_str_has_prefix(entry, "re:")) {
		entry = &entry[3];
		wl_add(entry, &pl_wl, XT_WL_PERSISTENT | XT_WL_REGEX);
	} else
		wl_add(entry, &pl_wl, XT_WL_PERSISTENT);
	return (0);
}

int
toggle_cwl(struct tab *t, struct karg *args)
{
	struct wl_entry		*w;
	const gchar		*uri;
	char			*dom = NULL;
	int			es;

	if (args == NULL)
		return (1);

	uri = get_uri(t);
	dom = find_domain(uri, args->i);

	if (uri == NULL || dom == NULL ||
	    webkit_web_view_get_load_status(t->wv) == WEBKIT_LOAD_FAILED) {
		show_oops(t, "Can't toggle domain in cookie white list");
		goto done;
	}
	w = wl_find(dom, &c_wl);

	if (w == NULL)
		es = 0;
	else
		es = 1;

	if (args->i & XT_WL_TOGGLE)
		es = !es;
	else if ((args->i & XT_WL_ENABLE) && es != 1)
		es = 1;
	else if ((args->i & XT_WL_DISABLE) && es != 0)
		es = 0;

	if (es) {
		/* enable cookies for domain */
		args->i |= !XT_WL_PERSISTENT;
		wl_add(dom, &c_wl, args->i);
	} else {
		/* disable cookies for domain */
		if (w != NULL) {
			TAILQ_REMOVE(&c_wl, w, entry);
			g_free(w->re);
			g_free(w->pat);
		}
	}

	if (args->i & XT_WL_RELOAD)
		webkit_web_view_reload(t->wv);

done:
	g_free(dom);
	return (0);
}

int
toggle_js(struct tab *t, struct karg *args)
{
	int			es;
	const gchar		*uri;
	struct wl_entry		*w;
	char			*dom = NULL;

	if (args == NULL)
		return (1);

	g_object_get(G_OBJECT(t->settings),
	    "enable-scripts", &es, (char *)NULL);
	if (args->i & XT_WL_TOGGLE)
		es = !es;
	else if ((args->i & XT_WL_ENABLE) && es != 1)
		es = 1;
	else if ((args->i & XT_WL_DISABLE) && es != 0)
		es = 0;
	else
		return (1);

	uri = get_uri(t);
	dom = find_domain(uri, args->i);

	if (uri == NULL || dom == NULL ||
	    webkit_web_view_get_load_status(t->wv) == WEBKIT_LOAD_FAILED) {
		show_oops(t, "Can't toggle domain in JavaScript white list");
		goto done;
	}

	if (es) {
		button_set_icon_name(t->js_toggle, "media-playback-start");
		args->i |= !XT_WL_PERSISTENT;
		wl_add(dom, &js_wl, args->i);
	} else {
		w = wl_find(dom, &js_wl);
		if (w != NULL) {
			TAILQ_REMOVE(&js_wl, w, entry);
			g_free(w->re);
			g_free(w->pat);
		}
		button_set_icon_name(t->js_toggle, "media-playback-pause");
	}
	g_object_set(G_OBJECT(t->settings),
	    "enable-scripts", es, (char *)NULL);
	g_object_set(G_OBJECT(t->settings),
	    "javascript-can-open-windows-automatically", js_auto_open_windows ? es : 0, (char *)NULL);
	webkit_web_view_set_settings(t->wv, t->settings);

	if (args->i & XT_WL_RELOAD)
		webkit_web_view_reload(t->wv);
done:
	if (dom)
		g_free(dom);
	return (0);
}

int
toggle_pl(struct tab *t, struct karg *args)
{
	int			es;
	const gchar		*uri;
	struct wl_entry		*w;
	char			*dom = NULL;

	if (args == NULL)
		return (1);

	g_object_get(G_OBJECT(t->settings),
	    "enable-plugins", &es, (char *)NULL);
	if (args->i & XT_WL_TOGGLE)
		es = !es;
	else if ((args->i & XT_WL_ENABLE) && es != 1)
		es = 1;
	else if ((args->i & XT_WL_DISABLE) && es != 0)
		es = 0;
	else
		return (1);

	uri = get_uri(t);
	dom = find_domain(uri, args->i);

	if (uri == NULL || dom == NULL ||
	    webkit_web_view_get_load_status(t->wv) == WEBKIT_LOAD_FAILED) {
		show_oops(t, "Can't toggle domain in plugins white list");
		goto done;
	}

	if (es) {
		args->i |= !XT_WL_PERSISTENT;
		wl_add(dom, &pl_wl, args->i);
	} else {
		w = wl_find(dom, &pl_wl);
		if (w != NULL) {
			TAILQ_REMOVE(&pl_wl, w, entry);
			g_free(w->re);
			g_free(w->pat);
		}
	}
	g_object_set(G_OBJECT(t->settings),
	    "enable-plugins", es, (char *)NULL);
	webkit_web_view_set_settings(t->wv, t->settings);

	if (args->i & XT_WL_RELOAD)
		webkit_web_view_reload(t->wv);
done:
	if (dom)
		g_free(dom);
	return (0);
}

int
toggle_force_https(struct tab *t, struct karg *args)
{
	int			es;
	const gchar		*uri;
	struct wl_entry		*w;
	char			*dom = NULL;

	if (args == NULL)
		return (1);

	uri = get_uri(t);
	dom = find_domain(uri, args->i);

	if (uri == NULL || dom == NULL ||
	    webkit_web_view_get_load_status(t->wv) == WEBKIT_LOAD_FAILED) {
		show_oops(t, "Can't toggle domain in https force list");
		goto done;
	}
	w = wl_find(dom, &force_https);

	if (w == NULL)
		es = 0;
	else
		es = 1;

	if (args->i & XT_WL_TOGGLE)
		es = !es;
	else if ((args->i & XT_WL_ENABLE) && es != 1)
		es = 1;
	else if ((args->i & XT_WL_DISABLE) && es != 0)
		es = 0;

	if (es) {
		args->i |= !XT_WL_PERSISTENT;
		wl_add(dom, &force_https, args->i);
	} else if (w != NULL) {
		TAILQ_REMOVE(&force_https, w, entry);
		g_free(w->re);
		g_free(w->pat);
	}

	if (args->i & XT_WL_RELOAD)
		webkit_web_view_reload(t->wv);
done:
	if (dom)
		g_free(dom);
	return (0);
}