merge of master; slight refactor of messaging and localstorage modules
This commit is contained in:
Коммит
0863c3d63b
3
TODO
3
TODO
|
@ -3,6 +3,9 @@
|
|||
- reorg directories; given the Jetpack doesn't allow more than one level of .., the consider top level firefox and chrome directories
|
||||
- think about "local only" mode on Mac OS X that writes passwords to Keychain
|
||||
- figure out API URL for different releases
|
||||
- this page causes lots of User.sync reads http://stackoverflow.com/questions/6570363/chrome-extension-content-scripts-and-iframe when you scroll
|
||||
- refactor password form inspector so that password form is responsible for figuring out its own form
|
||||
- it particular, it should look for an enclosing element that has a username field that preceeds the password field
|
||||
- revisit tobmog packaging
|
||||
- make sure linking creds are deleted if no logged in user or user dismisses but wait until after notification appears and user reacts
|
||||
- refactor user model to be as independent of sync method and client as possible
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
var AccountManager = function(Gombot, _) {
|
||||
|
||||
function createAccount(details, cb) {
|
||||
var userCollection = Gombot.users;
|
||||
|
||||
var user = new Gombot.User({
|
||||
'email': details.email,
|
||||
'pin': details.pin
|
||||
});
|
||||
|
||||
user.save(null, {
|
||||
success: function() {
|
||||
Gombot.setCurrentUser(user);
|
||||
userCollection.add(user);
|
||||
cb(null);
|
||||
},
|
||||
error: function(args) {
|
||||
cb(args);
|
||||
},
|
||||
password: details.password,
|
||||
newsletter: details.newsletter
|
||||
});
|
||||
}
|
||||
|
||||
function signIn(details, cb) {
|
||||
var userCollection = Gombot.users;
|
||||
var user = userCollection.find(function(obj) {
|
||||
return obj.get('email') === details.email;
|
||||
}) || new Gombot.User({ email: details.email });
|
||||
|
||||
user.fetch({
|
||||
success: function() {
|
||||
Gombot.setCurrentUser(user);
|
||||
userCollection.add(user);
|
||||
cb(null);
|
||||
},
|
||||
error: function(args) {
|
||||
cb(args);
|
||||
},
|
||||
password: details.password
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
createAccount: createAccount,
|
||||
signIn: signIn
|
||||
};
|
||||
};
|
|
@ -17,8 +17,8 @@
|
|||
<script src="clipboard.js"></script>
|
||||
<script src="infobar_hooks.js"></script>
|
||||
<script src="first_run.js"></script>
|
||||
<script src="chrome/chrome_messaging.js"></script>
|
||||
<script src="chrome/chrome_local_storage.js"></script>
|
||||
<script src="messaging.js"></script>
|
||||
<script src="local_storage.js"></script>
|
||||
<script src="command_handler.js"></script>
|
||||
<script src="captured_credential_storage.js"></script>
|
||||
<script src="site_configs.js"></script>
|
||||
|
@ -28,6 +28,7 @@
|
|||
<script src="models/user.js"></script>
|
||||
<script src="collections/user_collection.js"></script>
|
||||
<script src="linker.js"></script>
|
||||
<script src="account_manager.js"></script>
|
||||
<script src="gombot.js"></script>
|
||||
<script src="chrome/chrome_main.js"></script>
|
||||
<body>
|
||||
|
|
|
@ -1,9 +1,5 @@
|
|||
var Gombot;
|
||||
|
||||
(function() {
|
||||
var importedModules = {
|
||||
Messaging: ChromeMessaging,
|
||||
LocalStorage: ChromeLocalStorage
|
||||
};
|
||||
Gombot = _Gombot(importedModules); // create global namespace, for Chrome
|
||||
Gombot = _Gombot({}); // create global namespace, for Chrome
|
||||
})();
|
|
@ -1,15 +0,0 @@
|
|||
var ChromeMessaging = function() {
|
||||
|
||||
function addContentMessageListener(callback) {
|
||||
chrome.extension.onMessage.addListener(callback);
|
||||
}
|
||||
|
||||
function messageToContent(target, message) {
|
||||
chrome.tabs.sendMessage(target.tab.id, message);
|
||||
}
|
||||
|
||||
return {
|
||||
addContentMessageListener: addContentMessageListener,
|
||||
messageToContent: messageToContent
|
||||
};
|
||||
};
|
|
@ -83,6 +83,18 @@ var CommandHandler = function(Gombot, Messaging, _) {
|
|||
callback(Gombot.SiteConfigs[Gombot.TldService.getDomain(sender.tab.url)] || {});
|
||||
}
|
||||
|
||||
// create a new user account
|
||||
function createUser (message, sender, callback) {
|
||||
Gombot.AccountManager.createAccount(message, callback);
|
||||
return true;
|
||||
}
|
||||
|
||||
// sign into a user account
|
||||
function signIn (message, sender, callback) {
|
||||
Gombot.AccountManager.signIn(message, callback);
|
||||
return true;
|
||||
}
|
||||
|
||||
var commandHandlers = {
|
||||
'add_login': addLogin,
|
||||
'validate_pin': validatePin,
|
||||
|
@ -91,7 +103,9 @@ var CommandHandler = function(Gombot, Messaging, _) {
|
|||
'get_captured_credentials': getCapturedCredentials,
|
||||
'delete_captured_credentials': deleteCapturedCredentials,
|
||||
'get_saved_credentials': getSavedCredentials,
|
||||
'get_site_config': getSiteConfig
|
||||
'get_site_config': getSiteConfig,
|
||||
'create_user': createUser,
|
||||
'sign_in': signIn
|
||||
};
|
||||
|
||||
//
|
||||
|
|
|
@ -1,23 +0,0 @@
|
|||
var FirefoxLocalStorage = function() {
|
||||
var ss = require("simple-storage");
|
||||
var timers = require("timers");
|
||||
|
||||
// this module uses setTimeouts to roughly simulate the async interface in chrome
|
||||
return {
|
||||
getItem: function(key, callback) {
|
||||
timers.setTimeout(function() {
|
||||
callback(ss.storage[key]);
|
||||
}, 0);
|
||||
},
|
||||
setItem: function(key, data, callback) {
|
||||
ss.storage[key] = data;
|
||||
timers.setTimeout(callback,0);
|
||||
},
|
||||
removeItem: function(key, callback) {
|
||||
delete ss.storage[key];
|
||||
timers.setTimeout(callback, 0);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = FirefoxLocalStorage;
|
|
@ -60,8 +60,8 @@ windows.on('open', function(window) {
|
|||
var gombotModules = {
|
||||
Backbone: require("../lib/backbone"),
|
||||
_ : require("../lib/underscore"),
|
||||
Messaging: require("./firefox_messaging"),
|
||||
LocalStorage: require("./firefox_local_storage"),
|
||||
Messaging: require("../messaging"),
|
||||
LocalStorage: require("../local_storage"),
|
||||
Tld: require("./tld.js"),
|
||||
Uri: require("../lib/jsuri"),
|
||||
TldService: require("../tld_service"),
|
||||
|
|
|
@ -1,40 +0,0 @@
|
|||
var FirefoxMessaging = function() {
|
||||
|
||||
var commandHandlerCallback = null;
|
||||
|
||||
// callback is expected to be of the form: function
|
||||
// Format: { request: { message: <message data> },
|
||||
// sender: { tab: { id: <tab id>, url: <url currently in tab> } },
|
||||
// sendResponse: callback function with single parameter to respond to content scripts }
|
||||
function addContentMessageListener(callback) {
|
||||
commandHandlerCallback = callback;
|
||||
}
|
||||
|
||||
// TODO
|
||||
function messageToContent(target, message) {
|
||||
|
||||
}
|
||||
|
||||
function registerPageModWorker(worker) {
|
||||
// Firefox messages from content scripts should be like:
|
||||
// { callbackId: <callbackId>, // This is a callback identifer for the content script to invoke when this returns
|
||||
// message: <actual message data>
|
||||
// }
|
||||
worker.on('message', function (message) {
|
||||
var request = message.message,
|
||||
sender = { tab: { id: "", url: worker.url } },
|
||||
sendResponse = function(response) {
|
||||
worker.postMessage({ callbackId: message.callbackId, message: response });
|
||||
};
|
||||
commandHandlerCallback(request, sender, sendResponse);
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
registerPageModWorker: registerPageModWorker,
|
||||
addContentMessageListener: addContentMessageListener,
|
||||
messageToContent: messageToContent
|
||||
};
|
||||
};
|
||||
|
||||
module.exports = FirefoxMessaging;
|
|
@ -40,10 +40,8 @@ var _Gombot = function(importedModules, Gombot) {
|
|||
})()
|
||||
});
|
||||
|
||||
// These must be defined by importedModules
|
||||
Gombot.Messaging = importedModules.Messaging();
|
||||
Gombot.LocalStorage = importedModules.LocalStorage();
|
||||
|
||||
Gombot.Messaging = getModule("Messaging")();
|
||||
Gombot.LocalStorage = getModule("LocalStorage")();
|
||||
Gombot.TldService = getModule("TldService")(getModule("Tld"), getModule("Uri"));
|
||||
Gombot.SiteConfigs = getModule("SiteConfigs");
|
||||
Gombot.Realms = getModule("Realms")(Gombot, Gombot.SiteConfigs, getModule("Uri"));
|
||||
|
|
|
@ -137,7 +137,6 @@ var GombotSync = function(Gombot, Backbone, _) {
|
|||
// data: unencrypted model data,
|
||||
// ciphertext: current encrypted payload of user data,
|
||||
// updated: server timestamp of this data
|
||||
// }
|
||||
// All methods except for "create" require model.keys to exist and be valid
|
||||
function sync(method, model, options) {
|
||||
if (!(model instanceof Gombot.User)) return maybeHandleError(options.error, "sync only supports syncing instances of Gombot.User");
|
||||
|
@ -162,4 +161,4 @@ var GombotSync = function(Gombot, Backbone, _) {
|
|||
|
||||
if (typeof module !== "undefined" && module.exports) {
|
||||
module.exports = GombotSync;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
* local_storage.js
|
||||
*
|
||||
*
|
||||
* Handles persisting user data via localStorage.
|
||||
*
|
||||
*/
|
||||
|
||||
// This handles the low-level localStorage
|
||||
// TODO: handle errors
|
||||
var LocalStorage = function() {
|
||||
var ChromeLocalStorage = {
|
||||
getItem: function(key, callback) {
|
||||
chrome.storage.local.get(key, function(storageObj) {
|
||||
callback(storageObj[key]);
|
||||
});
|
||||
},
|
||||
setItem: function(key, data, callback) {
|
||||
var updatedObj = {};
|
||||
updatedObj[key] = data;
|
||||
chrome.storage.local.set(updatedObj, callback);
|
||||
},
|
||||
removeItem: function(key, callback) {
|
||||
chrome.storage.local.remove(key, callback);
|
||||
}
|
||||
};
|
||||
|
||||
var FirefoxLocalStorage = function() {
|
||||
var ss = require("simple-storage");
|
||||
var timers = require("timers");
|
||||
|
||||
// this module uses setTimeouts to roughly simulate the async interface in chrome
|
||||
return {
|
||||
getItem: function(key, callback) {
|
||||
timers.setTimeout(function() {
|
||||
callback(ss.storage[key]);
|
||||
}, 0);
|
||||
},
|
||||
setItem: function(key, data, callback) {
|
||||
ss.storage[key] = data;
|
||||
timers.setTimeout(callback,0);
|
||||
},
|
||||
removeItem: function(key, callback) {
|
||||
delete ss.storage[key];
|
||||
timers.setTimeout(callback, 0);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
if (typeof chrome !== "undefined") {
|
||||
return ChromeLocalStorage;
|
||||
}
|
||||
else if (typeof require === "function") {
|
||||
return FirefoxLocalStorage();
|
||||
}
|
||||
else {
|
||||
throw "Can't initialize LocalStorage. Can't find 'chrome' or 'require'.";
|
||||
}
|
||||
};
|
||||
|
||||
if (typeof module != 'undefined' && module.exports) {
|
||||
module.exports = LocalStorage;
|
||||
}
|
|
@ -0,0 +1,176 @@
|
|||
/*
|
||||
* main.js
|
||||
*
|
||||
*
|
||||
* Main file that "boots up" the extension with initGombot. Also handles popup notifications.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
// mixin guid creation into underscore
|
||||
_.mixin({
|
||||
guid: (function() {
|
||||
function S4() {
|
||||
return (((1+Math.random())*0x10000)|0).toString(16).substring(1);
|
||||
};
|
||||
// Generate a pseudo-GUID by concatenating random hexadecimal.
|
||||
return function() {
|
||||
return (S4()+S4()+"-"+S4()+"-"+S4()+"-"+S4()+"-"+S4()+S4()+S4());
|
||||
};
|
||||
})()
|
||||
});
|
||||
|
||||
var Gombot = {};
|
||||
Gombot.Messaging = ChromeMessaging();
|
||||
Gombot.TldService = TldService(Tld, Uri);
|
||||
Gombot.SiteConfigs = SiteConfigs || {};
|
||||
Gombot.Realms = Realms(Gombot.SiteConfigs, Uri, Gombot.TldService);
|
||||
Gombot.LocalStorage = LocalStorage();
|
||||
Gombot.Storage = Storage(Backbone, _, Gombot.LocalStorage); // defined by backbone.localStorage.js
|
||||
Gombot.Sync = GombotSync(GombotClient, Backbone, _, Gombot);
|
||||
Gombot.LoginCredential = LoginCredential(Backbone, _, Gombot.Realms);
|
||||
Gombot.LoginCredentialCollection = LoginCredentialCollection(Backbone, _, Gombot.LoginCredential, Gombot.Realms);
|
||||
Gombot.CapturedCredentialStorage = CapturedCredentialStorage(Gombot.Realms, Uri);
|
||||
Gombot.Linker = Linker(Gombot.Realms, Gombot.LoginCredential);
|
||||
Gombot.AccountManager = AccountManager(Gombot, _);
|
||||
Gombot.CommandHandler = CommandHandler(Gombot.Messaging,
|
||||
Gombot.CapturedCredentialStorage,
|
||||
Gombot.Realms,
|
||||
Gombot.Linker,
|
||||
Gombot.AccountManager);
|
||||
|
||||
|
||||
(function(Gombot) {
|
||||
var currentUser = null;
|
||||
Gombot.getCurrentUser = function() {
|
||||
return currentUser;
|
||||
};
|
||||
|
||||
Gombot.setCurrentUser = function(user) {
|
||||
currentUser = user;
|
||||
}
|
||||
|
||||
Gombot.clearCurrentUser = function(callback) {
|
||||
if (!currentUser) { callback(); return; }
|
||||
// TODO: revisit this after sync refactor. This has some gross abstractions going on.
|
||||
currentUser.destroy({ localOnly: true, success: function() { currentUser = null; callback(); }});
|
||||
}
|
||||
})(Gombot);
|
||||
|
||||
new Gombot.Storage("users", function(store) {
|
||||
Gombot.User = User(Backbone, _, Gombot.LoginCredentialCollection, Gombot.Sync, store);
|
||||
Gombot.UserCollection = UserCollection(Backbone, _, Gombot.User, store);
|
||||
checkFirstRun();
|
||||
});
|
||||
|
||||
function checkFirstRun() {
|
||||
Gombot.LocalStorage.getItem("firstRun", function(firstRun) {
|
||||
initGombot(firstRun);
|
||||
});
|
||||
}
|
||||
|
||||
function initGombot(firstRun) {
|
||||
Gombot.users = new Gombot.UserCollection();
|
||||
Gombot.users.fetch({
|
||||
success: function() {
|
||||
if (!firstRun) {
|
||||
startFirstRunFlow(false /* showSignInPage */); // shows signup page on first run
|
||||
Gombot.LocalStorage.setItem("firstRun", true);
|
||||
}
|
||||
var loggedInUser = Gombot.users.find(function(user) { return user.isAuthenticated() });
|
||||
if (loggedInUser) Gombot.setCurrentUser(loggedInUser);
|
||||
}});
|
||||
}
|
||||
|
||||
//
|
||||
// Infobar notifications
|
||||
//
|
||||
|
||||
function displayInfobar(notificationObj) {
|
||||
var infobarPaths = {
|
||||
password_observed: "/infobars/remember_password_infobar.html",
|
||||
update_password: "/infobars/update_password_infobar.html",
|
||||
signup_nag: "/infobars/signup_nag_infobar.html",
|
||||
pin_entry: "/infobars/pin_entry_infobar.html"
|
||||
};
|
||||
// Make sure we have a HTML infobar for this type of notification
|
||||
if (!infobarPaths[notificationObj.notification.type]) return;
|
||||
InfobarManager.run({
|
||||
path: infobarPaths[notificationObj.notification.type],
|
||||
tabId: notificationObj.tabID,
|
||||
height: '32px'
|
||||
}, genHandlerForNotification(notificationObj));
|
||||
|
||||
function genHandlerForNotification(notificationObj) {
|
||||
return function(err,response) {
|
||||
if (err) {
|
||||
console.log(err);
|
||||
return;
|
||||
}
|
||||
if (!response.type) return;
|
||||
if (!infobarHooks[response.type]) {
|
||||
console.log('Infobar returned unknown response type!');
|
||||
return;
|
||||
}
|
||||
infobarHooks[response.type].call(infobarHooks,notificationObj,response);
|
||||
};
|
||||
// <<<<<<< HEAD
|
||||
// // Make sure we have a HTML infobar for this type of notification
|
||||
// if (!infobarPaths[notificationObj.notification.type]) return;
|
||||
// InfobarManager.run({
|
||||
// path: infobarPaths[notificationObj.notification.type],
|
||||
// tabId: notificationObj.tabID,
|
||||
// height: '32px'
|
||||
// }, genHandlerForNotification(notificationObj));
|
||||
|
||||
// function genHandlerForNotification(notificationObj) {
|
||||
// return function(err,response) {
|
||||
// if (err) {
|
||||
// console.log(err);
|
||||
// return;
|
||||
// }
|
||||
// if (!response.type) return;
|
||||
// if (!infobarHooks[response.type]) {
|
||||
// console.log('Infobar returned unknown response type!');
|
||||
// return;
|
||||
// }
|
||||
// infobarHooks[response.type].call(infobarHooks,notificationObj,response);
|
||||
// };
|
||||
// }
|
||||
// =======
|
||||
}
|
||||
}
|
||||
|
||||
// Test function that spawns an example infobar on the current active tab.
|
||||
function testInfobarNotification() {
|
||||
getActiveTab(function(tab) {
|
||||
console.log("tab url: ", tab.url,' ', tab);
|
||||
displayInfobar({
|
||||
notify: true,
|
||||
tabID: tab.id,
|
||||
notification: {
|
||||
type: 'pin_entry',
|
||||
formEl: {},
|
||||
formSubmitURL: "",
|
||||
hash: "bc74f4f071a5a33f00ab88a6d6385b5e6638b86c",
|
||||
hostname: "t.nm.io",
|
||||
httpRealm: null,
|
||||
password: "green",
|
||||
passwordField: {},
|
||||
type: "password_observed",
|
||||
username: "gombottest",
|
||||
usernameField: {}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
//
|
||||
// PIN validation
|
||||
//
|
||||
|
||||
function validatePIN(_pin) {
|
||||
// If there's no PIN set, accept. Otherwise, validate.
|
||||
var currentUser = Gombot.getCurrentUser();
|
||||
return (currentUser.get('pin') === _pin);
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
var Messaging = function() {
|
||||
var addContentMessageListener,
|
||||
messageToContent,
|
||||
revealed = {};
|
||||
|
||||
if (typeof chrome !== "undefined") { // Chrome specific messaging to content scripts
|
||||
// callback is expected to be of the form: function
|
||||
// Format: { request: { message: <message data> },
|
||||
// sender: { tab: { id: <tab id>, url: <url currently in tab> } },
|
||||
// sendResponse: callback function with single parameter to respond to content scripts }
|
||||
addContentMessageListener = function(callback) {
|
||||
chrome.extension.onMessage.addListener(callback);
|
||||
};
|
||||
|
||||
messageToContent = function(target, message) {
|
||||
chrome.tabs.sendMessage(target.tab.id, message);
|
||||
};
|
||||
}
|
||||
else if (typeof require === "function") { // Firefox specific messaging to page mod workers
|
||||
(function() {
|
||||
var commandHandlerCallback = null;
|
||||
|
||||
// callback is expected to be of the form: function
|
||||
// Format: { request: { message: <message data> },
|
||||
// sender: { tab: { id: <tab id>, url: <url currently in tab> } },
|
||||
// sendResponse: callback function with single parameter to respond to content scripts }
|
||||
addContentMessageListener = function(callback) {
|
||||
commandHandlerCallback = callback;
|
||||
}
|
||||
|
||||
// TODO
|
||||
messageToContent = function(target, message) {
|
||||
|
||||
}
|
||||
|
||||
revealed.registerPageModWorker = function(worker) {
|
||||
// Firefox messages from content scripts should be like:
|
||||
// { callbackId: <callbackId>, // This is a callback identifer for the content script to invoke when this returns
|
||||
// message: <actual message data>
|
||||
// }
|
||||
worker.on('message', function (message) {
|
||||
var request = message.message,
|
||||
sender = { tab: { id: "", url: worker.url } },
|
||||
sendResponse = function(response) {
|
||||
worker.postMessage({ callbackId: message.callbackId, message: response });
|
||||
};
|
||||
commandHandlerCallback(request, sender, sendResponse);
|
||||
});
|
||||
}
|
||||
})();
|
||||
}
|
||||
else {
|
||||
throw "Can't initialize Messaging. Can't find 'chrome' or 'require'.";
|
||||
}
|
||||
|
||||
revealed.addContentMessageListener = addContentMessageListener;
|
||||
revealed.messageToContent = messageToContent;
|
||||
|
||||
return revealed;
|
||||
};
|
||||
|
||||
if (typeof module !== "undefined" && module.exports) {
|
||||
module.exports = Messaging;
|
||||
}
|
||||
|
|
@ -1,30 +1,4 @@
|
|||
/*
|
||||
* chrome_local_storage.js
|
||||
*
|
||||
*
|
||||
* Handles persisting user data via localStorage.
|
||||
*
|
||||
*/
|
||||
|
||||
// This handles the low-level localStorage
|
||||
// TODO: handle errors
|
||||
var ChromeLocalStorage = function() {
|
||||
return {
|
||||
getItem: function(key, callback) {
|
||||
chrome.storage.local.get(key, function(storageObj) {
|
||||
callback(storageObj[key]);
|
||||
});
|
||||
},
|
||||
setItem: function(key, data, callback) {
|
||||
var updatedObj = {};
|
||||
updatedObj[key] = data;
|
||||
chrome.storage.local.set(updatedObj, callback);
|
||||
},
|
||||
removeItem: function(key, callback) {
|
||||
chrome.storage.local.remove(key, callback);
|
||||
}
|
||||
}
|
||||
};
|
||||
// NOTE: This file is not being included for now
|
||||
|
||||
// Returns a string of a comma separated value file containing the hostname, username,
|
||||
// and password for each login the user has saved.
|
|
@ -1,97 +1,97 @@
|
|||
var Realms = function(Gombot, SiteConfigs, Uri) {
|
||||
|
||||
var realms = [];
|
||||
var realms = [];
|
||||
|
||||
function buildRealms(siteConfigs) {
|
||||
realms = siteConfigs.realms;
|
||||
}
|
||||
function buildRealms(siteConfigs) {
|
||||
realms = siteConfigs.realms;
|
||||
}
|
||||
|
||||
// fqOrigin cannot contain wildcards, realmOrigin may
|
||||
// TODO: make more general to account for wildcards in realmOrigins
|
||||
// fqOrigin cannot contain wildcards, realmOrigin may
|
||||
// TODO: make more general to account for wildcards in realmOrigins
|
||||
function fullyQualifiedOriginMatchesRealmOrigin(fqOrigin, realmOrigin) {
|
||||
return fqOrigin === realmOrigin;
|
||||
return fqOrigin === realmOrigin;
|
||||
}
|
||||
|
||||
function getRealmWrapperForOrigin(fqOrigin) {
|
||||
var length = realms.length;
|
||||
for (var i=0;i<length;i++) {
|
||||
if (isOriginMemberOfRealm(fqOrigin,realms[i].origins)) {
|
||||
return realms[i];
|
||||
}
|
||||
}
|
||||
return null;
|
||||
var length = realms.length;
|
||||
for (var i=0;i<length;i++) {
|
||||
if (isOriginMemberOfRealm(fqOrigin,realms[i].origins)) {
|
||||
return realms[i];
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// Determines a realm (array of origins, maybe with wildcards)
|
||||
// for a fully qualified origin. This will consult the realm map and if it finds
|
||||
// nothing, it will create the default realm for the origin (the origin wrapped in an array).
|
||||
// fqOrigin must be fully qualified (no wildcards)
|
||||
function getRealmForOrigin(fqOrigin) {
|
||||
var realmWrapper = getRealmWrapperForOrigin(fqOrigin);
|
||||
if (realmWrapper) return realmWrapper.origins;
|
||||
return [ fqOrigin ];
|
||||
}
|
||||
// Determines a realm (array of origins, maybe with wildcards)
|
||||
// for a fully qualified origin. This will consult the realm map and if it finds
|
||||
// nothing, it will create the default realm for the origin (the origin wrapped in an array).
|
||||
// fqOrigin must be fully qualified (no wildcards)
|
||||
function getRealmForOrigin(fqOrigin) {
|
||||
var realmWrapper = getRealmWrapperForOrigin(fqOrigin);
|
||||
if (realmWrapper) return realmWrapper.origins;
|
||||
return [ fqOrigin ];
|
||||
}
|
||||
|
||||
// extracts an origin string from a uri string
|
||||
function getOriginForUri(uriString) {
|
||||
var uri = new Uri(uriString),
|
||||
origin = uri.protocol()+"://"+uri.host(),
|
||||
port = uri.port();
|
||||
if (port) {
|
||||
origin += ":"+port;
|
||||
}
|
||||
return origin;
|
||||
var uri = new Uri(uriString),
|
||||
origin = uri.protocol()+"://"+uri.host(),
|
||||
port = uri.port();
|
||||
if (port) {
|
||||
origin += ":"+port;
|
||||
}
|
||||
return origin;
|
||||
}
|
||||
|
||||
function getRealmForUri(uriString) {
|
||||
return getRealmForOrigin(getOriginForUri(uriString));
|
||||
return getRealmForOrigin(getOriginForUri(uriString));
|
||||
}
|
||||
|
||||
function capitaliseFirstLetter(string)
|
||||
{
|
||||
{
|
||||
return string.charAt(0).toUpperCase() + string.slice(1);
|
||||
}
|
||||
}
|
||||
|
||||
function getTitleFromUri(uri) {
|
||||
var origin = getOriginForUri(uri);
|
||||
var realmWrapper = getRealmWrapperForOrigin(origin);
|
||||
if (realmWrapper && realmWrapper.title) return realmWrapper.title;
|
||||
if (Gombot.TldService.isIpAddress(origin)) {
|
||||
return Gombot.TldService.getFullHostnameWithPort(origin);
|
||||
}
|
||||
else {
|
||||
return capitaliseFirstLetter(Gombot.TldService.getDomain(origin).split(".")[0]);
|
||||
}
|
||||
var origin = getOriginForUri(uri);
|
||||
var realmWrapper = getRealmWrapperForOrigin(origin);
|
||||
if (realmWrapper && realmWrapper.title) return realmWrapper.title;
|
||||
if (Gombot.TldService.isIpAddress(origin)) {
|
||||
return Gombot.TldService.getFullHostnameWithPort(origin);
|
||||
}
|
||||
else {
|
||||
return capitaliseFirstLetter(Gombot.TldService.getDomain(origin).split(".")[0]);
|
||||
}
|
||||
}
|
||||
|
||||
// a realm is defined by an array of origins, maybe some with wildcards
|
||||
// fqOrigin must be fully qualified (no wildcards)
|
||||
function isOriginMemberOfRealm(fqOrigin, origins) {
|
||||
var i;
|
||||
for (i=0;i<origins.length;i++) {
|
||||
if (fullyQualifiedOriginMatchesRealmOrigin(fqOrigin,origins[i])) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
var i;
|
||||
for (i=0;i<origins.length;i++) {
|
||||
if (fullyQualifiedOriginMatchesRealmOrigin(fqOrigin,origins[i])) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function isUriMemberOfRealm(uri, origins) {
|
||||
return isOriginMemberOfRealm(getOriginForUri(uri), origins);
|
||||
return isOriginMemberOfRealm(getOriginForUri(uri), origins);
|
||||
}
|
||||
|
||||
buildRealms(SiteConfigs);
|
||||
buildRealms(SiteConfigs);
|
||||
|
||||
return {
|
||||
buildRealms: buildRealms,
|
||||
getRealmForOrigin: getRealmForOrigin,
|
||||
getOriginForUri: getOriginForUri,
|
||||
getRealmForUri: getRealmForUri,
|
||||
isUriMemberOfRealm: isUriMemberOfRealm,
|
||||
getTitleFromUri: getTitleFromUri
|
||||
};
|
||||
return {
|
||||
buildRealms: buildRealms,
|
||||
getRealmForOrigin: getRealmForOrigin,
|
||||
getOriginForUri: getOriginForUri,
|
||||
getRealmForUri: getRealmForUri,
|
||||
isUriMemberOfRealm: isUriMemberOfRealm,
|
||||
getTitleFromUri: getTitleFromUri
|
||||
};
|
||||
}
|
||||
|
||||
if (typeof module !== "undefined" && module.exports) {
|
||||
module.exports = Realms;
|
||||
}
|
||||
}
|
|
@ -31,7 +31,8 @@ $(document).ready(function() {
|
|||
e.preventDefault();
|
||||
});
|
||||
$('#export-data-link').click(function(e) {
|
||||
backgroundPage.downloadExportDataFile();
|
||||
// This functionality was removed for now.
|
||||
//backgroundPage.downloadExportDataFile();
|
||||
e.preventDefault();
|
||||
});
|
||||
initBrowserAction();
|
||||
|
|
|
@ -1,4 +1,9 @@
|
|||
var PasswordFormInspector = function($, PasswordForm, DomMonitor) {
|
||||
// TODO: put these in config so we can use them in both PasswordFromInspector and PasswordForm
|
||||
const VALID_USERNAME_INPUT_TYPES = ['text','email','url','tel','number'];
|
||||
|
||||
const INPUT_USERNAME_SELECTORS = $.map(VALID_USERNAME_INPUT_TYPES, function(type) { return "input[type="+type+"]"; }).join(",");
|
||||
|
||||
var running = false;
|
||||
|
||||
var observers = [];
|
||||
|
@ -26,16 +31,11 @@ var PasswordFormInspector = function($, PasswordForm, DomMonitor) {
|
|||
}
|
||||
|
||||
function getFormForElement($el) {
|
||||
var $closestForm = $el.closest('form');
|
||||
if ($closestForm.length === 0) {
|
||||
// Could not find an HTML form, so now just look for any element that
|
||||
// contains both the password field and some other input field with type=text.
|
||||
// Note: this will also find inputs with no type specified, which defaults to text.
|
||||
console.log("Could not find form element for el=", $el.get(0));
|
||||
$closestForm = $el.parents().has('input:text');
|
||||
if ($closestForm.length === 0) {
|
||||
$closestForm = $('body');
|
||||
}
|
||||
// Find the closest parent that also contains an input field that looks
|
||||
// like a username
|
||||
var $closestForm = $el.parents().has(INPUT_USERNAME_SELECTORS).first();
|
||||
if (!$closestForm || $closestForm.length === 0) {
|
||||
$closestForm = $('body');
|
||||
}
|
||||
return $closestForm;
|
||||
}
|
||||
|
@ -49,8 +49,12 @@ var PasswordFormInspector = function($, PasswordForm, DomMonitor) {
|
|||
$containingForm = getFormForElement($passwordEl),
|
||||
numPasswordInputs = $containingForm.find('input[type=password]').length;
|
||||
// If the containing form contains multiple password field, then ignore
|
||||
// for now. This is probably a change password field.
|
||||
if (numPasswordInputs > 1) return;
|
||||
// for now. This is probably a change password field or a signup field
|
||||
if (numPasswordInputs > 1) {
|
||||
console.log("found more than 1 password input, bailing");
|
||||
return;
|
||||
}
|
||||
|
||||
passwordForms.push(new PasswordForm({ id: generateId(),
|
||||
passwordEl: passwordEl,
|
||||
containingEl: $containingForm.get(0),
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
"content_scripts": [
|
||||
{
|
||||
"matches": ["<all_urls>"],
|
||||
"all_frames": true,
|
||||
"js": ["lib/jquery.js",
|
||||
"lib/underscore.js",
|
||||
"content_scripts/content_messaging.js",
|
||||
|
|
|
@ -144,6 +144,7 @@
|
|||
<script src="../../server/client/sjcl-with-cbc.js"></script>
|
||||
<script src="../../server/client/crypto.js"></script>
|
||||
<script src="../../server/client/client.js"></script>
|
||||
<script src="../../content_scripts/content_messaging.js"></script>
|
||||
<script src="create_account.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
$(document).ready(function() {
|
||||
var Gombot = chrome.extension.getBackgroundPage().Gombot;
|
||||
var userCollection = Gombot.users;
|
||||
var messenger = ContentMessaging();
|
||||
|
||||
var busy = false;
|
||||
|
||||
|
@ -26,22 +25,19 @@ $(document).ready(function() {
|
|||
var newsletter = $('[name="newsletter"]').is(':checked');
|
||||
var pin = $('[name="pin"]').get()[0].value;
|
||||
ProgressIndicator.show();
|
||||
var user = new Gombot.User({
|
||||
'email': email,
|
||||
'pin': pin
|
||||
});
|
||||
|
||||
user.save(null,{
|
||||
success: function() {
|
||||
ProgressIndicator.hide();
|
||||
Gombot.setCurrentUser(user);
|
||||
userCollection.add(user);
|
||||
window.location = '/pages/first_run/success.html';
|
||||
busy = false;
|
||||
},
|
||||
error: function(args) {
|
||||
console.log("ERROR", args);
|
||||
if (args.response && args.response.errorMessage.match(/That email has already been used/)) {
|
||||
messenger.messageToChrome({
|
||||
type: 'create_user',
|
||||
message: {
|
||||
password: password,
|
||||
email: email,
|
||||
pin: pin,
|
||||
newsletter: newsletter
|
||||
}
|
||||
}, function(err) {
|
||||
if (err) {
|
||||
console.log("ERROR", err);
|
||||
if (err.response && err.response.errorMessage.match(/That email has already been used/)) {
|
||||
$('.email').addClass('used');
|
||||
$('html, body').animate({
|
||||
scrollTop: $("#email").offset().top
|
||||
|
@ -50,9 +46,11 @@ $(document).ready(function() {
|
|||
// TODO: handle any errors
|
||||
ProgressIndicator.hide();
|
||||
busy = false;
|
||||
},
|
||||
password: password,
|
||||
newsletter: newsletter
|
||||
} else {
|
||||
ProgressIndicator.hide();
|
||||
window.location = '/pages/first_run/success.html';
|
||||
busy = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
else { // validation problem
|
||||
|
|
|
@ -109,6 +109,7 @@
|
|||
<script src="../../server/client/sjcl-with-cbc.js"></script>
|
||||
<script src="../../server/client/crypto.js"></script>
|
||||
<script src="../../server/client/client.js"></script>
|
||||
<script src="../../content_scripts/content_messaging.js"></script>
|
||||
<script src="sign_in.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -1,14 +1,7 @@
|
|||
$(document).ready(function() {
|
||||
var Gombot = chrome.extension.getBackgroundPage().Gombot;
|
||||
var userCollection = Gombot.users;
|
||||
//var server = 'https://gombot.org';
|
||||
//var client = new GombotClient(server + '/api');
|
||||
var busy = false;
|
||||
var messenger = ContentMessaging();
|
||||
|
||||
// seed entropy
|
||||
//client.context({}, function(err, data) {
|
||||
// client.timeOffset = (new Date()/1000 >>> 0) - data.server_time;
|
||||
//});
|
||||
var busy = false;
|
||||
|
||||
$('#sign-in-form').submit(function(e) {
|
||||
e.preventDefault();
|
||||
|
@ -18,22 +11,22 @@ $(document).ready(function() {
|
|||
$('#sign-in-form').removeClass('invalid');
|
||||
var email = $('[name="email"]').get()[0].value.trim();
|
||||
var password = $('[name="password"]').get()[0].value;
|
||||
var user = userCollection.find(function(obj) {
|
||||
return obj.get('email') === email;
|
||||
}) || new Gombot.User({ email: email });
|
||||
user.fetch({
|
||||
success: function() {
|
||||
ProgressIndicator.hide();
|
||||
Gombot.setCurrentUser(user);
|
||||
userCollection.add(user);
|
||||
window.location = '/pages/first_run/success.html';
|
||||
},
|
||||
error: function(err) {
|
||||
|
||||
messenger.messageToChrome({
|
||||
type: 'sign_in',
|
||||
message: {
|
||||
email: email,
|
||||
password: password
|
||||
}
|
||||
}, function(err) {
|
||||
if (err) {
|
||||
$('#sign-in-form').addClass('invalid');
|
||||
ProgressIndicator.hide();
|
||||
busy = false;
|
||||
},
|
||||
password: password
|
||||
} else {
|
||||
ProgressIndicator.hide();
|
||||
window.location = '/pages/first_run/success.html';
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
Загрузка…
Ссылка в новой задаче