diff --git a/services/sync/modules/service.js b/services/sync/modules/service.js index 66b497befcaf..6dc68c295fa2 100644 --- a/services/sync/modules/service.js +++ b/services/sync/modules/service.js @@ -85,6 +85,25 @@ WeaveSvc.prototype = { _loggedIn: false, keyGenEnabled: true, + get account() Svc.Prefs.get("account", this.username), + set account(value) { + if (value) { + value = value.toLowerCase(); + Svc.Prefs.set("account", value); + } else { + Svc.Prefs.reset("account"); + } + this.username = this._usernameFromAccount(value); + }, + + _usernameFromAccount: function _usernameFromAccount(value) { + // If we encounter characters not allowed by the API (as found for + // instance in an email address), hash the value. + if (value && value.match(/[^A-Z0-9._-]/i)) + return Utils.sha1Base32(value.toLowerCase()).toLowerCase(); + return value; + }, + get username() { return Svc.Prefs.get("username", "").toLowerCase(); }, @@ -92,9 +111,6 @@ WeaveSvc.prototype = { if (value) { // Make sure all uses of this new username is lowercase value = value.toLowerCase(); - // Tab characters are stripped from URIs, so make sure that the - // username doesn't contain any tabs. - value = value.replace("\t", "", "g"); Svc.Prefs.set("username", value); } else @@ -831,7 +847,13 @@ WeaveSvc.prototype = { } }, - checkUsername: function WeaveSvc_checkUsername(username) { + // Backwards compat with the Firefox UI. Remove once bug 595066 has landed. + checkUsername: function checkUsername(username) { + return this.checkAccount(username); + }, + + checkAccount: function checkAccount(account) { + let username = this._usernameFromAccount(account); let url = this.userAPI + username; let res = new Resource(url); res.authenticator = new NoOpAuthenticator(); @@ -853,8 +875,9 @@ WeaveSvc.prototype = { return this._errorStr(data); }, - createAccount: function WeaveSvc_createAccount(username, password, email, + createAccount: function WeaveSvc_createAccount(account, password, email, captchaChallenge, captchaResponse) { + let username = this._usernameFromAccount(account); let payload = JSON.stringify({ "password": Utils.encodeUTF8(password), "email": email, diff --git a/services/sync/tests/unit/test_service_attributes.js b/services/sync/tests/unit/test_service_attributes.js index 48d3d431b281..03a62919c8d9 100644 --- a/services/sync/tests/unit/test_service_attributes.js +++ b/services/sync/tests/unit/test_service_attributes.js @@ -5,24 +5,16 @@ Cu.import("resource://services-sync/service.js"); Cu.import("resource://services-sync/status.js"); Cu.import("resource://services-sync/util.js"); -function test_urlsAndIdentities() { - _("Various Service properties correspond to preference settings and update other object properties upon being set."); +function test_identities() { + _("Account related Service properties correspond to preference settings and update other object properties upon being set."); try { _("Verify initial state"); + do_check_eq(Svc.Prefs.get("account"), undefined); do_check_eq(Svc.Prefs.get("username"), undefined); - do_check_eq(PubKeys.defaultKeyUri, undefined); - do_check_eq(PrivKeys.defaultKeyUri, undefined); do_check_eq(ID.get("WeaveID").username, ""); do_check_eq(ID.get("WeaveCryptoID").username, ""); - do_check_true(!!Service.serverURL); // actual value may change - do_check_eq(Service.clusterURL, ""); - do_check_eq(Service.userBaseURL, undefined); - do_check_eq(Service.infoURL, undefined); - do_check_eq(Service.storageURL, undefined); - do_check_eq(Service.metaURL, undefined); - _("The 'username' attribute is normalized to lower case, updates preferences and identities."); Service.username = "TarZan"; do_check_eq(Service.username, "tarzan"); @@ -30,6 +22,58 @@ function test_urlsAndIdentities() { do_check_eq(ID.get("WeaveID").username, "tarzan"); do_check_eq(ID.get("WeaveCryptoID").username, "tarzan"); + _("If not set, the 'account attribute' falls back to the username for backwards compatibility."); + do_check_eq(Service.account, "tarzan"); + + _("Setting 'username' to a non-truthy value resets the pref."); + Service.username = null; + do_check_eq(Service.username, ""); + do_check_eq(Service.account, ""); + const default_marker = {}; + do_check_eq(Svc.Prefs.get("username", default_marker), default_marker); + do_check_eq(ID.get("WeaveID").username, null); + do_check_eq(ID.get("WeaveCryptoID").username, null); + + _("The 'account' attribute will set the 'username' if it doesn't contain characters that aren't allowed in the username."); + Service.account = "johndoe"; + do_check_eq(Service.account, "johndoe"); + do_check_eq(Service.username, "johndoe"); + do_check_eq(Svc.Prefs.get("username"), "johndoe"); + do_check_eq(ID.get("WeaveID").username, "johndoe"); + do_check_eq(ID.get("WeaveCryptoID").username, "johndoe"); + + _("If 'account' contains disallowed characters such as @, 'username' will the base32 encoded SHA1 hash of 'account'"); + Service.account = "John@Doe.com"; + do_check_eq(Service.account, "john@doe.com"); + do_check_eq(Service.username, "7wohs32cngzuqt466q3ge7indszva4of"); + + _("Setting 'account' to a non-truthy value resets the pref."); + Service.account = null; + do_check_eq(Service.account, ""); + do_check_eq(Svc.Prefs.get("account", default_marker), default_marker); + do_check_eq(Service.username, ""); + do_check_eq(Svc.Prefs.get("username", default_marker), default_marker); + + } finally { + Svc.Prefs.resetBranch(""); + } +} + +function test_urls() { + _("URL related Service properties corresopnd to preference settings."); + try { + do_check_eq(PubKeys.defaultKeyUri, undefined); + do_check_eq(PrivKeys.defaultKeyUri, undefined); + do_check_true(!!Service.serverURL); // actual value may change + do_check_eq(Service.clusterURL, ""); + do_check_eq(Service.userBaseURL, undefined); + do_check_eq(Service.infoURL, undefined); + do_check_eq(Service.storageURL, undefined); + do_check_eq(Service.metaURL, undefined); + + _("The 'clusterURL' attribute updates preferences and cached URLs."); + Service.username = "johndoe"; + // Since we don't have a cluster URL yet, these will still not be defined. do_check_eq(Service.infoURL, undefined); do_check_eq(Service.userBaseURL, undefined); @@ -38,15 +82,6 @@ function test_urlsAndIdentities() { do_check_eq(PubKeys.defaultKeyUri, undefined); do_check_eq(PrivKeys.defaultKeyUri, undefined); - _("Tabs are stripped from the 'username' attribute as they can't be part of a URI."); - Service.username = "jo\thn\tdoe"; - - do_check_eq(Service.username, "johndoe"); - do_check_eq(Svc.Prefs.get("username"), "johndoe"); - do_check_eq(ID.get("WeaveID").username, "johndoe"); - do_check_eq(ID.get("WeaveCryptoID").username, "johndoe"); - - _("The 'clusterURL' attribute updates preferences and cached URLs."); Service.serverURL = "http://weave.server/"; Service.clusterURL = "http://weave.cluster/"; do_check_eq(Svc.Prefs.get("clusterURL"), "http://weave.cluster/"); @@ -198,7 +233,8 @@ function test_locked() { } function run_test() { - test_urlsAndIdentities(); + test_identities(); + test_urls(); test_syncID(); test_prefAttributes(); test_locked(); diff --git a/services/sync/tests/unit/test_service_checkUsername.js b/services/sync/tests/unit/test_service_checkAccount.js similarity index 55% rename from services/sync/tests/unit/test_service_checkUsername.js rename to services/sync/tests/unit/test_service_checkAccount.js index 5374833f89fc..06861da86a92 100644 --- a/services/sync/tests/unit/test_service_checkUsername.js +++ b/services/sync/tests/unit/test_service_checkAccount.js @@ -12,19 +12,24 @@ function run_test() { do_test_pending(); let server = httpd_setup({ "/user/1.0/johndoe": send(200, "OK", "1"), - "/user/1.0/janedoe": send(200, "OK", "0") + "/user/1.0/janedoe": send(200, "OK", "0"), + // john@doe.com + "/user/1.0/7wohs32cngzuqt466q3ge7indszva4of": send(200, "OK", "0") }); try { Service.serverURL = "http://localhost:8080/"; _("A 404 will be recorded as 'generic-server-error'"); - do_check_eq(Service.checkUsername("jimdoe"), "generic-server-error"); + do_check_eq(Service.checkAccount("jimdoe"), "generic-server-error"); - _("Username that's not available."); - do_check_eq(Service.checkUsername("johndoe"), "notAvailable"); + _("Account that's not available."); + do_check_eq(Service.checkAccount("johndoe"), "notAvailable"); - _("Username that's available."); - do_check_eq(Service.checkUsername("janedoe"), "available"); + _("Account that's available."); + do_check_eq(Service.checkAccount("janedoe"), "available"); + + _("Email address based account."); + do_check_eq(Service.checkAccount("john@doe.com"), "available"); } finally { Svc.Prefs.resetBranch(""); diff --git a/services/sync/tests/unit/test_service_createAccount.js b/services/sync/tests/unit/test_service_createAccount.js index 8d45c6bdb23d..c633f9d6f4d8 100644 --- a/services/sync/tests/unit/test_service_createAccount.js +++ b/services/sync/tests/unit/test_service_createAccount.js @@ -19,6 +19,8 @@ function run_test() { do_test_pending(); let server = httpd_setup({ "/user/1.0/johndoe": send(200, "OK", "0"), + // john@doe.com + "/user/1.0/7wohs32cngzuqt466q3ge7indszva4of": send(200, "OK", "0"), "/user/1.0/janedoe": send(400, "Bad Request", "2"), "/user/1.0/jimdoe": send(500, "Server Error", "Server Error") }); @@ -35,6 +37,11 @@ function run_test() { do_check_eq(payload["captcha-challenge"], "challenge"); do_check_eq(payload["captcha-response"], "response"); + _("Create an email address based account."); + res = Service.createAccount("john@doe.com", "mysecretpw", "john@doe.com", + "challenge", "response"); + do_check_eq(res, null); + _("A non-ASCII password is UTF-8 encoded."); res = Service.createAccount("johndoe", "moneyislike$\u20ac\xa5\u5143", "john@doe", "challenge", "response");