merge of master; slight refactor of messaging and localstorage modules

This commit is contained in:
Chris Karlof 2013-01-25 11:55:43 -08:00
Родитель 991b248f9a 8479a970dc
Коммит 0863c3d63b
23 изменённых файлов: 494 добавлений и 236 удалений

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;
}

176
background/main.js Normal file
Просмотреть файл

@ -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);
}

65
background/messaging.js Normal file
Просмотреть файл

@ -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';
}
});
});
});