From 2c2c2ac95fa9863919e58a3dff87c08306d3eb7b Mon Sep 17 00:00:00 2001 From: portix Date: Thu, 19 Jul 2012 00:09:18 +0200 Subject: Adding extensions formfiller, perdomainsettings, requestpolicy and userscripts --- extensions/formfiller | 380 +++++++++++++++++++++++++++++++ extensions/perdomainsettings | 202 +++++++++++++++++ extensions/requestpolicy | 314 ++++++++++++++++++++++++++ extensions/userscripts | 521 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 1417 insertions(+) create mode 100644 extensions/formfiller create mode 100644 extensions/perdomainsettings create mode 100644 extensions/requestpolicy create mode 100644 extensions/userscripts (limited to 'extensions') diff --git a/extensions/formfiller b/extensions/formfiller new file mode 100644 index 00000000..ad331230 --- /dev/null +++ b/extensions/formfiller @@ -0,0 +1,380 @@ +// +// Copyright (c) 2012 Stefan Bolte +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 3 of the License, or +// (at your option) any later version. +// +// This program 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// + +/* + *Fill forms automatically + * + * Extension that saves form data and fills forms with previously saved data + * + * To use this extension save this script as $HOME/.local/share/dwb/extensions/formfiller + * and load it with a userscript in $HOME/.config/dwb/userscripts/, e.g. + * + * ------------------------------------------------------------------------------ + * |#!javascript | + * | | + * |extensions.load("formfiller"); | + * ------------------------------------------------------------------------------ + * + * + * Configuration options: + * + * formData : A path to a file where formdata will be saved, the default + * path is $XDG_CONFIG_HOME/dwb/forms + * + * scGetForm : Shortcut that gets and saves form data, the default value is + * 'efg' + * + * scFillForm : Shortcut that fills a form, the default value is 'eff' + * + * useGPG : Whether to use gpg2 to encrypt the formData file with a + * password. + * + * GPGOptEncrypt : Additional options that will be passed to gpg2 for + * encryption, the default gpg2 options are: + * --passphrase --batch --no-tty --yes -c --output + * default value: "" + * + * GPGOptDecrypt : Additional options that will be passed to gpg2 for + * decryption, the default gpg2 options are + * --passphrase --batch --no-tty --yes -d + * default value: "" + * + * keepPassword : Whether to save the gpg password in memory, if set to false the + * user will be prompted for the password every time a form + * is filled or new data is saved, default value: true + * + * keepFormdata : If useGPG is enabled and this value is set to true the + * complete formdata will be kept in memory, if set to false + * gpg2 will be called every time a form is filled, default + * value: false. + * + * + * Example (loading config with extensions.load()) + * + * ------------------------------------------------------------------------------ + * |extensions.load("formfiller", { | + * | formData : system.getEnv("HOME") + "/data/forms", | + * | scGetForm : "Control f", | + * | useGPG : true | + * |}); | + * ------------------------------------------------------------------------------ + * + * Example extensionrc: + * + * ------------------------------------------------------------------------------ + * |return { | + * | foo : { ... }, | + * | | + * | formfiller : { | + * | scGetForm : "efg", | + * | scFillForm : "eff", | + * | formData : "/path/to/data" | + * | }, | + * | bar : { ... } | + * |} | + * ------------------------------------------------------------------------------ + * + * */ + +var me = "formfiller"; +var defaultConfig = { + scGetForm : "efg", + scFillForm : "eff", + formData : data.configDir + "/forms", + useGPG : false, + GPGOptEncrypt : "", + GPGOptDecrypt : "", + keepPassword : true, + keepFormdata : false + +}; +var config = {}; +var passWord = null; +var formData = null; + +var injectGetForm = function () {//{{{ + var ret = null; + var forms = document.forms; + + function objectifyForm(f) { + var query = "descendant::input[not(@type='hidden') and (@type='text' or @type='password' or @type='checkbox' or not(@type) or @type='email')]"; + var input, data; + var r = document.evaluate(query, f, null, XPathResult.ORDERED_NODE_ITERATOR_TYPE, null); + var o = {}; + o.id = f.id || null; + o.form = {}; + var hasValue = false; + var hasIds = true; + + while ((input = r.iterateNext()) !== null) { + if (input.value && !(/^\s*$/.test(input.value))) { + if (/^\**$/.test(input.value) ) + return null; + if (!input.type || input.type.toLowerCase() === "text" || input.type.toLowerCase() === "password") + hasValue = true; + data = {}; + if (input.id) + data.id = input.id; + else + hasIds = false; + data.value = input.value; + o.form[input.name] = data; + } + } + if (hasValue) { + var ret = {}; + o.hasIds = hasIds; + ret[window.location.host] = o; + return ret; + } + return null; + } + + for (var i=0; i +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 3 of the License, or +// (at your option) any later version. +// +// This program 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// + + +/* + * Per domain settings extension + * + * This extensions can be used for per-domain-settings. Valid settings are + * the properties of WebKitWebSettings but in camelcase, see + * http://webkitgtk.org/reference/webkitgtk/unstable/WebKitWebSettings.html + * for details. + * + * To use this extension save this script as * $HOME/.local/share/dwb/extensions/perdomainsettings + * and load it with a userscript in $HOME/.config/dwb/userscripts/, e.g. + * + * ------------------------------------------------------------------------------ + * |#!javascript | + * | | + * |extensions.load("perdomainsettings"); | + * ------------------------------------------------------------------------------ + * + * The config can consist of four objects, + * + * domains: Settings applied based on the second level domain + * + * hosts: Settings applied based on the hostname + * + * uris: Settings applied based on the uri + * + * defaults: Default settings, for each setting in domains, hosts and uris a + * default-value should be specified + * + * Example extensionrc: + * + * ------------------------------------------------------------------------------ + * |return { | + * | foo : { ... }, | + * | | + * | perdomainsettings : { | + * | domains : { | + * | "example.com" : { | + * | "enablePlugins" : true | + * | }, | + * | "example.uk.com" : { | + * | "enablePlugins" : true, | + * | "enableScripts" : false | + * | } | + * | }, | + * | hosts : { | + * | "www.example1.com" : { | + * | "autoLoadImages" : true | + * | } | + * | }, | + * | uris : { | + * | "http://www.example2.com/login.php" : { | + * | "autoLoadImages" : false | + * | } | + * | }, | + * | defaults : { | + * | "enablePlugins" : false, | + * | "autoLoadImages" : false, | + * | "enableScripts" : true | + * | } | + * | }, | + * | | + * | bar : { ... } | + * |} | + * ------------------------------------------------------------------------------ + * + * Example using extensions.load: + * + * ------------------------------------------------------------------------------ + * |extensions.load("perdomainsettings", { | + * | domains : { "example.com" : { "enablePlugins" : true } }, | + * | defaults : { "enablePlugins" : false } | + * |}); | + * ------------------------------------------------------------------------------ + * + * */ + +var me = "perdomainsettings"; +var domains = null; +var hosts = null; +var uris = null; +var defaults = null; +var webviews = []; +var sigNavigation = -1; +var sigCloseTab = -1; + +function apply(o, settings) { + var key; + var defaults = true; + var websettings = o.settings; + for (key in settings) { + if (!o.set[key]) { + websettings[key] = settings[key]; + o.set[key] = true; + } + else { + defaults = false; + } + } + return defaults; +} + +function onNavigation(wv, frame, request, action) { + var length = webviews.length; + var i; + var found = false; + var o = null; + for (i=0; i= 0) { + signals.disconnect(sigNavigation); + sigNavigation = -1; + } + if (sigCloseTab >= 0) { + signals.disconnect(sigCloseTab); + sigCloseTab = -1; + } + } +}; + +// vim: set ft=javascript: diff --git a/extensions/requestpolicy b/extensions/requestpolicy new file mode 100644 index 00000000..1ed66ca2 --- /dev/null +++ b/extensions/requestpolicy @@ -0,0 +1,314 @@ +// +// Copyright (c) 2012 Stefan Bolte +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 3 of the License, or +// (at your option) any later version. +// +// This program 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// +/* + * Block requests from thirdparty domains + * + * Extension that blocks requests from thirdparty domains with whitelisting + * support, either permanently or just for the session. + * + * To use this extension save this script as $HOME/.local/share/dwb/extensions/requestpolicy + * and load it with a userscript in $HOME/.config/dwb/userscripts/, e.g. + * + * ------------------------------------------------------------------------------ + * |#!javascript | + * | | + * |extensions.load("requestpolicy"); | + * ------------------------------------------------------------------------------ + * + * + * Configuration options: + * + * shortcut : Shortcut to block / allow requests, default "erp" + * + * whitelist : A path to the whitelisting file, default is + * $XDG_CONFIG_HOME/dwb//requestpolicy.json + * + * autoreload : Whether to automatically reload the website after the + * whitelist has changed, default false + * + * notify : Whether to notify about blocked request, default true + * + * + * Example (loading config with extensions.load()) + * + * ------------------------------------------------------------------------------ + * |extensions.load("requestpolicy", { | + * | whitelist : system.getEnv("HOME") + "/.dwb_request_policy", | + * | autoreload : true | + * |}); | + * ------------------------------------------------------------------------------ + * + * Example extensionrc: + * + * ------------------------------------------------------------------------------ + * |return { | + * | foo : { ... }, | + * | | + * | requestpolicy : { | + * | autoreload : true | + * | shortcut : "rp", | + * | notify : false | + * | }, | + * | bar : { ... } | + * |} | + * ------------------------------------------------------------------------------ + * + * */ + +var me = "requestpolicy"; +var priv = "_requestPolicy" + parseInt(Math.random() * 9999999999, 10); + +var defaultConfig = { + whitelist : data.configDir + "/" + data.profile + "/requestpolicy.json", + shortcut : "erp", + autoreload : false, + notify : true +}; +var config = {}; + +var sigs = { + resource : -1, + navigation : -1, + loadFinished : -1 +}; + +var whiteList = null; +var tmpWhiteList = {}; + +var regex = { + empty : /^\s*$/ +}; + +function getPrivate(wv) { + var o = wv[priv]; + if (o === undefined) { + o = { domains : [], blocked : 0 }; + Object.defineProperty(wv, priv, { + value : o, + writable : true + }); + } + return o; +} + +// WHITELIST {{{ +function doWhiteList(o, key, value) { + if (!o[key]) + o[key] = []; + if (o[key].indexOf(value) == -1) + o[key].push(value); +} +function tmpWhiteListAction() { + doWhiteList(tmpWhiteList, tabs.current.mainFrame.domain, this.domain); +} +function whiteListAction() { + doWhiteList(whiteList, tabs.current.mainFrame.domain, this.domain); + io.write(config.whitelist, "w", JSON.stringify(whiteList)); +} + +function whiteListAllAction() { + doWhiteList(whiteList, "_all", tabs.current.mainFrame.domain); + io.write(config.whitelist, "w", JSON.stringify(whiteList)); +} +function tmpWhiteListAllAction() { + doWhiteList(tmpWhiteList, "_all", tabs.current.mainFrame.domain); +}//}}} + +// BLACKLIST {{{ +function doBlackList(o, firstParty, domain) { + var idx; + if (o[firstParty] && (idx = o[firstParty].indexOf(domain)) != -1) { + o[firstParty].splice(idx, 1); + if (o[firstParty].length === 0) + delete o[firstParty]; + return true; + } + return false; +} +function blackListAction() { + var firstParty = tabs.current.mainFrame.domain; + if (doBlackList(whiteList, firstParty, this.domain)) + io.write(config.whitelist, "w", JSON.stringify(whiteList)); + doBlackList(tmpWhiteList, firstParty, this.domain); + +} +function blackListAll() { + var i; + var blackListed = false; + var firstParty = tabs.current.mainFrame.domain; + var domains = getPrivate(tabs.current).domains; + for (i=0; i 0) + io.notify("RP: blocked " + blocked + " requests"); +} + +function connect() { + sigs.resource = signals.connect("resource", resourceCB); + sigs.navigation = signals.connect("navigation", navigationCB); + if (config.notify) + sigs.loadFinished = signals.connect("loadFinished", loadFinishedCB); +} +function disconnect() { + sigs.forEach(function (key, value) { + if (value != -1) { + signals.disconnect(value); + sigs[key] = -1; + } + }); +}//}}} +return { + init : function(c) { + if (c === null || c === undefined) + config = defaultConfig; + else { + defaultConfig.forEach(function (key, value, obj) { + config[key] = typeof c[key] == typeof defaultConfig[key] ? c[key] : defaultConfig[key]; + }); + } + if (system.fileTest(config.whitelist, FileTest.regular | FileTest.symlink)) { + var rawWhiteList = io.read(config.whitelist); + try { + whiteList = JSON.parse(rawWhiteList); + } + catch (e) { + extensions.debug(me, e, "Error parsing whitelist"); + } + } + whiteList = whiteList || {}; + connect(); + bind(config.shortcut, showMenu, "requestpolicy"); + return true; + }, + end : function () { + disconnect(); + unbind("requestpolicy"); + } +} +// vim: set ft=javascript: diff --git a/extensions/userscripts b/extensions/userscripts new file mode 100644 index 00000000..8038d353 --- /dev/null +++ b/extensions/userscripts @@ -0,0 +1,521 @@ +// +// Copyright (c) 2012 Stefan Bolte +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 3 of the License, or +// (at your option) any later version. +// +// This program 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// + + +/* + * TODO not finished yet + * + * userscripts extension, load userscripts and injects them into websites, this + * extension is mostly greasemonkey compatible. Scripts can be loaded by either + * specifying a path with using the configuration or putting them into + * $XDG_CONFIG_HOME/dwb/scripts/. + * + * + * To use this extension save this script as $HOME/.local/share/dwb/extensions/userscripts + * and load it with a userscript in $HOME/.config/dwb/userscripts/, e.g. + * + * ------------------------------------------------------------------------------ + * |#!javascript | + * | | + * |extensions.load("userscripts"); | + * ------------------------------------------------------------------------------ + * + * + * Config: An array of paths to userscripts + * + * Example (loading with extensions load): + * + * ------------------------------------------------------------------------------ + * |extensions.load("userscripts", [ "/path/to/script1", "/path/to/script2" ]); | | + * ------------------------------------------------------------------------------ + * + * Example (extensionsrc): + * + * ------------------------------------------------------------------------------ + * |return { | + * | ... : { ... }, // other config objects | + * | | + * | userscripts : [ "/path/to/script1", "/path/to/script2" ], | + * | | + * | ... : { ... } // other config objects | + * |} | + * ------------------------------------------------------------------------------ + * + * */ + +var me = "userscripts"; +var onStart = []; +var onEnd = []; +var sigDocument = -1; +var sigCommitted = -1; + +var metaData = {}; + +const DATA_DIR = data.userDataDir + "/extension_data/userscripts/resources"; +const META_DATA = DATA_DIR + "/.metadata"; + +UserScript.prototype = new Function(); +UserScript.prototype.constructor = UserScript; +function UserScript() +{ + this.description = null; + this.downloadURL = null; + this.exclude = []; + this.icon = null; + this.include = []; + this.match = []; + this.name = null; + this.namespace = null; + this.require = []; + this.resource = []; + this.runAt = "document-end"; + this.unwrap = false; + this.updateURL = null; + this.version = null; + this.script = null; + this.scriptId = null; + // scriptish + this.delay = 0; + this.noframes = false; + this.priority = 0; +} + +// Reused regular expressions +var regexes = { + isTld : /\.tld(?:\/|:|$)/, + isRegExp : /^\/.*\/$/ +}; + +var GM_compatability = function () { + var DWB_scriptPrefix = "dwb_userscript_"; + if (DWB_scriptId !== undefined) { + DWB_scriptPrefix = DWB_scriptPrefix + DWB_scriptId + "_"; + } + var GM_addStyle = function (styles) + { + var style = document.createElement("style"); + style.setAttribute("type", "text/css"); + style.appendChild(document.createTextNode(styles)); + document.getElementsByTagName("head")[0].appendChild(style); + }; + var GM_log = function (text) { + console.log(text); + }; + var GM_setValue = function (key, value) { + if (localStorage !== null && (typeof value === "string" || typeof value === "number" || typeof value == "boolean") ) + localStorage.setItem(DWB_scriptPrefix + key, value); + else + GM_log("GM_setValue only works with enabled localStorage and only for strings, numbers and booleans"); + }; + var GM_getValue = function (key, def) { + if (localStorage !== null) + return localStorage.getItem(DWB_scriptPrefix + key) || def; + else + GM_log("GM_getValue only works with enabled localStorage"); + return undefined; + }; + var GM_deleteValue = function (key) { + if (localStorage !== null) + localStorage.removeItem(DWB_scriptPrefix + key); + else + GM_log("GM_deleteValue only works with enabled localStorage"); + }; + var GM_listValues = function () { + var i; + var a = []; + for (i=0; i 0) { + timerStart(1000, function() { + frame.inject(item.script, item.unwrap); + return false; + }); + } + else { + frame.inject(item.script, item.unwrap); + } +} + +function handle(frame, array, isMainFrame) //{{{ +{ + var i, item; + for (i=0; i") { + return { allUrls : true }; + } + + var o = uriSplit(m); + if (o === null) { + extensions.warning(me, "Invalid or unsupported match rule: " + m); + return null; + } + if (!(/\*|http|https|file/.test(o.scheme))) { + extensions.warning(me, "Invalid scheme pattern: " + m); + return null; + } + else { + o.scheme = new RegExp(o.scheme.replace("*", ".*")); + } + if (! (/^(?:\*\.[^*\/]*|[^*]*|\*)$/.test(o.host))) { + extensions.warning(me, "Invalid host pattern: " + m); + return null; + } + else { + o.host = new RegExp(o.host.replace(/([.?+^$[\]\\(){}|-])/g, "\\$1").replace("*", ".*")); + } + if (! (/^\/.*/.test(o.path))) { + extensions.warning(me, "Invalid path pattern: " + m); + return null; + } + else if (o.path !== null) { + o.path = new RegExp(o.path.replace(/([.?+^$[\]\\(){}|-])/g, "\\$1").replace("*", ".*")); + } + return { host : o.host, scheme : o.scheme, path : o.path, allUrls : false }; +} + +function getRequirements(userscript) {//{{{ + var i; + for (i=0; i= 0 ? meta[i].substring(idx+1).trim() : null; + if (key == "description" || + key == "downloadURL" || + key == "icon" || + key == "name" || + key == "namespace" || + key == "updateURL" || + key == "version") + { + userscript[key] = value; + } + else if (typeof userscript[key] == "number") { + try { + numVal = parseInt(value, 10); + if (!isNaN(numVal)) + userscript[key] = numVal; + } + catch (e) { + extensions.debug(me, e); + } + } + else if (key == "unwrap") + userscript.unwrap = true; + else if (key == "noframes") + userscript.noframes = true; + else if (key == "run-at") + userscript.runAt = value; + else if (userscript[key] instanceof Array) { + userscript[key] = userscript[key].concat(value.match(/\S+/g)); + } + } + catch(e) { + extensions.debug(me, e); + } + + } + if (userscript.include.length === 0) + userscript.include.push({regExp : /.*/, isTld : false}); + else + parseIncludeExclude(userscript.include); + parseIncludeExclude(userscript.exclude); + // TODO resources + + var scriptId = new String(); + if (userscript.namespace === null || userscript.name === null) + userscript.scriptId = path; + else + userscript.scriptId = userscript.namespace + "::" + userscript.name; + userscript.scriptId = userscript.scriptId.replace(/\s+/g, "_"); + userscript.script = "var DWB_scriptId = '" + userscript.scriptId + "';" + + util.getBody(GM_compatability) + script.substring(0, metaStart) + + script.substring(scriptStart); + + getRequirements(userscript); + + for (i=0; i 0) { + onStart.sort(function(a, b) { return b.priority - a.priority; }); + sigCommitted = signals.connect("loadCommitted", loadCommittedCallback); + ret = true; + } + if (onEnd.length > 0) { + onEnd.sort(function(a, b) { return b.priority - a.priority; }); + sigDocument = signals.connect("documentLoaded", loadFinishedCallback); + ret = true; + } + //metaData = {}; + //onStart.concat(onEnd).forEach(function (v, k, obj) { + // var o = { + // require : obj[k].require, + // downloadURL : obj[k].downloadURL, + // updateURL : obj[k].updateURL, + // version : obj[k].version, + // resource : obj[k].resource + // }; + // metaData[obj[k].scriptId] = o; + //}); + //io.write(META_DATA, "w", JSON.stringify(metaData)); + return ret; +} +function parseScripts(scripts) //{{{ +{ + var i, path; + var scriptDir = data.configDir + "/scripts"; + for (i=0; i= 0) { + signals.disconnect(sigDocument); + sigDocument = -1; + } + if (sigCommitted >= 0) { + signals.disconnect(sigCommitted); + sigCommitted = -1; + } + + } +}; + +// vim: set ft=javascript: -- cgit v1.2.3