diff --git a/src/chrome/content/settings.js b/src/chrome/content/settings.js
index d354f6b..00e2061 100644
--- a/src/chrome/content/settings.js
+++ b/src/chrome/content/settings.js
@@ -28,7 +28,7 @@
* string, value: *}, port: {type: string, value: (string|string|string|Number)},
* storageFolder: {type: string, value: (string|string|string|Number)}, username: {type:
* string, value: (string|string|string|Number)}, protectUploads: {type: string, value:
- * (string|string|string|Number)}}}
+ * (string|string|string|Number), useRandomPassword: {type: bool, value: bool}}}
*/
function extraArgs () {
let displayName = document.getElementById("displayName").value;
@@ -37,6 +37,7 @@ function extraArgs () {
let storageFolderValue = document.getElementById("storageFolder").value;
let userValue = document.getElementById("username").value;
let protectUploadsValue = document.getElementById("protectUploads").value;
+ let useRandomPasswordValue = document.getElementById("useRandomPassword").checked;
return {
"displayName": {
@@ -62,6 +63,19 @@ function extraArgs () {
"protectUploads": {
type: "char",
value: protectUploadsValue
+ },
+ "useRandomPassword": {
+ type: "bool",
+ value: useRandomPasswordValue
}
};
}
+
+function onUseRandomPasswordClick () {
+ let useRandomPassword = document.getElementById("useRandomPassword").checked;
+ if (useRandomPassword) {
+ document.getElementById("protectUploads").disabled = "disabled";
+ } else {
+ document.getElementById("protectUploads").disabled = "";
+ }
+}
diff --git a/src/chrome/content/settings.xhtml b/src/chrome/content/settings.xhtml
index 9cf0926..f3e2b90 100644
--- a/src/chrome/content/settings.xhtml
+++ b/src/chrome/content/settings.xhtml
@@ -50,6 +50,9 @@
+
&nextcloudSettings.learnMore;
diff --git a/src/chrome/locale/de/settings.dtd b/src/chrome/locale/de/settings.dtd
index 155f3f4..0716e2c 100644
--- a/src/chrome/locale/de/settings.dtd
+++ b/src/chrome/locale/de/settings.dtd
@@ -30,3 +30,4 @@
+
diff --git a/src/chrome/locale/en/settings.dtd b/src/chrome/locale/en/settings.dtd
index 97f1a83..db641c5 100644
--- a/src/chrome/locale/en/settings.dtd
+++ b/src/chrome/locale/en/settings.dtd
@@ -30,3 +30,4 @@
+
diff --git a/src/chrome/locale/es/settings.dtd b/src/chrome/locale/es/settings.dtd
index 37b1fb0..af19c8e 100644
--- a/src/chrome/locale/es/settings.dtd
+++ b/src/chrome/locale/es/settings.dtd
@@ -30,3 +30,4 @@
+
diff --git a/src/chrome/locale/fr/settings.dtd b/src/chrome/locale/fr/settings.dtd
index c476944..0557d43 100644
--- a/src/chrome/locale/fr/settings.dtd
+++ b/src/chrome/locale/fr/settings.dtd
@@ -30,3 +30,4 @@
+
diff --git a/src/chrome/locale/nl/settings.dtd b/src/chrome/locale/nl/settings.dtd
index c7deb62..dcfae27 100644
--- a/src/chrome/locale/nl/settings.dtd
+++ b/src/chrome/locale/nl/settings.dtd
@@ -30,3 +30,4 @@
+
diff --git a/src/chrome/locale/pl/settings.dtd b/src/chrome/locale/pl/settings.dtd
index 2f4ad48..a492e0f 100644
--- a/src/chrome/locale/pl/settings.dtd
+++ b/src/chrome/locale/pl/settings.dtd
@@ -30,3 +30,4 @@
+
diff --git a/src/components/nsNextcloud.js b/src/components/nsNextcloud.js
index f20ab9a..9e09d9e 100644
--- a/src/components/nsNextcloud.js
+++ b/src/components/nsNextcloud.js
@@ -114,6 +114,7 @@ Nextcloud.prototype = {
_userName: "",
_password: "",
_protectUploads: "",
+ _useRandomPassword: false,
_prefBranch: null,
_loggedIn: false,
_authToken: "",
@@ -133,6 +134,7 @@ Nextcloud.prototype = {
_uploads: [],
_urlsForFiles: {},
_uploadInfo: {}, // upload info keyed on aFiles.
+ _messageWindow: null,
/**
* Initialize this instance of Nextcloud, setting the accountKey.
@@ -168,6 +170,14 @@ Nextcloud.prototype = {
if (this._prefBranch.prefHasUserValue("protectUploads")) {
this._protectUploads = this._prefBranch.getCharPref("protectUploads");
}
+
+ if (this._prefBranch.prefHasUserValue("useRandomPassword")) {
+ this._useRandomPassword = this._prefBranch.getBoolPref("useRandomPassword");
+ }
+
+ let windowMediator = Components.classes["@mozilla.org/appshell/window-mediator;1"]
+ .getService(Components.interfaces.nsIWindowMediator);
+ this._messageWindow = windowMediator.getMostRecentWindow("msgcompose");
},
/**
@@ -237,6 +247,32 @@ Nextcloud.prototype = {
* @param aFile the nsILocalFile to retrieve the URL for
*/
urlForFile: function nsNc_urlForFile (aFile) {
+ if (this._uploadInfo["downloadPassword"] == null) {
+ return this._urlsForFiles[aFile.path];
+ }
+
+ // Output download password
+ let document = this._messageWindow.document;
+ let contentFrame = document.getElementById("content-frame");
+ let contentDocument = contentFrame.contentDocument;
+ this.log.debug("Document body: " + contentDocument.body.innerHTML);
+
+ let cloudAttachmentPasswordList = contentDocument.getElementById("cloudAttachmentPasswordList");
+ if (cloudAttachmentPasswordList == null) {
+ // First cloud attachment
+ contentDocument.body.insertAdjacentHTML("afterbegin",
+ '
');
+ cloudAttachmentPasswordList = contentDocument.getElementById("cloudAttachmentPasswordList");
+ }
+ cloudAttachmentPasswordList.insertAdjacentHTML("beforeend",
+ '
* Download password for '
+ + aFile.leafName + ":
"
+ + this._uploadInfo["downloadPassword"] + '
');
+
+ if (contentFrame.editortype == "textmail") {
+ // Start a new line before url
+ return "\n" + this._urlsForFiles[aFile.path];
+ }
return this._urlsForFiles[aFile.path];
},
@@ -866,8 +902,15 @@ NextcloudFileUploader.prototype = {
let formData = "shareType=" + shareType + "&path=" + path;
// Request a password for the link if it has been defined during setup time
- if (this.nextcloud._protectUploads.length) {
- formData += "&password=" + wwwFormUrlEncode(this.nextcloud._protectUploads);
+ let downloadPassword = this.nextcloud._protectUploads;
+ // Use random password for each upload
+ if (this.nextcloud._useRandomPassword) {
+ downloadPassword = this._generatePassword(16);
+ }
+ if (downloadPassword.length) {
+ this.log.debug("FormData password: " + downloadPassword);
+ this.nextcloud._uploadInfo["downloadPassword"] = downloadPassword;
+ formData += "&password=" + wwwFormUrlEncode(downloadPassword);
}
req.open("POST",
@@ -918,6 +961,48 @@ NextcloudFileUploader.prototype = {
}.bind(this);
this.log.debug("Raw formData: " + formData);
req.send(formData);
+ },
+
+ /**
+ * A private function which generates a password.
+ *
+ * On Nextcloud, most strict password policy require:
+ * - Enforce upper and lower case characters
+ * - Enforce numeric characters
+ * - Enforce special characters
+ *
+ * @param length password length
+ * @private
+ */
+ _generatePassword: function generatePassword(length) {
+ const lower = "abcdefghijklmnopqrstuvwxyz";
+ const upper = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+ const numeric = "0123456789"
+ // Excludes characters that fail to output if continuous: <>
+ const special = "!\"#$%&'()*+,-./:;=?@[\\]^_`{|}~";
+ const seed = lower + upper + numeric + special;
+
+ const lowerRegex = new RegExp("[" + lower + "]");
+ const upperRegex = new RegExp("[" + upper + "]");
+ const numericRegex = new RegExp("[" + numeric + "]");
+ const specialRegex = new RegExp("[" + special + "]");
+
+ let limit = 100000;
+ let i = 0;
+ let password = "";
+ while (i < limit) {
+ i++;
+ password = Array.from(Array(length)).map(() => seed[Math.floor(Math.random() * seed.length)]).join("");
+
+ if (!lowerRegex.test(password)) continue;
+ if (!upperRegex.test(password)) continue;
+ if (!numericRegex.test(password)) continue;
+ if (!specialRegex.test(password)) continue;
+
+ break;
+ }
+ this.log.debug("Generated password: " + i + ": " + password);
+ return password;
}
};