Skip to content

Commit d189db2

Browse files
committed
Add random password generation support for each upload
The generated password is printed at the beginning of the message body. Also, if it disable the random password option, the fixed password is printed at the beginning of the message body. Fixes: #54 Signed-off-by: Jun Futagawa <jfut@integ.jp>
1 parent 0a1135f commit d189db2

9 files changed

Lines changed: 111 additions & 3 deletions

File tree

src/chrome/content/settings.js

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
* string, value: *}, port: {type: string, value: (string|string|string|Number)},
2929
* storageFolder: {type: string, value: (string|string|string|Number)}, username: {type:
3030
* string, value: (string|string|string|Number)}, protectUploads: {type: string, value:
31-
* (string|string|string|Number)}}}
31+
* (string|string|string|Number), useRandomPassword: {type: bool, value: bool}}}
3232
*/
3333
function extraArgs () {
3434
let displayName = document.getElementById("displayName").value;
@@ -37,6 +37,7 @@ function extraArgs () {
3737
let storageFolderValue = document.getElementById("storageFolder").value;
3838
let userValue = document.getElementById("username").value;
3939
let protectUploadsValue = document.getElementById("protectUploads").value;
40+
let useRandomPasswordValue = document.getElementById("useRandomPassword").checked;
4041

4142
return {
4243
"displayName": {
@@ -62,6 +63,19 @@ function extraArgs () {
6263
"protectUploads": {
6364
type: "char",
6465
value: protectUploadsValue
66+
},
67+
"useRandomPassword": {
68+
type: "bool",
69+
value: useRandomPasswordValue
6570
}
6671
};
6772
}
73+
74+
function onUseRandomPasswordClick () {
75+
let useRandomPassword = document.getElementById("useRandomPassword").checked;
76+
if (useRandomPassword) {
77+
document.getElementById("protectUploads").disabled = "disabled";
78+
} else {
79+
document.getElementById("protectUploads").disabled = "";
80+
}
81+
}

src/chrome/content/settings.xhtml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,9 @@
5050
<input id="storageFolder" type="text" required="true" value="/Mail-attachments"/>
5151
<label for="protectUploads">&nextcloudSettings.protectUploads;</label>
5252
<input id="protectUploads" type="password" value=""/>
53+
<label for="useRandomPassword">
54+
<input id="useRandomPassword" type="checkbox" style="display: inline-block; width: auto;" onclick="onUseRandomPasswordClick();"/>&nextcloudSettings.useRandomPassword;
55+
</label>
5356
</form>
5457
<div id="learn-more">
5558
<a href="https://nextcloud.com/">&nextcloudSettings.learnMore;</a>

src/chrome/locale/de/settings.dtd

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,3 +30,4 @@
3030
<!ENTITY nextcloudSettings.username "Benutzername">
3131
<!ENTITY nextcloudSettings.password "Passwort">
3232
<!ENTITY nextcloudSettings.protectUploads "Passwort für hochgeladene Dateien">
33+
<!ENTITY nextcloudSettings.useRandomPassword "Verwenden Sie für jeden Upload ein zufälliges Passwort">

src/chrome/locale/en/settings.dtd

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,3 +30,4 @@
3030
<!ENTITY nextcloudSettings.username "Username">
3131
<!ENTITY nextcloudSettings.password "Password">
3232
<!ENTITY nextcloudSettings.protectUploads "Password for uploaded files">
33+
<!ENTITY nextcloudSettings.useRandomPassword "Use random password for each upload">

src/chrome/locale/es/settings.dtd

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,3 +30,4 @@
3030
<!ENTITY nextcloudSettings.username "Nombre de usuario">
3131
<!ENTITY nextcloudSettings.password "Contraseña">
3232
<!ENTITY nextcloudSettings.protectUploads "Contraseña para archivos cargados">
33+
<!ENTITY nextcloudSettings.useRandomPassword "Utilice una contraseña aleatoria para cada carga">

src/chrome/locale/fr/settings.dtd

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,3 +30,4 @@
3030
<!ENTITY nextcloudSettings.username "Nom d'utilisateur">
3131
<!ENTITY nextcloudSettings.password "Mot de passe">
3232
<!ENTITY nextcloudSettings.protectUploads "Mot de passe pour fichiers téléversés">
33+
<!ENTITY nextcloudSettings.useRandomPassword "Utilisez un mot de passe aléatoire pour chaque téléchargement">

src/chrome/locale/nl/settings.dtd

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,3 +30,4 @@
3030
<!ENTITY nextcloudSettings.username "Gebruikersnaam">
3131
<!ENTITY nextcloudSettings.password "Wachtwoord">
3232
<!ENTITY nextcloudSettings.protectUploads "Wachtwoord voor geüploade bestanden">
33+
<!ENTITY nextcloudSettings.useRandomPassword "Gebruik een willekeurig wachtwoord voor elke upload">

src/chrome/locale/pl/settings.dtd

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,3 +30,4 @@
3030
<!ENTITY nextcloudSettings.username "Twoja nazwa użytkownika">
3131
<!ENTITY nextcloudSettings.password "Twoje hasło">
3232
<!ENTITY nextcloudSettings.protectUploads "Hasło dostępu do wgranych załączników">
33+
<!ENTITY nextcloudSettings.useRandomPassword "Użyj losowego hasła do każdego przesyłania">

src/components/nsNextcloud.js

Lines changed: 87 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@ Nextcloud.prototype = {
114114
_userName: "",
115115
_password: "",
116116
_protectUploads: "",
117+
_useRandomPassword: false,
117118
_prefBranch: null,
118119
_loggedIn: false,
119120
_authToken: "",
@@ -133,6 +134,7 @@ Nextcloud.prototype = {
133134
_uploads: [],
134135
_urlsForFiles: {},
135136
_uploadInfo: {}, // upload info keyed on aFiles.
137+
_messageWindow: null,
136138

137139
/**
138140
* Initialize this instance of Nextcloud, setting the accountKey.
@@ -168,6 +170,14 @@ Nextcloud.prototype = {
168170
if (this._prefBranch.prefHasUserValue("protectUploads")) {
169171
this._protectUploads = this._prefBranch.getCharPref("protectUploads");
170172
}
173+
174+
if (this._prefBranch.prefHasUserValue("useRandomPassword")) {
175+
this._useRandomPassword = this._prefBranch.getBoolPref("useRandomPassword");
176+
}
177+
178+
let windowMediator = Components.classes["@mozilla.org/appshell/window-mediator;1"]
179+
.getService(Components.interfaces.nsIWindowMediator);
180+
this._messageWindow = windowMediator.getMostRecentWindow("msgcompose");
171181
},
172182

173183
/**
@@ -237,6 +247,32 @@ Nextcloud.prototype = {
237247
* @param aFile the nsILocalFile to retrieve the URL for
238248
*/
239249
urlForFile: function nsNc_urlForFile (aFile) {
250+
if (this._uploadInfo["downloadPassword"] == null) {
251+
return this._urlsForFiles[aFile.path];
252+
}
253+
254+
// Output download password
255+
let document = this._messageWindow.document;
256+
let contentFrame = document.getElementById("content-frame");
257+
let contentDocument = contentFrame.contentDocument;
258+
this.log.debug("Document body: " + contentDocument.body.innerHTML);
259+
260+
let cloudAttachmentPasswordList = contentDocument.getElementById("cloudAttachmentPasswordList");
261+
if (cloudAttachmentPasswordList == null) {
262+
// First cloud attachment
263+
contentDocument.body.insertAdjacentHTML("afterbegin",
264+
'<div id="cloudAttachmentPasswordList"></div>');
265+
cloudAttachmentPasswordList = contentDocument.getElementById("cloudAttachmentPasswordList");
266+
}
267+
cloudAttachmentPasswordList.insertAdjacentHTML("beforeend",
268+
'<div class="cloudAttachmentPassword">* Download password for '
269+
+ aFile.leafName + ":<br>"
270+
+ this._uploadInfo["downloadPassword"] + '</div>');
271+
272+
if (contentFrame.editortype == "textmail") {
273+
// Start a new line before url
274+
return "\n" + this._urlsForFiles[aFile.path];
275+
}
240276
return this._urlsForFiles[aFile.path];
241277
},
242278

@@ -866,8 +902,15 @@ NextcloudFileUploader.prototype = {
866902

867903
let formData = "shareType=" + shareType + "&path=" + path;
868904
// Request a password for the link if it has been defined during setup time
869-
if (this.nextcloud._protectUploads.length) {
870-
formData += "&password=" + wwwFormUrlEncode(this.nextcloud._protectUploads);
905+
let downloadPassword = this.nextcloud._protectUploads;
906+
// Use random password for each upload
907+
if (this.nextcloud._useRandomPassword) {
908+
downloadPassword = this._generatePassword(16);
909+
}
910+
if (downloadPassword.length) {
911+
this.log.debug("FormData password: " + downloadPassword);
912+
this.nextcloud._uploadInfo["downloadPassword"] = downloadPassword;
913+
formData += "&password=" + wwwFormUrlEncode(downloadPassword);
871914
}
872915

873916
req.open("POST",
@@ -918,6 +961,48 @@ NextcloudFileUploader.prototype = {
918961
}.bind(this);
919962
this.log.debug("Raw formData: " + formData);
920963
req.send(formData);
964+
},
965+
966+
/**
967+
* A private function which generates a password.
968+
*
969+
* On Nextcloud, most strict password policy require:
970+
* - Enforce upper and lower case characters
971+
* - Enforce numeric characters
972+
* - Enforce special characters
973+
*
974+
* @param length password length
975+
* @private
976+
*/
977+
_generatePassword: function generatePassword(length) {
978+
const lower = "abcdefghijklmnopqrstuvwxyz";
979+
const upper = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
980+
const numeric = "0123456789"
981+
// Excludes characters that fail to output if continuous: <>
982+
const special = "!\"#$%&'()*+,-./:;=?@[\\]^_`{|}~";
983+
const seed = lower + upper + numeric + special;
984+
985+
const lowerRegex = new RegExp("[" + lower + "]");
986+
const upperRegex = new RegExp("[" + upper + "]");
987+
const numericRegex = new RegExp("[" + numeric + "]");
988+
const specialRegex = new RegExp("[" + special + "]");
989+
990+
let limit = 100000;
991+
let i = 0;
992+
let password = "";
993+
while (i < limit) {
994+
i++;
995+
password = Array.from(Array(length)).map(() => seed[Math.floor(Math.random() * seed.length)]).join("");
996+
997+
if (!lowerRegex.test(password)) continue;
998+
if (!upperRegex.test(password)) continue;
999+
if (!numericRegex.test(password)) continue;
1000+
if (!specialRegex.test(password)) continue;
1001+
1002+
break;
1003+
}
1004+
this.log.debug("Generated password: " + i + ": " + password);
1005+
return password;
9211006
}
9221007
};
9231008

0 commit comments

Comments
 (0)