Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add random password generation support for each upload #76

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 15 additions & 1 deletion src/chrome/content/settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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": {
Expand All @@ -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 = "";
}
}
3 changes: 3 additions & 0 deletions src/chrome/content/settings.xhtml
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,9 @@
<input id="storageFolder" type="text" required="true" value="/Mail-attachments"/>
<label for="protectUploads">&nextcloudSettings.protectUploads;</label>
<input id="protectUploads" type="password" value=""/>
<label for="useRandomPassword">
<input id="useRandomPassword" type="checkbox" style="display: inline-block; width: auto;" onclick="onUseRandomPasswordClick();"/>&nextcloudSettings.useRandomPassword;
</label>
</form>
<div id="learn-more">
<a href="https://nextcloud.com/">&nextcloudSettings.learnMore;</a>
Expand Down
1 change: 1 addition & 0 deletions src/chrome/locale/de/settings.dtd
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,4 @@
<!ENTITY nextcloudSettings.username "Benutzername">
<!ENTITY nextcloudSettings.password "Passwort">
<!ENTITY nextcloudSettings.protectUploads "Passwort für hochgeladene Dateien">
<!ENTITY nextcloudSettings.useRandomPassword "Verwenden Sie für jeden Upload ein zufälliges Passwort">
1 change: 1 addition & 0 deletions src/chrome/locale/en/settings.dtd
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,4 @@
<!ENTITY nextcloudSettings.username "Username">
<!ENTITY nextcloudSettings.password "Password">
<!ENTITY nextcloudSettings.protectUploads "Password for uploaded files">
<!ENTITY nextcloudSettings.useRandomPassword "Use random password for each upload">
1 change: 1 addition & 0 deletions src/chrome/locale/es/settings.dtd
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,4 @@
<!ENTITY nextcloudSettings.username "Nombre de usuario">
<!ENTITY nextcloudSettings.password "Contraseña">
<!ENTITY nextcloudSettings.protectUploads "Contraseña para archivos cargados">
<!ENTITY nextcloudSettings.useRandomPassword "Utilice una contraseña aleatoria para cada carga">
1 change: 1 addition & 0 deletions src/chrome/locale/fr/settings.dtd
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,4 @@
<!ENTITY nextcloudSettings.username "Nom d'utilisateur">
<!ENTITY nextcloudSettings.password "Mot de passe">
<!ENTITY nextcloudSettings.protectUploads "Mot de passe pour fichiers téléversés">
<!ENTITY nextcloudSettings.useRandomPassword "Utilisez un mot de passe aléatoire pour chaque téléchargement">
1 change: 1 addition & 0 deletions src/chrome/locale/nl/settings.dtd
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,4 @@
<!ENTITY nextcloudSettings.username "Gebruikersnaam">
<!ENTITY nextcloudSettings.password "Wachtwoord">
<!ENTITY nextcloudSettings.protectUploads "Wachtwoord voor geüploade bestanden">
<!ENTITY nextcloudSettings.useRandomPassword "Gebruik een willekeurig wachtwoord voor elke upload">
1 change: 1 addition & 0 deletions src/chrome/locale/pl/settings.dtd
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,4 @@
<!ENTITY nextcloudSettings.username "Twoja nazwa użytkownika">
<!ENTITY nextcloudSettings.password "Twoje hasło">
<!ENTITY nextcloudSettings.protectUploads "Hasło dostępu do wgranych załączników">
<!ENTITY nextcloudSettings.useRandomPassword "Użyj losowego hasła do każdego przesyłania">
89 changes: 87 additions & 2 deletions src/components/nsNextcloud.js
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ Nextcloud.prototype = {
_userName: "",
_password: "",
_protectUploads: "",
_useRandomPassword: false,
_prefBranch: null,
_loggedIn: false,
_authToken: "",
Expand All @@ -133,6 +134,7 @@ Nextcloud.prototype = {
_uploads: [],
_urlsForFiles: {},
_uploadInfo: {}, // upload info keyed on aFiles.
_messageWindow: null,

/**
* Initialize this instance of Nextcloud, setting the accountKey.
Expand Down Expand Up @@ -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");
},

/**
Expand Down Expand Up @@ -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",
'<div id="cloudAttachmentPasswordList"></div>');
cloudAttachmentPasswordList = contentDocument.getElementById("cloudAttachmentPasswordList");
}
cloudAttachmentPasswordList.insertAdjacentHTML("beforeend",
'<div class="cloudAttachmentPassword">* Download password for '
+ aFile.leafName + ":<br>"
+ this._uploadInfo["downloadPassword"] + '</div>');

if (contentFrame.editortype == "textmail") {
// Start a new line before url
return "\n" + this._urlsForFiles[aFile.path];
}
return this._urlsForFiles[aFile.path];
},

Expand Down Expand Up @@ -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",
Expand Down Expand Up @@ -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;
}
};

Expand Down