1
|
|
|
/** |
2
|
|
|
* Nextcloud - passman |
3
|
|
|
* |
4
|
|
|
* @copyright Copyright (c) 2016, Sander Brand ([email protected]) |
5
|
|
|
* @copyright Copyright (c) 2016, Marcos Zuriaga Miguel ([email protected]) |
6
|
|
|
* @license GNU AGPL version 3 or any later version |
7
|
|
|
* |
8
|
|
|
* This program is free software: you can redistribute it and/or modify |
9
|
|
|
* it under the terms of the GNU Affero General Public License as |
10
|
|
|
* published by the Free Software Foundation, either version 3 of the |
11
|
|
|
* License, or (at your option) any later version. |
12
|
|
|
* |
13
|
|
|
* This program is distributed in the hope that it will be useful, |
14
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
15
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
16
|
|
|
* GNU Affero General Public License for more details. |
17
|
|
|
* |
18
|
|
|
* You should have received a copy of the GNU Affero General Public License |
19
|
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>. |
20
|
|
|
* |
21
|
|
|
*/ |
22
|
|
|
|
23
|
|
|
(function () { |
24
|
|
|
'use strict'; |
25
|
|
|
|
26
|
|
|
/** |
27
|
|
|
* @ngdoc directive |
28
|
|
|
* @name passmanApp.directive:passwordGen |
29
|
|
|
* @description |
30
|
|
|
* # passwordGen |
31
|
|
|
*/ |
32
|
|
|
|
33
|
|
|
angular.module('passmanApp') |
34
|
|
|
.directive('passwordGen', function ($timeout, $translate) { |
35
|
|
|
/* jshint ignore:start */ |
36
|
|
|
function Arcfour () { |
37
|
|
|
this.j = this.i = 0, this.S = [] |
|
|
|
|
38
|
|
|
} |
39
|
|
|
|
40
|
|
|
function ARC4init (r) { |
41
|
|
|
var t, n, e; |
42
|
|
|
for (t = 0; 256 > t; ++t)this.S[t] = t |
|
|
|
|
43
|
|
|
for (t = n = 0; 256 > t; ++t)n = n + this.S[t] + r[t % r.length] & 255, e = this.S[t], this.S[t] = this.S[n], this.S[n] = e |
|
|
|
|
44
|
|
|
this.j = this.i = 0 |
45
|
|
|
} |
46
|
|
|
|
47
|
|
|
function ARC4next () { |
48
|
|
|
var r; |
49
|
|
|
return this.i = this.i + 1 & 255, this.j = this.j + this.S[this.i] & 255, r = this.S[this.i], this.S[this.i] = this.S[this.j], this.S[this.j] = r, this.S[r + this.S[this.i] & 255] |
|
|
|
|
50
|
|
|
} |
51
|
|
|
|
52
|
|
|
function prng_newstate () { |
53
|
|
|
return new Arcfour |
54
|
|
|
} |
55
|
|
|
|
56
|
|
|
function generatePassword (r, t, n, e, o, i, p, g) { |
57
|
|
|
var _, a, s, f, d, h, u, l, c, v, w, y, m; |
58
|
|
|
if (void 0 === r && (r = 8 + get_random(0, 1)), r > 256 && (r = 256, document.getElementById("length").value = 256), i > 256 && (i = 256), void 0 === t && (t = !0), void 0 === n && (n = !0), void 0 === e && (e = !0), void 0 === o && (o = !1), void 0 === i && (i = 0), void 0 === p && (p = !1), void 0 === g && (g = !0), _ = 0, a = 0, s = 0, g && (_ = a = s = 1), f = [], n && _ > 0)for (d = 0; _ > d; d++)f[f.length] = "L" |
|
|
|
|
59
|
|
|
if (t && a > 0)for (d = 0; a > d; d++)f[f.length] = "U" |
|
|
|
|
60
|
|
|
if (e && i > 0)for (d = 0; i > d; d++)f[f.length] = "D" |
|
|
|
|
61
|
|
|
if (o && s > 0)for (d = 0; s > d; d++)f[f.length] = "S" |
|
|
|
|
62
|
|
|
for (; f.length < r;)f[f.length] = "A" |
|
|
|
|
63
|
|
|
for (f.sort(function () { |
64
|
|
|
return 2 * get_random(0, 1) - 1 |
65
|
|
|
}), h = "", u = "abcdefghjkmnpqrstuvwxyz", p || (u += "ilo"), n && (h += u), l = "ABCDEFGHJKMNPQRSTUVWXYZ", p || (l += "ILO"), t && (h += l), c = "23456789", p || (c += "10"), e && (h += c), v = "!@#$%^&*", o && (h += v), w = "", y = 0; r > y; y++) { |
66
|
|
|
switch (f[y]) { |
|
|
|
|
67
|
|
|
case"L": |
68
|
|
|
m = u; |
69
|
|
|
break; |
70
|
|
|
case"U": |
71
|
|
|
m = l; |
72
|
|
|
break; |
73
|
|
|
case"D": |
74
|
|
|
m = c; |
75
|
|
|
break; |
76
|
|
|
case"S": |
77
|
|
|
m = v; |
78
|
|
|
break; |
79
|
|
|
case"A": |
80
|
|
|
m = h |
81
|
|
|
} |
82
|
|
|
d = get_random(0, m.length - 1), w += m.charAt(d) |
|
|
|
|
83
|
|
|
} |
84
|
|
|
return w |
85
|
|
|
} |
86
|
|
|
|
87
|
|
|
function rng_seed_int (r) { |
88
|
|
|
rng_pool[rng_pptr++] ^= 255 & r, rng_pool[rng_pptr++] ^= r >> 8 & 255, rng_pool[rng_pptr++] ^= r >> 16 & 255, rng_pool[rng_pptr++] ^= r >> 24 & 255, rng_pptr >= rng_psize && (rng_pptr -= rng_psize) |
|
|
|
|
89
|
|
|
} |
90
|
|
|
|
91
|
|
|
function rng_seed_time () { |
92
|
|
|
rng_seed_int((new Date).getTime()) |
93
|
|
|
} |
94
|
|
|
|
95
|
|
|
function rng_get_byte () { |
96
|
|
|
if (null == rng_state) { |
97
|
|
|
for (rng_seed_time(), rng_state = prng_newstate(), rng_state.init(rng_pool), rng_pptr = 0; rng_pptr < rng_pool.length; ++rng_pptr)rng_pool[rng_pptr] = 0 |
|
|
|
|
98
|
|
|
rng_pptr = 0 |
99
|
|
|
} |
100
|
|
|
return rng_state.next() |
|
|
|
|
101
|
|
|
} |
102
|
|
|
|
103
|
|
|
function rng_get_bytes (r) { |
104
|
|
|
var t; |
105
|
|
|
for (t = 0; t < r.length; ++t)r[t] = rng_get_byte() |
|
|
|
|
106
|
|
|
} |
107
|
|
|
|
108
|
|
|
function SecureRandom () { |
109
|
|
|
} |
110
|
|
|
|
111
|
|
|
function get_random (r, t) { |
112
|
|
|
var n, e, o, i = t - r + 1 |
113
|
|
|
for (rng_seed_time(), n = [], e = 0; 4 > e; e++)n[e] = 0 |
|
|
|
|
114
|
|
|
for (rng_get_bytes(n), o = 0, e = 0; 4 > e; e++)o *= 256, o += n[e] |
|
|
|
|
115
|
|
|
return o %= i, o += r |
|
|
|
|
116
|
|
|
} |
117
|
|
|
|
118
|
|
|
function get_random_password (r, t) { |
|
|
|
|
119
|
|
|
var n; |
120
|
|
|
var pwlen, newpw; |
121
|
|
|
for ("number" != typeof r && (r = 12), "number" != typeof t && (t = 16), r > t && (n = r, r = t, t = n), pwlen = get_random(r, t), newpw = ""; newpw.length < pwlen;)newpw += String.fromCharCode(get_random(32, 127)) |
|
|
|
|
122
|
|
|
return newpw |
123
|
|
|
} |
124
|
|
|
|
125
|
|
|
var rng_psize, rng_state, rng_pool, rng_pptr, t, z, crypt_obj, num, buf, i |
126
|
|
|
if (Arcfour.prototype.init = ARC4init, Arcfour.prototype.next = ARC4next, rng_psize = 256, null == rng_pool) { |
|
|
|
|
127
|
|
|
/** global: navigator */ |
128
|
|
|
if (rng_pool = [], rng_pptr = 0, "undefined" != typeof navigator && "Netscape" == navigator.appName && navigator.appVersion < "5" && "undefined" != typeof window && window.crypto)for (z = window.crypto.random(32), t = 0; t < z.length; ++t)rng_pool[rng_pptr++] = 255 & z.charCodeAt(t) |
|
|
|
|
129
|
|
|
try { |
130
|
|
|
if (crypt_obj = null, "undefined" != typeof window && void 0 !== window.crypto ? crypt_obj = window.crypto : "undefined" != typeof window && void 0 !== window.msCrypto && (crypt_obj = window.msCrypto), void 0 !== crypt_obj && "function" == typeof crypt_obj.getRandomValues && rng_psize > rng_pptr)for (num = Math.floor((rng_psize - rng_pptr) / 2) + 1, buf = new Uint16Array(num), crypt_obj.getRandomValues(buf), i = 0; i < buf.length; i++)t = buf[i], rng_pool[rng_pptr++] = t >>> 8, rng_pool[rng_pptr++] = 255 & t |
|
|
|
|
131
|
|
|
} catch (e) { |
|
|
|
|
132
|
|
|
} |
133
|
|
|
for (; rng_psize > rng_pptr;)t = Math.floor(65536 * sjcl.random.randomWords(1)), rng_pool[rng_pptr++] = t >>> 8, rng_pool[rng_pptr++] = 255 & t |
|
|
|
|
134
|
|
|
rng_pptr = 0, rng_seed_time() |
|
|
|
|
135
|
|
|
} |
136
|
|
|
SecureRandom.prototype.nextBytes = rng_get_bytes; |
137
|
|
|
/* jshint ignore:end */ |
138
|
|
|
return { |
139
|
|
|
scope: { |
140
|
|
|
model: "=ngModel", |
141
|
|
|
length: "@", |
142
|
|
|
placeholder: "@", |
143
|
|
|
settings: '=settings', |
144
|
|
|
callback: '&callback' |
145
|
|
|
}, |
146
|
|
|
|
147
|
|
|
restrict: "E", |
148
|
|
|
replace: "true", |
149
|
|
|
template: "" + |
150
|
|
|
"<div class=\" pw-gen \">" + |
151
|
|
|
"<div class=\"input-group \">" + |
152
|
|
|
"<input ng-show=\"!passwordVisible\" type=\"password\" ng-disabled=\"disabled\" class=\"form-control \" ng-model=\"password\" placeholder=\"{{placeholder}}\">" + |
153
|
|
|
"<input ng-show=\"passwordVisible\" type=\"text\" ng-disabled=\"disabled\" class=\"form-control \" ng-model=\"password\" placeholder=\"{{placeholder}}\">" + |
154
|
|
|
|
155
|
|
|
'<span class="generate_pw">' + |
156
|
|
|
'<div class="cell" tooltip="gen_msg" ng-click="generatePasswordStart()"><i class="fa fa-refresh"></i></div>' + |
157
|
|
|
'<div class="cell" tooltip="tggltxt" ng-click="toggleVisibility()"><i class="fa" ng-class="{\'fa-eye\': passwordVisible, \'fa-eye-slash\': !passwordVisible }"></i></div>' + |
158
|
|
|
'<div class="cell" tooltip="\'Copy password to clipboard\'"><i class="fa fa-clipboard" ngclipboard-success="onSuccess(e);" ngclipboard-error="onError(e);" ngclipboard data-clipboard-text="{{password}}"></i></div>' + |
159
|
|
|
"</button>" + |
160
|
|
|
"</div>" + |
161
|
|
|
"</div>", |
162
|
|
|
link: function (scope) { |
163
|
|
|
scope.callback = scope.callback(); |
164
|
|
|
scope.$watch("model", function () { |
165
|
|
|
scope.password = scope.model; |
166
|
|
|
}); |
167
|
|
|
scope.passwordVisible = false; |
168
|
|
|
scope.toggleVisibility = function () { |
169
|
|
|
scope.passwordVisible = !scope.passwordVisible; |
170
|
|
|
}; |
171
|
|
|
|
172
|
|
|
scope.passwordNotNull = false; |
173
|
|
|
scope.$watch("settings", function () { |
174
|
|
|
if (scope.settings) { |
175
|
|
|
if (!scope.password && scope.settings.generateOnCreate) { |
176
|
|
|
scope.generatePasswordStart(); |
177
|
|
|
} |
178
|
|
|
} |
179
|
|
|
}); |
180
|
|
|
|
181
|
|
|
$translate(['password.gen', 'password.copy', 'copied', 'toggle.visibility']).then(function (translations) { |
182
|
|
|
scope.tggltxt = translations['toggle.visibility']; |
183
|
|
|
scope.copy_msg = translations['password.copy']; |
184
|
|
|
scope.gen_msg = translations['password.gen']; |
185
|
|
|
}); |
186
|
|
|
|
187
|
|
|
scope.$watch("password", function () { |
188
|
|
|
scope.model = scope.password; |
189
|
|
|
scope.password_repeat = scope.model; |
190
|
|
|
}); |
191
|
|
|
// |
192
|
|
|
scope.onSuccess = function (e) { |
193
|
|
|
//@TODO move OC.Notification to a service |
194
|
|
|
OC.Notification.showTemporary($translate.instant('password.copied')); |
195
|
|
|
e.clearSelection(); |
196
|
|
|
}; |
197
|
|
|
|
198
|
|
|
scope.onError = function () { |
199
|
|
|
OC.Notification.showTemporary('Press Ctrl+C to copy!'); |
200
|
|
|
}; |
201
|
|
|
scope.progressDivShow = false; |
202
|
|
|
scope.generatePasswordStart = function () { |
203
|
|
|
scope.progressDivShow = true; |
204
|
|
|
scope.progressValue = 0; |
205
|
|
|
scope.progressWidth = {"width": scope.progressValue + "%"}; |
206
|
|
|
scope.generatePasswordProgress(); |
207
|
|
|
}; |
208
|
|
|
scope.generatePasswordProgress = function () { |
209
|
|
|
$timeout(function () { |
210
|
|
|
if (scope.progressValue < 100) { |
211
|
|
|
scope.password = scope._generatePassword(scope.settings); |
212
|
|
|
scope.progressValue += 10; |
213
|
|
|
scope.progressWidth = {"width": scope.progressValue + "%"}; |
214
|
|
|
scope.disabled = true; |
215
|
|
|
scope.generatePasswordProgress(); |
216
|
|
|
} else { |
217
|
|
|
scope.disabled = false; |
218
|
|
|
if (scope.callback) { |
219
|
|
|
scope.callback(scope.password); |
220
|
|
|
} |
221
|
|
|
} |
222
|
|
|
}, 10); |
223
|
|
|
}; |
224
|
|
|
|
225
|
|
|
|
226
|
|
|
scope._generatePassword = function (settings) { |
227
|
|
|
var _settings = { |
228
|
|
|
'length': 12, |
229
|
|
|
'useUppercase': true, |
230
|
|
|
'useLowercase': true, |
231
|
|
|
'useDigits': true, |
232
|
|
|
'useSpecialChars': true, |
233
|
|
|
'minimumDigitCount': 3, |
234
|
|
|
'avoidAmbiguousCharacters': false, |
235
|
|
|
'requireEveryCharType': true |
236
|
|
|
}; |
237
|
|
|
settings = angular.merge(_settings, settings); |
238
|
|
|
/* jshint ignore:start */ |
239
|
|
|
var password = generatePassword(settings['length'], |
240
|
|
|
settings.useUppercase, |
241
|
|
|
settings.useLowercase, |
242
|
|
|
settings.useDigits, |
243
|
|
|
settings.useSpecialChars, |
244
|
|
|
settings.minimumDigitCount, |
245
|
|
|
settings.avoidAmbiguousCharacters, |
246
|
|
|
settings.requireEveryCharType); |
247
|
|
|
/* jshint ignore:end */ |
248
|
|
|
return password; |
249
|
|
|
}; |
250
|
|
|
} |
251
|
|
|
}; |
252
|
|
|
}); |
253
|
|
|
}()); |
The sequence or comma operator allows the inclusion of multiple expressions where only is permitted. The result of the sequence is the value of the last expression.
This operator is most often used in
for
statements.Used in another places it can make code hard to read, especially when people do not realize it even exists as a seperate operator.
This check looks for usage of the sequence operator in locations where it is not necessary and could be replaced by a series of expressions or statements.
could just as well be written as:
To learn more about the sequence operator, please refer to the MDN.