Add Firefox WebExtension
This commit is contained in:
		
							
								
								
									
										17
									
								
								firefox_webextension/background.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								firefox_webextension/background.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,17 @@ | ||||
| browser.runtime.onMessage.addListener( | ||||
|     function(request) { | ||||
|  | ||||
| 	if (request.type == "notification") | ||||
| 	{ | ||||
| 	    options = { | ||||
| 		type: "basic", | ||||
| 		title : "gPass", | ||||
| 		message : request.options.message, | ||||
| 		iconUrl:browser.extension.getURL("gpass_icon_64.png") | ||||
| 	    }; | ||||
|  | ||||
| 	    browser.notifications.create("gPass", options); | ||||
|  | ||||
| 	    window.setTimeout(function() {browser.notifications.clear("gPass")}, 2000); | ||||
| 	} | ||||
|     }); | ||||
							
								
								
									
										220
									
								
								firefox_webextension/compat.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										220
									
								
								firefox_webextension/compat.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,220 @@ | ||||
| /* | ||||
|   Copyright (C) 2013-2016 Grégory Soutadé | ||||
|    | ||||
|   This file is part of gPass. | ||||
|    | ||||
|   gPass 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. | ||||
|    | ||||
|   gPass 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 gPass.  If not, see <http://www.gnu.org/licenses/>. | ||||
| */ | ||||
|  | ||||
| var default_preferences = {"pbkdf2_level": 1000, | ||||
| 			   "account_url": "https://gpass-demo.soutade.fr/demo"}; | ||||
|  | ||||
| function notify(text, data) | ||||
| { | ||||
|     browser.runtime.sendMessage({type: "notification", options:{"message":text}}); | ||||
| } | ||||
| // https://stackoverflow.com/questions/6965107/converting-between-strings-and-arraybuffers | ||||
| function ab2str(buf) { | ||||
|     return String.fromCharCode.apply(null, new Uint8Array(buf)); | ||||
| } | ||||
|  | ||||
| // https://developers.google.com/web/updates/2012/06/How-to-convert-ArrayBuffer-to-and-from-String | ||||
| function str2ab2(str) { | ||||
|     var chars = [] | ||||
|     for (var i=0, strLen=str.length; i < strLen; i++) { | ||||
| 	chars.push(str.charCodeAt(i)); | ||||
|     } | ||||
|     return new Uint8Array(chars); | ||||
| } | ||||
|  | ||||
| function str2ab(str) { | ||||
|     var buf = new ArrayBuffer(str.length); // 2 bytes for each char | ||||
|     // var buf = new ArrayBuffer(str.length*2); // 2 bytes for each char | ||||
|     var bufView = new Uint8Array(buf); | ||||
|     for (var i=0, strLen=str.length; i < strLen; i++) { | ||||
| 	bufView[i] = str.charCodeAt(i); | ||||
|     } | ||||
|     return bufView; | ||||
| } | ||||
|  | ||||
| function returnResult(result) { return result;} | ||||
| function onError(error) { console.error(error); } | ||||
|  | ||||
| function pbkdf2(mkey, salt, level) | ||||
| { | ||||
|     debug("Process pbkdf2 with " + mkey); | ||||
|  | ||||
|     AESCBC = { | ||||
|         name: "AES-CBC", | ||||
|         length: 256, | ||||
|     } | ||||
|     level=1000; | ||||
|  | ||||
|     var key = str2ab(mkey); | ||||
|     return window.crypto.subtle.importKey("raw", key, {name: "PBKDF2"}, false, ["deriveBits", "deriveKey"]) | ||||
| 	.then(function(key){ | ||||
|             //sha-256 | ||||
|             return window.crypto.subtle.deriveKey({ | ||||
| 		name: "PBKDF2", | ||||
| 		salt: str2ab(salt), | ||||
| 		iterations: level, | ||||
| 		hash: "SHA-256", | ||||
|             }, key, AESCBC, false, ["encrypt", "decrypt", "unwrapKey", "wrapKey"]) | ||||
| 		.then(function(key) { | ||||
| 		    return key; | ||||
| 		}) | ||||
| 		.catch(function(err){ | ||||
| 		    console.log("Error derive key " + err); | ||||
| 		}); | ||||
| 	}) | ||||
| 	.catch(function(err) { | ||||
| 	    console.log("Error import key" + err); | ||||
| 	}); | ||||
| } | ||||
|  | ||||
| function _encrypt(mkey, data) | ||||
| { | ||||
|     while ((data.length % 16)) | ||||
| 	data += "\0"; | ||||
|      | ||||
|     debug("Encrypt " + data); | ||||
|  | ||||
|     data = str2ab(data); | ||||
|  | ||||
|     nulliv = new Uint8Array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]); | ||||
|  | ||||
|     promise = mkey.then(function(mkey){ | ||||
|     	return window.crypto.subtle.encrypt({ | ||||
|             name: "AES-CBC", | ||||
|             iv: nulliv | ||||
|     	}, mkey, data)}) | ||||
|     	.then(function(encrypted) { | ||||
|     	    return ab2str(encrypted); | ||||
|     	}) | ||||
|     	.catch(function(encryption) { | ||||
|     	    console.log("Encryption rejected " + encryption); | ||||
|     	}); | ||||
|  | ||||
|     return promise; | ||||
| } | ||||
|  | ||||
| async function _decrypt(mkey, data) | ||||
| { | ||||
|     while ((data.length % 16)) | ||||
| 	data += "\0"; | ||||
|  | ||||
|     pkcs7_padding = new Uint8Array([16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16]); | ||||
|     pkcs7_padding = await _encrypt(mkey, ab2str(pkcs7_padding)); | ||||
|  | ||||
|     debug("Decrypt " + data); | ||||
|  | ||||
|     data = str2ab(data + pkcs7_padding); | ||||
|  | ||||
|     nulliv = new Uint8Array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]); | ||||
|  | ||||
|     promise = mkey.then(function(mkey){ | ||||
|     	return window.crypto.subtle.decrypt({ | ||||
|             name: "AES-CBC", | ||||
|             iv: nulliv | ||||
|     	}, mkey, data)}) | ||||
|     	.then(function(decrypted) { | ||||
|     	    return ab2str(decrypted); | ||||
|     	}) | ||||
|     	.catch(function(decryption) { | ||||
|     	    console.log("Decryption rejected " + decryption); | ||||
|     	}); | ||||
|  | ||||
|     return promise; | ||||
| } | ||||
|  | ||||
| async function encrypt(mkey, data) | ||||
| { | ||||
|     var result = ""; | ||||
|      | ||||
|     while (data.length > 16) | ||||
|     { | ||||
| 	res = await _encrypt(mkey, data.slice(0, 16)); | ||||
| 	// Remove PKCS7 padding | ||||
| 	result += res.slice(0, 16); | ||||
| 	data = data.slice(16); | ||||
|     } | ||||
|     res = await _encrypt(mkey, data); | ||||
|     result += res.slice(0, 16); | ||||
|  | ||||
|     return result; | ||||
| } | ||||
|  | ||||
| async function decrypt(mkey, data) | ||||
| { | ||||
|     var result = ""; | ||||
|      | ||||
|     while (data.length > 16) | ||||
|     { | ||||
| 	res = await _decrypt(mkey, data.slice(0, 16)); | ||||
| 	// Remove PKCS7 padding | ||||
| 	result += res.slice(0, 16); | ||||
| 	data = data.slice(16); | ||||
|     } | ||||
|     res = await _decrypt(mkey, data); | ||||
|     result += res.slice(0, 16); | ||||
|  | ||||
|     return result; | ||||
| } | ||||
|  | ||||
| function getPref(key) | ||||
| { | ||||
|     return browser.storage.local.get(key) | ||||
| 	.then( | ||||
| 	    function (pref) { | ||||
| 		if (!pref.hasOwnProperty(key)) | ||||
| 		    return default_preferences[key]; | ||||
| 		return pref[key]; | ||||
| 	    } | ||||
| 	    , | ||||
| 	    function (err) { | ||||
| 		console.log("Error getting preference " + err); | ||||
| 	    } | ||||
| 	); | ||||
| } | ||||
|  | ||||
| function setPref(key, value) | ||||
| { | ||||
|     browser.storage.local.set({key:value}); | ||||
| } | ||||
|  | ||||
| // function getPref(key) | ||||
| // { | ||||
| //     res = localStorage.getItem(key); | ||||
| //     if (res == null) | ||||
| // 	return default_preferences[key]; | ||||
| //     return res; | ||||
| // } | ||||
|  | ||||
| // function setPref(key, value) | ||||
| // { | ||||
| //     localStorage.setItem(key, value); | ||||
| // } | ||||
|  | ||||
| // function load_preferences() | ||||
| // { | ||||
| //     preferences = {}; | ||||
|  | ||||
| //     for (var i = 0; i < localStorage.length; i++) | ||||
| //     { | ||||
| // 	k = localStorage.key(i); | ||||
| // 	preferences[k] = getPref[k]; | ||||
| //     } | ||||
|  | ||||
| //     return preferences; | ||||
| // } | ||||
							
								
								
									
										1
									
								
								firefox_webextension/gpass_icon_128.png
									
									
									
									
									
										Symbolic link
									
								
							
							
						
						
									
										1
									
								
								firefox_webextension/gpass_icon_128.png
									
									
									
									
									
										Symbolic link
									
								
							| @@ -0,0 +1 @@ | ||||
| ../resources/gpass_icon_128.png | ||||
							
								
								
									
										1
									
								
								firefox_webextension/gpass_icon_16.png
									
									
									
									
									
										Symbolic link
									
								
							
							
						
						
									
										1
									
								
								firefox_webextension/gpass_icon_16.png
									
									
									
									
									
										Symbolic link
									
								
							| @@ -0,0 +1 @@ | ||||
| ../resources/gpass_icon_16.png | ||||
							
								
								
									
										1
									
								
								firefox_webextension/gpass_icon_32.png
									
									
									
									
									
										Symbolic link
									
								
							
							
						
						
									
										1
									
								
								firefox_webextension/gpass_icon_32.png
									
									
									
									
									
										Symbolic link
									
								
							| @@ -0,0 +1 @@ | ||||
| ../resources/gpass_icon_32.png | ||||
							
								
								
									
										1
									
								
								firefox_webextension/gpass_icon_64.png
									
									
									
									
									
										Symbolic link
									
								
							
							
						
						
									
										1
									
								
								firefox_webextension/gpass_icon_64.png
									
									
									
									
									
										Symbolic link
									
								
							| @@ -0,0 +1 @@ | ||||
| ../resources/gpass_icon_64.png | ||||
							
								
								
									
										1
									
								
								firefox_webextension/lib
									
									
									
									
									
										Symbolic link
									
								
							
							
						
						
									
										1
									
								
								firefox_webextension/lib
									
									
									
									
									
										Symbolic link
									
								
							| @@ -0,0 +1 @@ | ||||
| ../chrome_addon/lib/ | ||||
							
								
								
									
										35
									
								
								firefox_webextension/manifest.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								firefox_webextension/manifest.json
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,35 @@ | ||||
| { | ||||
|     "manifest_version": 2, | ||||
|  | ||||
|     "name": "gPass", | ||||
|     "short_name": "gPass", | ||||
|     "version": "0.8", | ||||
|     "description": "gPass : global password manager", | ||||
|     "icons" : {"16":"gpass_icon_16.png", "32":"gpass_icon_32.png", "64":"gpass_icon_64.png", "128":"gpass_icon_128.png"}, | ||||
|     "author" : "Grégory Soutadé", | ||||
|     "homepage_url" : "http://indefero.soutade.fr/p/gpass", | ||||
|      | ||||
|     "content_scripts": [ | ||||
| 	{ | ||||
| 	    "matches": ["https://*/*", "http://*/*"], | ||||
| 	    "js": ["lib/parseuri.js", "compat.js", "lib/main.js"], | ||||
| 	    "run_at" : "document_idle", | ||||
| 	    "all_frames" : true | ||||
| 	} | ||||
|     ], | ||||
|  | ||||
|     "background": { | ||||
| 	"persistent": false, | ||||
| 	"scripts": ["background.js"] | ||||
|     }, | ||||
|  | ||||
|     "options_ui": { "page":"options.html" }, | ||||
|  | ||||
|     "permissions": [ | ||||
| 	"https://*/", | ||||
| 	"http://*/", | ||||
| 	"notifications", | ||||
| 	"storage", | ||||
| 	"activeTab" | ||||
|     ] | ||||
| } | ||||
							
								
								
									
										1
									
								
								firefox_webextension/options.html
									
									
									
									
									
										Symbolic link
									
								
							
							
						
						
									
										1
									
								
								firefox_webextension/options.html
									
									
									
									
									
										Symbolic link
									
								
							| @@ -0,0 +1 @@ | ||||
| ../chrome_addon/options.html | ||||
							
								
								
									
										35
									
								
								firefox_webextension/options.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								firefox_webextension/options.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,35 @@ | ||||
| var default_preferences = {"pbkdf2_level": 1000, | ||||
| 			   "account_url": "https://gpass-demo.soutade.fr/demo"}; | ||||
|  | ||||
| function save() { | ||||
|     var account_url = document.getElementById('account_url').value; | ||||
|     var pbkdf2 = document.getElementById('pbkdf2').value; | ||||
|  | ||||
|     browser.storage.local.set({ | ||||
| 	"account_url":account_url, | ||||
| 	"pbkdf2_level":pbkdf2 | ||||
|     }) | ||||
| 	.then(function ok() { alert("Saved"); }, | ||||
| 	      function err() { alert("Cannot save your preferences");} | ||||
| 	     ); | ||||
| } | ||||
|  | ||||
| function restoreOptions() | ||||
| { | ||||
|     document.getElementById('account_url').value = default_preferences['account_url']; | ||||
|     document.getElementById('pbkdf2').value = default_preferences['pbkdf2_level']; | ||||
|  | ||||
|     browser.storage.local.get().then( | ||||
| 	function(prefs) | ||||
| 	{ | ||||
| 	    if (prefs.hasOwnProperty("account_url")) | ||||
| 		document.getElementById('account_url').value = prefs["account_url"]; | ||||
|  | ||||
| 	    if (prefs.hasOwnProperty("pbkdf2_level")) | ||||
| 		document.getElementById('pbkdf2').value = prefs["pbkdf2_level"]; | ||||
| 	} | ||||
|     ); | ||||
| } | ||||
|  | ||||
| document.getElementById('save').addEventListener("click", save); | ||||
| document.addEventListener("DOMContentLoaded", restoreOptions); | ||||
		Reference in New Issue
	
	Block a user