diff options
author | Giuseppe Borzi | 2015-06-11 23:53:34 +0200 |
---|---|---|
committer | Giuseppe Borzi | 2015-06-11 23:53:34 +0200 |
commit | e548ea4d69182d648bd46346afb8daf8482bf009 (patch) | |
tree | e1263ac7fd429ed46fcb87011e794671831ae96a | |
download | aur-e548ea4d69182d648bd46346afb8daf8482bf009.tar.gz |
midori-passwordmanager 0.3-13
-rw-r--r-- | .SRCINFO | 32 | ||||
-rw-r--r-- | PKGBUILD | 44 | ||||
-rw-r--r-- | README | 34 | ||||
-rw-r--r-- | cmakelist.diff | 10 | ||||
-rw-r--r-- | lpins.c | 54 | ||||
-rw-r--r-- | passwordmanager.c | 361 | ||||
-rw-r--r-- | passwordmanager.js | 118 |
7 files changed, 653 insertions, 0 deletions
diff --git a/.SRCINFO b/.SRCINFO new file mode 100644 index 000000000000..5b0b13d53a9e --- /dev/null +++ b/.SRCINFO @@ -0,0 +1,32 @@ +pkgbase = midori-passwordmanager + pkgdesc = A password manager for Midori + pkgver = 0.3 + pkgrel = 13 + url = http://www.midori-browser.org + arch = i686 + arch = x86_64 + license = GPL2 + makedepends = python2 + makedepends = intltool + makedepends = vala + makedepends = librsvg + makedepends = cmake + depends = midori + depends = gnome-keyring + depends = libgnome-keyring + optdepends = seahorse: to edit/delete passwords + source = http://www.midori-browser.org/downloads/midori_0.5.10_all_.tar.bz2 + source = passwordmanager.c + source = passwordmanager.js + source = cmakelist.diff + source = README + source = lpins.c + md5sums = 2f250a5015923b6eeca606629e7bf042 + md5sums = 94c6ec8ddd50ca4d226d8413ef85c0f2 + md5sums = f9a91b8d929d4cb6407a769603fca619 + md5sums = 51c3e704947b0626716ab83e199d06c4 + md5sums = defadec00ebd02506fb1106f7fe5f2ae + md5sums = d11b1f035e4a044e2727ef226db9482b + +pkgname = midori-passwordmanager + diff --git a/PKGBUILD b/PKGBUILD new file mode 100644 index 000000000000..47e2f8622179 --- /dev/null +++ b/PKGBUILD @@ -0,0 +1,44 @@ +# Maintainer: Giuseppe Borzi <gborzi@ieee.org> + +pkgname=midori-passwordmanager +_pkgname=midori +pkgver=0.3 +_pkgver=0.5.10 +pkgrel=13 +pkgdesc="A password manager for Midori" +arch=('i686' 'x86_64') +url="http://www.midori-browser.org" +license=('GPL2') +depends=('midori' 'gnome-keyring' 'libgnome-keyring') +makedepends=('python2' 'intltool' 'vala' 'librsvg' 'cmake') +optdepends=('seahorse: to edit/delete passwords') +source=("$url/downloads/${_pkgname}_${_pkgver}_all_.tar.bz2" passwordmanager.c passwordmanager.js cmakelist.diff README lpins.c) +md5sums=('2f250a5015923b6eeca606629e7bf042' + '94c6ec8ddd50ca4d226d8413ef85c0f2' + 'f9a91b8d929d4cb6407a769603fca619' + '51c3e704947b0626716ab83e199d06c4' + 'defadec00ebd02506fb1106f7fe5f2ae' + 'd11b1f035e4a044e2727ef226db9482b') +build() { + cd "${srcdir}" + + patch -Np0 -i "${srcdir}/cmakelist.diff" + cp "$srcdir/passwordmanager.c" extensions + + mkdir -p build + cd build + cmake .. -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_INSTALL_LIBDIR=lib + + make + cc `pkg-config --cflags --libs gnome-keyring-1` "$srcdir/lpins.c" -o lpins +} + +package() { + cd "${srcdir}/build" + install -Dm644 extensions/libpasswordmanager.so \ + "${pkgdir}/usr/lib/midori/libpasswordmanager.so" + install -Dm644 "${srcdir}/passwordmanager.js" \ + "${pkgdir}/usr/share/midori/res/passwordmanager.js" + install -Dm755 lpins "${pkgdir}/usr/bin/lpins" + install -Dm644 "${srcdir}/README" "${pkgdir}/usr/share/doc/$pkgname/README" +} diff --git a/README b/README new file mode 100644 index 000000000000..3a5757efde18 --- /dev/null +++ b/README @@ -0,0 +1,34 @@ + + +The password manager extension for Midori is based on formhistory.c and on my +userscript for password management (http://userscripts.org/scripts/show/62098). +It works by reading the network passwords with domain "midori" from the login +keyring and storing them in a GHashTable. Whenever your browser loads a page +with a corresponding address in the GHashTable, a script that inserts user +and password is built and executed on that page. Whenever you submit a login +form, a similar script is built and executed, and returns the new data, which +is stored in the GHashTable and in the login keyring. +When you choose to never store a password for a site, the extension will store +a user/password pair equal to __never_store_here__/whatever. The user part of +the pair (i.e. __never_store_here__) is used to remember that passwords must +not be stored. +Sometimes the extension fails to detect that a form has been submitted, so it +won't store your user/password pair. In such cases use the lpins utility to +manually insert the pair into the login keyring, like this + +$ lpins http://www.averystrangelogin.com user password + +Note that the pair is inserted in the login keyring, not in the GHashTable, so +you need to deactivate/reactivate the extension so it'll read the new pair. + +Missing features: +* I don't know how to check when the login is successful, so wrong user- + password pairs will be stored. +* There isn't a utility for listing/deleting/modifying passwords, use seahorse + for these tasks (Midori passwords have domain "midori"). +* I don't know how to deal with password forms that uses md5hash for basic + protection (like ubuntu forums), so the extension won't work for these sites. + +Please note that I'm not an expert in internet security, crypting algorithms, +javascript programming or webkit programming, so use this extension at your +own risk. diff --git a/cmakelist.diff b/cmakelist.diff new file mode 100644 index 000000000000..fc492dfb9c0c --- /dev/null +++ b/cmakelist.diff @@ -0,0 +1,10 @@ +--- CMakeLists.txt.orig 2014-04-08 03:24:14.093572141 +0200 ++++ CMakeLists.txt 2014-04-08 03:24:26.476905529 +0200 +@@ -119,6 +119,7 @@ + gmodule-2.0 + gio-2.0>=2.32.3 + libsoup-gnome-2.4>=2.27.90 ++ gnome-keyring-1 + ) + add_definitions("-DHAVE_LIBXML") + add_definitions("-DGIO_VERSION=\"${DEPS_gio-2.0_VERSION}\"") diff --git a/lpins.c b/lpins.c new file mode 100644 index 000000000000..1ffd998c386e --- /dev/null +++ b/lpins.c @@ -0,0 +1,54 @@ +/* + Copyright (C) 2011 Giuseppe Borzi <gborzi@ieee.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. +*/ + + +#include <gnome-keyring.h> + +gchar* cleanurl( const gchar *url ) +{ + gchar *cleaned, *id; + gssize il = -1; + gsize lprt; + if ( ( id = g_strstr_len(url + 8,il,"/") ) != NULL ) + { + lprt = id - url; + cleaned = g_strndup(url,lprt); + } + else + cleaned = g_strdup(url); + return cleaned; +} + +int main( int argc, char **argv ) { + + if ( argc < 4 ) { + g_print("Usage: %s url user password\n",argv[0]); + return 1; + } + + if ( gnome_keyring_is_available() ) { + guint32 item_id; gchar *cleaned = cleanurl(argv[1]); + gnome_keyring_set_network_password_sync(NULL, + argv[2], + "midori", + cleaned, + NULL, + NULL, + NULL, + 0, + argv[3], + &item_id); + g_free(cleaned); + g_print("Created Gnome Keyring entry # %d\n",item_id); + } else { + g_print("Gnome Keyring not available!\n"); + return 1; + } + return 0; +} diff --git a/passwordmanager.c b/passwordmanager.c new file mode 100644 index 000000000000..9a8129b0a04d --- /dev/null +++ b/passwordmanager.c @@ -0,0 +1,361 @@ +/* + Copyright (C) 2011 Giuseppe Borzi <gborzi@ieee.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + Derived from formhistory.c extension, copyrighted by + Alexander Butenko <a.butenka@gmail.com> + Christian Dywan <christian@twotoasts.de> +*/ + +#include <midori/midori.h> + +#include "config.h" +#include "midori/sokoke.h" + +#include <gnome-keyring.h> +#include <glib/gstdio.h> +#include <stdlib.h> + +#ifdef G_OS_WIN32 + #define LIBPREFIX "" +#else + #define LIBPREFIX "lib" +#endif + +static GHashTable* log_pass; +static gchar* jspassm; + +static gboolean +passwman_prepare_js () +{ + gchar* passwordmanager; + + if (!g_file_get_contents ("/usr/share/midori/res/passwordmanager.js", \ + &passwordmanager, NULL, NULL)) + { + return FALSE; + } + g_strchomp (passwordmanager); + + jspassm = g_strdup_printf ( "%s", passwordmanager ); + g_strstrip (jspassm); + g_free (passwordmanager); + + return TRUE; +/* gchar* data_name; + gchar* data_path; + gchar* passwordmanager; + gchar* file; + + data_name = g_build_filename (PACKAGE_NAME, "res", NULL); + data_path = sokoke_find_data_filename (data_name,TRUE); + g_free (data_name); + file = g_build_filename(data_path,G_DIR_SEPARATOR_S,\ + "passwordmanager.js",NULL); + if (!g_file_get_contents (file, &passwordmanager, NULL, NULL)) + return FALSE; + g_strchomp (passwordmanager); + + jspassm = g_strdup_printf ( "%s", passwordmanager ); + g_strstrip (jspassm); + g_free (data_path); + g_free (file); + g_free (passwordmanager); + return TRUE;*/ +} + +static gchar* +cleanurl( const gchar *url ) +{ + gchar *cleaned, *id; + gssize il = -1; + gsize lprt; + if ( ( id = g_strstr_len(url+8,il,"/") ) != NULL ) + { + lprt = id - url; + cleaned = g_strndup(url,lprt); + } + else + cleaned = g_strdup(url); + return cleaned; +} + +static gchar* +passwman_build_js( const gchar *url ) +{ + gchar* script, *array; + + if ( log_pass && ( array = g_hash_table_lookup(log_pass,url) ) ) + script = g_strdup_printf("function getValue() { " + "var values = new Array(%s);" + "return values;" + "};" + "%s" + "window.addEventListener('load'," + "function() {PassMan.fillogpass(document);} , true);", + array, + jspassm); + else + script = NULL; + return script; +} + +static gboolean +passwman_navigation_decision_cb (WebKitWebView* web_view, + WebKitWebFrame* web_frame, + WebKitNetworkRequest* request, + WebKitWebNavigationAction* action, + WebKitWebPolicyDecision* decision, + MidoriExtension* extension) +{ + gchar* url; + url = cleanurl( webkit_web_view_get_uri(web_view) ); + if ( log_pass ) + { + gchar *array, *script; + array = g_hash_table_lookup(log_pass,url); + if ( array == NULL ) + script = g_strdup_printf ("function getValue() { " + "var values = new Array();" + "return values;" + "};" + "%s" + "PassMan.dologpass(document);" + "Store.dump();", + jspassm); + else + script = g_strdup_printf ("function getValue() { " + "var values = new Array(%s);" + "return values;" + "};" + "%s" + "PassMan.dologpass(document);" + "Store.dump();", + array, + jspassm); + if (webkit_web_navigation_action_get_reason (action) == \ + WEBKIT_WEB_NAVIGATION_REASON_FORM_SUBMITTED) + { + JSContextRef js_context = webkit_web_frame_get_global_context (web_frame); + gchar* value = sokoke_js_script_eval (js_context, script, NULL); + if (value && *value) + { + guint32 item_id; + g_hash_table_insert(log_pass,g_strdup(url),g_strdup(value)); + if ( g_strcmp0(value,"\"0\"") == 0 ) + gnome_keyring_set_network_password_sync(NULL, + "__never_store_here__", + "midori", + url, + NULL, + NULL, + NULL, + 0, + "whatever", + &item_id); + else + { + gchar *id; + gchar **up; + gsize lprt; + id = g_strrstr(value,"\",\""); lprt = id-value; + id = g_strrstr_len(value,lprt,"\",\""); id += 3; + up = g_strsplit(id,"\"",4); + gnome_keyring_set_network_password_sync(NULL, + up[0], + "midori", + url, + NULL, + NULL, + NULL, + 0, + up[2], + &item_id); + g_strfreev(up); + } + + + } + } + g_free(script); + } + g_free(url); + return FALSE; +} + +static void +passwman_window_object_cleared_cb (WebKitWebView* web_view, + WebKitWebFrame* web_frame, + JSContextRef js_context, + JSObjectRef js_window) +{ + gchar* url; gchar* script; + url = cleanurl( webkit_web_view_get_uri(web_view) ); + script = passwman_build_js (url); + if ( script ) { + sokoke_js_script_eval (js_context, script, NULL); + g_free (script); + } + g_free(url); +} + +static void +passwman_add_tab_cb (MidoriBrowser* browser, + MidoriView* view, + MidoriExtension* extension) +{ + GtkWidget* web_view = midori_view_get_web_view (view); + g_signal_connect (web_view, "window-object-cleared", + G_CALLBACK (passwman_window_object_cleared_cb), NULL); + g_signal_connect (web_view, "navigation-policy-decision-requested", + G_CALLBACK (passwman_navigation_decision_cb), extension); +} + +static void +passwman_deactivate_cb (MidoriExtension* extension, + MidoriBrowser* browser); + +static void +passwman_app_add_browser_cb (MidoriApp* app, + MidoriBrowser* browser, + MidoriExtension* extension) +{ + GList* tabs = midori_browser_get_tabs (browser); + for (; tabs; tabs = g_list_next (tabs)) + passwman_add_tab_cb (browser, tabs->data, extension); + g_list_free (tabs); + g_signal_connect (browser, "add-tab", + G_CALLBACK (passwman_add_tab_cb), extension); + g_signal_connect (extension, "deactivate", + G_CALLBACK (passwman_deactivate_cb), browser); +} + +static void +passwman_deactivate_tab (MidoriView* view, + MidoriExtension* extension) +{ + GtkWidget* web_view = midori_view_get_web_view (view); + g_signal_handlers_disconnect_by_func ( + web_view, passwman_window_object_cleared_cb, extension); + g_signal_handlers_disconnect_by_func ( + web_view, passwman_navigation_decision_cb, extension); +} + +static void +passwman_deactivate_cb(MidoriExtension* extension, + MidoriBrowser* browser) +{ + MidoriApp* app = midori_extension_get_app (extension); + + g_signal_handlers_disconnect_by_func ( + browser, passwman_add_tab_cb, extension); + g_signal_handlers_disconnect_by_func ( + extension, passwman_deactivate_cb, browser); + g_signal_handlers_disconnect_by_func ( + app, passwman_app_add_browser_cb, extension); + GList* tabs = midori_browser_get_tabs (browser); + for (; tabs; tabs = g_list_next (tabs)) + passwman_deactivate_tab (tabs->data, extension); + g_list_free (tabs); + + katze_assign (jspassm, NULL); + if (log_pass) + g_hash_table_destroy (log_pass); +} + +static void +passwman_activate_cb (MidoriExtension* extension, + MidoriApp* app) +{ + KatzeArray* browsers; + MidoriBrowser* browser; + + log_pass = g_hash_table_new_full (g_str_hash, g_str_equal, + (GDestroyNotify)g_free, + (GDestroyNotify)g_free); + if ( !jspassm ) + passwman_prepare_js(); + GnomeKeyringResult res; GList *results; results = NULL; + res = gnome_keyring_find_network_password_sync(NULL, + "midori", + NULL, + NULL, + NULL, + NULL, + 0, + &results); + if ( res == GNOME_KEYRING_RESULT_OK ) { + GList *r; gchar *nlp; gchar *server; gchar *tmp; + for( r = results; r; r = r->next ) { + GnomeKeyringNetworkPasswordData* data = \ + (GnomeKeyringNetworkPasswordData*)r->data; + server = data->server; + if ( g_strcmp0(data->user,"__never_store_here__") == 0 ) + nlp = g_strdup("\"0\""); + else if ( ( tmp = g_hash_table_lookup(log_pass,server) ) ) + { + if ( g_strcmp0(tmp,"\"0\"") == 0 ) + nlp = g_strdup("\"0\""); + else + { + gssize il = -1; gchar *id, *num; gsize lprt, n; + id = g_strstr_len(tmp,il,","); lprt = id - tmp -1; + num = g_strndup(tmp+1,lprt); n = atoi(num)+1; + nlp = g_strdup_printf("\"%i\"%s,\"%s\",\"%s\"",n,id,\ + data->user,data->password); + } + } + else + nlp = g_strdup_printf("\"1\",\"%s\",\"%s\"",data->user,data->password); + g_hash_table_insert(log_pass,g_strdup(server),nlp); + } + gnome_keyring_network_password_list_free(results); + } + browsers = katze_object_get_object (app, "browsers"); + KATZE_ARRAY_FOREACH_ITEM (browser, browsers) + passwman_app_add_browser_cb (app, browser, extension); + g_signal_connect (app, "add-browser", + G_CALLBACK (passwman_app_add_browser_cb), extension); + + g_object_unref (browsers); +} + +MidoriExtension* +extension_init (void) +{ + gboolean should_init = TRUE; + const gchar* ver; + gchar* desc; + MidoriExtension* extension; + + if ( passwman_prepare_js() && gnome_keyring_is_available() ) + { + ver = "0.3" MIDORI_VERSION_SUFFIX; + desc = g_strdup (_("Stores login/password data")); + } + else + { + desc = g_strdup_printf (_("Not available: %s"), + _("Resource files or gnome-keyring")); + ver = NULL; + should_init = FALSE; + } + + extension = g_object_new (MIDORI_TYPE_EXTENSION, + "name", _("Password Manager"), + "description", desc, + "version", ver, + "authors", "Giuseppe Borzi <gborzi@ieee.org>", + NULL); + g_free (desc); + + if (should_init) + g_signal_connect (extension, "activate", + G_CALLBACK (passwman_activate_cb), NULL); + + return extension; +} diff --git a/passwordmanager.js b/passwordmanager.js new file mode 100644 index 000000000000..abdc129f1a64 --- /dev/null +++ b/passwordmanager.js @@ -0,0 +1,118 @@ +/*
+ * LoginPasswordManager from Giuseppe Borzi <gborzi AT ieee DOT org>
+ * A userscript modified to work with libpasswordmanager.so.
+ * Copyright 2011 by Giuseppe Borzi
+ */
+
+var ans;
+
+var Store = {
+ set: function( values ) {
+ ans = "\""+values[0]+"\"";
+ for( var i = 1; i < values.length; i++ )
+ ans = ans+",\""+values[i]+"\"";
+ },
+ dump: function() {
+ if ( ans ) return ans;
+ else return "";
+ }
+};
+
+setValue = Store.set;
+
+var PassMan = {};
+
+PassMan.askstore = "Store Login/Password for this site?",
+PassMan.askneverstore = "Click OK to never store Login/Password for this site",
+PassMan.askpasstore = "Store new password for login: ",
+
+PassMan.il = -1;
+PassMan.ip = -1;
+PassMan.inptg = null;
+
+PassMan.findlp = function(doc) {
+ var inptg = doc.getElementsByTagName("input"), ip = -1;
+ for ( var i = 0; i < inptg.length; i++ )
+ if ( inptg[i].type == "password" ) { ip = i; break; }
+ var found = ip > -1;
+ if ( found ) {
+ this.ip = ip; this.inptg = inptg;
+ for( var i = ip-1; i > -1; i--) if ( inptg[i].type == "text" ) { this.il = i; break; }
+ }
+ return found;
+};
+
+PassMan.buildLoginMenu = function( np, lp ) {
+ var oSel=document.createElement("SELECT");
+ oSel.addEventListener('change', function() {}, false);
+ var oOpt=document.createElement("OPTION"); oOpt.innerHTML = "Which Login?";
+ oSel.appendChild(oOpt);
+ for( var i = 0 ; i < np; i++ ) {
+ var oOpt=document.createElement("OPTION");
+ oOpt.innerHTML = lp[2*i+1]; oSel.appendChild(oOpt);
+ }
+ return(oSel);
+};
+
+PassMan.fillp = function( np, lp ) {
+ if ( this.il > -1 ) this.inptg[this.il].value = lp[1];
+ this.inptg[this.ip].value = lp[2];
+ if ( np > 1 ) {
+ var il = this.il, ip = this.ip, inptg = this.inptg;
+ var fUL = inptg[ip].parentNode; var oSel = this.buildLoginMenu(np,lp);
+ var oLi = document.createElement("LI");
+ oLi.className = 'lgn_menu'; fUL.appendChild(oLi); oLi.appendChild(oSel);
+ oSel.addEventListener('change', function(){
+ var isel = oSel.selectedIndex; var jl = 2*isel-1;
+ if ( jl > -1 ) {
+ inptg[il].value = lp[jl]; inptg[ip].value = lp[jl+1];
+ } else { inptg[il].value = ""; inptg[ip].value = "" }
+ },false);
+ }
+};
+
+PassMan.storelp = function( np, lp ) {
+ var newlog = ( this.il == -1 ) ? "dummy": this.inptg[this.il].value,
+ newpass = this.inptg[this.ip].value;
+ if( newpass.length == 0 || newlog.length == 0 ) return;
+ var jl = 0, jp;
+ for( var i = 0; i < np; i++ ) {
+ if( lp[2*i+1] == newlog ) { jl = 2*i+1; jp = jl+1; break; }
+ }
+ if ( jl == 0 ) {
+ if( confirm(this.askstore) ) {
+ var np1 = np+1; lp[0] = np1+'';
+ lp.push(newlog,newpass); setValue(lp);
+ } else {
+ if( confirm(this.askneverstore) ) {
+ var nostore = ["0"]; setValue(nostore);
+ }
+ }
+ } else {
+ if ( lp[jp] !== newpass && confirm(this.askpasstore+newlog) ) {
+ lp[jp] = newpass; setValue(lp);
+ }
+ }
+};
+
+PassMan.fillogpass = function(doc) {
+ if ( this.findlp(doc) ) {
+ var lp = getValue(), storepass = true, np = 0;
+ if ( lp.length > 0 ) {
+ np = parseInt(lp[0]); storepass = np > 0;
+ if ( storepass ) this.fillp( np, lp );
+ }
+ }
+};
+
+PassMan.dologpass = function(doc) {
+ if ( this.findlp(doc) ) {
+ var lp = getValue(), storepass = true, np = 0;
+ if ( lp.length > 0 ) {
+ np = parseInt(lp[0]); storepass = np > 0;
+ //if ( storepass ) this.fillp( np, lp );
+ }
+ if ( storepass ) PassMan.storelp(np,lp);
+ }
+};
+
|