libves 1.0.3 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +26 -7
- package/libVES.node.js +1248 -322
- package/libves-2.0.0.tgz +0 -0
- package/package.json +7 -3
package/libVES.node.js
CHANGED
|
@@ -1,13 +1,39 @@
|
|
|
1
|
-
|
|
1
|
+
/***************************************************************************
|
|
2
|
+
* ___ ___
|
|
3
|
+
* / \ / \ VESvault
|
|
4
|
+
* \__ / \ __/ Encrypt Everything without fear of losing the Key
|
|
5
|
+
* \\ // https://vesvault.com https://ves.host
|
|
6
|
+
* \\ //
|
|
7
|
+
* ___ \\_//
|
|
8
|
+
* / \ / \ libVES: VESvault API library
|
|
9
|
+
* \__ / \ __/
|
|
10
|
+
* \\ //
|
|
11
|
+
* \\ //
|
|
12
|
+
* \\_// - Key Management and Exchange
|
|
13
|
+
* / \ - Item Encryption and Sharing
|
|
14
|
+
* \___/ - VESrecovery (TM)
|
|
15
|
+
*
|
|
16
|
+
*
|
|
17
|
+
* (c) 2017 - 2022 VESvault Corp
|
|
18
|
+
* Jim Zubov <jz@vesvault.com>
|
|
19
|
+
*
|
|
20
|
+
* GNU General Public License v3
|
|
21
|
+
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
|
|
22
|
+
* copies of the Software, and permit persons to whom the Software is
|
|
23
|
+
* furnished to do so, under the terms of the COPYING file.
|
|
24
|
+
*
|
|
25
|
+
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
|
26
|
+
* KIND, either express or implied.
|
|
27
|
+
*
|
|
2
28
|
* @title libVES
|
|
3
29
|
* @dev A JavaScript end-to-end encryption interface to VESvault REST API
|
|
4
|
-
* @version
|
|
30
|
+
* @version 2.00
|
|
5
31
|
*
|
|
6
32
|
* @dev Official source code: https://github.com/vesvault/libVES
|
|
7
33
|
*
|
|
8
|
-
* @author Jim Zubov <jz@vesvault.com> (VESvault)
|
|
9
|
-
*
|
|
10
|
-
|
|
34
|
+
* @author Jim Zubov <jz@vesvault.com> (VESvault Corp)
|
|
35
|
+
*
|
|
36
|
+
***************************************************************************/
|
|
11
37
|
|
|
12
38
|
if (!window.libVES) window.libVES = function(optns) {
|
|
13
39
|
try {
|
|
@@ -26,8 +52,8 @@ if (!window.libVES) window.libVES = function(optns) {
|
|
|
26
52
|
libVES.prototype = {
|
|
27
53
|
apiUrl: 'https://api.ves.host/v1/',
|
|
28
54
|
wwwUrl: 'https://www.vesvault.com/',
|
|
29
|
-
keyAlgo: '
|
|
30
|
-
textCipher: '
|
|
55
|
+
keyAlgo: 'ECDH',
|
|
56
|
+
textCipher: 'AES256GCMp',
|
|
31
57
|
defaultHash: 'SHA256',
|
|
32
58
|
|
|
33
59
|
request: function(method,uri,body,optns) {
|
|
@@ -62,7 +88,7 @@ libVES.prototype = {
|
|
|
62
88
|
if (body != null) xhr.setRequestHeader('Content-Type','application/json');
|
|
63
89
|
xhr.setRequestHeader('Accept','application/json');
|
|
64
90
|
if (this.user && optns.password) xhr.setRequestHeader('Authorization','Basic ' + btoa(this.user + ':' + optns.password));
|
|
65
|
-
else if (this.token) xhr.setRequestHeader('Authorization','Bearer ' + this.token);
|
|
91
|
+
else if (optns.token || this.token) xhr.setRequestHeader('Authorization','Bearer ' + (optns.token ? optns.token : this.token));
|
|
66
92
|
xhr.responseType = 'json';
|
|
67
93
|
xhr.send(body);
|
|
68
94
|
}.bind(this));
|
|
@@ -87,6 +113,18 @@ libVES.prototype = {
|
|
|
87
113
|
}
|
|
88
114
|
return '';
|
|
89
115
|
},
|
|
116
|
+
elevateAuth: function(optns) {
|
|
117
|
+
var self = this;
|
|
118
|
+
if (optns && (optns.password || optns.token)) return Promise.resolve(optns);
|
|
119
|
+
return (optns && optns.authVaultKey ? Promise.resolve(optns.authVaultKey) : self.getVaultKey()).then(function(vkey) {
|
|
120
|
+
return vkey.getSessionToken().then(function(tkn) {
|
|
121
|
+
if (!tkn) return optns;
|
|
122
|
+
var o = {token: tkn};
|
|
123
|
+
if (optns) for (var k in optns) o[k] = optns[k];
|
|
124
|
+
return o;
|
|
125
|
+
});
|
|
126
|
+
});
|
|
127
|
+
},
|
|
90
128
|
login: function(passwd) {
|
|
91
129
|
if (this.token) return this.me();
|
|
92
130
|
var self = this;
|
|
@@ -102,12 +140,83 @@ libVES.prototype = {
|
|
|
102
140
|
this.token = undefined;
|
|
103
141
|
return this.lock();
|
|
104
142
|
},
|
|
105
|
-
delegate: function() {
|
|
143
|
+
delegate: function(optns) {
|
|
106
144
|
var self = this;
|
|
107
145
|
return libVES.getModule(libVES,'Delegate').then(function(dlg) {
|
|
108
|
-
return dlg.login(self)
|
|
146
|
+
return dlg.login(self,null,optns).then(function() {
|
|
147
|
+
return self;
|
|
148
|
+
});
|
|
109
149
|
});
|
|
110
150
|
},
|
|
151
|
+
getVESflow: function() {
|
|
152
|
+
var self = this;
|
|
153
|
+
if (!this.VESflow) this.VESflow = libVES.getModule(libVES, 'Flow').then(function(fw) {
|
|
154
|
+
var flow = new fw('VES');
|
|
155
|
+
var authf = self.authorize.bind(self);
|
|
156
|
+
self.authorize = function(msg) {
|
|
157
|
+
flow.setValue(msg);
|
|
158
|
+
return authf(msg);
|
|
159
|
+
};
|
|
160
|
+
var outf = self.logout.bind(self);
|
|
161
|
+
self.logout = function() {
|
|
162
|
+
flow.logout();
|
|
163
|
+
return outf();
|
|
164
|
+
};
|
|
165
|
+
return flow;
|
|
166
|
+
});
|
|
167
|
+
return this.VESflow;
|
|
168
|
+
},
|
|
169
|
+
flow: function(start, optns) {
|
|
170
|
+
var self = this;
|
|
171
|
+
return self.getVESflow().then(function(flow) {
|
|
172
|
+
return flow.get().then(function(auth) {
|
|
173
|
+
return self.authorize(auth);
|
|
174
|
+
}).catch(function(e) {
|
|
175
|
+
if (!start || (e && e.code == 'Reload')) throw e;
|
|
176
|
+
var url = self.wwwUrl + 'vv/unlock?url=' + encodeURIComponent(document.location.href) + '&domain=' + encodeURIComponent(self.domain);
|
|
177
|
+
if (optns) for (var k in optns) if (optns[k] != null) url += '&' + encodeURIComponent(k) + '=' + encodeURIComponent(optns[k]);
|
|
178
|
+
flow.url = undefined;
|
|
179
|
+
return flow.setValue(undefined).then(function() {
|
|
180
|
+
return flow.addToken(url).then(function(url) {
|
|
181
|
+
document.location.replace(url);
|
|
182
|
+
throw {code: 'Redirect', message: 'Starting VES Authorization...'};
|
|
183
|
+
});
|
|
184
|
+
});
|
|
185
|
+
});
|
|
186
|
+
});
|
|
187
|
+
},
|
|
188
|
+
authorize: function(msg) {
|
|
189
|
+
var self = this;
|
|
190
|
+
if (msg.token) this.token = msg.token;
|
|
191
|
+
if (msg.domain) this.domain = msg.domain;
|
|
192
|
+
if (msg.externalId) this.externalId = msg.externalId;
|
|
193
|
+
return (msg.VESkey ? this.unlock(msg.VESkey) : this.me()).then(function() {
|
|
194
|
+
return self;
|
|
195
|
+
});
|
|
196
|
+
},
|
|
197
|
+
carry: function(optns) {
|
|
198
|
+
var cr = {};
|
|
199
|
+
if (this.externalId) cr.externalId = this.externalId;
|
|
200
|
+
if (this.domain) cr.domain = this.domain;
|
|
201
|
+
if (this.token) cr.token = this.token;
|
|
202
|
+
if (this.VESkey) cr.VESkey = this.VESkey;
|
|
203
|
+
try {
|
|
204
|
+
sessionStorage['libVES_carry'] = JSON.stringify(cr);
|
|
205
|
+
} catch (e) {
|
|
206
|
+
return Promise.reject(e);
|
|
207
|
+
}
|
|
208
|
+
return Promise.resolve(true);
|
|
209
|
+
},
|
|
210
|
+
pick: function(optns) {
|
|
211
|
+
try {
|
|
212
|
+
if (!sessionStorage['libVES_carry']) throw new libVES.Error('NotFound','No libVES_carry in sessionStorage');
|
|
213
|
+
var cr = JSON.parse(sessionStorage['libVES_carry']);
|
|
214
|
+
delete(sessionStorage['libVES_carry']);
|
|
215
|
+
return this.authorize(cr);
|
|
216
|
+
} catch (e) {
|
|
217
|
+
return Promise.reject(e);
|
|
218
|
+
}
|
|
219
|
+
},
|
|
111
220
|
me: function() {
|
|
112
221
|
var self = this;
|
|
113
222
|
if (!this.userMe) this.userMe = this.get('me').then((function(data) {
|
|
@@ -119,16 +228,17 @@ libVES.prototype = {
|
|
|
119
228
|
var self = this;
|
|
120
229
|
return this.getVaultKey().then(function(vkey) {
|
|
121
230
|
return vkey.unlock(Promise.resolve(veskey)).then(function(cryptoKey) {
|
|
231
|
+
if (self.VESkey === null) self.VESkey = veskey;
|
|
122
232
|
if (!self.token && self.type == 'secondary') return vkey.getSessionToken().then(function(tkn) {
|
|
123
233
|
self.token = tkn;
|
|
124
|
-
return
|
|
125
|
-
if (veskey) return vkey.reshareVESkey(veskey).catch(function(){});
|
|
126
|
-
}).then(function() {
|
|
127
|
-
return cryptoKey;
|
|
128
|
-
});
|
|
234
|
+
return cryptoKey;
|
|
129
235
|
});
|
|
130
236
|
return cryptoKey;
|
|
131
237
|
});
|
|
238
|
+
}).then(function(ck) {
|
|
239
|
+
return self.handleAttn().catch(function() {}).then(function() {
|
|
240
|
+
return ck;
|
|
241
|
+
});
|
|
132
242
|
});
|
|
133
243
|
},
|
|
134
244
|
lock: function() {
|
|
@@ -162,7 +272,7 @@ libVES.prototype = {
|
|
|
162
272
|
});
|
|
163
273
|
},
|
|
164
274
|
getVaultKeysById: function() {
|
|
165
|
-
|
|
275
|
+
return this.me().then(function(me) {
|
|
166
276
|
return me.getVaultKeys().then(function(vaultKeys) {
|
|
167
277
|
return Promise.all(vaultKeys.map(function(e,i) {
|
|
168
278
|
return e.getId();
|
|
@@ -173,7 +283,6 @@ libVES.prototype = {
|
|
|
173
283
|
});
|
|
174
284
|
});
|
|
175
285
|
});
|
|
176
|
-
return this.vaultKeysById;
|
|
177
286
|
},
|
|
178
287
|
getItems: function() {
|
|
179
288
|
var self = this;
|
|
@@ -211,7 +320,7 @@ libVES.prototype = {
|
|
|
211
320
|
if (u instanceof libVES.VaultKey) return [u];
|
|
212
321
|
else if (u instanceof libVES.External) return [new libVES.VaultKey({externals:[u]},self)];
|
|
213
322
|
else if (u instanceof libVES.User) return self.getUserKeys(u);
|
|
214
|
-
else if (u instanceof Array || u.domain != null || u.externalId != null) return self._matchSecondaryKey(u,u.user).then(function(vkey) {
|
|
323
|
+
else if (u instanceof Array || u.domain != null || u.externalId != null) return self._matchSecondaryKey(u, u.user, u.appUrl).then(function(vkey) {
|
|
215
324
|
return [vkey];
|
|
216
325
|
});
|
|
217
326
|
}
|
|
@@ -229,10 +338,23 @@ libVES.prototype = {
|
|
|
229
338
|
} else if (typeof(u) == 'string' && u.match(/^\S+\@\S+$/)) return new libVES.User({email: u},this);
|
|
230
339
|
throw new libVES.Error('BadUser',"Cannot match user: " + u,{value: u});
|
|
231
340
|
},
|
|
232
|
-
_matchSecondaryKey: function(ext,user) {
|
|
341
|
+
_matchSecondaryKey: function(ext, user, appUrl) {
|
|
233
342
|
var self = this;
|
|
234
343
|
var m = function() {
|
|
235
|
-
return libVES.getModule(libVES.Domain,ext.domain)
|
|
344
|
+
return libVES.getModule(libVES.Domain,ext.domain).catch(function(e) {
|
|
345
|
+
return {
|
|
346
|
+
userToVaultRef: function(u) {
|
|
347
|
+
return u.getEmail().then(function(email) {
|
|
348
|
+
return email.toLowerCase();
|
|
349
|
+
});
|
|
350
|
+
},
|
|
351
|
+
vaultRefToUser: function(ext) {
|
|
352
|
+
var email = ext.externalId ? ext.externalId.replace(/\!.*/, '') : '';
|
|
353
|
+
if (!email.match(/\@/)) throw {code: 'NotFound', message: 'externalId is not an email for non-existing vault'};
|
|
354
|
+
return new libVES.User({email: email}, self);
|
|
355
|
+
}
|
|
356
|
+
};
|
|
357
|
+
});
|
|
236
358
|
};
|
|
237
359
|
return (ext.externalId ? self.prepareExternals(ext) : m().then(function(dom) {
|
|
238
360
|
return Promise.resolve(user || self.me()).then(function(u) {
|
|
@@ -241,7 +363,7 @@ libVES.prototype = {
|
|
|
241
363
|
return self.prepareExternals([ex]);
|
|
242
364
|
});
|
|
243
365
|
}).catch(function(e) {
|
|
244
|
-
throw new libVES.Error('NotFound','Cannot match externalId for domain:' + ext.domain + ', user:' + user + '. Define libVES.Domain.' + ext.domain + '.userToVaultRef(user) to return a valid reference.',{error: e});
|
|
366
|
+
throw new libVES.Error('NotFound', 'Cannot match externalId for domain:' + ext.domain + ', user:' + user + '. Define libVES.Domain.' + ext.domain + '.userToVaultRef(user) to return a valid reference.',{error: e});
|
|
245
367
|
})).then(function(exts) {
|
|
246
368
|
var vkey = new libVES.VaultKey({externals: exts, creator: self.me()},self);
|
|
247
369
|
return vkey.getId().then(function() {
|
|
@@ -251,16 +373,17 @@ libVES.prototype = {
|
|
|
251
373
|
return Promise.resolve(user || m().then(function(dom) {
|
|
252
374
|
return dom.vaultRefToUser(exts[0]);
|
|
253
375
|
})).catch(function(e) {
|
|
254
|
-
throw new libVES.Error('NotFound','No matching secondary
|
|
376
|
+
throw new libVES.Error('NotFound', 'No matching secondary vault key',{error: e});
|
|
255
377
|
}).then(function(u) {
|
|
256
378
|
return self.me().then(function(me) {
|
|
257
379
|
return Promise.all([me.getId(),u.getId()]).then(function(ids) {
|
|
258
380
|
if (ids[0] == ids[1]) return self.getSecondaryKey(exts,true);
|
|
259
381
|
}).catch(function(e) {
|
|
260
|
-
if (e != 'NotFound') throw e;
|
|
382
|
+
if (e.code != 'NotFound') throw e;
|
|
261
383
|
}).then(function(rs) {
|
|
262
384
|
return rs || self.createTempKey(self._matchUser(u)).then(function(vkey) {
|
|
263
385
|
return vkey.setField('externals',exts).then(function() {
|
|
386
|
+
if (appUrl) vkey.setField('appUrl', appUrl);
|
|
264
387
|
return vkey;
|
|
265
388
|
});
|
|
266
389
|
});
|
|
@@ -292,21 +415,21 @@ libVES.prototype = {
|
|
|
292
415
|
return keys;
|
|
293
416
|
});
|
|
294
417
|
},
|
|
295
|
-
createTempKey: function(usr,optns) {
|
|
418
|
+
createTempKey: function(usr, optns) {
|
|
296
419
|
var self = this;
|
|
297
|
-
var key = new libVES.VaultKey({type: 'temp', algo: this.keyAlgo, user: usr},self);
|
|
420
|
+
var key = new libVES.VaultKey({type: 'temp', algo: this.keyAlgo, user: usr}, self);
|
|
298
421
|
var veskey = this.generateVESkey(usr);
|
|
299
|
-
return key.generate(veskey,optns).then(function(k) {
|
|
300
|
-
if (self.e2e && self.e2e.length) usr.e2e = self.getVESkeyE2E(veskey,usr);
|
|
301
|
-
key.setField('vaultItems',veskey.then(function(v) {
|
|
302
|
-
var vi = new libVES.VaultItem({type: 'password'},self);
|
|
303
|
-
return self.me().then(function(
|
|
304
|
-
return vi.shareWith(
|
|
422
|
+
return key.generate(veskey, optns).then(function(k) {
|
|
423
|
+
if (self.e2e && self.e2e.length) usr.e2e = self.getVESkeyE2E(veskey, usr);
|
|
424
|
+
key.setField('vaultItems', veskey.then(function(v) {
|
|
425
|
+
var vi = new libVES.VaultItem({type: 'password'}, self);
|
|
426
|
+
return Promise.all(self.type == 'secondary' ? [self.me(), self.getVaultKey()] : [self.me()]).then(function(sh) {
|
|
427
|
+
return vi.shareWith(sh, v, false).then(function() {
|
|
305
428
|
return [vi];
|
|
306
429
|
});
|
|
307
430
|
});
|
|
308
431
|
}));
|
|
309
|
-
key.setField('creator',self.me());
|
|
432
|
+
key.setField('creator', self.me());
|
|
310
433
|
return key;
|
|
311
434
|
});
|
|
312
435
|
},
|
|
@@ -331,22 +454,31 @@ libVES.prototype = {
|
|
|
331
454
|
var self = this;
|
|
332
455
|
return this.me().then(function(me) {
|
|
333
456
|
return (new libVES.VaultKey({type: 'current', algo: self.keyAlgo, user: me},self)).generate(Promise.resolve(veskey),options).then(function(k) {
|
|
334
|
-
return
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
457
|
+
return me.getCurrentVaultKey().then(function(cur) {
|
|
458
|
+
return (cur ? cur.unlock().then(function() {
|
|
459
|
+
return k.rekeyFrom(cur);
|
|
460
|
+
}).catch(function(e) {
|
|
461
|
+
if (!lost) throw e;
|
|
462
|
+
}) : Promise.resolve(null)).then(function() {
|
|
463
|
+
var r;
|
|
464
|
+
if (cur && lost) r = cur.setField('type','lost').then(function() {
|
|
338
465
|
k.user = undefined;
|
|
339
466
|
return me.setField('vaultKeys',[cur,k]).then(function() {
|
|
340
467
|
return me;
|
|
341
468
|
});
|
|
342
469
|
});
|
|
343
|
-
else r = k
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
470
|
+
else r = k;
|
|
471
|
+
me.currentVaultKey = me.activeVaultKeys = me.shadowVaultKey = undefined;
|
|
472
|
+
if (!cur || !lost) me.vaultKeys = undefined;
|
|
473
|
+
return r;
|
|
474
|
+
});
|
|
348
475
|
}).then(function(r) {
|
|
349
|
-
return
|
|
476
|
+
return self.elevateAuth(options).then(function(optns) {
|
|
477
|
+
return r.post(undefined, undefined, optns);
|
|
478
|
+
});
|
|
479
|
+
}).catch(function(e) {
|
|
480
|
+
self.reset();
|
|
481
|
+
throw e;
|
|
350
482
|
}).then(function(post) {
|
|
351
483
|
return self.reset(post);
|
|
352
484
|
}).then(function() {
|
|
@@ -370,21 +502,21 @@ libVES.prototype = {
|
|
|
370
502
|
return rs;
|
|
371
503
|
});
|
|
372
504
|
},
|
|
373
|
-
getSecondaryKey: function(ext,force) {
|
|
505
|
+
getSecondaryKey: function(ext, force) {
|
|
374
506
|
var self = this;
|
|
375
507
|
return this.prepareExternals(Promise.resolve(ext).then(function(e) {
|
|
376
|
-
if (e.domain && !e.externalId) return libVES.getModule(libVES.Domain,e.domain).then(function(mod) {
|
|
508
|
+
if (e.domain && !e.externalId) return libVES.getModule(libVES.Domain, e.domain).then(function(mod) {
|
|
377
509
|
return self.me().then(function(me) {
|
|
378
|
-
return mod.userToVaultRef(me,self);
|
|
510
|
+
return mod.userToVaultRef(me, self);
|
|
379
511
|
});
|
|
380
512
|
});
|
|
381
513
|
return e;
|
|
382
514
|
})).then(function(ext) {
|
|
383
|
-
var vkey = new libVES.VaultKey({externals: ext},self);
|
|
515
|
+
var vkey = new libVES.VaultKey({externals: ext}, self);
|
|
384
516
|
return vkey.getId().then(function(id) {
|
|
385
517
|
return vkey;
|
|
386
518
|
}).catch(function(e) {
|
|
387
|
-
if (!force) throw e;
|
|
519
|
+
if (!force || e.code != 'NotFound') throw e;
|
|
388
520
|
return self.setSecondaryKey(ext);
|
|
389
521
|
});
|
|
390
522
|
});
|
|
@@ -395,14 +527,25 @@ libVES.prototype = {
|
|
|
395
527
|
if (!veskey) veskey = self.generateVESkey();
|
|
396
528
|
return self.me().then(function(me) {
|
|
397
529
|
return (new libVES.VaultKey({type: 'secondary', algo: self.keyAlgo, user: me, externals: ext},self)).generate(veskey,optns).then(function(k) {
|
|
530
|
+
return self.getSecondaryKey(ext).then(function(k2) {
|
|
531
|
+
return k.rekeyFrom(k2);
|
|
532
|
+
}).catch(function(e) {
|
|
533
|
+
delete(k.vaultEntries);
|
|
534
|
+
return k;
|
|
535
|
+
});
|
|
536
|
+
}).then(function(k) {
|
|
398
537
|
var vi = new libVES.VaultItem({type: "password"},self);
|
|
399
538
|
k.setField('vaultItems',[vi]);
|
|
400
539
|
return Promise.resolve(veskey).then(function(v) {
|
|
401
540
|
if (!v) throw new libVES.Error('InvalidValue','VESkey cannot be empty');
|
|
402
541
|
return vi.shareWith([me],v,false).then(function() {
|
|
403
|
-
return
|
|
404
|
-
|
|
405
|
-
|
|
542
|
+
return self.elevateAuth(optns);
|
|
543
|
+
}).then(function(optns) {
|
|
544
|
+
return k.post(undefined, undefined, optns).then(function(post) {
|
|
545
|
+
return k.setField('id', post.id, false).then(function() {
|
|
546
|
+
k.fieldUpdate = {id: true};
|
|
547
|
+
return k;
|
|
548
|
+
});
|
|
406
549
|
});
|
|
407
550
|
});
|
|
408
551
|
});
|
|
@@ -410,15 +553,44 @@ libVES.prototype = {
|
|
|
410
553
|
});
|
|
411
554
|
});
|
|
412
555
|
},
|
|
556
|
+
setAnonymousKey: function(veskey, optns) {
|
|
557
|
+
var self = this;
|
|
558
|
+
return this.prepareExternals({externalId: self.externalId}).then(function(ext) {
|
|
559
|
+
if (!veskey) throw new libVES.Error('InvalidValue','VESkey cannot be empty');
|
|
560
|
+
return (new libVES.VaultKey({type: 'secondary', algo: (optns && optns.algo ? optns.algo : self.keyAlgo), externals: ext},self)).generate(veskey, optns).then(function(k) {
|
|
561
|
+
return k.post(undefined, ['encSessionToken'], optns).then(function(post) {
|
|
562
|
+
return k.setField('id', post.id, false).then(function() {
|
|
563
|
+
k.fieldUpdate = {id: true};
|
|
564
|
+
});
|
|
565
|
+
}).catch(function(e) {
|
|
566
|
+
if (!e || e.code != 'Unauthorized') throw e;
|
|
567
|
+
}).then(function() {
|
|
568
|
+
return self.unlock(veskey);
|
|
569
|
+
});
|
|
570
|
+
});
|
|
571
|
+
});
|
|
572
|
+
},
|
|
413
573
|
setShadow: function(usrs,optns) {
|
|
414
|
-
if (!optns || !optns.n) return Promise.reject(new libVES.Error('InvalidValue','optns.n must be an integer'));
|
|
415
574
|
var self = this;
|
|
575
|
+
if (!(usrs instanceof Array)) return Promise.reject(new libVES.Error('InvalidValue', 'usrs must be an array'));
|
|
576
|
+
if (!usrs.length) {
|
|
577
|
+
return self.getShadowKey().then(function(sh) {
|
|
578
|
+
return (sh ? sh.getId().then(function(id) {
|
|
579
|
+
return self.elevateAuth(optns).then(function(optns) {
|
|
580
|
+
return self.post('vaultKeys/' + id, {'$op': 'delete'}, undefined, optns). then(function() {
|
|
581
|
+
return null;
|
|
582
|
+
});
|
|
583
|
+
});
|
|
584
|
+
}) : null);
|
|
585
|
+
});
|
|
586
|
+
}
|
|
587
|
+
if (!optns || !optns.n) return Promise.reject(new libVES.Error('InvalidValue','optns.n must be an integer'));
|
|
416
588
|
var rkey = new Uint8Array(32);
|
|
417
589
|
window.crypto.getRandomValues(rkey);
|
|
418
590
|
var algo = optns.v ? libVES.Scramble.algo[optns.v] : libVES.Scramble.RDX;
|
|
419
591
|
if (!algo) return Promise.reject(new libVES.Error('InvalidValue','Unknown scramble algorithm: ' + optns.v));
|
|
420
592
|
var s = new algo(optns.n);
|
|
421
|
-
return s.explode(rkey,usrs.length).then(function(tkns) {
|
|
593
|
+
return s.explode(rkey,usrs.length,optns).then(function(tkns) {
|
|
422
594
|
return self.me().then(function(me) {
|
|
423
595
|
me.activeVaultKeys = undefined;
|
|
424
596
|
return me.setField('shadowVaultKey',new libVES.VaultKey({type: 'shadow', user: me, algo: self.keyAlgo},self).generate(rkey,optns),false).then(function(k) {
|
|
@@ -434,14 +606,16 @@ libVES.prototype = {
|
|
|
434
606
|
delete(libVES.Object._refs);
|
|
435
607
|
return vis;
|
|
436
608
|
}));
|
|
437
|
-
return
|
|
609
|
+
return self.elevateAuth(optns).then(function(optns) {
|
|
610
|
+
return k.post(undefined, undefined, optns);
|
|
611
|
+
});
|
|
438
612
|
});
|
|
439
613
|
});
|
|
440
614
|
}).catch(function(e) {
|
|
441
615
|
me.shadowVaultKey = undefined;
|
|
442
616
|
throw e;
|
|
443
617
|
}).then(function() {
|
|
444
|
-
me.currentVaultKey = me.activeVaultKeys = undefined;
|
|
618
|
+
me.currentVaultKey = me.shadowVaultKey = me.activeVaultKeys = undefined;
|
|
445
619
|
return me.getShadowVaultKey();
|
|
446
620
|
});
|
|
447
621
|
});
|
|
@@ -467,30 +641,11 @@ libVES.prototype = {
|
|
|
467
641
|
putValue: function(fileRef,value,shareWith) {
|
|
468
642
|
var self = this;
|
|
469
643
|
return this.getFileItem(fileRef).then(function(vaultItem) {
|
|
470
|
-
return vaultItem.setField('type',libVES.VaultItem.Type._detect(value)).then(function(
|
|
471
|
-
return vaultItem.getFile().then(function(file) {
|
|
472
|
-
return file.getExternals().then(function(exts) {
|
|
473
|
-
return exts[0].getDomain().then(function(domain) {
|
|
474
|
-
var m = libVES.getModule(libVES.Domain,domain);
|
|
475
|
-
file.setField('path',m.then(function(mod) {
|
|
476
|
-
return mod.defaultFilePath(file,exts[0]);
|
|
477
|
-
}).catch(function() {
|
|
478
|
-
return '';
|
|
479
|
-
}));
|
|
480
|
-
file.setField('name',m.then(function(mod) {
|
|
481
|
-
return mod.defaultFileName(file,exts[0]);
|
|
482
|
-
}).catch(function() {
|
|
483
|
-
return null;
|
|
484
|
-
}));
|
|
485
|
-
return type;
|
|
486
|
-
});
|
|
487
|
-
});
|
|
488
|
-
});
|
|
489
|
-
}).then(function() {
|
|
644
|
+
return vaultItem.setField('type',libVES.VaultItem.Type._detect(value)).then(function() {
|
|
490
645
|
return Promise.resolve(shareWith || self.getFileItem(fileRef).then(function(vi) {
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
return self.usersToKeys([{domain: fileRef.domain}]);
|
|
646
|
+
return vi.getShareList();
|
|
647
|
+
}).catch(function(e) {
|
|
648
|
+
return self.usersToKeys([{domain: (fileRef.domain || VES.domain)}]);
|
|
494
649
|
})).then(function(shareWith) {
|
|
495
650
|
return vaultItem.shareWith(shareWith,value);
|
|
496
651
|
});
|
|
@@ -502,6 +657,16 @@ libVES.prototype = {
|
|
|
502
657
|
return vaultItem.shareWith(shareWith);
|
|
503
658
|
});
|
|
504
659
|
},
|
|
660
|
+
fileExists: function(fileRef) {
|
|
661
|
+
return this.getFileItem(fileRef).then(function(vaultItem) {
|
|
662
|
+
return vaultItem.getId().then(function(id) {
|
|
663
|
+
return true;
|
|
664
|
+
}).catch(function(e) {
|
|
665
|
+
if (e.code == 'NotFound') return false;
|
|
666
|
+
throw e;
|
|
667
|
+
});
|
|
668
|
+
});
|
|
669
|
+
},
|
|
505
670
|
deleteFile: function(fileRef) {
|
|
506
671
|
return this.getFile(fileRef).then(function(file) {
|
|
507
672
|
return file.delete();
|
|
@@ -539,8 +704,8 @@ libVES.prototype = {
|
|
|
539
704
|
hashText: function(text,cls) {
|
|
540
705
|
if (cls) cls = cls.split('.')[0];
|
|
541
706
|
else cls = this.defaultHash;
|
|
542
|
-
return libVES.getModule(libVES.Util,['Hash',cls]).then(function(
|
|
543
|
-
return
|
|
707
|
+
return libVES.getModule(libVES.Util,['Hash',cls]).then(function(mod) {
|
|
708
|
+
return mod.hash(libVES.Util.StringToByteArray(text)).then(function(buf) {
|
|
544
709
|
return cls + '.' + libVES.Util.ByteArrayToB64W(buf);
|
|
545
710
|
});
|
|
546
711
|
});
|
|
@@ -579,8 +744,6 @@ libVES.prototype = {
|
|
|
579
744
|
}).then(function() {
|
|
580
745
|
chain = chain.then(function(ct) {
|
|
581
746
|
return vaultKey.rekey().then(function() {
|
|
582
|
-
if (self.onRekey) return self.onRekey(vaultKey);
|
|
583
|
-
}).then(function() {
|
|
584
747
|
return ct + 1;
|
|
585
748
|
});
|
|
586
749
|
}).catch(function(e) {console.log(e);});;
|
|
@@ -597,35 +760,104 @@ libVES.prototype = {
|
|
|
597
760
|
var self = this;
|
|
598
761
|
return self.me().then(function(me) {
|
|
599
762
|
return me.getVaultKeys().then(function(vaultKeys) {
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
});
|
|
763
|
+
return Promise.all(vaultKeys.map(function(e,i) {
|
|
764
|
+
return e.getType();
|
|
765
|
+
})).then(function(types) {
|
|
766
|
+
var rs = [];
|
|
767
|
+
for (var i = 0; i < types.length; i++) switch (types[i]) {
|
|
768
|
+
case 'recovery': case 'shadow':
|
|
769
|
+
rs.push(vaultKeys[i].getRecovery());
|
|
770
|
+
}
|
|
771
|
+
return Promise.all(rs);
|
|
610
772
|
});
|
|
773
|
+
});
|
|
611
774
|
});
|
|
612
775
|
},
|
|
613
776
|
getFriendsRecoveries: function() {
|
|
614
777
|
var self = this;
|
|
615
778
|
return self.me().then(function(me) {
|
|
616
|
-
return me.
|
|
617
|
-
|
|
618
|
-
|
|
779
|
+
return me.getFriendsKeyItems().then(function(vaultItems) {
|
|
780
|
+
var vaultKeys = [];
|
|
781
|
+
return Promise.all(vaultItems.map(function(e,i) {
|
|
782
|
+
return e.getVaultKey().then(function(vk) {
|
|
783
|
+
vaultKeys[i] = vk;
|
|
784
|
+
if (vk) return vk.getType();
|
|
785
|
+
});
|
|
619
786
|
})).then(function(types) {
|
|
620
787
|
var rs = [];
|
|
621
788
|
for (var i = 0; i < types.length; i++) switch (types[i]) {
|
|
622
789
|
case 'recovery': case 'shadow':
|
|
623
|
-
rs.push(vaultKeys[i].getRecovery());
|
|
790
|
+
rs.push(vaultKeys[i].getRecovery([vaultItems[i]]));
|
|
624
791
|
}
|
|
625
792
|
return Promise.all(rs);
|
|
626
793
|
});
|
|
627
794
|
});
|
|
628
795
|
});
|
|
796
|
+
},
|
|
797
|
+
getUnlockableKeys: function() {
|
|
798
|
+
var self = this;
|
|
799
|
+
return self.getVaultKey().then(function(vk) {
|
|
800
|
+
return vk.getField('unlockableVaultKeys').then(function(vks) {
|
|
801
|
+
var rs = {};
|
|
802
|
+
return Promise.all(vks.map(function(e, i) {
|
|
803
|
+
return e.getId().then(function(id) {
|
|
804
|
+
rs[id] = e;
|
|
805
|
+
});
|
|
806
|
+
})).then(function() {
|
|
807
|
+
return rs;
|
|
808
|
+
});
|
|
809
|
+
});
|
|
810
|
+
});
|
|
811
|
+
},
|
|
812
|
+
getAttn: function() {
|
|
813
|
+
var self = this;
|
|
814
|
+
var rs = {};
|
|
815
|
+
return self.get('attn').then(function(attn) {
|
|
816
|
+
return attn ? Promise.all([(attn.vaultKeys ? Promise.all(attn.vaultKeys.map(function(vk, i) {
|
|
817
|
+
return new libVES.VaultKey(vk, self);
|
|
818
|
+
})).then(function(vks) {
|
|
819
|
+
rs.vaultKeys = vks;
|
|
820
|
+
}) : null)]) : null;
|
|
821
|
+
}).then(function() {
|
|
822
|
+
return rs;
|
|
823
|
+
});
|
|
824
|
+
},
|
|
825
|
+
handleAttn: function(attn) {
|
|
826
|
+
var self = this;
|
|
827
|
+
return (attn ? Promise.resolve(attn) : self.getAttn()).then(function(attn) {
|
|
828
|
+
if (attn) return Promise.all([(attn.vaultKeys ? self.attnVaultKeys(attn.vaultKeys) : null)]);
|
|
829
|
+
});
|
|
830
|
+
},
|
|
831
|
+
attnVaultKeys: function(vkeys) {
|
|
832
|
+
var self = this;
|
|
833
|
+
return Promise.all(vkeys.map(function(vkey, i) {
|
|
834
|
+
console.log('attnVaultKeys:', vkey);
|
|
835
|
+
return vkey.getType().then(function(type) {
|
|
836
|
+
switch (type) {
|
|
837
|
+
case 'temp':
|
|
838
|
+
case 'lost':
|
|
839
|
+
return vkey.getUser().then(function(user) {
|
|
840
|
+
return self.me().then(function(me) {
|
|
841
|
+
return Promise.all([user.getId(), me.getId()]).then(function(ids) {
|
|
842
|
+
if (ids[0] == ids[1]) return type == 'temp' ? vkey.rekey()
|
|
843
|
+
: self.elevateAuth({authVaultKey: vkey}).then(function(optns) {
|
|
844
|
+
return vkey.rekey(optns);
|
|
845
|
+
});
|
|
846
|
+
else return vkey.getVaultItems().then(function(vis) {
|
|
847
|
+
return Promise.all(vis.map(function(vi, i) {
|
|
848
|
+
return vi.reshareWith([user]);
|
|
849
|
+
}));
|
|
850
|
+
});
|
|
851
|
+
});
|
|
852
|
+
});
|
|
853
|
+
});
|
|
854
|
+
case 'recovery':
|
|
855
|
+
return vkey.getRecovery().then(function(rcv) {
|
|
856
|
+
return rcv.recover();
|
|
857
|
+
});
|
|
858
|
+
}
|
|
859
|
+
});
|
|
860
|
+
}));
|
|
629
861
|
}
|
|
630
862
|
};
|
|
631
863
|
|
|
@@ -756,7 +988,7 @@ libVES.Util = {
|
|
|
756
988
|
}
|
|
757
989
|
},
|
|
758
990
|
ASN1: {
|
|
759
|
-
decode: function(der) {
|
|
991
|
+
decode: function(der,fStruct) {
|
|
760
992
|
var p = 0;
|
|
761
993
|
var data = function() {
|
|
762
994
|
var l = der[p++];
|
|
@@ -771,10 +1003,14 @@ libVES.Util = {
|
|
|
771
1003
|
};
|
|
772
1004
|
var rs = [];
|
|
773
1005
|
for (; p < der.length;) {
|
|
1006
|
+
if (!fStruct && p) {
|
|
1007
|
+
rs.push(der.slice(p));
|
|
1008
|
+
break;
|
|
1009
|
+
}
|
|
774
1010
|
var tag = der[p++];
|
|
775
1011
|
switch (tag) {
|
|
776
1012
|
case 48:
|
|
777
|
-
rs.push(libVES.Util.ASN1.decode(data()));
|
|
1013
|
+
rs.push(libVES.Util.ASN1.decode(data(),true));
|
|
778
1014
|
break;
|
|
779
1015
|
case 6:
|
|
780
1016
|
rs.push(new libVES.Util.OID(data()));
|
|
@@ -796,7 +1032,7 @@ libVES.Util = {
|
|
|
796
1032
|
}
|
|
797
1033
|
return rs;
|
|
798
1034
|
},
|
|
799
|
-
encode: function(data) {
|
|
1035
|
+
encode: function(data,fStruct) {
|
|
800
1036
|
var i2a = function(v) {
|
|
801
1037
|
if (v < 0) throw new libVES.Error('Internal',"Negative value for ASN.1 integer!");
|
|
802
1038
|
var rs = [];
|
|
@@ -827,10 +1063,10 @@ libVES.Util = {
|
|
|
827
1063
|
return rs;
|
|
828
1064
|
};
|
|
829
1065
|
var d;
|
|
830
|
-
for (var i = 0; i < data.length; i++) switch (typeof(d = data[i])) {
|
|
1066
|
+
for (var i = 0; i < data.length; i++) if (fStruct || !i) switch (typeof(d = data[i])) {
|
|
831
1067
|
case 'object':
|
|
832
1068
|
if (d == null) buf(5,new Uint8Array(0));
|
|
833
|
-
else if (d instanceof Array) buf(48,libVES.Util.ASN1.encode(d));
|
|
1069
|
+
else if (d instanceof Array) buf(48,libVES.Util.ASN1.encode(d,true));
|
|
834
1070
|
else if (d instanceof libVES.Util.OID) buf(6,d.getBuffer());
|
|
835
1071
|
else if (d instanceof Uint8Array || d instanceof ArrayBuffer) buf((d.ASN1type || 4),d);
|
|
836
1072
|
else throw new libVES.Error('Internal',"ASN.1 encode - Unknown type");
|
|
@@ -839,7 +1075,7 @@ libVES.Util = {
|
|
|
839
1075
|
buf(2,i2a(d));
|
|
840
1076
|
break;
|
|
841
1077
|
default: throw new libVES.Error('Internal',"ASN.1 encode - Unknown type");
|
|
842
|
-
}
|
|
1078
|
+
} else bufs.push(d);
|
|
843
1079
|
var l = 0;
|
|
844
1080
|
for (var i = 0; i < bufs.length; i++) l += bufs[i].length;
|
|
845
1081
|
var der = new Uint8Array(l);
|
|
@@ -848,7 +1084,7 @@ libVES.Util = {
|
|
|
848
1084
|
return der;
|
|
849
1085
|
},
|
|
850
1086
|
import: function(der,optns) {
|
|
851
|
-
var k = libVES.Util.ASN1.decode(der)[0];
|
|
1087
|
+
var k = optns && optns.decoded || libVES.Util.ASN1.decode(der)[0];
|
|
852
1088
|
if (!k) throw new libVES.Error('Internal','Empty ASN.1 package?');
|
|
853
1089
|
var i = 0;
|
|
854
1090
|
if (typeof(k[i]) == 'number') (optns || (optns = {})).version = k[i++];
|
|
@@ -894,6 +1130,11 @@ libVES.Util = {
|
|
|
894
1130
|
return crypto.subtle.importKey('pkcs8',der,{name:'RSA-OAEP', hash:'SHA-1'},true,['decrypt']);
|
|
895
1131
|
});
|
|
896
1132
|
});
|
|
1133
|
+
},
|
|
1134
|
+
encode: function(key,optns) {
|
|
1135
|
+
return crypto.subtle.exportKey('spki',key).then(function(der) {
|
|
1136
|
+
return libVES.Util.PEM.encode(der,'PUBLIC KEY');
|
|
1137
|
+
});
|
|
897
1138
|
}
|
|
898
1139
|
},
|
|
899
1140
|
PKCS5: {
|
|
@@ -908,7 +1149,7 @@ libVES.Util = {
|
|
|
908
1149
|
else return fp;
|
|
909
1150
|
})(args[i],f);
|
|
910
1151
|
return f('import',optns).then(function(der) {
|
|
911
|
-
return
|
|
1152
|
+
return libVES.Util.ASN1.import(new Uint8Array(der));
|
|
912
1153
|
}).catch(function(e) {
|
|
913
1154
|
throw new libVES.Error('InvalidKey',"Cannot import the private key (Invalid VESkey?)");
|
|
914
1155
|
});
|
|
@@ -930,10 +1171,108 @@ libVES.Util = {
|
|
|
930
1171
|
});
|
|
931
1172
|
}
|
|
932
1173
|
},
|
|
1174
|
+
PKCS8: {
|
|
1175
|
+
encode: function(key,optns) {
|
|
1176
|
+
var ops = {};
|
|
1177
|
+
for (var k in optns) ops[k] = optns[k];
|
|
1178
|
+
if (!ops.members) ops.members = [
|
|
1179
|
+
libVES.getModule(libVES.Util,'PBKDF2'),
|
|
1180
|
+
libVES.getModule(libVES.Cipher,'AES256CBC')
|
|
1181
|
+
];
|
|
1182
|
+
return Promise.all(ops.members).then(function(ms) {
|
|
1183
|
+
ops.members = ms;
|
|
1184
|
+
return crypto.subtle.exportKey('pkcs8',key).catch(function(e) {
|
|
1185
|
+
console.log('PKCS8 failed, trying JWK...');
|
|
1186
|
+
return crypto.subtle.exportKey('jwk', key).then(function(jwk) {
|
|
1187
|
+
return libVES.Util.PKCS8.fromJWK(jwk);
|
|
1188
|
+
});
|
|
1189
|
+
}).then(function(der) {
|
|
1190
|
+
ops.content = der;
|
|
1191
|
+
var rec = [];
|
|
1192
|
+
if (ops.password) return libVES.Util.PKCS5.export(function(call,optns) {
|
|
1193
|
+
rec[1] = optns.content;
|
|
1194
|
+
return Promise.resolve();
|
|
1195
|
+
},ops).then(function(data) {
|
|
1196
|
+
rec[0] = data;
|
|
1197
|
+
return libVES.Util.PEM.encode(libVES.Util.ASN1.encode([rec]),'ENCRYPTED PRIVATE KEY');
|
|
1198
|
+
});
|
|
1199
|
+
else if (ops.opentext) return libVES.Util.PEM.encode(der,'PRIVATE KEY');
|
|
1200
|
+
else throw new libVES.Error('Internal','No password for key export (opentext=true to export without password?)');
|
|
1201
|
+
});
|
|
1202
|
+
});
|
|
1203
|
+
},
|
|
1204
|
+
fromJWK: function(jwk) {
|
|
1205
|
+
if (jwk.kty != 'EC') throw new libVES.Error('Internal', 'kty=="EC" expected (workaround for Firefox)');
|
|
1206
|
+
var pubx = libVES.Util.B64ToByteArray(jwk.x);
|
|
1207
|
+
var puby = libVES.Util.B64ToByteArray(jwk.y);
|
|
1208
|
+
var pub = new Uint8Array(pubx.byteLength + puby.byteLength + 2);
|
|
1209
|
+
pub[0] = 0;
|
|
1210
|
+
pub[1] = 4;
|
|
1211
|
+
pub.set(new Uint8Array(pubx), 2);
|
|
1212
|
+
pub.set(new Uint8Array(puby), pubx.byteLength + 2);
|
|
1213
|
+
pub.ASN1type = 3;
|
|
1214
|
+
pub = libVES.Util.ASN1.encode([pub]);
|
|
1215
|
+
pub.ASN1type = 0xa1;
|
|
1216
|
+
return libVES.Util.ASN1.encode([[
|
|
1217
|
+
0,
|
|
1218
|
+
[
|
|
1219
|
+
new libVES.Util.OID('1.2.840.10045.2.1'),
|
|
1220
|
+
new libVES.Util.OID((function(crvs) {
|
|
1221
|
+
for (var k in crvs) if (crvs[k] == jwk.crv) return k;
|
|
1222
|
+
throw new libVES.Error('Internal', 'Unknown named curve: ' + jwk.crv);
|
|
1223
|
+
})(libVES.Util.EC.namedCurves))
|
|
1224
|
+
],
|
|
1225
|
+
libVES.Util.ASN1.encode([[
|
|
1226
|
+
1,
|
|
1227
|
+
libVES.Util.B64ToByteArray(jwk.d),
|
|
1228
|
+
pub
|
|
1229
|
+
]])
|
|
1230
|
+
]]).buffer;
|
|
1231
|
+
},
|
|
1232
|
+
toJWK: function(key) {
|
|
1233
|
+
var der = libVES.Util.ASN1.decode(key)[0];
|
|
1234
|
+
var idx = 0;
|
|
1235
|
+
if (!(der[0] instanceof Array)) idx++;
|
|
1236
|
+
switch (String(der[idx][0])) {
|
|
1237
|
+
case '1.2.840.10045.2.1':
|
|
1238
|
+
case '1.3.132.1.12':
|
|
1239
|
+
case '1.3.132.112': // Firefox on Mac - apparently a misspelling of the former
|
|
1240
|
+
break;
|
|
1241
|
+
default:
|
|
1242
|
+
console.log(der);
|
|
1243
|
+
throw new libVES.Error('Internal', 'EC PKCS8 expected');
|
|
1244
|
+
}
|
|
1245
|
+
var der2 = idx ? libVES.Util.ASN1.decode(der[idx + 1])[0] : null;
|
|
1246
|
+
var pub = idx ? (der2[2] ? libVES.Util.ASN1.decode(der2[2])[0] : null) : der[1];
|
|
1247
|
+
var publ = 0;
|
|
1248
|
+
if (pub && pub.byteLength > 2 && pub[1] == 4) publ = pub.byteLength / 2 - 1;
|
|
1249
|
+
return {
|
|
1250
|
+
crv: libVES.Util.EC.namedCurves[der[idx][1]],
|
|
1251
|
+
d: (idx ? libVES.Util.ByteArrayToB64W(der2[1]) : undefined),
|
|
1252
|
+
ext: true,
|
|
1253
|
+
key_ops: (idx ? ['deriveKey', 'deriveBits'] : []),
|
|
1254
|
+
kty: 'EC',
|
|
1255
|
+
x: (publ ? libVES.Util.ByteArrayToB64W(pub.slice(2, publ + 2)) : ''),
|
|
1256
|
+
y: (publ ? libVES.Util.ByteArrayToB64W(pub.slice(publ + 2, 2 * publ + 2)) : '')
|
|
1257
|
+
};
|
|
1258
|
+
}
|
|
1259
|
+
},
|
|
933
1260
|
PBKDF2: {
|
|
934
|
-
deriveKey: function(args,pwd,algo) {
|
|
935
|
-
return crypto.subtle.importKey('raw',libVES.Util.StringToByteArray(pwd),'PBKDF2',false,['deriveKey']).then(function(k) {
|
|
936
|
-
|
|
1261
|
+
deriveKey: function(args, pwd, algo) {
|
|
1262
|
+
return crypto.subtle.importKey('raw', libVES.Util.StringToByteArray(pwd), 'PBKDF2', false, ['deriveKey']).then(function(k) {
|
|
1263
|
+
var keyargs = {name:'PBKDF2', salt:args[0], iterations:args[1]};
|
|
1264
|
+
var ka;
|
|
1265
|
+
if (args[2] && (args[2][0] instanceof libVES.Util.OID)) ka = args[2][0].object().then(function(obj) {
|
|
1266
|
+
obj.setArgs(keyargs, args[2][1]);
|
|
1267
|
+
return keyargs;
|
|
1268
|
+
});
|
|
1269
|
+
else {
|
|
1270
|
+
keyargs.hash = 'SHA-1';
|
|
1271
|
+
ka = Promise.resolve(keyargs);
|
|
1272
|
+
}
|
|
1273
|
+
return ka.then(function(keyargs) {
|
|
1274
|
+
return crypto.subtle.deriveKey(keyargs, k, algo, true, ['encrypt', 'decrypt']);
|
|
1275
|
+
});
|
|
937
1276
|
});
|
|
938
1277
|
},
|
|
939
1278
|
import: function(args,chain,optns) {
|
|
@@ -960,9 +1299,61 @@ libVES.Util = {
|
|
|
960
1299
|
});
|
|
961
1300
|
}
|
|
962
1301
|
},
|
|
1302
|
+
EC: {
|
|
1303
|
+
import: function(args,chain,optns) {
|
|
1304
|
+
return chain('container',optns).then(function(der) {
|
|
1305
|
+
var a = {name:'ECDH',namedCurve:libVES.Util.EC.namedCurves[String(args)]};
|
|
1306
|
+
return crypto.subtle.importKey('spki',der,a,true,[]).catch(function() {;
|
|
1307
|
+
return crypto.subtle.importKey('pkcs8',der,a,true,['deriveKey','deriveBits']).catch(function(e) {
|
|
1308
|
+
console.log('PKCS8 failed, trying JWK...');
|
|
1309
|
+
var jwk = libVES.Util.PKCS8.toJWK(der);
|
|
1310
|
+
return crypto.subtle.importKey('jwk', jwk, a, true, jwk.key_ops);
|
|
1311
|
+
});
|
|
1312
|
+
});
|
|
1313
|
+
});
|
|
1314
|
+
},
|
|
1315
|
+
namedCurves: {
|
|
1316
|
+
"1.3.132.0.10": "P-256",
|
|
1317
|
+
"1.3.132.0.34": "P-384",
|
|
1318
|
+
"1.3.132.0.35": "P-521"
|
|
1319
|
+
}
|
|
1320
|
+
},
|
|
963
1321
|
Hash: {
|
|
964
|
-
|
|
965
|
-
|
|
1322
|
+
SHA1: {
|
|
1323
|
+
setArgs: function(args, optns) {
|
|
1324
|
+
args.hash = 'SHA-1';
|
|
1325
|
+
return args;
|
|
1326
|
+
},
|
|
1327
|
+
hash: function(buf) {
|
|
1328
|
+
return crypto.subtle.digest('SHA-1',buf);
|
|
1329
|
+
}
|
|
1330
|
+
},
|
|
1331
|
+
SHA256: {
|
|
1332
|
+
setArgs: function(args, optns) {
|
|
1333
|
+
args.hash = 'SHA-256';
|
|
1334
|
+
return args;
|
|
1335
|
+
},
|
|
1336
|
+
hash: function(buf) {
|
|
1337
|
+
return crypto.subtle.digest('SHA-256',buf);
|
|
1338
|
+
}
|
|
1339
|
+
},
|
|
1340
|
+
SHA384: {
|
|
1341
|
+
setArgs: function(args, optns) {
|
|
1342
|
+
args.hash = 'SHA-384';
|
|
1343
|
+
return args;
|
|
1344
|
+
},
|
|
1345
|
+
hash: function(buf) {
|
|
1346
|
+
return crypto.subtle.digest('SHA-384',buf);
|
|
1347
|
+
}
|
|
1348
|
+
},
|
|
1349
|
+
SHA512: {
|
|
1350
|
+
setArgs: function(args, optns) {
|
|
1351
|
+
args.hash = 'SHA-512';
|
|
1352
|
+
return args;
|
|
1353
|
+
},
|
|
1354
|
+
hash: function(buf) {
|
|
1355
|
+
return crypto.subtle.digest('SHA-512',buf);
|
|
1356
|
+
}
|
|
966
1357
|
}
|
|
967
1358
|
}
|
|
968
1359
|
};
|
|
@@ -993,10 +1384,15 @@ libVES.Util.OID.prototype = {
|
|
|
993
1384
|
}
|
|
994
1385
|
}
|
|
995
1386
|
|
|
996
|
-
libVES.Util.OID['1.2.840.113549.1.5.13'] = libVES.getModuleFunc(libVES,['Util','PKCS5']);
|
|
997
|
-
libVES.Util.OID['1.2.840.113549.1.5.12'] = libVES.getModuleFunc(libVES,['Util','PBKDF2']);
|
|
998
|
-
libVES.Util.OID['2.16.840.1.101.3.4.1.42'] = libVES.getModuleFunc(libVES,['Cipher','AES256CBC']);
|
|
999
|
-
libVES.Util.OID['1.2.840.113549.1.1.1'] = libVES.getModuleFunc(libVES,['Util','PKCS1']);
|
|
1387
|
+
libVES.Util.OID['1.2.840.113549.1.5.13'] = libVES.getModuleFunc(libVES, ['Util', 'PKCS5']);
|
|
1388
|
+
libVES.Util.OID['1.2.840.113549.1.5.12'] = libVES.getModuleFunc(libVES, ['Util', 'PBKDF2']);
|
|
1389
|
+
libVES.Util.OID['2.16.840.1.101.3.4.1.42'] = libVES.getModuleFunc(libVES, ['Cipher', 'AES256CBC']);
|
|
1390
|
+
libVES.Util.OID['1.2.840.113549.1.1.1'] = libVES.getModuleFunc(libVES, ['Util', 'PKCS1']);
|
|
1391
|
+
libVES.Util.OID['1.2.840.10045.2.1'] = libVES.Util.OID['1.3.132.1.12'] = libVES.Util.OID['1.3.132.112'] = libVES.getModuleFunc(libVES, ['Util', 'EC']);
|
|
1392
|
+
libVES.Util.OID['1.2.840.113549.2.7'] = libVES.getModuleFunc(libVES, ['Util', 'Hash', 'SHA1']);
|
|
1393
|
+
libVES.Util.OID['1.2.840.113549.2.9'] = libVES.getModuleFunc(libVES, ['Util', 'Hash', 'SHA256']);
|
|
1394
|
+
libVES.Util.OID['1.2.840.113549.2.10'] = libVES.getModuleFunc(libVES, ['Util', 'Hash', 'SHA384']);
|
|
1395
|
+
libVES.Util.OID['1.2.840.113549.2.11'] = libVES.getModuleFunc(libVES, ['Util', 'Hash', 'SHA512']);
|
|
1000
1396
|
|
|
1001
1397
|
libVES.Math = {
|
|
1002
1398
|
pad: function(a,n) {
|
|
@@ -1374,10 +1770,6 @@ libVES.External = function(data,VES,refs) {
|
|
|
1374
1770
|
this.init(data,VES,refs);
|
|
1375
1771
|
};
|
|
1376
1772
|
|
|
1377
|
-
libVES.Lockbox = function(data,VES,refs) {
|
|
1378
|
-
this.init(data,VES,refs);
|
|
1379
|
-
};
|
|
1380
|
-
|
|
1381
1773
|
libVES.File = function(data,VES,refs) {
|
|
1382
1774
|
this.init(data,VES,refs);
|
|
1383
1775
|
};
|
|
@@ -1386,7 +1778,7 @@ libVES.User.prototype = new libVES.Object({
|
|
|
1386
1778
|
apiUri: 'users',
|
|
1387
1779
|
fieldList: {id: true, email: true, type: true, firstName: true, lastName: true},
|
|
1388
1780
|
fieldExtra: {vaultKeys: true, activeVaultKeys: true, currentVaultKey: true},
|
|
1389
|
-
fieldClass: {vaultKeys: libVES.VaultKey, activeVaultKeys: libVES.VaultKey, currentVaultKey: libVES.VaultKey, shadowVaultKey: libVES.VaultKey,
|
|
1781
|
+
fieldClass: {vaultKeys: libVES.VaultKey, activeVaultKeys: libVES.VaultKey, currentVaultKey: libVES.VaultKey, shadowVaultKey: libVES.VaultKey, friendsKeyItems: libVES.VaultItem},
|
|
1390
1782
|
getEmail: function() {
|
|
1391
1783
|
return this.getField('email');
|
|
1392
1784
|
},
|
|
@@ -1416,11 +1808,10 @@ libVES.User.prototype = new libVES.Object({
|
|
|
1416
1808
|
});
|
|
1417
1809
|
return this.getField('activeVaultKeys');
|
|
1418
1810
|
},
|
|
1419
|
-
|
|
1420
|
-
return this.getField('
|
|
1811
|
+
getFriendsKeyItems: function() {
|
|
1812
|
+
return this.getField('friendsKeyItems');
|
|
1421
1813
|
},
|
|
1422
1814
|
getCurrentVaultKey: function() {
|
|
1423
|
-
|
|
1424
1815
|
return this.getField('currentVaultKey');
|
|
1425
1816
|
},
|
|
1426
1817
|
getShadowVaultKey: function() {
|
|
@@ -1452,9 +1843,9 @@ libVES.User.prototype = new libVES.Object({
|
|
|
1452
1843
|
libVES.VaultKey.prototype = new libVES.Object({
|
|
1453
1844
|
apiUri: 'vaultKeys',
|
|
1454
1845
|
fieldList: {id: true, algo: true, type: true, publicKey: true, privateKey: true},
|
|
1455
|
-
fieldClass: {user: libVES.User, vaultItems: libVES.VaultItem, externals: libVES.External,
|
|
1846
|
+
fieldClass: {user: libVES.User, vaultItems: libVES.VaultItem, externals: libVES.External, unlockableVaultKeys: libVES.VaultKey, creator: libVES.User},
|
|
1456
1847
|
fieldExtra: {user: true, vaultItems: true},
|
|
1457
|
-
fieldSets: [{vaultEntries: {id: true, encData: true, vaultItem: {id: true}}},{type: true, algo: true, publicKey: true}],
|
|
1848
|
+
fieldSets: [{vaultEntries: {id: true, encData: true, vaultItem: {id: true}}},{type: true, algo: true, publicKey: true}, {unlockableVaultKeys: {id: true, type: true}}],
|
|
1458
1849
|
getAlgo: function() {
|
|
1459
1850
|
return this.getField('algo');
|
|
1460
1851
|
},
|
|
@@ -1478,18 +1869,12 @@ libVES.VaultKey.prototype = new libVES.Object({
|
|
|
1478
1869
|
getVaultItems: function() {
|
|
1479
1870
|
return this.getField('vaultItems');
|
|
1480
1871
|
},
|
|
1481
|
-
getSharedKeys: function() {
|
|
1482
|
-
return this.getField('sharedKeys');
|
|
1483
|
-
},
|
|
1484
1872
|
getExternals: function() {
|
|
1485
1873
|
return this.getField('externals');
|
|
1486
1874
|
},
|
|
1487
1875
|
getUser: function() {
|
|
1488
1876
|
return this.getField('user');
|
|
1489
1877
|
},
|
|
1490
|
-
getVaultItems: function() {
|
|
1491
|
-
return this.getField('vaultItems');
|
|
1492
|
-
},
|
|
1493
1878
|
resolveVESkey: function(veskey) {
|
|
1494
1879
|
if (veskey) return Promise.resolve(veskey);
|
|
1495
1880
|
var self = this;
|
|
@@ -1497,6 +1882,7 @@ libVES.VaultKey.prototype = new libVES.Object({
|
|
|
1497
1882
|
switch (t) {
|
|
1498
1883
|
case 'secondary':
|
|
1499
1884
|
case 'temp':
|
|
1885
|
+
case 'lost':
|
|
1500
1886
|
return self.getVaultItems().then(function(vis) {
|
|
1501
1887
|
var f = function(vis) {
|
|
1502
1888
|
if (!vis.length) throw new libVES.Error('InvalidKey','Cannot unlock the secondary key');
|
|
@@ -1564,10 +1950,12 @@ libVES.VaultKey.prototype = new libVES.Object({
|
|
|
1564
1950
|
self.setField('algo',wc.engine.tag);
|
|
1565
1951
|
if (!wc.privateKey) throw new libVES.Error('InvalidValue','Private key expected');
|
|
1566
1952
|
return wc;
|
|
1567
|
-
}) :
|
|
1568
|
-
return
|
|
1569
|
-
ks
|
|
1570
|
-
|
|
1953
|
+
}) : (optns && optns.algo ? self.setField('algo',optns.algo) : Promise.resolve()).then(function() {
|
|
1954
|
+
return self.engine().then(function(e) {
|
|
1955
|
+
return e.generate(optns).then(function(ks) {
|
|
1956
|
+
ks.engine = e;
|
|
1957
|
+
return ks;
|
|
1958
|
+
});
|
|
1571
1959
|
});
|
|
1572
1960
|
});
|
|
1573
1961
|
return Promise.resolve(veskey).then(function(v) {
|
|
@@ -1611,16 +1999,14 @@ libVES.VaultKey.prototype = new libVES.Object({
|
|
|
1611
1999
|
var self = this;
|
|
1612
2000
|
var old_vis = {};
|
|
1613
2001
|
return (self.vaultEntries ? self.vaultEntries.then(function(old_ves) {
|
|
1614
|
-
return old_ves.map(function(ve,i) {
|
|
2002
|
+
if (old_ves) return old_ves.map(function(ve,i) {
|
|
1615
2003
|
old_vis[ve.vaultItem.id] = true;
|
|
1616
2004
|
});
|
|
1617
2005
|
}) : Promise.resolve(null)).then(function() {
|
|
1618
2006
|
return self.setField('vaultEntries',key.unlock(veskey).then(function() {
|
|
1619
2007
|
return key.getVaultEntries().then(function(ves) {
|
|
1620
2008
|
return Promise.all(ves.map(function(ve) {
|
|
1621
|
-
return old_vis[ve.vaultItem.id] ?
|
|
1622
|
-
vaultItem: {id: ve.vaultItem.id}
|
|
1623
|
-
}) : key.decrypt(ve.encData).then(function(ptxt) {
|
|
2009
|
+
return old_vis[ve.vaultItem.id] ? null : key.decrypt(ve.encData).then(function(ptxt) {
|
|
1624
2010
|
return self.encrypt(ptxt).then(function(ctxt) {
|
|
1625
2011
|
return {
|
|
1626
2012
|
vaultItem: {id: ve.vaultItem.id},
|
|
@@ -1633,6 +2019,8 @@ libVES.VaultKey.prototype = new libVES.Object({
|
|
|
1633
2019
|
"$op": "ignore"
|
|
1634
2020
|
};
|
|
1635
2021
|
});
|
|
2022
|
+
}).filter(function(e, i) {
|
|
2023
|
+
return !!e;
|
|
1636
2024
|
}));
|
|
1637
2025
|
});
|
|
1638
2026
|
}));
|
|
@@ -1640,7 +2028,7 @@ libVES.VaultKey.prototype = new libVES.Object({
|
|
|
1640
2028
|
return self;
|
|
1641
2029
|
});
|
|
1642
2030
|
},
|
|
1643
|
-
rekey: function() {
|
|
2031
|
+
rekey: function(optns) {
|
|
1644
2032
|
var self = this;
|
|
1645
2033
|
return self.getUser().then(function(user) {
|
|
1646
2034
|
return self.getExternals().then(function(exts) {
|
|
@@ -1661,20 +2049,24 @@ libVES.VaultKey.prototype = new libVES.Object({
|
|
|
1661
2049
|
}));
|
|
1662
2050
|
}).then(function(keys) {
|
|
1663
2051
|
return user.setField('vaultKeys',keys).then(function() {
|
|
1664
|
-
|
|
2052
|
+
if (!optns) optns = {};
|
|
2053
|
+
optns.refs = {'#/': user};
|
|
2054
|
+
return user.post(null,{vaultEntries: true}, optns).then(function(data) {
|
|
1665
2055
|
self.setFields(data,false);
|
|
1666
|
-
return self
|
|
2056
|
+
return self.VES.onRekey ? self.VES.onRekey(self).catch(function() {}).then(function() {
|
|
2057
|
+
return self;
|
|
2058
|
+
}) : self;
|
|
1667
2059
|
});
|
|
1668
2060
|
});
|
|
1669
2061
|
});
|
|
1670
2062
|
});
|
|
1671
2063
|
},
|
|
1672
|
-
getRecovery: function() {
|
|
2064
|
+
getRecovery: function(myItems) {
|
|
1673
2065
|
var self = this;
|
|
1674
2066
|
return self.getType().then(function(t) {
|
|
1675
2067
|
switch (t) {
|
|
1676
2068
|
case 'shadow': case 'recovery':
|
|
1677
|
-
return new libVES.Recovery(self);
|
|
2069
|
+
return new libVES.Recovery(self, myItems);
|
|
1678
2070
|
default: throw new libVES.Error('InvalidValue','Recovery is not applicable for VaultKey type ' + t);
|
|
1679
2071
|
}
|
|
1680
2072
|
});
|
|
@@ -1682,18 +2074,21 @@ libVES.VaultKey.prototype = new libVES.Object({
|
|
|
1682
2074
|
getSessionToken: function() {
|
|
1683
2075
|
var self = this;
|
|
1684
2076
|
return this.getField('encSessionToken').then(function(tk) {
|
|
2077
|
+
if (!tk) return null;
|
|
1685
2078
|
return self.decrypt(tk).then(function(b) {
|
|
1686
2079
|
return libVES.Util.ByteArrayToString(b);
|
|
1687
2080
|
});
|
|
1688
2081
|
});
|
|
1689
2082
|
},
|
|
1690
|
-
reshareVESkey: function(veskey) {
|
|
2083
|
+
reshareVESkey: function(veskey, optns) {
|
|
1691
2084
|
var self = this;
|
|
1692
2085
|
return self.getVaultItems().then(function(vaultItems) {
|
|
1693
2086
|
return self.getUser().then(function(user) {
|
|
1694
2087
|
return Promise.all(vaultItems.map(function(vaultItem,i) {
|
|
1695
2088
|
return vaultItem.getType().then(function(t) {
|
|
1696
|
-
if (t == 'password') return vaultItem.reshareWith([user],veskey)
|
|
2089
|
+
if (t == 'password') return vaultItem.reshareWith([user], veskey, false).then(function(vi) {
|
|
2090
|
+
return vi.post(undefined, undefined, optns);
|
|
2091
|
+
});
|
|
1697
2092
|
});
|
|
1698
2093
|
}));
|
|
1699
2094
|
});
|
|
@@ -1708,29 +2103,33 @@ libVES.VaultItem.prototype = new libVES.Object({
|
|
|
1708
2103
|
apiUri: 'vaultItems',
|
|
1709
2104
|
fieldList: {id: true},
|
|
1710
2105
|
fieldClass: {vaultKey: libVES.VaultKey, file: libVES.File},
|
|
1711
|
-
fieldSets: [{type: true, meta: true},{vaultEntries: {id: true, encData: true, vaultKey: {id: true
|
|
1712
|
-
defaultCipher: '
|
|
2106
|
+
fieldSets: [{type: true, meta: true},{vaultEntries: {id: true, encData: true, vaultKey: {id: true, type: true, user: {id: true}, algo: true, externals: {id: true}}}},{vaultKey: true, file: true}],
|
|
2107
|
+
defaultCipher: 'AES256GCM',
|
|
1713
2108
|
getRaw: function() {
|
|
1714
2109
|
var self = this;
|
|
1715
|
-
|
|
1716
|
-
var
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
return k.decrypt(d).catch(fn);
|
|
1724
|
-
}
|
|
2110
|
+
var f = function(vaultEntries, vaultKeys) {
|
|
2111
|
+
var i = 0;
|
|
2112
|
+
var fn = function() {
|
|
2113
|
+
if (vaultEntries) for (; i < vaultEntries.length; i++) {
|
|
2114
|
+
var k, d;
|
|
2115
|
+
if ((d = vaultEntries[i].encData) != null && vaultKeys[(k = vaultEntries[i].vaultKey).id]) {
|
|
2116
|
+
i++;
|
|
2117
|
+
return new libVES.VaultKey(k, self.VES).decrypt(d).catch(fn);
|
|
1725
2118
|
}
|
|
1726
|
-
|
|
1727
|
-
};
|
|
1728
|
-
return fn();
|
|
2119
|
+
}
|
|
2120
|
+
return Promise.reject(new libVES.Error('InvalidKey',"No unlocked key to decrypt the item",{vaultItem: self}));
|
|
1729
2121
|
};
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
2122
|
+
return fn();
|
|
2123
|
+
};
|
|
2124
|
+
var vaultEntries = [];
|
|
2125
|
+
if (self.vaultEntryByKey) for (var k in self.vaultEntryByKey) vaultEntries.push(self.vaultEntryByKey[k]);
|
|
2126
|
+
return f(vaultEntries, self.VES.unlockedKeys).catch(function() {
|
|
2127
|
+
return self.getVaultEntries().then(function(vaultEntries) {
|
|
2128
|
+
return f(vaultEntries, self.VES.unlockedKeys).catch(function() {
|
|
2129
|
+
return self.VES.getUnlockableKeys().then(function(vks) {
|
|
2130
|
+
return f(vaultEntries, vks);
|
|
2131
|
+
});
|
|
2132
|
+
});
|
|
1734
2133
|
});
|
|
1735
2134
|
});
|
|
1736
2135
|
},
|
|
@@ -1749,7 +2148,7 @@ libVES.VaultItem.prototype = new libVES.Object({
|
|
|
1749
2148
|
getVaultEntries: function() {
|
|
1750
2149
|
var self = this;
|
|
1751
2150
|
return this.getField('vaultEntries').then(function(ves) {
|
|
1752
|
-
for (var i = 0; i < ves.length; i++) self.vaultEntryByKey[ves[i].vaultKey.id] = ves[i];
|
|
2151
|
+
if (ves) for (var i = 0; i < ves.length; i++) self.vaultEntryByKey[ves[i].vaultKey.id] = ves[i];
|
|
1753
2152
|
return ves;
|
|
1754
2153
|
});
|
|
1755
2154
|
},
|
|
@@ -1759,9 +2158,6 @@ libVES.VaultItem.prototype = new libVES.Object({
|
|
|
1759
2158
|
getFile: function() {
|
|
1760
2159
|
return this.getField('file');
|
|
1761
2160
|
},
|
|
1762
|
-
getLockbox: function() {
|
|
1763
|
-
return this.getField('lockbox');
|
|
1764
|
-
},
|
|
1765
2161
|
parse: function(buf) {
|
|
1766
2162
|
var self = this;
|
|
1767
2163
|
return this.getType().then(function(type) {
|
|
@@ -1780,42 +2176,49 @@ libVES.VaultItem.prototype = new libVES.Object({
|
|
|
1780
2176
|
});
|
|
1781
2177
|
});
|
|
1782
2178
|
},
|
|
2179
|
+
resolveRaw: function(val) {
|
|
2180
|
+
return (val == null ? this.getRaw() : this.build(val));
|
|
2181
|
+
},
|
|
1783
2182
|
shareWith: function(usrs,val,save) {
|
|
1784
2183
|
var self = this;
|
|
1785
|
-
return
|
|
1786
|
-
return self.
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
return
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
2184
|
+
return self.VES.usersToKeys(usrs).then(function(ks) {
|
|
2185
|
+
return (val == null || self.id ? self.getVaultEntries().then(function(ves) {
|
|
2186
|
+
var k_ves = {};
|
|
2187
|
+
var k_used = {};
|
|
2188
|
+
for (var j = 0; j < ves.length; j++) k_ves[ves[j].vaultKey.id] = ves[j];
|
|
2189
|
+
return Promise.all(ks.map(function(k,j) {
|
|
2190
|
+
return k.getId().then(function(k_id) {
|
|
2191
|
+
k_used[k_id] = true;
|
|
2192
|
+
return k_ves[k_id];
|
|
2193
|
+
}).catch(function(){});
|
|
2194
|
+
})).then(function(old_ves) {
|
|
2195
|
+
for (var k_id in k_ves) if (!k_used[k_id]) old_ves.push(k_ves[k_id]);
|
|
2196
|
+
return old_ves;
|
|
2197
|
+
});
|
|
2198
|
+
}) : Promise.resolve([])).then(function(old_ves) {
|
|
2199
|
+
var new_ves = [];
|
|
2200
|
+
var set_ves = [];
|
|
2201
|
+
var valr = null;
|
|
2202
|
+
return Promise.all(ks.map(function(k,j) {
|
|
2203
|
+
return new_ves[j] = (old_ves[j] || (valr != null ? valr : valr = self.resolveRaw(val)).then(function(v) {
|
|
2204
|
+
return k.encrypt(v).then(function(ctext) {
|
|
2205
|
+
return (function(refs) {
|
|
2206
|
+
if (refs) for (var i in refs) if (refs[i] === k) return Promise.resolve({'$ref':i});
|
|
2207
|
+
return k.postData(null,refs);
|
|
2208
|
+
})(libVES.Object._refs).then(function(pd) {
|
|
1806
2209
|
return set_ves.push({vaultKey: pd, encData: ctext});
|
|
1807
2210
|
});
|
|
1808
|
-
})
|
|
1809
|
-
}))
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
});
|
|
1814
|
-
})
|
|
1815
|
-
})
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
|
|
2211
|
+
});
|
|
2212
|
+
}));
|
|
2213
|
+
})).then(function() {
|
|
2214
|
+
return Promise.all(old_ves.slice(ks.length).map(function(ve,j) {
|
|
2215
|
+
return (new libVES.VaultKey(ve.vaultKey,self.VES)).matchVaults(ks).then(function(f) {
|
|
2216
|
+
if (f === false) set_ves.push({vaultKey: {id: ve.vaultKey.id}, '$op': 'delete'});
|
|
2217
|
+
});
|
|
2218
|
+
}));
|
|
2219
|
+
}).then(function() {
|
|
2220
|
+
if (!set_ves.length) return save = false;
|
|
2221
|
+
return self.setField('vaultEntries',set_ves);
|
|
1819
2222
|
});
|
|
1820
2223
|
});
|
|
1821
2224
|
}).then(function() {
|
|
@@ -1835,7 +2238,9 @@ libVES.VaultItem.prototype = new libVES.Object({
|
|
|
1835
2238
|
var m_curr_ks = {};
|
|
1836
2239
|
for (var i = 0; i < curr_ks.length; i++) m_curr_ks[curr_ids[i]] = curr_ks[i];
|
|
1837
2240
|
return Promise.all(new_ks.map(function(k,i) {
|
|
1838
|
-
return k.getId()
|
|
2241
|
+
return k.getId().catch(function(e) {
|
|
2242
|
+
if (e.code != 'NotFound') throw e;
|
|
2243
|
+
});
|
|
1839
2244
|
})).then(function(new_ids) {
|
|
1840
2245
|
for (var i = 0; i < new_ks.length; i++) if (!m_curr_ks[new_ids[i]]) curr_ks.push(m_curr_ks[new_ids[i]] = new_ks[i]);
|
|
1841
2246
|
return self.shareWith(curr_ks,val,save);
|
|
@@ -1898,8 +2303,9 @@ libVES.VaultItem.Type = {
|
|
|
1898
2303
|
return new ci(new Uint8Array(buf));
|
|
1899
2304
|
});
|
|
1900
2305
|
},
|
|
1901
|
-
|
|
2306
|
+
build: function(data) {
|
|
1902
2307
|
if (!(data instanceof libVES.Cipher)) throw new libVES.Error('InvalidData',"Content of a VaultItem type 'file' must be libVES.Cipher");
|
|
2308
|
+
this.setField('meta', data.getMeta());
|
|
1903
2309
|
return data.getSecret();
|
|
1904
2310
|
}
|
|
1905
2311
|
},
|
|
@@ -1921,10 +2327,13 @@ libVES.VaultItem.Type.password = libVES.VaultItem.Type.string;
|
|
|
1921
2327
|
libVES.File.prototype = new libVES.Object({
|
|
1922
2328
|
apiUri: 'files',
|
|
1923
2329
|
fieldList: {id: true},
|
|
1924
|
-
fieldClass: {externals: libVES.External},
|
|
2330
|
+
fieldClass: {externals: libVES.External, creator: libVES.User},
|
|
1925
2331
|
getExternals: function() {
|
|
1926
2332
|
return this.getField('externals');
|
|
1927
|
-
}
|
|
2333
|
+
},
|
|
2334
|
+
getCreator: function() {
|
|
2335
|
+
return this.getField('creator');
|
|
2336
|
+
},
|
|
1928
2337
|
});
|
|
1929
2338
|
|
|
1930
2339
|
libVES.External.prototype = new libVES.Object({
|
|
@@ -1944,49 +2353,171 @@ libVES.External.prototype = new libVES.Object({
|
|
|
1944
2353
|
});
|
|
1945
2354
|
|
|
1946
2355
|
libVES.Algo = {
|
|
1947
|
-
|
|
1948
|
-
tag: '
|
|
2356
|
+
ECDH: {
|
|
2357
|
+
tag: 'ECDH',
|
|
1949
2358
|
decrypt: function(k,buf) {
|
|
1950
|
-
|
|
2359
|
+
var b = new Uint8Array(buf);
|
|
2360
|
+
var data = libVES.Util.ASN1.decode(b);
|
|
2361
|
+
if (!data || data.length < 2) throw new libVES.Error('InvalidValue','Error parsing ECIES: Invalid ciphertext?');
|
|
2362
|
+
return libVES.Util.ASN1.import(b.slice(0,b.byteLength - data[1].byteLength),{decoded:data[0]}).then(function(eKey) {
|
|
2363
|
+
return libVES.Algo.ECDH.cipher(k,eKey).then(function(ci) {
|
|
2364
|
+
return ci.decrypt(data[1],true).catch(function(e) {
|
|
2365
|
+
if (e instanceof libVES.Error) throw e;
|
|
2366
|
+
throw new libVES.Error('InvalidValue','Error decrypting ECIES payload: Invalid ciphertext?',{error:e});
|
|
2367
|
+
});
|
|
2368
|
+
}).catch(function(e) {
|
|
2369
|
+
if (e instanceof libVES.Error) throw e;
|
|
2370
|
+
throw new libVES.Error('InvalidValue','Error negotiating DH cipher key: Invalid ciphertext?',{error:e});
|
|
2371
|
+
});
|
|
2372
|
+
}).catch(function(e) {
|
|
2373
|
+
if (e instanceof libVES.Error) throw e;
|
|
2374
|
+
throw new libVES.Error('InvalidValue','Error loading EC ephemeral: Invalid ciphertext?',{error:e});
|
|
2375
|
+
});
|
|
1951
2376
|
},
|
|
1952
2377
|
encrypt: function(k,buf) {
|
|
1953
|
-
return
|
|
2378
|
+
return libVES.Algo.ECDH.eKey(k).then(function(eKey) {
|
|
2379
|
+
return libVES.Algo.ECDH.cipher(eKey.privateKey,k).then(function(ci) {
|
|
2380
|
+
return Promise.all([
|
|
2381
|
+
crypto.subtle.exportKey('spki',eKey.publicKey),
|
|
2382
|
+
ci.encrypt(buf,true)
|
|
2383
|
+
]).then(function(bufs) {
|
|
2384
|
+
var buf = new Uint8Array(bufs[0].byteLength + bufs[1].byteLength);
|
|
2385
|
+
buf.set(new Uint8Array(bufs[0]),0);
|
|
2386
|
+
buf.set(new Uint8Array(bufs[1]),bufs[0].byteLength);
|
|
2387
|
+
return buf;
|
|
2388
|
+
});
|
|
2389
|
+
}).catch(function(e) {
|
|
2390
|
+
if (e instanceof libVES.Error) throw e;
|
|
2391
|
+
throw new libVES.Error('InvalidValue','Error generating ECIES DH cipher',{error:e});
|
|
2392
|
+
});
|
|
2393
|
+
});
|
|
2394
|
+
},
|
|
2395
|
+
eKey: function(pub) {
|
|
2396
|
+
return crypto.subtle.exportKey('jwk',pub).then(function(kdata) {
|
|
2397
|
+
return crypto.subtle.generateKey({name:'ECDH',namedCurve: kdata.crv},true,['deriveKey','deriveBits']).catch(function(e) {
|
|
2398
|
+
throw new libVES.Error('InvalidValue','Error generating ECIES ephemeral',{error: e});
|
|
2399
|
+
});
|
|
2400
|
+
});
|
|
2401
|
+
},
|
|
2402
|
+
cipher: function(priv,pub) {
|
|
2403
|
+
return libVES.getModule(libVES.Cipher,'AES256GCMp').then(function(m) {
|
|
2404
|
+
return Promise.resolve(libVES.Algo.ECDH.curveBytes[pub.algorithm.namedCurve] || crypto.subtle.exportKey('jwk',pub).then(function(jwk) {
|
|
2405
|
+
return jwk.x.length * 3 / 4;
|
|
2406
|
+
})).then(function(len) {
|
|
2407
|
+
return crypto.subtle.deriveBits({name:'ECDH',public:pub},priv,8 * len).then(function(raw) {
|
|
2408
|
+
return crypto.subtle.digest({name:'SHA-384'},raw).then(function(buf) {
|
|
2409
|
+
return new m(new Uint8Array(buf).slice(0,m.prototype.keySize + m.prototype.ivSize));
|
|
2410
|
+
});
|
|
2411
|
+
});
|
|
2412
|
+
});
|
|
2413
|
+
});
|
|
2414
|
+
},
|
|
2415
|
+
curveBytes: {
|
|
2416
|
+
'P-256': 32,
|
|
2417
|
+
'P-384': 48,
|
|
2418
|
+
'P-521': 66
|
|
1954
2419
|
},
|
|
1955
2420
|
import: function(data,optns) {
|
|
1956
2421
|
return libVES.Util.PEM.import(data,optns);
|
|
1957
2422
|
},
|
|
1958
2423
|
export: function(data,optns) {
|
|
1959
2424
|
if (data instanceof CryptoKey) switch (data.type) {
|
|
1960
|
-
case 'private':
|
|
1961
|
-
var ops = {};
|
|
1962
|
-
for (var k in optns) ops[k] = optns[k];
|
|
1963
|
-
if (!ops.members) ops.members = [
|
|
1964
|
-
libVES.getModule(libVES.Util,'PBKDF2'),
|
|
1965
|
-
libVES.getModule(libVES.Cipher,'AES256CBC')
|
|
1966
|
-
];
|
|
1967
|
-
return Promise.all(ops.members).then(function(ms) {
|
|
1968
|
-
ops.members = ms;
|
|
1969
|
-
return crypto.subtle.exportKey('pkcs8',data).then(function(der) {
|
|
1970
|
-
ops.content = der;
|
|
1971
|
-
var rec = [];
|
|
1972
|
-
if (ops.password) return libVES.Util.PKCS5.export(function(call,optns) {
|
|
1973
|
-
rec[1] = optns.content;
|
|
1974
|
-
return Promise.resolve();
|
|
1975
|
-
},ops).then(function(data) {
|
|
1976
|
-
rec[0] = data;
|
|
1977
|
-
return libVES.Util.PEM.encode(libVES.Util.ASN1.encode([rec]),'ENCRYPTED PRIVATE KEY');
|
|
1978
|
-
});
|
|
1979
|
-
else if (ops.opentext) return crypto.subtle.exportKey('pkcs8',data).then(function(der) {
|
|
1980
|
-
return libVES.Util.PEM.encode(der,'PRIVATE KEY');
|
|
1981
|
-
});
|
|
1982
|
-
else throw libVES.Error('Internal','No password for key export (opentext=true to export without password?)');
|
|
1983
|
-
});
|
|
1984
|
-
});
|
|
2425
|
+
case 'private': return libVES.Util.PKCS8.encode(data, optns);
|
|
1985
2426
|
case 'public':
|
|
1986
|
-
return crypto.subtle.exportKey('spki',data).then(function(der) {
|
|
1987
|
-
|
|
2427
|
+
return crypto.subtle.exportKey('spki', data).then(function(der) {
|
|
2428
|
+
var asn = libVES.Util.ASN1.decode(new Uint8Array(der))[0];
|
|
2429
|
+
console.log(asn);
|
|
2430
|
+
switch (String(asn[0][0])) {
|
|
2431
|
+
case '1.2.840.10045.2.1':
|
|
2432
|
+
return der;
|
|
2433
|
+
case '1.3.132.1.12':
|
|
2434
|
+
case '1.3.132.112': // Firefox on Mac - apparently a misspelling of the former
|
|
2435
|
+
asn[0][0] = new libVES.Util.OID('1.2.840.10045.2.1');
|
|
2436
|
+
asn[1].ASN1type = 3;
|
|
2437
|
+
return libVES.Util.ASN1.encode([asn]);
|
|
2438
|
+
default:
|
|
2439
|
+
console.log(asn);
|
|
2440
|
+
throw new libVES.Error('Internal', 'Unexpected EC pubkey format');
|
|
2441
|
+
}
|
|
2442
|
+
return der;
|
|
2443
|
+
}).then(function(der) {
|
|
2444
|
+
return libVES.Util.PEM.encode(der, 'PUBLIC KEY');
|
|
1988
2445
|
});
|
|
1989
2446
|
}
|
|
2447
|
+
throw new libVES.Error('Internal', "Unknown type of key object");
|
|
2448
|
+
},
|
|
2449
|
+
generate: function(optns) {
|
|
2450
|
+
var op = {name:'ECDH', namedCurve:'P-384'};
|
|
2451
|
+
if (optns) for (var k in optns) op[k] = optns[k];
|
|
2452
|
+
return crypto.subtle.generateKey(op,true,['deriveKey','deriveBits']);
|
|
2453
|
+
},
|
|
2454
|
+
getPublic: function(priv) {
|
|
2455
|
+
return crypto.subtle.exportKey('jwk',priv).then(function(k) {
|
|
2456
|
+
return crypto.subtle.importKey('jwk',{
|
|
2457
|
+
crv: k.crv,
|
|
2458
|
+
ext: true,
|
|
2459
|
+
key_ops: [],
|
|
2460
|
+
kty: 'EC',
|
|
2461
|
+
x: k.x,
|
|
2462
|
+
y: k.y
|
|
2463
|
+
},{name:'ECDH'},true,[]);
|
|
2464
|
+
});
|
|
2465
|
+
}
|
|
2466
|
+
},
|
|
2467
|
+
RSA: {
|
|
2468
|
+
tag: 'RSA',
|
|
2469
|
+
decrypt: function(k,buf) {
|
|
2470
|
+
var self = libVES.Algo.RSA;
|
|
2471
|
+
var maxl = (k.algorithm.modulusLength + 7) >> 3;
|
|
2472
|
+
if (buf.byteLength <= maxl) return self.decryptRSA(k,buf);
|
|
2473
|
+
var b = new Uint8Array(buf);
|
|
2474
|
+
return self.decryptRSA(k,b.slice(0,maxl)).then(function(ck) {
|
|
2475
|
+
return self.cipher(ck).then(function(ci) {
|
|
2476
|
+
return ci.decrypt(b.slice(maxl),true);
|
|
2477
|
+
});
|
|
2478
|
+
});
|
|
2479
|
+
},
|
|
2480
|
+
decryptRSA: function(k,buf) {
|
|
2481
|
+
return crypto.subtle.decrypt('RSA-OAEP',k,buf).catch(function(e) {
|
|
2482
|
+
throw new libVES.Error('InvalidValue','Error decrypting RSA OAEP: Invalid ciphertext?',{error:e});
|
|
2483
|
+
});
|
|
2484
|
+
},
|
|
2485
|
+
encrypt: function(k,buf) {
|
|
2486
|
+
var self = libVES.Algo.RSA;
|
|
2487
|
+
var maxl = ((k.algorithm.modulusLength + 7) >> 3) - 48;
|
|
2488
|
+
if (buf.byteLength <= maxl) return self.encryptRSA(k,buf);
|
|
2489
|
+
return self.cipher().then(function(ci) {
|
|
2490
|
+
return Promise.all([
|
|
2491
|
+
ci.getSecret().then(function(sk) {
|
|
2492
|
+
return self.encryptRSA(k,sk);
|
|
2493
|
+
}),
|
|
2494
|
+
ci.encrypt(buf,true)
|
|
2495
|
+
]).then(function(bufs) {
|
|
2496
|
+
var rs = new Uint8Array(bufs[0].byteLength + bufs[1].byteLength);
|
|
2497
|
+
rs.set(new Uint8Array(bufs[0]),0);
|
|
2498
|
+
rs.set(new Uint8Array(bufs[1]),bufs[0].byteLength);
|
|
2499
|
+
return rs;
|
|
2500
|
+
});
|
|
2501
|
+
});
|
|
2502
|
+
},
|
|
2503
|
+
encryptRSA: function(k,buf) {
|
|
2504
|
+
return crypto.subtle.encrypt('RSA-OAEP',k,buf).catch(function(e) {
|
|
2505
|
+
throw new libVES.Error('InvalidValue','Error encrypting RSA OAEP: Buffer is too long?',{error:e});
|
|
2506
|
+
});;
|
|
2507
|
+
},
|
|
2508
|
+
cipher: function(secret) {
|
|
2509
|
+
return libVES.getModule(libVES.Cipher,'AES256GCMp').then(function(cls) {
|
|
2510
|
+
return new cls(secret);
|
|
2511
|
+
});
|
|
2512
|
+
},
|
|
2513
|
+
import: function(data,optns) {
|
|
2514
|
+
return libVES.Util.PEM.import(data,optns);
|
|
2515
|
+
},
|
|
2516
|
+
export: function(data,optns) {
|
|
2517
|
+
if (data instanceof CryptoKey) switch (data.type) {
|
|
2518
|
+
case 'private': return libVES.Util.PKCS8.encode(data,optns);
|
|
2519
|
+
case 'public': return libVES.Util.PKCS1.encode(data,optns);
|
|
2520
|
+
}
|
|
1990
2521
|
throw new libVES.Error('Internal',"Unknown type of key object");
|
|
1991
2522
|
},
|
|
1992
2523
|
generate: function(optns) {
|
|
@@ -2006,7 +2537,6 @@ libVES.Algo = {
|
|
|
2006
2537
|
},{name:'RSA-OAEP',hash:'SHA-1'},true,['encrypt']);
|
|
2007
2538
|
});
|
|
2008
2539
|
}
|
|
2009
|
-
|
|
2010
2540
|
},
|
|
2011
2541
|
RSA_PKCS1_15: {
|
|
2012
2542
|
tag: 'RSA_PKCS1_15',
|
|
@@ -2066,26 +2596,31 @@ libVES.Cipher.prototype = {
|
|
|
2066
2596
|
}
|
|
2067
2597
|
},
|
|
2068
2598
|
getSecret: function() {
|
|
2599
|
+
var self = this;
|
|
2069
2600
|
var meta = null;
|
|
2070
2601
|
if (this.meta) for (var k in this.meta) {
|
|
2071
2602
|
meta = libVES.Util.StringToByteArray(JSON.stringify(this.meta));
|
|
2072
2603
|
break;
|
|
2073
2604
|
}
|
|
2074
2605
|
var buf = new Uint8Array(this.keySize + this.ivSize + (meta ? meta.byteLength : 0));
|
|
2075
|
-
return Promise.all([this.
|
|
2076
|
-
return crypto.subtle.exportKey("raw",
|
|
2077
|
-
|
|
2078
|
-
|
|
2079
|
-
|
|
2080
|
-
|
|
2081
|
-
|
|
2606
|
+
return Promise.all([(this.algo ? this.key.then(function(key) {
|
|
2607
|
+
return crypto.subtle.exportKey("raw", key);
|
|
2608
|
+
}) : this.key), this.IV]).then(function(data) {
|
|
2609
|
+
buf.set(new Uint8Array(data[0]), 0);
|
|
2610
|
+
buf.set(new Uint8Array(data[1]), data[0].byteLength);
|
|
2611
|
+
if (meta) buf.set(new Uint8Array(meta), data[0].byteLength + data[1].byteLength);
|
|
2612
|
+
return buf;
|
|
2082
2613
|
});
|
|
2083
2614
|
},
|
|
2615
|
+
getMeta: function() {
|
|
2616
|
+
return {a: this.a};
|
|
2617
|
+
},
|
|
2084
2618
|
buildKey: function(key) {
|
|
2085
2619
|
if (!this.algo) return Promise.resolve(key);
|
|
2086
2620
|
return crypto.subtle.importKey('raw',key,this.algo,true,['encrypt','decrypt']);
|
|
2087
2621
|
},
|
|
2088
|
-
process: function(buf,final,callbk,
|
|
2622
|
+
process: function(buf,final,callbk,sizefn) {
|
|
2623
|
+
var self = this;
|
|
2089
2624
|
buf = new Uint8Array(buf);
|
|
2090
2625
|
if (this.processBuf) {
|
|
2091
2626
|
var b = new Uint8Array(buf.byteLength + this.processBuf.byteLength);
|
|
@@ -2093,9 +2628,24 @@ libVES.Cipher.prototype = {
|
|
|
2093
2628
|
b.set(buf,this.processBuf.byteLength);
|
|
2094
2629
|
buf = b;
|
|
2095
2630
|
}
|
|
2096
|
-
var
|
|
2097
|
-
|
|
2098
|
-
|
|
2631
|
+
var over = !final;
|
|
2632
|
+
var fn = function(cprev) {
|
|
2633
|
+
var chunkSize = sizefn();
|
|
2634
|
+
if ((!buf.byteLength && over) || (!final && (!chunkSize || buf.byteLength < chunkSize))) {
|
|
2635
|
+
self.processBuf = buf.byteLength ? buf : null;
|
|
2636
|
+
return Promise.resolve(cprev);
|
|
2637
|
+
}
|
|
2638
|
+
var cl = (chunkSize && chunkSize < buf.byteLength) ? chunkSize : buf.byteLength;
|
|
2639
|
+
if (!chunkSize || cl < chunkSize) over = true;
|
|
2640
|
+
return callbk(buf.slice(0, cl)).then(function(ctext) {
|
|
2641
|
+
buf = buf.slice(cl);
|
|
2642
|
+
var r = new Uint8Array(cprev.byteLength + ctext.byteLength);
|
|
2643
|
+
r.set(cprev, 0);
|
|
2644
|
+
r.set(new Uint8Array(ctext), cprev.byteLength);
|
|
2645
|
+
return r;
|
|
2646
|
+
}).then(fn);
|
|
2647
|
+
};
|
|
2648
|
+
return fn(new Uint8Array(0));
|
|
2099
2649
|
},
|
|
2100
2650
|
encryptChunk: function(buf) {
|
|
2101
2651
|
return Promise.all([this.key,this.algoInfo()]).then(function(info) {
|
|
@@ -2111,37 +2661,60 @@ libVES.Cipher.prototype = {
|
|
|
2111
2661
|
return Promise.resolve(this.algo);
|
|
2112
2662
|
},
|
|
2113
2663
|
encrypt: function(buf,final) {
|
|
2114
|
-
return this.process(buf,final,this.encryptChunk.bind(this),this.chunkSizeP);
|
|
2664
|
+
return this.process(buf,final,this.encryptChunk.bind(this),(function() { return this.chunkSizeP; }).bind(this));
|
|
2115
2665
|
},
|
|
2116
2666
|
decrypt: function(buf,final) {
|
|
2117
|
-
return this.process(buf,final,this.decryptChunk.bind(this),this.chunkSizeC);
|
|
2667
|
+
return this.process(buf,final,this.decryptChunk.bind(this),(function() { return this.chunkSizeC; }).bind(this));
|
|
2118
2668
|
}
|
|
2119
2669
|
};
|
|
2120
2670
|
|
|
2121
|
-
libVES.Cipher.
|
|
2671
|
+
libVES.Cipher.NULL = function(rec) {
|
|
2122
2672
|
this.init(rec);
|
|
2673
|
+
}
|
|
2674
|
+
|
|
2675
|
+
libVES.Cipher.AES = function(data) {
|
|
2676
|
+
for (var k in data) this[k] = data[k];
|
|
2123
2677
|
};
|
|
2124
2678
|
|
|
2125
2679
|
libVES.Cipher.AES256CBC = function(rec) {
|
|
2126
2680
|
this.init(rec);
|
|
2127
2681
|
};
|
|
2128
2682
|
|
|
2129
|
-
libVES.Cipher.
|
|
2130
|
-
|
|
2131
|
-
|
|
2683
|
+
libVES.Cipher.AES256GCM = function(rec) {
|
|
2684
|
+
this.init(rec);
|
|
2685
|
+
};
|
|
2686
|
+
|
|
2687
|
+
libVES.Cipher.AES256GCMp = function(rec) {
|
|
2688
|
+
this.init(rec);
|
|
2689
|
+
};
|
|
2690
|
+
|
|
2691
|
+
libVES.Cipher.AES256GCM1K = function(rec) {
|
|
2692
|
+
this.init(rec);
|
|
2693
|
+
};
|
|
2694
|
+
|
|
2695
|
+
libVES.Cipher.NULL.prototype = new libVES.Cipher({
|
|
2696
|
+
a: 'NULL',
|
|
2697
|
+
keySize: 0,
|
|
2698
|
+
ivSize: 0
|
|
2132
2699
|
});
|
|
2133
2700
|
|
|
2134
|
-
libVES.Cipher.
|
|
2135
|
-
algo: 'AES-CBC',
|
|
2701
|
+
libVES.Cipher.AES.prototype = new libVES.Cipher({
|
|
2136
2702
|
keySize: 32,
|
|
2137
|
-
ivSize:
|
|
2703
|
+
ivSize: 32,
|
|
2138
2704
|
algoInfo: function() {
|
|
2705
|
+
var self = this;
|
|
2139
2706
|
return this.IV.then(function(iv) {
|
|
2140
|
-
return {name:
|
|
2707
|
+
return {name: self.algo, iv: iv};
|
|
2141
2708
|
});
|
|
2142
2709
|
}
|
|
2143
2710
|
});
|
|
2144
2711
|
|
|
2712
|
+
libVES.Cipher.AES256CBC.prototype = new libVES.Cipher.AES({
|
|
2713
|
+
algo: 'AES-CBC',
|
|
2714
|
+
keySize: 32,
|
|
2715
|
+
ivSize: 16
|
|
2716
|
+
});
|
|
2717
|
+
|
|
2145
2718
|
libVES.Cipher.AES256CBC.import = function(args,chain,optns) {
|
|
2146
2719
|
return chain('import').then(function(buf) {
|
|
2147
2720
|
return crypto.subtle.decrypt({name: 'AES-CBC', iv: args},optns.key,buf);
|
|
@@ -2160,6 +2733,88 @@ libVES.Cipher.AES256CBC.info = function(chain,optns) {
|
|
|
2160
2733
|
return Promise.resolve({algorithm: {name: 'AES-CBC', length: 256}});
|
|
2161
2734
|
};
|
|
2162
2735
|
|
|
2736
|
+
libVES.Cipher.AES256GCM.prototype = new libVES.Cipher.AES({
|
|
2737
|
+
algo: 'AES-GCM',
|
|
2738
|
+
keySize: 32,
|
|
2739
|
+
ivSize: 12
|
|
2740
|
+
});
|
|
2741
|
+
|
|
2742
|
+
libVES.Cipher.AES256GCMp.prototype = new libVES.Cipher.AES({
|
|
2743
|
+
algo: 'AES-GCM',
|
|
2744
|
+
keySize: 32,
|
|
2745
|
+
ivSize: 12,
|
|
2746
|
+
padSize: 32,
|
|
2747
|
+
encryptChunk: function(buf0) {
|
|
2748
|
+
var buf = new Uint8Array(buf0);
|
|
2749
|
+
var pad = this.padSize - (buf.byteLength % this.padSize) - 1;
|
|
2750
|
+
var bufp = new Uint8Array(buf.byteLength + pad + 1);
|
|
2751
|
+
bufp[0] = pad;
|
|
2752
|
+
bufp.set(buf,1);
|
|
2753
|
+
return libVES.Cipher.prototype.encryptChunk.call(this,bufp);
|
|
2754
|
+
},
|
|
2755
|
+
decryptChunk: function(buf) {
|
|
2756
|
+
return libVES.Cipher.prototype.decryptChunk.call(this,buf).then(function(bufp0) {
|
|
2757
|
+
var bufp = new Uint8Array(bufp0);
|
|
2758
|
+
return bufp.slice(1,bufp.byteLength - bufp[0]);
|
|
2759
|
+
});
|
|
2760
|
+
}
|
|
2761
|
+
});
|
|
2762
|
+
|
|
2763
|
+
libVES.Cipher.AES256GCM1K.prototype = new libVES.Cipher.AES({
|
|
2764
|
+
algo: 'AES-GCM',
|
|
2765
|
+
keySize: 32,
|
|
2766
|
+
ivSize: 12,
|
|
2767
|
+
chunkSizeP: 1024,
|
|
2768
|
+
chunkSizeC: 16,
|
|
2769
|
+
algoInfo: function() {
|
|
2770
|
+
var self = this;
|
|
2771
|
+
if (!this.lastGCM) throw new libVES.Error('Internal', 'GCM HMAC is not buffered');
|
|
2772
|
+
return this.IV.then(function(iv) {
|
|
2773
|
+
var buf = new Uint8Array(iv.byteLength + self.lastGCM.byteLength);
|
|
2774
|
+
buf.set(new Uint8Array(iv), 0);
|
|
2775
|
+
buf.set(new Uint8Array(self.lastGCM), iv.byteLength);
|
|
2776
|
+
return libVES.Util.Hash.SHA256.hash(buf).then(function(sha) {
|
|
2777
|
+
return { name: self.algo, iv: sha.slice(0, self.ivSize) };
|
|
2778
|
+
});
|
|
2779
|
+
});
|
|
2780
|
+
},
|
|
2781
|
+
encryptChunk: function(buf) {
|
|
2782
|
+
var self = this;
|
|
2783
|
+
var seed = null;
|
|
2784
|
+
if (!this.lastGCM) {
|
|
2785
|
+
seed = new Uint8Array(16);
|
|
2786
|
+
crypto.getRandomValues(seed);
|
|
2787
|
+
this.lastGCM = seed;
|
|
2788
|
+
}
|
|
2789
|
+
return Promise.all([this.key, this.algoInfo()]).then(function(info) {
|
|
2790
|
+
return crypto.subtle.encrypt(info[1], info[0], buf).then(function(ctext) {
|
|
2791
|
+
self.lastGCM = new Uint8Array(ctext.slice(-16));
|
|
2792
|
+
if (!seed) return ctext;
|
|
2793
|
+
var rs = new Uint8Array(seed.byteLength + ctext.byteLength);
|
|
2794
|
+
rs.set(seed, 0);
|
|
2795
|
+
rs.set(new Uint8Array(ctext), seed.byteLength);
|
|
2796
|
+
return rs;
|
|
2797
|
+
});
|
|
2798
|
+
});
|
|
2799
|
+
},
|
|
2800
|
+
decryptChunk: function(buf) {
|
|
2801
|
+
var self = this;
|
|
2802
|
+
if (buf.byteLength < 16) throw new libVES.Error('Crypto', 'Invalid ciphertext block size');
|
|
2803
|
+
var rs;
|
|
2804
|
+
if (this.lastGCM) {
|
|
2805
|
+
rs = Promise.all([this.key, this.algoInfo()]).then(function(info) {
|
|
2806
|
+
self.lastGCM = buf.slice(-16);
|
|
2807
|
+
return crypto.subtle.decrypt(info[1], info[0], buf);
|
|
2808
|
+
});
|
|
2809
|
+
} else {
|
|
2810
|
+
rs = Promise.resolve(new Uint8Array(0));
|
|
2811
|
+
this.chunkSizeC = 1040;
|
|
2812
|
+
this.lastGCM = buf;
|
|
2813
|
+
}
|
|
2814
|
+
return rs;
|
|
2815
|
+
}
|
|
2816
|
+
});
|
|
2817
|
+
|
|
2163
2818
|
libVES.Scramble = {
|
|
2164
2819
|
RDX: function(x) {
|
|
2165
2820
|
this.size = x;
|
|
@@ -2230,17 +2885,23 @@ libVES.Scramble.RDX.prototype = {
|
|
|
2230
2885
|
scramble: function(vec,b) {
|
|
2231
2886
|
return libVES.Math.mulv(vec,this.getCv(b));
|
|
2232
2887
|
},
|
|
2233
|
-
explode: function(sc,ct) {
|
|
2888
|
+
explode: function(sc,ct,optns) {
|
|
2234
2889
|
var self = this;
|
|
2235
2890
|
return this.toVector(sc).then(function(v) {
|
|
2236
2891
|
var bs = self.getBases(ct);
|
|
2237
2892
|
var rs = [];
|
|
2238
2893
|
for (i = 0; i < bs.length; i++) rs[i] = {
|
|
2239
|
-
meta: {
|
|
2894
|
+
meta: (function(m) {
|
|
2895
|
+
if (optns) {
|
|
2896
|
+
if (optns.t != null) m.t = optns.t;
|
|
2897
|
+
if (optns.shadow) for (var k in optns.shadow) m[k] = optns.shadow[k];
|
|
2898
|
+
}
|
|
2899
|
+
return m;
|
|
2900
|
+
})({
|
|
2240
2901
|
v: self.tag,
|
|
2241
2902
|
n: self.size,
|
|
2242
2903
|
b: bs[i]
|
|
2243
|
-
},
|
|
2904
|
+
}),
|
|
2244
2905
|
value: self.scramble(v,bs[i])
|
|
2245
2906
|
}
|
|
2246
2907
|
return rs;
|
|
@@ -2305,8 +2966,9 @@ libVES.Scramble.algo = {
|
|
|
2305
2966
|
'RDX1.2': libVES.Scramble.RDX
|
|
2306
2967
|
};
|
|
2307
2968
|
|
|
2308
|
-
libVES.Recovery = function(vaultKey) {
|
|
2969
|
+
libVES.Recovery = function(vaultKey, myItems) {
|
|
2309
2970
|
this.vaultKey = vaultKey;
|
|
2971
|
+
if (myItems) this.myItems = Promise.resolve(myItems);
|
|
2310
2972
|
};
|
|
2311
2973
|
|
|
2312
2974
|
libVES.Recovery.prototype = {
|
|
@@ -2315,7 +2977,7 @@ libVES.Recovery.prototype = {
|
|
|
2315
2977
|
var self = this;
|
|
2316
2978
|
return this.tokens = self.vaultKey.getType().then(function(t) {
|
|
2317
2979
|
switch (t) {
|
|
2318
|
-
case 'shadow': case 'recovery': return self.vaultKey.getField('vaultItems',{
|
|
2980
|
+
case 'shadow': case 'recovery': return (self.myItems ? self.myItems : self.vaultKey.getField('vaultItems',{
|
|
2319
2981
|
id: true,
|
|
2320
2982
|
meta: true,
|
|
2321
2983
|
type: true,
|
|
@@ -2326,7 +2988,7 @@ libVES.Recovery.prototype = {
|
|
|
2326
2988
|
type: true
|
|
2327
2989
|
}
|
|
2328
2990
|
}
|
|
2329
|
-
},true).then(function(vis) {
|
|
2991
|
+
},true)).then(function(vis) {
|
|
2330
2992
|
var frnds = {};
|
|
2331
2993
|
var fn = function() {
|
|
2332
2994
|
return self.vaultKey.getUser().then(function(my_u) {
|
|
@@ -2336,10 +2998,15 @@ libVES.Recovery.prototype = {
|
|
|
2336
2998
|
return Promise.all([
|
|
2337
2999
|
vi.getVaultEntries().then(function(ves) {
|
|
2338
3000
|
return Promise.all(ves.map(function(ve) {
|
|
2339
|
-
|
|
3001
|
+
var vk = new libVES.VaultKey(ve.vaultKey,self.vaultKey.VES);
|
|
3002
|
+
return vk.getUser().then(function(u) {
|
|
2340
3003
|
return u.getId().then(function(uid) {
|
|
2341
|
-
if (uid == my_uid)
|
|
2342
|
-
|
|
3004
|
+
if (uid == my_uid) {
|
|
3005
|
+
frnd.assisted = true;
|
|
3006
|
+
return vk.getType().then(function(type) {
|
|
3007
|
+
if (type == 'current') frnd.current = true;
|
|
3008
|
+
});
|
|
3009
|
+
} else {
|
|
2343
3010
|
frnd.user = u;
|
|
2344
3011
|
frnds[uid] = frnd;
|
|
2345
3012
|
}
|
|
@@ -2398,10 +3065,10 @@ libVES.Recovery.prototype = {
|
|
|
2398
3065
|
return Promise.all(tkns.map(function(v,i) {
|
|
2399
3066
|
return v.user.getId();
|
|
2400
3067
|
})).then(function(uids) {
|
|
2401
|
-
|
|
2402
|
-
|
|
2403
|
-
|
|
2404
|
-
|
|
3068
|
+
return user.getId().then(function(uid) {
|
|
3069
|
+
for (var i = 0; i < uids.length; i++) if (uids[i] == uid) return tkns[i];
|
|
3070
|
+
throw new libVES.Error('InvalidValue','Not a friend: ' + uid);
|
|
3071
|
+
});
|
|
2405
3072
|
});
|
|
2406
3073
|
});
|
|
2407
3074
|
},
|
|
@@ -2424,22 +3091,11 @@ libVES.Recovery.prototype = {
|
|
|
2424
3091
|
getFriendsAssisted: function() {
|
|
2425
3092
|
var self = this;
|
|
2426
3093
|
return this.getTokens().then(function(tkns) {
|
|
2427
|
-
|
|
2428
|
-
|
|
2429
|
-
|
|
2430
|
-
});
|
|
2431
|
-
})).then(function(ves) {
|
|
2432
|
-
return self.vaultKey.getUser().then(function(user) {
|
|
2433
|
-
return user.getCurrentVaultKey().then(function(vk) {
|
|
2434
|
-
return vk.getId().then(function(vkid) {
|
|
2435
|
-
var rs = 0;
|
|
2436
|
-
for (var i = 0; i < ves.length; i++) if (ves[i]) if(ves[i][vkid]) rs++;
|
|
2437
|
-
return rs;
|
|
2438
|
-
});
|
|
2439
|
-
});
|
|
2440
|
-
});
|
|
3094
|
+
var a = 0;
|
|
3095
|
+
tkns.map(function(t, i) {
|
|
3096
|
+
if (t.assisted) a++;
|
|
2441
3097
|
});
|
|
2442
|
-
return
|
|
3098
|
+
return a;
|
|
2443
3099
|
});
|
|
2444
3100
|
},
|
|
2445
3101
|
getFriendsToGo: function() {
|
|
@@ -2464,7 +3120,10 @@ libVES.Recovery.prototype = {
|
|
|
2464
3120
|
});
|
|
2465
3121
|
},
|
|
2466
3122
|
assist: function() {
|
|
2467
|
-
|
|
3123
|
+
var self = this;
|
|
3124
|
+
return self.vaultKey.getType().then(function(t) {
|
|
3125
|
+
return t == 'recovery' ? self._assist(true) : null;
|
|
3126
|
+
});
|
|
2468
3127
|
},
|
|
2469
3128
|
revoke: function() {
|
|
2470
3129
|
return this._assist(false);
|
|
@@ -2484,7 +3143,9 @@ libVES.Recovery.prototype = {
|
|
|
2484
3143
|
_recover: function() {
|
|
2485
3144
|
var self = this;
|
|
2486
3145
|
return self.unlock().then(function() {
|
|
2487
|
-
return self.vaultKey.
|
|
3146
|
+
return self.vaultKey.VES.elevateAuth({authVaultKey: self.vaultKey}).then(function(optns) {
|
|
3147
|
+
return self.vaultKey.rekey(optns);
|
|
3148
|
+
});
|
|
2488
3149
|
});
|
|
2489
3150
|
},
|
|
2490
3151
|
recover: function() {
|
|
@@ -2500,11 +3161,14 @@ libVES.Delegate = {
|
|
|
2500
3161
|
html: '<div style="position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,0.5);display:table;z-index:200000;">'
|
|
2501
3162
|
+ '<div style="display:table-row;"><div style="display:table-cell;vertical-align:middle;text-align:center;">'
|
|
2502
3163
|
+ '<div style="min-width:320px;max-width:640px;;background-color:white;margin: auto;padding: 30px;">'
|
|
2503
|
-
+ '
|
|
2504
|
-
+ '<p class="VESvaultDelegateBlockerMsg" style="color: #bf7f00; font-style:italic;"> </p>'
|
|
2505
|
-
+ '<p><a class="VESvaultDelegateRetryLnk" href="{$url}" target="VESvaultDelegate" onclick="return !libVES.Delegate.retryPopup(this.href,this)">Click here</a> if you can\'t see VESvault popup window</p>'
|
|
2506
|
-
+ '<p><a class="VESvaultDelegateCancelLnk" href="#" onclick="libVES.Delegate.cancel(); return false;">Cancel</a></p>'
|
|
3164
|
+
+ '{$content}'
|
|
2507
3165
|
+ '</div></div></div></div>',
|
|
3166
|
+
htmlDlg: '<p>Use the VESvault popup window to grant access to the App Vault</p>'
|
|
3167
|
+
+ '<p class="VESvaultDelegateBlockerMsg" style="color: #bf7f00; font-style:italic;"> </p>'
|
|
3168
|
+
+ '<p><a class="VESvaultDelegateRetryLnk" href="{$url}" target="VESvaultDelegate" onclick="return !libVES.Delegate.retryPopup(this.href,this)">Click here</a> if you can\'t see VESvault popup window</p>'
|
|
3169
|
+
+ '<p><a class="VESvaultDelegateCancelLnk" href="#" onclick="libVES.Delegate.cancel(); return false;">Cancel</a></p>',
|
|
3170
|
+
htmlFlw: '<p>Authorizing VES Access</p>'
|
|
3171
|
+
+ '<iframe style="width: 100%; height: 48px; border: none;" src="{$url}"></iframe>',
|
|
2508
3172
|
htmlBlockerMsg: 'Looks like your browser is using a popup blocker...',
|
|
2509
3173
|
name: 'VESvaultDelegate',
|
|
2510
3174
|
login: function(VES,challenge,optns) {
|
|
@@ -2518,11 +3182,10 @@ libVES.Delegate = {
|
|
|
2518
3182
|
return this.response = new Promise(function(resolve,reject) {
|
|
2519
3183
|
self.reject = reject;
|
|
2520
3184
|
self.resolve = resolve;
|
|
2521
|
-
var url = VES.wwwUrl + '
|
|
2522
|
-
|
|
2523
|
-
self.
|
|
2524
|
-
self.
|
|
2525
|
-
document.getElementsByTagName('BODY')[0].appendChild(self.popup);
|
|
3185
|
+
var url = VES.wwwUrl + 'vv/unlock?via=delegate&url=' + encodeURIComponent(document.location.href) + '&domain=' + encodeURIComponent(VES.domain);
|
|
3186
|
+
if (optns) for (var k in optns) if (optns[k] != null) url += '&' + encodeURIComponent(k) + '=' + encodeURIComponent(optns[k]);
|
|
3187
|
+
self.setOrigin(url);
|
|
3188
|
+
self.showOverlay(self.htmlDlg.replace('{$url}',url));
|
|
2526
3189
|
self.retryPopupCalled = 0;
|
|
2527
3190
|
try {
|
|
2528
3191
|
document.getElementsByClassName('VESvaultDelegateRetryLnk')[0].onclick = function() {
|
|
@@ -2545,43 +3208,55 @@ libVES.Delegate = {
|
|
|
2545
3208
|
self.popupInterval = window.setInterval(self.chkCancel.bind(self),1000);
|
|
2546
3209
|
});
|
|
2547
3210
|
},
|
|
3211
|
+
flow: function(VES, start, optns) {
|
|
3212
|
+
if (this.response) return this.response;
|
|
3213
|
+
this.VES = VES;
|
|
3214
|
+
var self = this;
|
|
3215
|
+
var unlk = VES.wwwUrl + 'vv/unlock';
|
|
3216
|
+
if (start || (!sessionStorage['libVES.flowStarted'] && document.referrer.substr(0, unlk.length).toLowerCase() == unlk.toLowerCase())) {
|
|
3217
|
+
return self.response = new Promise(function(resolve, reject) {
|
|
3218
|
+
self.reject = reject;
|
|
3219
|
+
self.resolve = resolve;
|
|
3220
|
+
var ifrm = VES.wwwUrl + 'vv/flowin?url=' + encodeURIComponent(document.location.href) + '&domain=' + encodeURIComponent(VES.domain);
|
|
3221
|
+
if (optns) for (var k in optns) if (optns[k] != null) ifrm += '&' + encodeURIComponent(k) + '=' + encodeURIComponent(optns[k]);
|
|
3222
|
+
self.setOrigin(ifrm);
|
|
3223
|
+
window.addEventListener('message',self.listener.bind(self));
|
|
3224
|
+
self.showOverlay(self.htmlFlw.replace('{$url}', ifrm));
|
|
3225
|
+
if (start) delete(sessionStorage['libVES.flowStarted'])
|
|
3226
|
+
else sessionStorage['libVES.flowStarted'] = true;
|
|
3227
|
+
});
|
|
3228
|
+
} else {
|
|
3229
|
+
return new Promise(function(){});
|
|
3230
|
+
}
|
|
3231
|
+
},
|
|
3232
|
+
showOverlay: function(cont) {
|
|
3233
|
+
this.popup = document.createElement('DIV');
|
|
3234
|
+
this.popup.innerHTML = this.html.replace('{$content}', cont);
|
|
3235
|
+
document.getElementsByTagName('BODY')[0].appendChild(this.popup);
|
|
3236
|
+
},
|
|
3237
|
+
setOrigin: function(url) {
|
|
3238
|
+
this.matchOrigin = (function(m) { return m ? m[0] : document.location.protocol + '//' + document.location.host; })(url.match(/^(https\:\/\/[^\/\?\#]+)/));
|
|
3239
|
+
},
|
|
2548
3240
|
openPopup: function(url) {
|
|
2549
3241
|
return this.popupWindow = window.open(url,this.name,"width=600,height=600,top=100,left=100");
|
|
2550
3242
|
},
|
|
2551
3243
|
retryPopup: function(url,href) {
|
|
2552
|
-
var f = this.retryPopupCalled;
|
|
2553
3244
|
this.retryPopupCalled++;
|
|
2554
|
-
if (
|
|
2555
|
-
else if (this.popupWindow) try {
|
|
3245
|
+
if (this.popupWindow) try {
|
|
2556
3246
|
this.popupWindow.focus();
|
|
3247
|
+
return true;
|
|
2557
3248
|
} catch(e) {}
|
|
2558
|
-
|
|
3249
|
+
this.openPopup(url);
|
|
3250
|
+
return true;
|
|
2559
3251
|
},
|
|
2560
3252
|
listener: function(evnt) {
|
|
2561
|
-
if (this.
|
|
3253
|
+
if (this.popup && evnt.origin == this.matchOrigin) try {
|
|
2562
3254
|
var msg = JSON.parse(evnt.data);
|
|
2563
|
-
|
|
2564
|
-
|
|
2565
|
-
|
|
2566
|
-
this.resolve(VES.
|
|
2567
|
-
|
|
2568
|
-
}));
|
|
2569
|
-
} else if (msg.token) {
|
|
2570
|
-
VES.token = msg.token;
|
|
2571
|
-
this.resolve(VES.getSecondaryKey({domain:VES.domain},true).then(function(vaultKey) {
|
|
2572
|
-
return vaultKey.getExternals().then(function(externals) {
|
|
2573
|
-
return Promise.all(externals.map(function(ext,i) {
|
|
2574
|
-
return ext.getDomain();
|
|
2575
|
-
})).then(function(domains) {
|
|
2576
|
-
for (var i = 0; i < domains.length; i++) if (domains[i] == VES.domain) return externals[i].getExternalId();
|
|
2577
|
-
throw new libVES.Error('Internal','No external id found for newly created secondary key');
|
|
2578
|
-
}).then(function(extId) {
|
|
2579
|
-
VES.externalId = extId;
|
|
2580
|
-
return VES;
|
|
2581
|
-
});
|
|
2582
|
-
});
|
|
2583
|
-
}));
|
|
2584
|
-
} else return;
|
|
3255
|
+
if (msg.redirect) {
|
|
3256
|
+
document.location.replace(msg.redirect);
|
|
3257
|
+
} else {
|
|
3258
|
+
this.resolve(this.VES.authorize(msg));
|
|
3259
|
+
}
|
|
2585
3260
|
this.close();
|
|
2586
3261
|
if (!evnt.source.closed) evnt.source.close();
|
|
2587
3262
|
} catch(e) {}
|
|
@@ -2598,7 +3273,7 @@ libVES.Delegate = {
|
|
|
2598
3273
|
this.popupInterval = null;
|
|
2599
3274
|
this.popup.parentNode.removeChild(this.popup);
|
|
2600
3275
|
this.popup = null;
|
|
2601
|
-
return
|
|
3276
|
+
return this.response;
|
|
2602
3277
|
}
|
|
2603
3278
|
},
|
|
2604
3279
|
cancel: function() {
|
|
@@ -2611,4 +3286,255 @@ libVES.Delegate = {
|
|
|
2611
3286
|
}
|
|
2612
3287
|
};
|
|
2613
3288
|
|
|
3289
|
+
|
|
3290
|
+
libVES.Flow = function(name, optns) {
|
|
3291
|
+
this.name = name;
|
|
3292
|
+
this.origin = document.location.origin;
|
|
3293
|
+
this.url = this.origin + '/VESflow';
|
|
3294
|
+
if (optns) for (var k in optns) this[k] = optns[k];
|
|
3295
|
+
return this;
|
|
3296
|
+
};
|
|
3297
|
+
|
|
3298
|
+
libVES.Flow.algo = {name: 'ECDH', namedCurve: 'P-256'};
|
|
3299
|
+
|
|
3300
|
+
libVES.Flow.keyAlgo = function(jwk) {
|
|
3301
|
+
if (jwk && jwk.kty == 'EC') return {name: 'ECDH', namedCurve: jwk.crv};
|
|
3302
|
+
return null;
|
|
3303
|
+
};
|
|
3304
|
+
|
|
3305
|
+
libVES.Flow.toOrigin = function(url) {
|
|
3306
|
+
var a = document.createElement('a');
|
|
3307
|
+
a.href = url;
|
|
3308
|
+
return a.origin;
|
|
3309
|
+
};
|
|
3310
|
+
|
|
3311
|
+
libVES.Flow.jwkPub = function(jwk) {
|
|
3312
|
+
delete(jwk.d);
|
|
3313
|
+
delete(jwk.key_ops);
|
|
3314
|
+
delete(jwk.ext);
|
|
3315
|
+
return jwk;
|
|
3316
|
+
};
|
|
3317
|
+
|
|
3318
|
+
libVES.Flow.parseToken = function(src, callbk) {
|
|
3319
|
+
src = src.replace(/\#VESflow\.(\w+)=([^\#\&\=]+)/g, function(s, k, v) {
|
|
3320
|
+
var tk;
|
|
3321
|
+
try {
|
|
3322
|
+
tk = JSON.parse(decodeURIComponent(v));
|
|
3323
|
+
if (callbk(decodeURIComponent(k), tk)) return '';
|
|
3324
|
+
} catch(e) {
|
|
3325
|
+
console.log(e);
|
|
3326
|
+
}
|
|
3327
|
+
return s;
|
|
3328
|
+
});
|
|
3329
|
+
return src;
|
|
3330
|
+
};
|
|
3331
|
+
|
|
3332
|
+
libVES.Flow.logout = function() {
|
|
3333
|
+
for (var k in sessionStorage) if (k.match(/^VESflow\b/)) delete(sessionStorage[k]);
|
|
3334
|
+
};
|
|
3335
|
+
|
|
3336
|
+
libVES.Flow.prototype.source = function(src) {
|
|
3337
|
+
if (src != null) history.replaceState(null, '', src);
|
|
3338
|
+
return document.location.href;
|
|
3339
|
+
};
|
|
3340
|
+
|
|
3341
|
+
libVES.Flow.prototype.privKey = function(algo) {
|
|
3342
|
+
if (!algo) algo = libVES.Flow.algo;
|
|
3343
|
+
var a = JSON.stringify(algo);
|
|
3344
|
+
return Promise.resolve(sessionStorage['VESflow' + a]).then(function(k) {
|
|
3345
|
+
if (!k) throw null;
|
|
3346
|
+
return crypto.subtle.importKey('jwk', JSON.parse(k), algo, true, ['deriveBits', 'deriveKey']);
|
|
3347
|
+
}).catch(function(e) {
|
|
3348
|
+
return crypto.subtle.generateKey(algo, true, ['deriveBits', 'deriveKey']).then(function(pair) {
|
|
3349
|
+
return crypto.subtle.exportKey('jwk', pair.privateKey).then(function(jwk) {
|
|
3350
|
+
sessionStorage['VESflow' + a] = JSON.stringify(jwk);
|
|
3351
|
+
return pair.privateKey;
|
|
3352
|
+
});
|
|
3353
|
+
});
|
|
3354
|
+
});
|
|
3355
|
+
};
|
|
3356
|
+
|
|
3357
|
+
libVES.Flow.prototype.pubJWK = function(org) {
|
|
3358
|
+
return ((!org || org == this.origin) ? this.privKey().then(function(priv) {
|
|
3359
|
+
return crypto.subtle.exportKey('jwk', priv).then(function(jwk) {
|
|
3360
|
+
return libVES.Flow.jwkPub(jwk);
|
|
3361
|
+
});
|
|
3362
|
+
}) : Promise.resolve(sessionStorage['VESflow|' + org]).then(function(k) {
|
|
3363
|
+
if (!k) throw {code: 'NotFound', message: 'No public key stored for ' + org};
|
|
3364
|
+
return JSON.parse(k);
|
|
3365
|
+
}));
|
|
3366
|
+
};
|
|
3367
|
+
|
|
3368
|
+
libVES.Flow.prototype.pubKey = function(org) {
|
|
3369
|
+
return this.pubJWK(org).then(function(jwk) {
|
|
3370
|
+
return crypto.subtle.importKey('jwk', jwk, libVES.Flow.keyAlgo(jwk), true, []);
|
|
3371
|
+
});
|
|
3372
|
+
};
|
|
3373
|
+
|
|
3374
|
+
libVES.Flow.prototype.cipher = function(url) {
|
|
3375
|
+
var self = this;
|
|
3376
|
+
return self.pubKey(libVES.Flow.toOrigin(url)).then(function(pub) {
|
|
3377
|
+
return self.privKey(pub.algorithm).then(function(priv) {
|
|
3378
|
+
return crypto.subtle.deriveBits({name: 'ECDH', public: pub}, priv, 8 * libVES.Algo.ECDH.curveBytes[pub.algorithm.namedCurve]);
|
|
3379
|
+
});
|
|
3380
|
+
}).then(function(raw) {
|
|
3381
|
+
return crypto.subtle.digest({name: 'SHA-256'}, raw).then(function(buf) {
|
|
3382
|
+
return crypto.subtle.importKey('raw', buf, 'AES-GCM', false, ['encrypt', 'decrypt']);
|
|
3383
|
+
});
|
|
3384
|
+
});
|
|
3385
|
+
};
|
|
3386
|
+
|
|
3387
|
+
libVES.Flow.prototype.encrypt = function(url, val) {
|
|
3388
|
+
var self = this;
|
|
3389
|
+
return Promise.resolve(val || this.value()).then(function(val) {
|
|
3390
|
+
if (val == null) throw {code: 'NoData', message: 'Empty value'};
|
|
3391
|
+
return self.cipher(url).then(function(ci) {
|
|
3392
|
+
var iv = new Uint8Array(12);
|
|
3393
|
+
crypto.getRandomValues(iv);
|
|
3394
|
+
return crypto.subtle.encrypt({name: 'AES-GCM', iv: iv.buffer}, ci, libVES.Util.StringToByteArray(JSON.stringify(val))).then(function(ctext) {
|
|
3395
|
+
return libVES.Util.ByteArrayToB64W(iv) + '.' + libVES.Util.ByteArrayToB64W(ctext);
|
|
3396
|
+
});
|
|
3397
|
+
});
|
|
3398
|
+
});
|
|
3399
|
+
};
|
|
3400
|
+
|
|
3401
|
+
libVES.Flow.prototype.token = function(url) {
|
|
3402
|
+
var self = this;
|
|
3403
|
+
return this.pubJWK().then(function(jwk) {
|
|
3404
|
+
return {url: self.url, key: jwk};
|
|
3405
|
+
}).then(function(tk) {
|
|
3406
|
+
return self.encrypt(url).then(function(ctext) {
|
|
3407
|
+
tk.enc = ctext;
|
|
3408
|
+
self.erase(url);
|
|
3409
|
+
self.sent = true;
|
|
3410
|
+
return tk;
|
|
3411
|
+
}).catch(function(e) {
|
|
3412
|
+
self.store(url).catch(function(e) {});
|
|
3413
|
+
return tk;
|
|
3414
|
+
});
|
|
3415
|
+
});
|
|
3416
|
+
};
|
|
3417
|
+
|
|
3418
|
+
libVES.Flow.prototype.addToken = function(url) {
|
|
3419
|
+
var self = this;
|
|
3420
|
+
return self.token(url).then(function(tk) {
|
|
3421
|
+
return url + '#VESflow.' + self.name + '=' + encodeURIComponent(JSON.stringify(tk));
|
|
3422
|
+
});
|
|
3423
|
+
};
|
|
3424
|
+
|
|
3425
|
+
libVES.Flow.prototype.decrypt = function(ctext, url) {
|
|
3426
|
+
var self = this;
|
|
3427
|
+
var c = ctext.split('.');
|
|
3428
|
+
return self.cipher(url).then(function(ci) {
|
|
3429
|
+
return crypto.subtle.decrypt({name: 'AES-GCM', iv: libVES.Util.B64ToByteArray(c[0])}, ci, libVES.Util.B64ToByteArray(c[1])).then(function(ptext) {
|
|
3430
|
+
return JSON.parse(libVES.Util.ByteArrayToString(ptext));
|
|
3431
|
+
});
|
|
3432
|
+
});
|
|
3433
|
+
};
|
|
3434
|
+
|
|
3435
|
+
libVES.Flow.prototype.value = function() {
|
|
3436
|
+
var self = this;
|
|
3437
|
+
return Promise.resolve(history.state && history.state['VESflow.' + self.name]).then(function(ctext) {
|
|
3438
|
+
return self.decrypt(ctext);
|
|
3439
|
+
});
|
|
3440
|
+
};
|
|
3441
|
+
|
|
3442
|
+
libVES.Flow.prototype.setValue = function(val) {
|
|
3443
|
+
var self = this;
|
|
3444
|
+
return Promise.resolve(val? self.encrypt(null, val) : null).then(function(ctext) {
|
|
3445
|
+
var s = {};
|
|
3446
|
+
if (history.state) for (var k in history.state) s[k] = history.state[k];
|
|
3447
|
+
if (ctext) s['VESflow.' + self.name] = ctext;
|
|
3448
|
+
else delete(s['VESflow.' + self.name]);
|
|
3449
|
+
history.replaceState(s, '');
|
|
3450
|
+
return val;
|
|
3451
|
+
});
|
|
3452
|
+
};
|
|
3453
|
+
|
|
3454
|
+
libVES.Flow.prototype.click = function(a) {
|
|
3455
|
+
var self = this;
|
|
3456
|
+
(a.origin == this.origin ? self.store() : self.addToken(a.href).then(function(url) {
|
|
3457
|
+
a.href = url;
|
|
3458
|
+
})).then(function() {
|
|
3459
|
+
document.location.href = a.href;
|
|
3460
|
+
});
|
|
3461
|
+
return false;
|
|
3462
|
+
};
|
|
3463
|
+
|
|
3464
|
+
libVES.Flow.prototype.reload = function(e) {
|
|
3465
|
+
if (!this.sent) this.store().catch(function(e) {});
|
|
3466
|
+
};
|
|
3467
|
+
|
|
3468
|
+
libVES.Flow.prototype.recv = function(dval) {
|
|
3469
|
+
var self = this;
|
|
3470
|
+
return Promise.resolve(self.source()).then(function(src) {
|
|
3471
|
+
var tk = null;
|
|
3472
|
+
src = libVES.Flow.parseToken(src, function(k, t) {
|
|
3473
|
+
if (k != self.name) return false;
|
|
3474
|
+
tk = t;
|
|
3475
|
+
return true;
|
|
3476
|
+
});
|
|
3477
|
+
if (tk == null) throw {code: 'NotFound', message: 'No valid token in the source url'};
|
|
3478
|
+
return Promise.resolve(self.source(src)).then(function() {
|
|
3479
|
+
if (dval) for (var k in dval) if (tk[k] === undefined) tk[k] = dval[k];
|
|
3480
|
+
return self.recvToken(tk);
|
|
3481
|
+
});
|
|
3482
|
+
});
|
|
3483
|
+
};
|
|
3484
|
+
|
|
3485
|
+
libVES.Flow.prototype.recvToken = function(tk) {
|
|
3486
|
+
var org = libVES.Flow.toOrigin(tk.url);
|
|
3487
|
+
if (org != this.origin && tk.key) sessionStorage['VESflow|' + org] = JSON.stringify(tk.key);
|
|
3488
|
+
if (!tk.enc) return Promise.reject({url: tk.url, code: 'Incomplete', message: 'Missing encrypted data'});
|
|
3489
|
+
return this.decrypt(tk.enc, org);
|
|
3490
|
+
};
|
|
3491
|
+
|
|
3492
|
+
libVES.Flow.prototype.get = function() {
|
|
3493
|
+
var self = this;
|
|
3494
|
+
return self.fetch().catch(function(e) {
|
|
3495
|
+
if (!e || e.code != 'NotFound') console.log(e);
|
|
3496
|
+
return null;
|
|
3497
|
+
}).then(function(data) {
|
|
3498
|
+
return self.recv().catch(function(e) {
|
|
3499
|
+
if (e && e.code == 'Incomplete') {
|
|
3500
|
+
self.url = document.location.href;
|
|
3501
|
+
return self.addToken(e.url).then(function(url) {
|
|
3502
|
+
document.location.replace(url);
|
|
3503
|
+
throw {code: 'Reload', message: 'Completing the key exchange'};
|
|
3504
|
+
});
|
|
3505
|
+
}
|
|
3506
|
+
if (!data) throw e;
|
|
3507
|
+
return data;
|
|
3508
|
+
});
|
|
3509
|
+
});
|
|
3510
|
+
};
|
|
3511
|
+
|
|
3512
|
+
libVES.Flow.prototype.store = function(url) {
|
|
3513
|
+
if (history.state && history.state['VESflow.' + this.name]) {
|
|
3514
|
+
this.sent = 1;
|
|
3515
|
+
return Promise.resolve(sessionStorage['VESflow.' + this.name + '>' + libVES.Flow.toOrigin(url)] = history.state['VESflow.' + this.name]);
|
|
3516
|
+
}
|
|
3517
|
+
return Promise.reject({code: 'NotFound', message: 'Value is not set'});
|
|
3518
|
+
};
|
|
3519
|
+
|
|
3520
|
+
libVES.Flow.prototype.fetch = function(url) {
|
|
3521
|
+
var self = this;
|
|
3522
|
+
return Promise.resolve(sessionStorage['VESflow.' + self.name + '>' + libVES.Flow.toOrigin(url)]).then(function(ctext) {
|
|
3523
|
+
if (!ctext) throw {code: 'NotFound', message: 'Not in the session storage'};
|
|
3524
|
+
return self.decrypt(ctext).then(function(data) {
|
|
3525
|
+
self.erase(url);
|
|
3526
|
+
return data;
|
|
3527
|
+
});
|
|
3528
|
+
});
|
|
3529
|
+
};
|
|
3530
|
+
|
|
3531
|
+
libVES.Flow.prototype.erase = function(url) {
|
|
3532
|
+
delete(sessionStorage['VESflow.' + this.name + '>' + libVES.Flow.toOrigin(url)]);
|
|
3533
|
+
};
|
|
3534
|
+
|
|
3535
|
+
libVES.Flow.prototype.logout = function() {
|
|
3536
|
+
this.setValue(undefined);
|
|
3537
|
+
return libVES.Flow.logout();
|
|
3538
|
+
};
|
|
3539
|
+
|
|
2614
3540
|
module.exports = libVES;
|