summaryrefslogtreecommitdiffstats
path: root/content/manager/createAccount.js
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--content/manager/createAccount.js524
1 files changed, 524 insertions, 0 deletions
diff --git a/content/manager/createAccount.js b/content/manager/createAccount.js
new file mode 100644
index 0000000..3e331fe
--- /dev/null
+++ b/content/manager/createAccount.js
@@ -0,0 +1,524 @@
+/*
+ * This file is part of DAV-4-TbSync.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+"use strict";
+
+var { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
+var { TbSync } = ChromeUtils.import("chrome://tbsync/content/tbsync.jsm");
+
+const dav = TbSync.providers.dav;
+
+var tbSyncDavNewAccount = {
+
+ // standard data fields
+ get elementName() { return document.getElementById('tbsync.newaccount.name'); },
+ get elementUser() { return document.getElementById('tbsync.newaccount.user'); },
+ get elementPass() { return document.getElementById('tbsync.newaccount.password'); },
+ get elementServer() { return document.getElementById('tbsync.newaccount.server'); },
+ get elementCalDavServer() { return document.getElementById('tbsync.newaccount.caldavserver'); },
+ get elementCardDavServer() { return document.getElementById('tbsync.newaccount.carddavserver'); },
+ get serviceproviderlist() { return document.getElementById('tbsync.newaccount.serviceproviderlist'); },
+
+ get accountname() { return this.elementName.value.trim(); },
+ get username() { return this.elementUser.value.trim(); },
+ get password() { return this.elementPass.value.trim(); },
+ get server() { return this.elementServer.value.trim(); },
+ get calDavServer() { return this.elementCalDavServer.value.trim(); },
+ get cardDavServer() { return this.elementCardDavServer.value.trim(); },
+ get serviceprovider() { return this.serviceproviderlist.value; },
+ get userdomain() {
+ let parts = this.username.split("@");
+ if (parts.length == 2) {
+ let subparts = parts[1].split(".");
+ if (subparts.length > 1 && subparts[subparts.length-1].length > 1) return parts[1];
+ }
+ return null;
+ },
+
+ set accountname(v) { this.elementName.value = v; },
+ set username(v) { this.elementUser.value = v; },
+ set password(v) { this.elementPass.value = v; },
+ set server(v) { this.elementServer.value = v; },
+ set calDavServer(v) { this.elementCalDavServer.value = v; },
+ set cardDavServer(v) { this.elementCardDavServer.value = v; },
+
+
+
+ // final data fields on final page
+ get elementFinalName() { return document.getElementById('tbsync.finalaccount.name'); },
+ get elementFinalUser() { return document.getElementById('tbsync.finalaccount.user'); },
+ get elementFinalCalDavServer() { return document.getElementById('tbsync.finalaccount.caldavserver'); },
+ get elementFinalCardDavServer() { return document.getElementById('tbsync.finalaccount.carddavserver'); },
+
+ get finalAccountname() { return this.elementFinalName.value.trim(); },
+ get finalUsername() { return this.elementFinalUser.value.trim(); },
+ get finalCalDavServer() { return this.elementFinalCalDavServer.value.trim(); },
+ get finalCardDavServer() { return this.elementFinalCardDavServer.value.trim(); },
+
+ set finalAccountname(v) { this.elementFinalName.value = v;},
+ set finalUsername(v) {
+ this.elementFinalUser.value = v;
+ this.elementFinalUser.setAttribute("tooltiptext", v);
+ },
+ set finalCalDavServer(v) {
+ this.elementFinalCalDavServer.value = v;
+ this.elementFinalCalDavServer.setAttribute("tooltiptext", v);
+ document.getElementById("tbsyncfinalaccount.caldavserver.row").hidden = (v.trim() == "");
+ },
+ set finalCardDavServer(v) {
+ this.elementFinalCardDavServer.value = v;
+ this.elementFinalCardDavServer.setAttribute("tooltiptext", v);
+ document.getElementById("tbsyncfinalaccount.carddavserver.row").hidden = (v.trim() == "");
+ },
+
+ get validated() { return this._validated || false; },
+ set validated(v) {
+ this._validated = v;
+ if (v) {
+ this.finalAccountname = this.accountname;
+ } else {
+ this.finalAccountname = "";
+ this.finalUsername = "";
+ this.finalCalDavServer = "";
+ this.finalCardDavServer = "";
+ }
+ },
+
+
+ showSpinner: function(spinnerText) {
+ document.getElementById("tbsync.spinner").hidden = false;
+ document.getElementById("tbsync.spinner.label").value = TbSync.getString("add.spinner." + spinnerText, "dav");
+ },
+
+ hideSpinner: function() {
+ document.getElementById("tbsync.spinner").hidden = true;
+ },
+
+ onLoad: function () {
+ this.providerData = new TbSync.ProviderData("dav");
+
+ //init list
+ this.serviceproviderlist.appendChild(this.addProviderEntry("sabredav32.png", "discovery"));
+ this.serviceproviderlist.appendChild(this.addProviderEntry("sabredav32.png", "custom"));
+ for (let p in dav.sync.serviceproviders) {
+ this.serviceproviderlist.appendChild(this.addProviderEntry(dav.sync.serviceproviders[p].icon +"32.png", p));
+ }
+
+ document.addEventListener("wizardfinish", tbSyncDavNewAccount.onFinish.bind(this));
+ document.addEventListener("wizardnext", tbSyncDavNewAccount.onAdvance.bind(this));
+ document.addEventListener("wizardcancel", tbSyncDavNewAccount.onCancel.bind(this));
+ document.getElementById("firstPage").addEventListener("pageshow", tbSyncDavNewAccount.resetFirstPage.bind(this));
+ document.getElementById("secondPage").addEventListener("pageshow", tbSyncDavNewAccount.resetSecondPage.bind(this));
+ document.getElementById("thirdPage").addEventListener("pageshow", tbSyncDavNewAccount.resetThirdPage.bind(this));
+
+ this.serviceproviderlist.selectedIndex = 0;
+ tbSyncDavNewAccount.resetFirstPage();
+ },
+
+ onUnload: function () {
+ },
+
+ onClose: function () {
+ //disallow closing of wizard while isLocked
+ return !this.isLocked;
+ },
+
+ onCancel: function (event) {
+ //disallow closing of wizard while isLocked
+ if (this.isLocked) {
+ event.preventDefault();
+ }
+ },
+
+ onFinish () {
+ let newAccountEntry = this.providerData.getDefaultAccountEntries();
+ newAccountEntry.createdWithProviderVersion = this.providerData.getVersion();
+ newAccountEntry.serviceprovider = this.serviceprovider == "discovery" ? "custom" : this.serviceprovider;
+ newAccountEntry.serviceproviderRevision = dav.sync.serviceproviders.hasOwnProperty(this.serviceprovider) ? dav.sync.serviceproviders[this.serviceprovider].revision : 0
+ newAccountEntry.calDavHost = this.finalCalDavServer;
+ newAccountEntry.cardDavHost = this.finalCardDavServer;
+
+ // Add the new account.
+ let newAccountData = this.providerData.addAccount(this.finalAccountname, newAccountEntry);
+ dav.network.getAuthData(newAccountData).updateLoginData(this.finalUsername, this.password);
+ },
+
+
+
+
+
+ // HELPER FUNCTIONS
+ addProviderEntry: function (icon, serviceprovider) {
+ let name = TbSync.getString("add.serverprofile."+serviceprovider, "dav");
+ let description = TbSync.getString("add.serverprofile."+serviceprovider+".description", "dav");
+
+ //left column
+ let image = document.createXULElement("image");
+ image.setAttribute("src", "chrome://dav4tbsync/content/skin/" + icon);
+ image.setAttribute("style", "margin:1ex;");
+
+ let leftColumn = document.createXULElement("vbox");
+ leftColumn.appendChild(image);
+
+ //right column
+ let label = document.createXULElement("label");
+ label.setAttribute("class", "header");
+ label.setAttribute("value", name);
+
+ let desc = document.createXULElement("description");
+ desc.setAttribute("style", "width: 300px");
+ desc.textContent = description;
+
+ let rightColumn = document.createXULElement("vbox");
+ rightColumn.appendChild(label);
+ rightColumn.appendChild(desc);
+
+ //columns
+ let columns = document.createXULElement("hbox");
+ columns.appendChild(leftColumn);
+ columns.appendChild(rightColumn);
+
+ //richlistitem
+ let richlistitem = document.createXULElement("richlistitem");
+ richlistitem.setAttribute("style", "padding:4px");
+ richlistitem.setAttribute("value", serviceprovider);
+ richlistitem.appendChild(columns);
+
+ return richlistitem;
+ },
+
+ checkUrlForPrincipal: async function (job) {
+ // according to RFC6764, we must also try the username with cut-off domain part
+ // Note: This is never called for OAUTH serves (see onAdvance)
+ let users = [];
+ users.push(this.username);
+ if (this.userdomain) users.push(this.username.split("@")[0]);
+
+ for (let user of users) {
+ let connectionData = new dav.network.ConnectionData();
+ connectionData.password = this.password;
+ connectionData.username = user;
+ connectionData.timeout = 5000;
+
+ //only needed for proper error reporting - that dav needs this is beyond API - connectionData is not used by TbSync
+ //connectionData is a structure which contains all the information needed to establish and evaluate a network connection
+ connectionData.eventLogInfo = new TbSync.EventLogInfo("dav", this.accountname);
+
+ job.valid = false;
+ job.error = "";
+
+ try {
+ let response = await dav.network.sendRequest("<d:propfind "+dav.tools.xmlns(["d"])+"><d:prop><d:current-user-principal /></d:prop></d:propfind>", job.server , "PROPFIND", connectionData, {"Depth": "0", "Prefer": "return=minimal"}, {containerRealm: "setup", containerReset: true, passwordRetries: 0});
+ // allow 404 because iCloud sends it on valid answer (yeah!)
+ let principal = (response && response.multi) ? dav.tools.getNodeTextContentFromMultiResponse(response, [["d","prop"], ["d","current-user-principal"], ["d","href"]], null, ["200","404"]) : null;
+ job.valid = (principal !== null);
+ if (!job.valid) {
+ job.error = job.type + "servernotfound";
+ TbSync.eventlog.add("warning", connectionData.eventLogInfo, job.error, response ? response.commLog : "");
+ } else {
+ job.validUser = user;
+ job.validUrl = (response ? response.permanentlyRedirectedUrl : null) || job.server;
+ return;
+ }
+ } catch (e) {
+ job.valid = false;
+ job.error = (e.statusData ? e.statusData.message : e.message);
+
+ if (e.name == "dav4tbsync") {
+ TbSync.eventlog.add("warning", connectionData.eventLogInfo, e.statusData.message, e.statusData.details);
+ } else {
+ Components.utils.reportError(e);
+ }
+ }
+
+ // only retry with other user, if 401
+ if (!job.error.startsWith("401")) {
+ break;
+ }
+ }
+
+ return;
+ },
+
+ advance: function () {
+ document.getElementById("tbsync.newaccount.wizard").advance(null);
+ },
+
+
+
+
+
+ // RESET AND INIT FUNCTIONS
+ clearValues: function () {
+ //clear fields
+ this.username = "";
+ this.password = "";
+ this.server = "";
+ this.calDavServer = "";
+ this.cardDavServer = "";
+
+ if (this.serviceprovider == "discovery" || this.serviceprovider == "custom") {
+ this.accountname = "";
+ } else {
+ this.accountname = TbSync.getString("add.serverprofile." + this.serviceprovider, "dav");
+ }
+ },
+
+ resetFirstPage: function () {
+ // RESET / INIT first page
+ document.getElementById("tbsync.newaccount.wizard").canRewind = false;
+ document.getElementById("tbsync.newaccount.wizard").canAdvance = true;
+ // bug https://bugzilla.mozilla.org/show_bug.cgi?id=1618252
+ document.getElementById('tbsync.newaccount.wizard')._adjustWizardHeader();
+ this.isLocked = false;
+ this.validated = false;
+ },
+
+ resetSecondPage: function () {
+ // RESET / INIT second page
+ this.isLocked = false;
+ this.validated = false;
+
+ document.getElementById("tbsync.newaccount.wizard").canRewind = true;
+ document.getElementById("tbsync.newaccount.wizard").canAdvance = false;
+ this.hideSpinner();
+ document.getElementById("tbsync.error").hidden = true;
+
+ this.checkUI();
+ },
+
+ resetThirdPage: function () {
+ // RESET / INIT third page
+ document.getElementById("tbsync.newaccount.wizard").canRewind = true;
+ document.getElementById("tbsync.newaccount.wizard").canAdvance = true;
+ this.isLocked = false;
+ },
+
+
+
+
+
+ // UI FUNCTIONS
+ lockUI: function(spinnerText) {
+ this.showSpinner(spinnerText);
+ document.getElementById("tbsync.error").hidden = true;
+ document.getElementById("tbsync.newaccount.wizard").canAdvance = false;
+ document.getElementById("tbsync.newaccount.wizard").canRewind = false;
+ this.isLocked = true;
+ },
+
+ unlockUI: function() {
+ this.hideSpinner();
+ document.getElementById("tbsync.newaccount.wizard").canRewind = true;
+ this.isLocked = false;
+ this.checkUI();
+ },
+
+ checkUI: function (hideError) {
+ if (hideError) {
+ document.getElementById("tbsync.error").hidden = true;
+ }
+
+ // determine, if we can advance or not
+ if (this.serviceprovider == "discovery") {
+ document.getElementById("tbsync.newaccount.wizard").canAdvance = !(
+ (this.accountname == "") ||
+ (this.server == "" && !this.userdomain) ||
+ (this.server == "" && this.username == ""));
+ } else if (this.serviceprovider == "custom") {
+ // custom does not need username or password (allow annonymous access)
+ document.getElementById("tbsync.newaccount.wizard").canAdvance = !(
+ (this.accountname == "") ||
+ (this.calDavServer + this.cardDavServer == ""));
+ } else {
+ // build in service providers do need a username and password
+ document.getElementById("tbsync.newaccount.wizard").canAdvance = !(
+ (this.accountname == "") ||
+ (this.password == "") ||
+ (this.username == ""));
+ }
+
+ // update placeholder attribute of server
+ this.elementServer.setAttribute("placeholder", this.userdomain ? TbSync.getString("add.serverprofile.discovery.server-optional", "dav") : "");
+
+
+ //show/hide additional descriptions (if avail)
+ let dFound = 0;
+ for (let i=1; i < 4; i++) {
+ let dElement = document.getElementById("tbsync.newaccount.details" + i);
+ let dLocaleString = "add.serverprofile." + this.serviceprovider + ".details" + i;
+ let dLocaleValue = TbSync.getString(dLocaleString, "dav");
+
+ let hide = (dLocaleValue == dLocaleString);
+ if (this.serviceprovider == "discovery") {
+ // show them according to UI state
+ switch (i) {
+ case 1:
+ hide = false;
+ break;
+ case 2:
+ hide = !this.userdomain;
+ break;
+ }
+ }
+
+ if (hide) {
+ dElement.textContent = "";
+ dElement.hidden = true;
+ } else {
+ dFound++;
+ dElement.textContent = dLocaleValue
+ dElement.hidden =false;
+ }
+ }
+
+ //hide Notes header, if no descriptions avail
+ let dLabel = document.getElementById("tbsync.newaccount.details.header");
+ dLabel.hidden = (dFound == 0);
+
+
+ //which server fields to show?
+ document.getElementById("tbsync.newaccount.finaluser.row").hidden = false;
+ document.getElementById("tbsync.newaccount.user.row").hidden = false;
+ document.getElementById("tbsync.newaccount.password.row").hidden = false;
+
+ if (this.serviceprovider == "discovery") {
+ document.getElementById("tbsync.newaccount.caldavserver.row").hidden = true;
+ document.getElementById("tbsync.newaccount.carddavserver.row").hidden = true;
+ document.getElementById("tbsync.newaccount.server.row").hidden = false;
+ //this.elementCalDavServer.disabled = false;
+ //this.elementCardDavServer.disabled = false;
+ } else if (this.serviceprovider == "custom") {
+ // custom
+ document.getElementById("tbsync.newaccount.caldavserver.row").hidden = false;
+ document.getElementById("tbsync.newaccount.carddavserver.row").hidden = false;
+ document.getElementById("tbsync.newaccount.server.row").hidden = true;
+ //this.elementCalDavServer.disabled = false;
+ //this.elementCardDavServer.disabled = false;
+ } else {
+ // build in service provider
+ document.getElementById("tbsync.newaccount.caldavserver.row").hidden = true;
+ document.getElementById("tbsync.newaccount.carddavserver.row").hidden = true;
+ document.getElementById("tbsync.newaccount.server.row").hidden = true;
+ //this.elementCalDavServer.disabled = true;
+ //this.elementCardDavServer.disabled = true;
+ this.calDavServer = dav.sync.serviceproviders[this.serviceprovider].caldav;
+ this.cardDavServer = dav.sync.serviceproviders[this.serviceprovider].carddav;
+ }
+ },
+
+
+
+
+
+ // SETUP LOGIC FUNCTION
+ onAdvance: function (event) {
+ // do not prevent advancing if we go from page 1 to page 2, or if validation succeeded
+ if (document.getElementById("tbsync.newaccount.wizard").currentPage.id == "firstPage" || this.validated) {
+ return;
+ }
+
+ // if we reach this, we are on page 2 but may not advance but
+ // go through the setup steps
+
+ if (this.serviceprovider == "discovery") {
+ while (this.server.endsWith("/")) { this.server = this.server.slice(0,-1); }
+ // the user may either specify a server or he could have entered an email with domain
+ let parts = (this.server || this.userdomain).split("://");
+ let scheme = (parts.length > 1) ? parts[0].toLowerCase() : "";
+ let host = parts[parts.length-1];
+
+ this.calDavServer = scheme + "caldav6764://" + host;
+ this.cardDavServer = scheme + "carddav6764://" + host;
+ this.validateDavServers();
+ } else {
+ // custom or service provider
+ this.validateDavServers();
+ }
+
+ event.preventDefault();
+ },
+
+ validateDavServers: async function() {
+ this.lockUI("validating");
+
+ // Do not manipulate input here.
+ //while (this.calDavServer.endsWith("/")) { this.calDavServer = this.calDavServer.slice(0,-1); }
+ //while (this.cardDavServer.endsWith("/")) { this.cardDavServer = this.cardDavServer.slice(0,-1); }
+
+ // Default to https, if http is not explicitly specified
+ if (this.calDavServer && !dav.network.startsWithScheme(this.calDavServer)) {
+ this.calDavServer = "https://" + this.calDavServer;
+ }
+ if (this.cardDavServer && !dav.network.startsWithScheme(this.cardDavServer)) {
+ this.cardDavServer = "https://" + this.cardDavServer;
+ }
+
+ let davJobs = [
+ {type: "caldav", server: this.calDavServer},
+ {type: "carddav", server: this.cardDavServer},
+ ];
+
+ let failedDavJobs = [];
+ let validUserFound = "";
+
+ for (let job = 0; job < davJobs.length; job++) {
+ if (!davJobs[job].server) {
+ continue;
+ }
+ await this.checkUrlForPrincipal(davJobs[job]);
+ if (!davJobs[job].valid) {
+ failedDavJobs.push(job);
+ } else if (!validUserFound) {
+ // set the found user
+ validUserFound = davJobs[job].validUser;
+ } else if (validUserFound != davJobs[job].validUser) {
+ // users do not match
+ failedDavJobs.push(job);
+ }
+ }
+
+ if (failedDavJobs.length == 0) {
+ // boom, setup completed
+ this.finalCalDavServer = davJobs[0].validUrl || "";
+ this.finalCardDavServer = davJobs[1].validUrl || "";
+ this.finalUsername = validUserFound;
+ this.validated = true;
+ this.unlockUI();
+ this.advance();
+ return;
+ } else {
+ //only display one error
+ let failedJob = failedDavJobs[0];
+ console.log("ERROR ("+davJobs[failedJob].type+"): " + davJobs[failedJob].error.toString());
+ switch (davJobs[failedJob].error.toString().split("::")[0]) {
+ case "401":
+ case "403":
+ case "503":
+ case "security":
+ document.getElementById("tbsync.error.message").textContent = TbSync.getString("status."+davJobs[failedJob].error, "dav");
+ break;
+ default:
+ if (this.serviceprovider == "discovery" && this.userdomain && !this.server) {
+ // the discovery mode has a special error msg, in case a userdomain was used as server, but failed and we need the user to provide the server
+ document.getElementById("tbsync.error.message").textContent = TbSync.getString("status.rfc6764-lookup-failed::" +this.userdomain, "dav");
+ } else if (this.serviceprovider != "discovery" && this.serviceprovider != "custom") {
+ // error msg, that the serviceprovider setup seems wrong
+ document.getElementById("tbsync.error.message").textContent = TbSync.getString("status.service-provider-setup-failed", "dav");
+ } else if (dav.network.isRFC6764Request(davJobs[failedJob].server)) {
+ // error msg, that discovery mode failed
+ document.getElementById("tbsync.error.message").textContent = TbSync.getString("status.service-discovery-failed::" +davJobs[failedJob].server.split("://")[1], "dav");
+ } else {
+ document.getElementById("tbsync.error.message").textContent = TbSync.getString("status." + davJobs[failedJob].type + "servernotfound", "dav");
+ }
+ }
+ document.getElementById("tbsync.error").hidden = false;
+ this.unlockUI();
+ }
+ },
+};