libves 1.0.4 → 1.9.9
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/libVES.node.js +1223 -316
- package/libves-1.9.9.tgz +0 -0
- package/package.json +1 -1
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 - 2020 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 1.
|
|
30
|
+
* @version 1.99
|
|
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,11 +140,82 @@ 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
|
+
});
|
|
149
|
+
});
|
|
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;
|
|
109
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
|
+
}
|
|
110
219
|
},
|
|
111
220
|
me: function() {
|
|
112
221
|
var self = this;
|
|
@@ -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,21 @@ 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
|
+
return new libVES.User({email: ext.externalId}, self);
|
|
353
|
+
}
|
|
354
|
+
};
|
|
355
|
+
});
|
|
236
356
|
};
|
|
237
357
|
return (ext.externalId ? self.prepareExternals(ext) : m().then(function(dom) {
|
|
238
358
|
return Promise.resolve(user || self.me()).then(function(u) {
|
|
@@ -257,10 +377,11 @@ libVES.prototype = {
|
|
|
257
377
|
return Promise.all([me.getId(),u.getId()]).then(function(ids) {
|
|
258
378
|
if (ids[0] == ids[1]) return self.getSecondaryKey(exts,true);
|
|
259
379
|
}).catch(function(e) {
|
|
260
|
-
if (e != 'NotFound') throw e;
|
|
380
|
+
if (e.code != 'NotFound') throw e;
|
|
261
381
|
}).then(function(rs) {
|
|
262
382
|
return rs || self.createTempKey(self._matchUser(u)).then(function(vkey) {
|
|
263
383
|
return vkey.setField('externals',exts).then(function() {
|
|
384
|
+
if (appUrl) vkey.setField('appUrl', appUrl);
|
|
264
385
|
return vkey;
|
|
265
386
|
});
|
|
266
387
|
});
|
|
@@ -292,21 +413,21 @@ libVES.prototype = {
|
|
|
292
413
|
return keys;
|
|
293
414
|
});
|
|
294
415
|
},
|
|
295
|
-
createTempKey: function(usr,optns) {
|
|
416
|
+
createTempKey: function(usr, optns) {
|
|
296
417
|
var self = this;
|
|
297
|
-
var key = new libVES.VaultKey({type: 'temp', algo: this.keyAlgo, user: usr},self);
|
|
418
|
+
var key = new libVES.VaultKey({type: 'temp', algo: this.keyAlgo, user: usr}, self);
|
|
298
419
|
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(
|
|
420
|
+
return key.generate(veskey, optns).then(function(k) {
|
|
421
|
+
if (self.e2e && self.e2e.length) usr.e2e = self.getVESkeyE2E(veskey, usr);
|
|
422
|
+
key.setField('vaultItems', veskey.then(function(v) {
|
|
423
|
+
var vi = new libVES.VaultItem({type: 'password'}, self);
|
|
424
|
+
return Promise.all(self.type == 'secondary' ? [self.me(), self.getVaultKey()] : [self.me()]).then(function(sh) {
|
|
425
|
+
return vi.shareWith(sh, v, false).then(function() {
|
|
305
426
|
return [vi];
|
|
306
427
|
});
|
|
307
428
|
});
|
|
308
429
|
}));
|
|
309
|
-
key.setField('creator',self.me());
|
|
430
|
+
key.setField('creator', self.me());
|
|
310
431
|
return key;
|
|
311
432
|
});
|
|
312
433
|
},
|
|
@@ -331,22 +452,31 @@ libVES.prototype = {
|
|
|
331
452
|
var self = this;
|
|
332
453
|
return this.me().then(function(me) {
|
|
333
454
|
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
|
-
|
|
455
|
+
return me.getCurrentVaultKey().then(function(cur) {
|
|
456
|
+
return (cur ? cur.unlock().then(function() {
|
|
457
|
+
return k.rekeyFrom(cur);
|
|
458
|
+
}).catch(function(e) {
|
|
459
|
+
if (!lost) throw e;
|
|
460
|
+
}) : Promise.resolve(null)).then(function() {
|
|
461
|
+
var r;
|
|
462
|
+
if (cur && lost) r = cur.setField('type','lost').then(function() {
|
|
338
463
|
k.user = undefined;
|
|
339
464
|
return me.setField('vaultKeys',[cur,k]).then(function() {
|
|
340
465
|
return me;
|
|
341
466
|
});
|
|
342
467
|
});
|
|
343
|
-
else r = k
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
468
|
+
else r = k;
|
|
469
|
+
me.currentVaultKey = me.activeVaultKeys = me.shadowVaultKey = undefined;
|
|
470
|
+
if (!cur || !lost) me.vaultKeys = undefined;
|
|
471
|
+
return r;
|
|
472
|
+
});
|
|
348
473
|
}).then(function(r) {
|
|
349
|
-
return
|
|
474
|
+
return self.elevateAuth(options).then(function(optns) {
|
|
475
|
+
return r.post(undefined, undefined, optns);
|
|
476
|
+
});
|
|
477
|
+
}).catch(function(e) {
|
|
478
|
+
self.reset();
|
|
479
|
+
throw e;
|
|
350
480
|
}).then(function(post) {
|
|
351
481
|
return self.reset(post);
|
|
352
482
|
}).then(function() {
|
|
@@ -370,21 +500,21 @@ libVES.prototype = {
|
|
|
370
500
|
return rs;
|
|
371
501
|
});
|
|
372
502
|
},
|
|
373
|
-
getSecondaryKey: function(ext,force) {
|
|
503
|
+
getSecondaryKey: function(ext, force) {
|
|
374
504
|
var self = this;
|
|
375
505
|
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) {
|
|
506
|
+
if (e.domain && !e.externalId) return libVES.getModule(libVES.Domain, e.domain).then(function(mod) {
|
|
377
507
|
return self.me().then(function(me) {
|
|
378
|
-
return mod.userToVaultRef(me,self);
|
|
508
|
+
return mod.userToVaultRef(me, self);
|
|
379
509
|
});
|
|
380
510
|
});
|
|
381
511
|
return e;
|
|
382
512
|
})).then(function(ext) {
|
|
383
|
-
var vkey = new libVES.VaultKey({externals: ext},self);
|
|
513
|
+
var vkey = new libVES.VaultKey({externals: ext}, self);
|
|
384
514
|
return vkey.getId().then(function(id) {
|
|
385
515
|
return vkey;
|
|
386
516
|
}).catch(function(e) {
|
|
387
|
-
if (!force) throw e;
|
|
517
|
+
if (!force || e.code != 'NotFound') throw e;
|
|
388
518
|
return self.setSecondaryKey(ext);
|
|
389
519
|
});
|
|
390
520
|
});
|
|
@@ -395,14 +525,25 @@ libVES.prototype = {
|
|
|
395
525
|
if (!veskey) veskey = self.generateVESkey();
|
|
396
526
|
return self.me().then(function(me) {
|
|
397
527
|
return (new libVES.VaultKey({type: 'secondary', algo: self.keyAlgo, user: me, externals: ext},self)).generate(veskey,optns).then(function(k) {
|
|
528
|
+
return self.getSecondaryKey(ext).then(function(k2) {
|
|
529
|
+
return k.rekeyFrom(k2);
|
|
530
|
+
}).catch(function(e) {
|
|
531
|
+
delete(k.vaultEntries);
|
|
532
|
+
return k;
|
|
533
|
+
});
|
|
534
|
+
}).then(function(k) {
|
|
398
535
|
var vi = new libVES.VaultItem({type: "password"},self);
|
|
399
536
|
k.setField('vaultItems',[vi]);
|
|
400
537
|
return Promise.resolve(veskey).then(function(v) {
|
|
401
538
|
if (!v) throw new libVES.Error('InvalidValue','VESkey cannot be empty');
|
|
402
539
|
return vi.shareWith([me],v,false).then(function() {
|
|
403
|
-
return
|
|
404
|
-
|
|
405
|
-
|
|
540
|
+
return self.elevateAuth(optns);
|
|
541
|
+
}).then(function(optns) {
|
|
542
|
+
return k.post(undefined, undefined, optns).then(function(post) {
|
|
543
|
+
return k.setField('id', post.id, false).then(function() {
|
|
544
|
+
k.fieldUpdate = {id: true};
|
|
545
|
+
return k;
|
|
546
|
+
});
|
|
406
547
|
});
|
|
407
548
|
});
|
|
408
549
|
});
|
|
@@ -411,14 +552,26 @@ libVES.prototype = {
|
|
|
411
552
|
});
|
|
412
553
|
},
|
|
413
554
|
setShadow: function(usrs,optns) {
|
|
414
|
-
if (!optns || !optns.n) return Promise.reject(new libVES.Error('InvalidValue','optns.n must be an integer'));
|
|
415
555
|
var self = this;
|
|
556
|
+
if (!(usrs instanceof Array)) return Promise.reject(new libVES.Error('InvalidValue', 'usrs must be an array'));
|
|
557
|
+
if (!usrs.length) {
|
|
558
|
+
return self.getShadowKey().then(function(sh) {
|
|
559
|
+
return (sh ? sh.getId().then(function(id) {
|
|
560
|
+
return self.elevateAuth(optns).then(function(optns) {
|
|
561
|
+
return self.post('vaultKeys/' + id, {'$op': 'delete'}, undefined, optns). then(function() {
|
|
562
|
+
return null;
|
|
563
|
+
});
|
|
564
|
+
});
|
|
565
|
+
}) : null);
|
|
566
|
+
});
|
|
567
|
+
}
|
|
568
|
+
if (!optns || !optns.n) return Promise.reject(new libVES.Error('InvalidValue','optns.n must be an integer'));
|
|
416
569
|
var rkey = new Uint8Array(32);
|
|
417
570
|
window.crypto.getRandomValues(rkey);
|
|
418
571
|
var algo = optns.v ? libVES.Scramble.algo[optns.v] : libVES.Scramble.RDX;
|
|
419
572
|
if (!algo) return Promise.reject(new libVES.Error('InvalidValue','Unknown scramble algorithm: ' + optns.v));
|
|
420
573
|
var s = new algo(optns.n);
|
|
421
|
-
return s.explode(rkey,usrs.length).then(function(tkns) {
|
|
574
|
+
return s.explode(rkey,usrs.length,optns).then(function(tkns) {
|
|
422
575
|
return self.me().then(function(me) {
|
|
423
576
|
me.activeVaultKeys = undefined;
|
|
424
577
|
return me.setField('shadowVaultKey',new libVES.VaultKey({type: 'shadow', user: me, algo: self.keyAlgo},self).generate(rkey,optns),false).then(function(k) {
|
|
@@ -434,14 +587,16 @@ libVES.prototype = {
|
|
|
434
587
|
delete(libVES.Object._refs);
|
|
435
588
|
return vis;
|
|
436
589
|
}));
|
|
437
|
-
return
|
|
590
|
+
return self.elevateAuth(optns).then(function(optns) {
|
|
591
|
+
return k.post(undefined, undefined, optns);
|
|
592
|
+
});
|
|
438
593
|
});
|
|
439
594
|
});
|
|
440
595
|
}).catch(function(e) {
|
|
441
596
|
me.shadowVaultKey = undefined;
|
|
442
597
|
throw e;
|
|
443
598
|
}).then(function() {
|
|
444
|
-
me.currentVaultKey = me.activeVaultKeys = undefined;
|
|
599
|
+
me.currentVaultKey = me.shadowVaultKey = me.activeVaultKeys = undefined;
|
|
445
600
|
return me.getShadowVaultKey();
|
|
446
601
|
});
|
|
447
602
|
});
|
|
@@ -467,30 +622,11 @@ libVES.prototype = {
|
|
|
467
622
|
putValue: function(fileRef,value,shareWith) {
|
|
468
623
|
var self = this;
|
|
469
624
|
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() {
|
|
625
|
+
return vaultItem.setField('type',libVES.VaultItem.Type._detect(value)).then(function() {
|
|
490
626
|
return Promise.resolve(shareWith || self.getFileItem(fileRef).then(function(vi) {
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
return self.usersToKeys([{domain: fileRef.domain}]);
|
|
627
|
+
return vi.getShareList();
|
|
628
|
+
}).catch(function(e) {
|
|
629
|
+
return self.usersToKeys([{domain: (fileRef.domain || VES.domain)}]);
|
|
494
630
|
})).then(function(shareWith) {
|
|
495
631
|
return vaultItem.shareWith(shareWith,value);
|
|
496
632
|
});
|
|
@@ -502,6 +638,16 @@ libVES.prototype = {
|
|
|
502
638
|
return vaultItem.shareWith(shareWith);
|
|
503
639
|
});
|
|
504
640
|
},
|
|
641
|
+
fileExists: function(fileRef) {
|
|
642
|
+
return this.getFileItem(fileRef).then(function(vaultItem) {
|
|
643
|
+
return vaultItem.getId().then(function(id) {
|
|
644
|
+
return true;
|
|
645
|
+
}).catch(function(e) {
|
|
646
|
+
if (e.code == 'NotFound') return false;
|
|
647
|
+
throw e;
|
|
648
|
+
});
|
|
649
|
+
});
|
|
650
|
+
},
|
|
505
651
|
deleteFile: function(fileRef) {
|
|
506
652
|
return this.getFile(fileRef).then(function(file) {
|
|
507
653
|
return file.delete();
|
|
@@ -539,8 +685,8 @@ libVES.prototype = {
|
|
|
539
685
|
hashText: function(text,cls) {
|
|
540
686
|
if (cls) cls = cls.split('.')[0];
|
|
541
687
|
else cls = this.defaultHash;
|
|
542
|
-
return libVES.getModule(libVES.Util,['Hash',cls]).then(function(
|
|
543
|
-
return
|
|
688
|
+
return libVES.getModule(libVES.Util,['Hash',cls]).then(function(mod) {
|
|
689
|
+
return mod.hash(libVES.Util.StringToByteArray(text)).then(function(buf) {
|
|
544
690
|
return cls + '.' + libVES.Util.ByteArrayToB64W(buf);
|
|
545
691
|
});
|
|
546
692
|
});
|
|
@@ -579,8 +725,6 @@ libVES.prototype = {
|
|
|
579
725
|
}).then(function() {
|
|
580
726
|
chain = chain.then(function(ct) {
|
|
581
727
|
return vaultKey.rekey().then(function() {
|
|
582
|
-
if (self.onRekey) return self.onRekey(vaultKey);
|
|
583
|
-
}).then(function() {
|
|
584
728
|
return ct + 1;
|
|
585
729
|
});
|
|
586
730
|
}).catch(function(e) {console.log(e);});;
|
|
@@ -597,35 +741,104 @@ libVES.prototype = {
|
|
|
597
741
|
var self = this;
|
|
598
742
|
return self.me().then(function(me) {
|
|
599
743
|
return me.getVaultKeys().then(function(vaultKeys) {
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
});
|
|
744
|
+
return Promise.all(vaultKeys.map(function(e,i) {
|
|
745
|
+
return e.getType();
|
|
746
|
+
})).then(function(types) {
|
|
747
|
+
var rs = [];
|
|
748
|
+
for (var i = 0; i < types.length; i++) switch (types[i]) {
|
|
749
|
+
case 'recovery': case 'shadow':
|
|
750
|
+
rs.push(vaultKeys[i].getRecovery());
|
|
751
|
+
}
|
|
752
|
+
return Promise.all(rs);
|
|
610
753
|
});
|
|
754
|
+
});
|
|
611
755
|
});
|
|
612
756
|
},
|
|
613
757
|
getFriendsRecoveries: function() {
|
|
614
758
|
var self = this;
|
|
615
759
|
return self.me().then(function(me) {
|
|
616
|
-
return me.
|
|
617
|
-
|
|
618
|
-
|
|
760
|
+
return me.getFriendsKeyItems().then(function(vaultItems) {
|
|
761
|
+
var vaultKeys = [];
|
|
762
|
+
return Promise.all(vaultItems.map(function(e,i) {
|
|
763
|
+
return e.getVaultKey().then(function(vk) {
|
|
764
|
+
vaultKeys[i] = vk;
|
|
765
|
+
if (vk) return vk.getType();
|
|
766
|
+
});
|
|
619
767
|
})).then(function(types) {
|
|
620
768
|
var rs = [];
|
|
621
769
|
for (var i = 0; i < types.length; i++) switch (types[i]) {
|
|
622
770
|
case 'recovery': case 'shadow':
|
|
623
|
-
rs.push(vaultKeys[i].getRecovery());
|
|
771
|
+
rs.push(vaultKeys[i].getRecovery([vaultItems[i]]));
|
|
624
772
|
}
|
|
625
773
|
return Promise.all(rs);
|
|
626
774
|
});
|
|
627
775
|
});
|
|
628
776
|
});
|
|
777
|
+
},
|
|
778
|
+
getUnlockableKeys: function() {
|
|
779
|
+
var self = this;
|
|
780
|
+
return self.getVaultKey().then(function(vk) {
|
|
781
|
+
return vk.getField('unlockableVaultKeys').then(function(vks) {
|
|
782
|
+
var rs = {};
|
|
783
|
+
return Promise.all(vks.map(function(e, i) {
|
|
784
|
+
return e.getId().then(function(id) {
|
|
785
|
+
rs[id] = e;
|
|
786
|
+
});
|
|
787
|
+
})).then(function() {
|
|
788
|
+
return rs;
|
|
789
|
+
});
|
|
790
|
+
});
|
|
791
|
+
});
|
|
792
|
+
},
|
|
793
|
+
getAttn: function() {
|
|
794
|
+
var self = this;
|
|
795
|
+
var rs = {};
|
|
796
|
+
return self.get('attn').then(function(attn) {
|
|
797
|
+
return attn ? Promise.all([(attn.vaultKeys ? Promise.all(attn.vaultKeys.map(function(vk, i) {
|
|
798
|
+
return new libVES.VaultKey(vk, self);
|
|
799
|
+
})).then(function(vks) {
|
|
800
|
+
rs.vaultKeys = vks;
|
|
801
|
+
}) : null)]) : null;
|
|
802
|
+
}).then(function() {
|
|
803
|
+
return rs;
|
|
804
|
+
});
|
|
805
|
+
},
|
|
806
|
+
handleAttn: function(attn) {
|
|
807
|
+
var self = this;
|
|
808
|
+
return (attn ? Promise.resolve(attn) : self.getAttn()).then(function(attn) {
|
|
809
|
+
if (attn) return Promise.all([(attn.vaultKeys ? self.attnVaultKeys(attn.vaultKeys) : null)]);
|
|
810
|
+
});
|
|
811
|
+
},
|
|
812
|
+
attnVaultKeys: function(vkeys) {
|
|
813
|
+
var self = this;
|
|
814
|
+
return Promise.all(vkeys.map(function(vkey, i) {
|
|
815
|
+
console.log('attnVaultKeys:', vkey);
|
|
816
|
+
return vkey.getType().then(function(type) {
|
|
817
|
+
switch (type) {
|
|
818
|
+
case 'temp':
|
|
819
|
+
case 'lost':
|
|
820
|
+
return vkey.getUser().then(function(user) {
|
|
821
|
+
return self.me().then(function(me) {
|
|
822
|
+
return Promise.all([user.getId(), me.getId()]).then(function(ids) {
|
|
823
|
+
if (ids[0] == ids[1]) return type == 'temp' ? vkey.rekey()
|
|
824
|
+
: self.elevateAuth({authVaultKey: vkey}).then(function(optns) {
|
|
825
|
+
return vkey.rekey(optns);
|
|
826
|
+
});
|
|
827
|
+
else return vkey.getVaultItems().then(function(vis) {
|
|
828
|
+
return Promise.all(vis.map(function(vi, i) {
|
|
829
|
+
return vi.reshareWith([user]);
|
|
830
|
+
}));
|
|
831
|
+
});
|
|
832
|
+
});
|
|
833
|
+
});
|
|
834
|
+
});
|
|
835
|
+
case 'recovery':
|
|
836
|
+
return vkey.getRecovery().then(function(rcv) {
|
|
837
|
+
return rcv.recover();
|
|
838
|
+
});
|
|
839
|
+
}
|
|
840
|
+
});
|
|
841
|
+
}));
|
|
629
842
|
}
|
|
630
843
|
};
|
|
631
844
|
|
|
@@ -756,7 +969,7 @@ libVES.Util = {
|
|
|
756
969
|
}
|
|
757
970
|
},
|
|
758
971
|
ASN1: {
|
|
759
|
-
decode: function(der) {
|
|
972
|
+
decode: function(der,fStruct) {
|
|
760
973
|
var p = 0;
|
|
761
974
|
var data = function() {
|
|
762
975
|
var l = der[p++];
|
|
@@ -771,10 +984,14 @@ libVES.Util = {
|
|
|
771
984
|
};
|
|
772
985
|
var rs = [];
|
|
773
986
|
for (; p < der.length;) {
|
|
987
|
+
if (!fStruct && p) {
|
|
988
|
+
rs.push(der.slice(p));
|
|
989
|
+
break;
|
|
990
|
+
}
|
|
774
991
|
var tag = der[p++];
|
|
775
992
|
switch (tag) {
|
|
776
993
|
case 48:
|
|
777
|
-
rs.push(libVES.Util.ASN1.decode(data()));
|
|
994
|
+
rs.push(libVES.Util.ASN1.decode(data(),true));
|
|
778
995
|
break;
|
|
779
996
|
case 6:
|
|
780
997
|
rs.push(new libVES.Util.OID(data()));
|
|
@@ -796,7 +1013,7 @@ libVES.Util = {
|
|
|
796
1013
|
}
|
|
797
1014
|
return rs;
|
|
798
1015
|
},
|
|
799
|
-
encode: function(data) {
|
|
1016
|
+
encode: function(data,fStruct) {
|
|
800
1017
|
var i2a = function(v) {
|
|
801
1018
|
if (v < 0) throw new libVES.Error('Internal',"Negative value for ASN.1 integer!");
|
|
802
1019
|
var rs = [];
|
|
@@ -827,10 +1044,10 @@ libVES.Util = {
|
|
|
827
1044
|
return rs;
|
|
828
1045
|
};
|
|
829
1046
|
var d;
|
|
830
|
-
for (var i = 0; i < data.length; i++) switch (typeof(d = data[i])) {
|
|
1047
|
+
for (var i = 0; i < data.length; i++) if (fStruct || !i) switch (typeof(d = data[i])) {
|
|
831
1048
|
case 'object':
|
|
832
1049
|
if (d == null) buf(5,new Uint8Array(0));
|
|
833
|
-
else if (d instanceof Array) buf(48,libVES.Util.ASN1.encode(d));
|
|
1050
|
+
else if (d instanceof Array) buf(48,libVES.Util.ASN1.encode(d,true));
|
|
834
1051
|
else if (d instanceof libVES.Util.OID) buf(6,d.getBuffer());
|
|
835
1052
|
else if (d instanceof Uint8Array || d instanceof ArrayBuffer) buf((d.ASN1type || 4),d);
|
|
836
1053
|
else throw new libVES.Error('Internal',"ASN.1 encode - Unknown type");
|
|
@@ -839,7 +1056,7 @@ libVES.Util = {
|
|
|
839
1056
|
buf(2,i2a(d));
|
|
840
1057
|
break;
|
|
841
1058
|
default: throw new libVES.Error('Internal',"ASN.1 encode - Unknown type");
|
|
842
|
-
}
|
|
1059
|
+
} else bufs.push(d);
|
|
843
1060
|
var l = 0;
|
|
844
1061
|
for (var i = 0; i < bufs.length; i++) l += bufs[i].length;
|
|
845
1062
|
var der = new Uint8Array(l);
|
|
@@ -848,7 +1065,7 @@ libVES.Util = {
|
|
|
848
1065
|
return der;
|
|
849
1066
|
},
|
|
850
1067
|
import: function(der,optns) {
|
|
851
|
-
var k = libVES.Util.ASN1.decode(der)[0];
|
|
1068
|
+
var k = optns && optns.decoded || libVES.Util.ASN1.decode(der)[0];
|
|
852
1069
|
if (!k) throw new libVES.Error('Internal','Empty ASN.1 package?');
|
|
853
1070
|
var i = 0;
|
|
854
1071
|
if (typeof(k[i]) == 'number') (optns || (optns = {})).version = k[i++];
|
|
@@ -894,6 +1111,11 @@ libVES.Util = {
|
|
|
894
1111
|
return crypto.subtle.importKey('pkcs8',der,{name:'RSA-OAEP', hash:'SHA-1'},true,['decrypt']);
|
|
895
1112
|
});
|
|
896
1113
|
});
|
|
1114
|
+
},
|
|
1115
|
+
encode: function(key,optns) {
|
|
1116
|
+
return crypto.subtle.exportKey('spki',key).then(function(der) {
|
|
1117
|
+
return libVES.Util.PEM.encode(der,'PUBLIC KEY');
|
|
1118
|
+
});
|
|
897
1119
|
}
|
|
898
1120
|
},
|
|
899
1121
|
PKCS5: {
|
|
@@ -908,7 +1130,7 @@ libVES.Util = {
|
|
|
908
1130
|
else return fp;
|
|
909
1131
|
})(args[i],f);
|
|
910
1132
|
return f('import',optns).then(function(der) {
|
|
911
|
-
return
|
|
1133
|
+
return libVES.Util.ASN1.import(new Uint8Array(der));
|
|
912
1134
|
}).catch(function(e) {
|
|
913
1135
|
throw new libVES.Error('InvalidKey',"Cannot import the private key (Invalid VESkey?)");
|
|
914
1136
|
});
|
|
@@ -930,10 +1152,108 @@ libVES.Util = {
|
|
|
930
1152
|
});
|
|
931
1153
|
}
|
|
932
1154
|
},
|
|
1155
|
+
PKCS8: {
|
|
1156
|
+
encode: function(key,optns) {
|
|
1157
|
+
var ops = {};
|
|
1158
|
+
for (var k in optns) ops[k] = optns[k];
|
|
1159
|
+
if (!ops.members) ops.members = [
|
|
1160
|
+
libVES.getModule(libVES.Util,'PBKDF2'),
|
|
1161
|
+
libVES.getModule(libVES.Cipher,'AES256CBC')
|
|
1162
|
+
];
|
|
1163
|
+
return Promise.all(ops.members).then(function(ms) {
|
|
1164
|
+
ops.members = ms;
|
|
1165
|
+
return crypto.subtle.exportKey('pkcs8',key).catch(function(e) {
|
|
1166
|
+
console.log('PKCS8 failed, trying JWK...');
|
|
1167
|
+
return crypto.subtle.exportKey('jwk', key).then(function(jwk) {
|
|
1168
|
+
return libVES.Util.PKCS8.fromJWK(jwk);
|
|
1169
|
+
});
|
|
1170
|
+
}).then(function(der) {
|
|
1171
|
+
ops.content = der;
|
|
1172
|
+
var rec = [];
|
|
1173
|
+
if (ops.password) return libVES.Util.PKCS5.export(function(call,optns) {
|
|
1174
|
+
rec[1] = optns.content;
|
|
1175
|
+
return Promise.resolve();
|
|
1176
|
+
},ops).then(function(data) {
|
|
1177
|
+
rec[0] = data;
|
|
1178
|
+
return libVES.Util.PEM.encode(libVES.Util.ASN1.encode([rec]),'ENCRYPTED PRIVATE KEY');
|
|
1179
|
+
});
|
|
1180
|
+
else if (ops.opentext) return libVES.Util.PEM.encode(der,'PRIVATE KEY');
|
|
1181
|
+
else throw new libVES.Error('Internal','No password for key export (opentext=true to export without password?)');
|
|
1182
|
+
});
|
|
1183
|
+
});
|
|
1184
|
+
},
|
|
1185
|
+
fromJWK: function(jwk) {
|
|
1186
|
+
if (jwk.kty != 'EC') throw new libVES.Error('Internal', 'kty=="EC" expected (workaround for Firefox)');
|
|
1187
|
+
var pubx = libVES.Util.B64ToByteArray(jwk.x);
|
|
1188
|
+
var puby = libVES.Util.B64ToByteArray(jwk.y);
|
|
1189
|
+
var pub = new Uint8Array(pubx.byteLength + puby.byteLength + 2);
|
|
1190
|
+
pub[0] = 0;
|
|
1191
|
+
pub[1] = 4;
|
|
1192
|
+
pub.set(new Uint8Array(pubx), 2);
|
|
1193
|
+
pub.set(new Uint8Array(puby), pubx.byteLength + 2);
|
|
1194
|
+
pub.ASN1type = 3;
|
|
1195
|
+
pub = libVES.Util.ASN1.encode([pub]);
|
|
1196
|
+
pub.ASN1type = 0xa1;
|
|
1197
|
+
return libVES.Util.ASN1.encode([[
|
|
1198
|
+
0,
|
|
1199
|
+
[
|
|
1200
|
+
new libVES.Util.OID('1.2.840.10045.2.1'),
|
|
1201
|
+
new libVES.Util.OID((function(crvs) {
|
|
1202
|
+
for (var k in crvs) if (crvs[k] == jwk.crv) return k;
|
|
1203
|
+
throw new libVES.Error('Internal', 'Unknown named curve: ' + jwk.crv);
|
|
1204
|
+
})(libVES.Util.EC.namedCurves))
|
|
1205
|
+
],
|
|
1206
|
+
libVES.Util.ASN1.encode([[
|
|
1207
|
+
1,
|
|
1208
|
+
libVES.Util.B64ToByteArray(jwk.d),
|
|
1209
|
+
pub
|
|
1210
|
+
]])
|
|
1211
|
+
]]).buffer;
|
|
1212
|
+
},
|
|
1213
|
+
toJWK: function(key) {
|
|
1214
|
+
var der = libVES.Util.ASN1.decode(key)[0];
|
|
1215
|
+
var idx = 0;
|
|
1216
|
+
if (!(der[0] instanceof Array)) idx++;
|
|
1217
|
+
switch (String(der[idx][0])) {
|
|
1218
|
+
case '1.2.840.10045.2.1':
|
|
1219
|
+
case '1.3.132.1.12':
|
|
1220
|
+
case '1.3.132.112': // Firefox on Mac - apparently a misspelling of the former
|
|
1221
|
+
break;
|
|
1222
|
+
default:
|
|
1223
|
+
console.log(der);
|
|
1224
|
+
throw new libVES.Error('Internal', 'EC PKCS8 expected');
|
|
1225
|
+
}
|
|
1226
|
+
var der2 = idx ? libVES.Util.ASN1.decode(der[idx + 1])[0] : null;
|
|
1227
|
+
var pub = idx ? (der2[2] ? libVES.Util.ASN1.decode(der2[2])[0] : null) : der[1];
|
|
1228
|
+
var publ = 0;
|
|
1229
|
+
if (pub && pub.byteLength > 2 && pub[1] == 4) publ = pub.byteLength / 2 - 1;
|
|
1230
|
+
return {
|
|
1231
|
+
crv: libVES.Util.EC.namedCurves[der[idx][1]],
|
|
1232
|
+
d: (idx ? libVES.Util.ByteArrayToB64W(der2[1]) : undefined),
|
|
1233
|
+
ext: true,
|
|
1234
|
+
key_ops: (idx ? ['deriveKey', 'deriveBits'] : []),
|
|
1235
|
+
kty: 'EC',
|
|
1236
|
+
x: (publ ? libVES.Util.ByteArrayToB64W(pub.slice(2, publ + 2)) : ''),
|
|
1237
|
+
y: (publ ? libVES.Util.ByteArrayToB64W(pub.slice(publ + 2, 2 * publ + 2)) : '')
|
|
1238
|
+
};
|
|
1239
|
+
}
|
|
1240
|
+
},
|
|
933
1241
|
PBKDF2: {
|
|
934
|
-
deriveKey: function(args,pwd,algo) {
|
|
935
|
-
return crypto.subtle.importKey('raw',libVES.Util.StringToByteArray(pwd),'PBKDF2',false,['deriveKey']).then(function(k) {
|
|
936
|
-
|
|
1242
|
+
deriveKey: function(args, pwd, algo) {
|
|
1243
|
+
return crypto.subtle.importKey('raw', libVES.Util.StringToByteArray(pwd), 'PBKDF2', false, ['deriveKey']).then(function(k) {
|
|
1244
|
+
var keyargs = {name:'PBKDF2', salt:args[0], iterations:args[1]};
|
|
1245
|
+
var ka;
|
|
1246
|
+
if (args[2] && (args[2][0] instanceof libVES.Util.OID)) ka = args[2][0].object().then(function(obj) {
|
|
1247
|
+
obj.setArgs(keyargs, args[2][1]);
|
|
1248
|
+
return keyargs;
|
|
1249
|
+
});
|
|
1250
|
+
else {
|
|
1251
|
+
keyargs.hash = 'SHA-1';
|
|
1252
|
+
ka = Promise.resolve(keyargs);
|
|
1253
|
+
}
|
|
1254
|
+
return ka.then(function(keyargs) {
|
|
1255
|
+
return crypto.subtle.deriveKey(keyargs, k, algo, true, ['encrypt', 'decrypt']);
|
|
1256
|
+
});
|
|
937
1257
|
});
|
|
938
1258
|
},
|
|
939
1259
|
import: function(args,chain,optns) {
|
|
@@ -960,9 +1280,61 @@ libVES.Util = {
|
|
|
960
1280
|
});
|
|
961
1281
|
}
|
|
962
1282
|
},
|
|
1283
|
+
EC: {
|
|
1284
|
+
import: function(args,chain,optns) {
|
|
1285
|
+
return chain('container',optns).then(function(der) {
|
|
1286
|
+
var a = {name:'ECDH',namedCurve:libVES.Util.EC.namedCurves[String(args)]};
|
|
1287
|
+
return crypto.subtle.importKey('spki',der,a,true,[]).catch(function() {;
|
|
1288
|
+
return crypto.subtle.importKey('pkcs8',der,a,true,['deriveKey','deriveBits']).catch(function(e) {
|
|
1289
|
+
console.log('PKCS8 failed, trying JWK...');
|
|
1290
|
+
var jwk = libVES.Util.PKCS8.toJWK(der);
|
|
1291
|
+
return crypto.subtle.importKey('jwk', jwk, a, true, jwk.key_ops);
|
|
1292
|
+
});
|
|
1293
|
+
});
|
|
1294
|
+
});
|
|
1295
|
+
},
|
|
1296
|
+
namedCurves: {
|
|
1297
|
+
"1.3.132.0.10": "P-256",
|
|
1298
|
+
"1.3.132.0.34": "P-384",
|
|
1299
|
+
"1.3.132.0.35": "P-521"
|
|
1300
|
+
}
|
|
1301
|
+
},
|
|
963
1302
|
Hash: {
|
|
964
|
-
|
|
965
|
-
|
|
1303
|
+
SHA1: {
|
|
1304
|
+
setArgs: function(args, optns) {
|
|
1305
|
+
args.hash = 'SHA-1';
|
|
1306
|
+
return args;
|
|
1307
|
+
},
|
|
1308
|
+
hash: function(buf) {
|
|
1309
|
+
return crypto.subtle.digest('SHA-1',buf);
|
|
1310
|
+
}
|
|
1311
|
+
},
|
|
1312
|
+
SHA256: {
|
|
1313
|
+
setArgs: function(args, optns) {
|
|
1314
|
+
args.hash = 'SHA-256';
|
|
1315
|
+
return args;
|
|
1316
|
+
},
|
|
1317
|
+
hash: function(buf) {
|
|
1318
|
+
return crypto.subtle.digest('SHA-256',buf);
|
|
1319
|
+
}
|
|
1320
|
+
},
|
|
1321
|
+
SHA384: {
|
|
1322
|
+
setArgs: function(args, optns) {
|
|
1323
|
+
args.hash = 'SHA-384';
|
|
1324
|
+
return args;
|
|
1325
|
+
},
|
|
1326
|
+
hash: function(buf) {
|
|
1327
|
+
return crypto.subtle.digest('SHA-384',buf);
|
|
1328
|
+
}
|
|
1329
|
+
},
|
|
1330
|
+
SHA512: {
|
|
1331
|
+
setArgs: function(args, optns) {
|
|
1332
|
+
args.hash = 'SHA-512';
|
|
1333
|
+
return args;
|
|
1334
|
+
},
|
|
1335
|
+
hash: function(buf) {
|
|
1336
|
+
return crypto.subtle.digest('SHA-512',buf);
|
|
1337
|
+
}
|
|
966
1338
|
}
|
|
967
1339
|
}
|
|
968
1340
|
};
|
|
@@ -993,10 +1365,15 @@ libVES.Util.OID.prototype = {
|
|
|
993
1365
|
}
|
|
994
1366
|
}
|
|
995
1367
|
|
|
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']);
|
|
1368
|
+
libVES.Util.OID['1.2.840.113549.1.5.13'] = libVES.getModuleFunc(libVES, ['Util', 'PKCS5']);
|
|
1369
|
+
libVES.Util.OID['1.2.840.113549.1.5.12'] = libVES.getModuleFunc(libVES, ['Util', 'PBKDF2']);
|
|
1370
|
+
libVES.Util.OID['2.16.840.1.101.3.4.1.42'] = libVES.getModuleFunc(libVES, ['Cipher', 'AES256CBC']);
|
|
1371
|
+
libVES.Util.OID['1.2.840.113549.1.1.1'] = libVES.getModuleFunc(libVES, ['Util', 'PKCS1']);
|
|
1372
|
+
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']);
|
|
1373
|
+
libVES.Util.OID['1.2.840.113549.2.7'] = libVES.getModuleFunc(libVES, ['Util', 'Hash', 'SHA1']);
|
|
1374
|
+
libVES.Util.OID['1.2.840.113549.2.9'] = libVES.getModuleFunc(libVES, ['Util', 'Hash', 'SHA256']);
|
|
1375
|
+
libVES.Util.OID['1.2.840.113549.2.10'] = libVES.getModuleFunc(libVES, ['Util', 'Hash', 'SHA384']);
|
|
1376
|
+
libVES.Util.OID['1.2.840.113549.2.11'] = libVES.getModuleFunc(libVES, ['Util', 'Hash', 'SHA512']);
|
|
1000
1377
|
|
|
1001
1378
|
libVES.Math = {
|
|
1002
1379
|
pad: function(a,n) {
|
|
@@ -1374,10 +1751,6 @@ libVES.External = function(data,VES,refs) {
|
|
|
1374
1751
|
this.init(data,VES,refs);
|
|
1375
1752
|
};
|
|
1376
1753
|
|
|
1377
|
-
libVES.Lockbox = function(data,VES,refs) {
|
|
1378
|
-
this.init(data,VES,refs);
|
|
1379
|
-
};
|
|
1380
|
-
|
|
1381
1754
|
libVES.File = function(data,VES,refs) {
|
|
1382
1755
|
this.init(data,VES,refs);
|
|
1383
1756
|
};
|
|
@@ -1386,7 +1759,7 @@ libVES.User.prototype = new libVES.Object({
|
|
|
1386
1759
|
apiUri: 'users',
|
|
1387
1760
|
fieldList: {id: true, email: true, type: true, firstName: true, lastName: true},
|
|
1388
1761
|
fieldExtra: {vaultKeys: true, activeVaultKeys: true, currentVaultKey: true},
|
|
1389
|
-
fieldClass: {vaultKeys: libVES.VaultKey, activeVaultKeys: libVES.VaultKey, currentVaultKey: libVES.VaultKey, shadowVaultKey: libVES.VaultKey,
|
|
1762
|
+
fieldClass: {vaultKeys: libVES.VaultKey, activeVaultKeys: libVES.VaultKey, currentVaultKey: libVES.VaultKey, shadowVaultKey: libVES.VaultKey, friendsKeyItems: libVES.VaultItem},
|
|
1390
1763
|
getEmail: function() {
|
|
1391
1764
|
return this.getField('email');
|
|
1392
1765
|
},
|
|
@@ -1416,11 +1789,10 @@ libVES.User.prototype = new libVES.Object({
|
|
|
1416
1789
|
});
|
|
1417
1790
|
return this.getField('activeVaultKeys');
|
|
1418
1791
|
},
|
|
1419
|
-
|
|
1420
|
-
return this.getField('
|
|
1792
|
+
getFriendsKeyItems: function() {
|
|
1793
|
+
return this.getField('friendsKeyItems');
|
|
1421
1794
|
},
|
|
1422
1795
|
getCurrentVaultKey: function() {
|
|
1423
|
-
|
|
1424
1796
|
return this.getField('currentVaultKey');
|
|
1425
1797
|
},
|
|
1426
1798
|
getShadowVaultKey: function() {
|
|
@@ -1452,9 +1824,9 @@ libVES.User.prototype = new libVES.Object({
|
|
|
1452
1824
|
libVES.VaultKey.prototype = new libVES.Object({
|
|
1453
1825
|
apiUri: 'vaultKeys',
|
|
1454
1826
|
fieldList: {id: true, algo: true, type: true, publicKey: true, privateKey: true},
|
|
1455
|
-
fieldClass: {user: libVES.User, vaultItems: libVES.VaultItem, externals: libVES.External,
|
|
1827
|
+
fieldClass: {user: libVES.User, vaultItems: libVES.VaultItem, externals: libVES.External, unlockableVaultKeys: libVES.VaultKey, creator: libVES.User},
|
|
1456
1828
|
fieldExtra: {user: true, vaultItems: true},
|
|
1457
|
-
fieldSets: [{vaultEntries: {id: true, encData: true, vaultItem: {id: true}}},{type: true, algo: true, publicKey: true}],
|
|
1829
|
+
fieldSets: [{vaultEntries: {id: true, encData: true, vaultItem: {id: true}}},{type: true, algo: true, publicKey: true}, {unlockableVaultKeys: {id: true, type: true}}],
|
|
1458
1830
|
getAlgo: function() {
|
|
1459
1831
|
return this.getField('algo');
|
|
1460
1832
|
},
|
|
@@ -1478,18 +1850,12 @@ libVES.VaultKey.prototype = new libVES.Object({
|
|
|
1478
1850
|
getVaultItems: function() {
|
|
1479
1851
|
return this.getField('vaultItems');
|
|
1480
1852
|
},
|
|
1481
|
-
getSharedKeys: function() {
|
|
1482
|
-
return this.getField('sharedKeys');
|
|
1483
|
-
},
|
|
1484
1853
|
getExternals: function() {
|
|
1485
1854
|
return this.getField('externals');
|
|
1486
1855
|
},
|
|
1487
1856
|
getUser: function() {
|
|
1488
1857
|
return this.getField('user');
|
|
1489
1858
|
},
|
|
1490
|
-
getVaultItems: function() {
|
|
1491
|
-
return this.getField('vaultItems');
|
|
1492
|
-
},
|
|
1493
1859
|
resolveVESkey: function(veskey) {
|
|
1494
1860
|
if (veskey) return Promise.resolve(veskey);
|
|
1495
1861
|
var self = this;
|
|
@@ -1497,6 +1863,7 @@ libVES.VaultKey.prototype = new libVES.Object({
|
|
|
1497
1863
|
switch (t) {
|
|
1498
1864
|
case 'secondary':
|
|
1499
1865
|
case 'temp':
|
|
1866
|
+
case 'lost':
|
|
1500
1867
|
return self.getVaultItems().then(function(vis) {
|
|
1501
1868
|
var f = function(vis) {
|
|
1502
1869
|
if (!vis.length) throw new libVES.Error('InvalidKey','Cannot unlock the secondary key');
|
|
@@ -1564,10 +1931,12 @@ libVES.VaultKey.prototype = new libVES.Object({
|
|
|
1564
1931
|
self.setField('algo',wc.engine.tag);
|
|
1565
1932
|
if (!wc.privateKey) throw new libVES.Error('InvalidValue','Private key expected');
|
|
1566
1933
|
return wc;
|
|
1567
|
-
}) :
|
|
1568
|
-
return
|
|
1569
|
-
ks
|
|
1570
|
-
|
|
1934
|
+
}) : (optns && optns.algo ? self.setField('algo',optns.algo) : Promise.resolve()).then(function() {
|
|
1935
|
+
return self.engine().then(function(e) {
|
|
1936
|
+
return e.generate(optns).then(function(ks) {
|
|
1937
|
+
ks.engine = e;
|
|
1938
|
+
return ks;
|
|
1939
|
+
});
|
|
1571
1940
|
});
|
|
1572
1941
|
});
|
|
1573
1942
|
return Promise.resolve(veskey).then(function(v) {
|
|
@@ -1611,16 +1980,14 @@ libVES.VaultKey.prototype = new libVES.Object({
|
|
|
1611
1980
|
var self = this;
|
|
1612
1981
|
var old_vis = {};
|
|
1613
1982
|
return (self.vaultEntries ? self.vaultEntries.then(function(old_ves) {
|
|
1614
|
-
return old_ves.map(function(ve,i) {
|
|
1983
|
+
if (old_ves) return old_ves.map(function(ve,i) {
|
|
1615
1984
|
old_vis[ve.vaultItem.id] = true;
|
|
1616
1985
|
});
|
|
1617
1986
|
}) : Promise.resolve(null)).then(function() {
|
|
1618
1987
|
return self.setField('vaultEntries',key.unlock(veskey).then(function() {
|
|
1619
1988
|
return key.getVaultEntries().then(function(ves) {
|
|
1620
1989
|
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) {
|
|
1990
|
+
return old_vis[ve.vaultItem.id] ? null : key.decrypt(ve.encData).then(function(ptxt) {
|
|
1624
1991
|
return self.encrypt(ptxt).then(function(ctxt) {
|
|
1625
1992
|
return {
|
|
1626
1993
|
vaultItem: {id: ve.vaultItem.id},
|
|
@@ -1633,6 +2000,8 @@ libVES.VaultKey.prototype = new libVES.Object({
|
|
|
1633
2000
|
"$op": "ignore"
|
|
1634
2001
|
};
|
|
1635
2002
|
});
|
|
2003
|
+
}).filter(function(e, i) {
|
|
2004
|
+
return !!e;
|
|
1636
2005
|
}));
|
|
1637
2006
|
});
|
|
1638
2007
|
}));
|
|
@@ -1640,7 +2009,7 @@ libVES.VaultKey.prototype = new libVES.Object({
|
|
|
1640
2009
|
return self;
|
|
1641
2010
|
});
|
|
1642
2011
|
},
|
|
1643
|
-
rekey: function() {
|
|
2012
|
+
rekey: function(optns) {
|
|
1644
2013
|
var self = this;
|
|
1645
2014
|
return self.getUser().then(function(user) {
|
|
1646
2015
|
return self.getExternals().then(function(exts) {
|
|
@@ -1661,20 +2030,24 @@ libVES.VaultKey.prototype = new libVES.Object({
|
|
|
1661
2030
|
}));
|
|
1662
2031
|
}).then(function(keys) {
|
|
1663
2032
|
return user.setField('vaultKeys',keys).then(function() {
|
|
1664
|
-
|
|
2033
|
+
if (!optns) optns = {};
|
|
2034
|
+
optns.refs = {'#/': user};
|
|
2035
|
+
return user.post(null,{vaultEntries: true}, optns).then(function(data) {
|
|
1665
2036
|
self.setFields(data,false);
|
|
1666
|
-
return self
|
|
2037
|
+
return self.VES.onRekey ? self.VES.onRekey(self).catch(function() {}).then(function() {
|
|
2038
|
+
return self;
|
|
2039
|
+
}) : self;
|
|
1667
2040
|
});
|
|
1668
2041
|
});
|
|
1669
2042
|
});
|
|
1670
2043
|
});
|
|
1671
2044
|
},
|
|
1672
|
-
getRecovery: function() {
|
|
2045
|
+
getRecovery: function(myItems) {
|
|
1673
2046
|
var self = this;
|
|
1674
2047
|
return self.getType().then(function(t) {
|
|
1675
2048
|
switch (t) {
|
|
1676
2049
|
case 'shadow': case 'recovery':
|
|
1677
|
-
return new libVES.Recovery(self);
|
|
2050
|
+
return new libVES.Recovery(self, myItems);
|
|
1678
2051
|
default: throw new libVES.Error('InvalidValue','Recovery is not applicable for VaultKey type ' + t);
|
|
1679
2052
|
}
|
|
1680
2053
|
});
|
|
@@ -1682,18 +2055,21 @@ libVES.VaultKey.prototype = new libVES.Object({
|
|
|
1682
2055
|
getSessionToken: function() {
|
|
1683
2056
|
var self = this;
|
|
1684
2057
|
return this.getField('encSessionToken').then(function(tk) {
|
|
2058
|
+
if (!tk) return null;
|
|
1685
2059
|
return self.decrypt(tk).then(function(b) {
|
|
1686
2060
|
return libVES.Util.ByteArrayToString(b);
|
|
1687
2061
|
});
|
|
1688
2062
|
});
|
|
1689
2063
|
},
|
|
1690
|
-
reshareVESkey: function(veskey) {
|
|
2064
|
+
reshareVESkey: function(veskey, optns) {
|
|
1691
2065
|
var self = this;
|
|
1692
2066
|
return self.getVaultItems().then(function(vaultItems) {
|
|
1693
2067
|
return self.getUser().then(function(user) {
|
|
1694
2068
|
return Promise.all(vaultItems.map(function(vaultItem,i) {
|
|
1695
2069
|
return vaultItem.getType().then(function(t) {
|
|
1696
|
-
if (t == 'password') return vaultItem.reshareWith([user],veskey)
|
|
2070
|
+
if (t == 'password') return vaultItem.reshareWith([user], veskey, false).then(function(vi) {
|
|
2071
|
+
return vi.post(undefined, undefined, optns);
|
|
2072
|
+
});
|
|
1697
2073
|
});
|
|
1698
2074
|
}));
|
|
1699
2075
|
});
|
|
@@ -1708,29 +2084,33 @@ libVES.VaultItem.prototype = new libVES.Object({
|
|
|
1708
2084
|
apiUri: 'vaultItems',
|
|
1709
2085
|
fieldList: {id: true},
|
|
1710
2086
|
fieldClass: {vaultKey: libVES.VaultKey, file: libVES.File},
|
|
1711
|
-
fieldSets: [{type: true, meta: true},{vaultEntries: {id: true, encData: true, vaultKey: {id: true}}},{vaultKey: true, file: true
|
|
1712
|
-
defaultCipher: '
|
|
2087
|
+
fieldSets: [{type: true, meta: true},{vaultEntries: {id: true, encData: true, vaultKey: {id: true, type: true, user: {id: true}, algo: true}}},{vaultKey: true, file: true}],
|
|
2088
|
+
defaultCipher: 'AES256GCM',
|
|
1713
2089
|
getRaw: function() {
|
|
1714
2090
|
var self = this;
|
|
1715
|
-
|
|
1716
|
-
var
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
return k.decrypt(d).catch(fn);
|
|
1724
|
-
}
|
|
2091
|
+
var f = function(vaultEntries, vaultKeys) {
|
|
2092
|
+
var i = 0;
|
|
2093
|
+
var fn = function() {
|
|
2094
|
+
if (vaultEntries) for (; i < vaultEntries.length; i++) {
|
|
2095
|
+
var k, d;
|
|
2096
|
+
if ((d = vaultEntries[i].encData) != null && vaultKeys[(k = vaultEntries[i].vaultKey).id]) {
|
|
2097
|
+
i++;
|
|
2098
|
+
return new libVES.VaultKey(k, self.VES).decrypt(d).catch(fn);
|
|
1725
2099
|
}
|
|
1726
|
-
|
|
1727
|
-
};
|
|
1728
|
-
return fn();
|
|
2100
|
+
}
|
|
2101
|
+
return Promise.reject(new libVES.Error('InvalidKey',"No unlocked key to decrypt the item",{vaultItem: self}));
|
|
1729
2102
|
};
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
2103
|
+
return fn();
|
|
2104
|
+
};
|
|
2105
|
+
var vaultEntries = [];
|
|
2106
|
+
if (self.vaultEntryByKey) for (var k in self.vaultEntryByKey) vaultEntries.push(self.vaultEntryByKey[k]);
|
|
2107
|
+
return f(vaultEntries, self.VES.unlockedKeys).catch(function() {
|
|
2108
|
+
return self.getVaultEntries().then(function(vaultEntries) {
|
|
2109
|
+
return f(vaultEntries, self.VES.unlockedKeys).catch(function() {
|
|
2110
|
+
return self.VES.getUnlockableKeys().then(function(vks) {
|
|
2111
|
+
return f(vaultEntries, vks);
|
|
2112
|
+
});
|
|
2113
|
+
});
|
|
1734
2114
|
});
|
|
1735
2115
|
});
|
|
1736
2116
|
},
|
|
@@ -1749,7 +2129,7 @@ libVES.VaultItem.prototype = new libVES.Object({
|
|
|
1749
2129
|
getVaultEntries: function() {
|
|
1750
2130
|
var self = this;
|
|
1751
2131
|
return this.getField('vaultEntries').then(function(ves) {
|
|
1752
|
-
for (var i = 0; i < ves.length; i++) self.vaultEntryByKey[ves[i].vaultKey.id] = ves[i];
|
|
2132
|
+
if (ves) for (var i = 0; i < ves.length; i++) self.vaultEntryByKey[ves[i].vaultKey.id] = ves[i];
|
|
1753
2133
|
return ves;
|
|
1754
2134
|
});
|
|
1755
2135
|
},
|
|
@@ -1759,9 +2139,6 @@ libVES.VaultItem.prototype = new libVES.Object({
|
|
|
1759
2139
|
getFile: function() {
|
|
1760
2140
|
return this.getField('file');
|
|
1761
2141
|
},
|
|
1762
|
-
getLockbox: function() {
|
|
1763
|
-
return this.getField('lockbox');
|
|
1764
|
-
},
|
|
1765
2142
|
parse: function(buf) {
|
|
1766
2143
|
var self = this;
|
|
1767
2144
|
return this.getType().then(function(type) {
|
|
@@ -1780,42 +2157,49 @@ libVES.VaultItem.prototype = new libVES.Object({
|
|
|
1780
2157
|
});
|
|
1781
2158
|
});
|
|
1782
2159
|
},
|
|
2160
|
+
resolveRaw: function(val) {
|
|
2161
|
+
return (val == null ? this.getRaw() : this.build(val));
|
|
2162
|
+
},
|
|
1783
2163
|
shareWith: function(usrs,val,save) {
|
|
1784
2164
|
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
|
-
|
|
2165
|
+
return self.VES.usersToKeys(usrs).then(function(ks) {
|
|
2166
|
+
return (val == null || self.id ? self.getVaultEntries().then(function(ves) {
|
|
2167
|
+
var k_ves = {};
|
|
2168
|
+
var k_used = {};
|
|
2169
|
+
for (var j = 0; j < ves.length; j++) k_ves[ves[j].vaultKey.id] = ves[j];
|
|
2170
|
+
return Promise.all(ks.map(function(k,j) {
|
|
2171
|
+
return k.getId().then(function(k_id) {
|
|
2172
|
+
k_used[k_id] = true;
|
|
2173
|
+
return k_ves[k_id];
|
|
2174
|
+
}).catch(function(){});
|
|
2175
|
+
})).then(function(old_ves) {
|
|
2176
|
+
for (var k_id in k_ves) if (!k_used[k_id]) old_ves.push(k_ves[k_id]);
|
|
2177
|
+
return old_ves;
|
|
2178
|
+
});
|
|
2179
|
+
}) : Promise.resolve([])).then(function(old_ves) {
|
|
2180
|
+
var new_ves = [];
|
|
2181
|
+
var set_ves = [];
|
|
2182
|
+
var valr = null;
|
|
2183
|
+
return Promise.all(ks.map(function(k,j) {
|
|
2184
|
+
return new_ves[j] = (old_ves[j] || (valr != null ? valr : valr = self.resolveRaw(val)).then(function(v) {
|
|
2185
|
+
return k.encrypt(v).then(function(ctext) {
|
|
2186
|
+
return (function(refs) {
|
|
2187
|
+
if (refs) for (var i in refs) if (refs[i] === k) return Promise.resolve({'$ref':i});
|
|
2188
|
+
return k.postData(null,refs);
|
|
2189
|
+
})(libVES.Object._refs).then(function(pd) {
|
|
1806
2190
|
return set_ves.push({vaultKey: pd, encData: ctext});
|
|
1807
2191
|
});
|
|
1808
|
-
})
|
|
1809
|
-
}))
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
});
|
|
1814
|
-
})
|
|
1815
|
-
})
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
|
|
2192
|
+
});
|
|
2193
|
+
}));
|
|
2194
|
+
})).then(function() {
|
|
2195
|
+
return Promise.all(old_ves.slice(ks.length).map(function(ve,j) {
|
|
2196
|
+
return (new libVES.VaultKey(ve.vaultKey,self.VES)).matchVaults(ks).then(function(f) {
|
|
2197
|
+
if (f === false) set_ves.push({vaultKey: {id: ve.vaultKey.id}, '$op': 'delete'});
|
|
2198
|
+
});
|
|
2199
|
+
}));
|
|
2200
|
+
}).then(function() {
|
|
2201
|
+
if (!set_ves.length) return save = false;
|
|
2202
|
+
return self.setField('vaultEntries',set_ves);
|
|
1819
2203
|
});
|
|
1820
2204
|
});
|
|
1821
2205
|
}).then(function() {
|
|
@@ -1835,7 +2219,9 @@ libVES.VaultItem.prototype = new libVES.Object({
|
|
|
1835
2219
|
var m_curr_ks = {};
|
|
1836
2220
|
for (var i = 0; i < curr_ks.length; i++) m_curr_ks[curr_ids[i]] = curr_ks[i];
|
|
1837
2221
|
return Promise.all(new_ks.map(function(k,i) {
|
|
1838
|
-
return k.getId()
|
|
2222
|
+
return k.getId().catch(function(e) {
|
|
2223
|
+
if (e.code != 'NotFound') throw e;
|
|
2224
|
+
});
|
|
1839
2225
|
})).then(function(new_ids) {
|
|
1840
2226
|
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
2227
|
return self.shareWith(curr_ks,val,save);
|
|
@@ -1898,8 +2284,9 @@ libVES.VaultItem.Type = {
|
|
|
1898
2284
|
return new ci(new Uint8Array(buf));
|
|
1899
2285
|
});
|
|
1900
2286
|
},
|
|
1901
|
-
|
|
2287
|
+
build: function(data) {
|
|
1902
2288
|
if (!(data instanceof libVES.Cipher)) throw new libVES.Error('InvalidData',"Content of a VaultItem type 'file' must be libVES.Cipher");
|
|
2289
|
+
this.setField('meta', data.getMeta());
|
|
1903
2290
|
return data.getSecret();
|
|
1904
2291
|
}
|
|
1905
2292
|
},
|
|
@@ -1921,10 +2308,13 @@ libVES.VaultItem.Type.password = libVES.VaultItem.Type.string;
|
|
|
1921
2308
|
libVES.File.prototype = new libVES.Object({
|
|
1922
2309
|
apiUri: 'files',
|
|
1923
2310
|
fieldList: {id: true},
|
|
1924
|
-
fieldClass: {externals: libVES.External},
|
|
2311
|
+
fieldClass: {externals: libVES.External, creator: libVES.User},
|
|
1925
2312
|
getExternals: function() {
|
|
1926
2313
|
return this.getField('externals');
|
|
1927
|
-
}
|
|
2314
|
+
},
|
|
2315
|
+
getCreator: function() {
|
|
2316
|
+
return this.getField('creator');
|
|
2317
|
+
},
|
|
1928
2318
|
});
|
|
1929
2319
|
|
|
1930
2320
|
libVES.External.prototype = new libVES.Object({
|
|
@@ -1944,49 +2334,171 @@ libVES.External.prototype = new libVES.Object({
|
|
|
1944
2334
|
});
|
|
1945
2335
|
|
|
1946
2336
|
libVES.Algo = {
|
|
1947
|
-
|
|
1948
|
-
tag: '
|
|
2337
|
+
ECDH: {
|
|
2338
|
+
tag: 'ECDH',
|
|
1949
2339
|
decrypt: function(k,buf) {
|
|
1950
|
-
|
|
2340
|
+
var b = new Uint8Array(buf);
|
|
2341
|
+
var data = libVES.Util.ASN1.decode(b);
|
|
2342
|
+
if (!data || data.length < 2) throw new libVES.Error('InvalidValue','Error parsing ECIES: Invalid ciphertext?');
|
|
2343
|
+
return libVES.Util.ASN1.import(b.slice(0,b.byteLength - data[1].byteLength),{decoded:data[0]}).then(function(eKey) {
|
|
2344
|
+
return libVES.Algo.ECDH.cipher(k,eKey).then(function(ci) {
|
|
2345
|
+
return ci.decrypt(data[1],true).catch(function(e) {
|
|
2346
|
+
if (e instanceof libVES.Error) throw e;
|
|
2347
|
+
throw new libVES.Error('InvalidValue','Error decrypting ECIES payload: Invalid ciphertext?',{error:e});
|
|
2348
|
+
});
|
|
2349
|
+
}).catch(function(e) {
|
|
2350
|
+
if (e instanceof libVES.Error) throw e;
|
|
2351
|
+
throw new libVES.Error('InvalidValue','Error negotiating DH cipher key: Invalid ciphertext?',{error:e});
|
|
2352
|
+
});
|
|
2353
|
+
}).catch(function(e) {
|
|
2354
|
+
if (e instanceof libVES.Error) throw e;
|
|
2355
|
+
throw new libVES.Error('InvalidValue','Error loading EC ephemeral: Invalid ciphertext?',{error:e});
|
|
2356
|
+
});
|
|
1951
2357
|
},
|
|
1952
2358
|
encrypt: function(k,buf) {
|
|
1953
|
-
return
|
|
2359
|
+
return libVES.Algo.ECDH.eKey(k).then(function(eKey) {
|
|
2360
|
+
return libVES.Algo.ECDH.cipher(eKey.privateKey,k).then(function(ci) {
|
|
2361
|
+
return Promise.all([
|
|
2362
|
+
crypto.subtle.exportKey('spki',eKey.publicKey),
|
|
2363
|
+
ci.encrypt(buf,true)
|
|
2364
|
+
]).then(function(bufs) {
|
|
2365
|
+
var buf = new Uint8Array(bufs[0].byteLength + bufs[1].byteLength);
|
|
2366
|
+
buf.set(new Uint8Array(bufs[0]),0);
|
|
2367
|
+
buf.set(new Uint8Array(bufs[1]),bufs[0].byteLength);
|
|
2368
|
+
return buf;
|
|
2369
|
+
});
|
|
2370
|
+
}).catch(function(e) {
|
|
2371
|
+
if (e instanceof libVES.Error) throw e;
|
|
2372
|
+
throw new libVES.Error('InvalidValue','Error generating ECIES DH cipher',{error:e});
|
|
2373
|
+
});
|
|
2374
|
+
});
|
|
2375
|
+
},
|
|
2376
|
+
eKey: function(pub) {
|
|
2377
|
+
return crypto.subtle.exportKey('jwk',pub).then(function(kdata) {
|
|
2378
|
+
return crypto.subtle.generateKey({name:'ECDH',namedCurve: kdata.crv},true,['deriveKey','deriveBits']).catch(function(e) {
|
|
2379
|
+
throw new libVES.Error('InvalidValue','Error generating ECIES ephemeral',{error: e});
|
|
2380
|
+
});
|
|
2381
|
+
});
|
|
2382
|
+
},
|
|
2383
|
+
cipher: function(priv,pub) {
|
|
2384
|
+
return libVES.getModule(libVES.Cipher,'AES256GCMp').then(function(m) {
|
|
2385
|
+
return Promise.resolve(libVES.Algo.ECDH.curveBytes[pub.algorithm.namedCurve] || crypto.subtle.exportKey('jwk',pub).then(function(jwk) {
|
|
2386
|
+
return jwk.x.length * 3 / 4;
|
|
2387
|
+
})).then(function(len) {
|
|
2388
|
+
return crypto.subtle.deriveBits({name:'ECDH',public:pub},priv,8 * len).then(function(raw) {
|
|
2389
|
+
return crypto.subtle.digest({name:'SHA-384'},raw).then(function(buf) {
|
|
2390
|
+
return new m(new Uint8Array(buf).slice(0,m.prototype.keySize + m.prototype.ivSize));
|
|
2391
|
+
});
|
|
2392
|
+
});
|
|
2393
|
+
});
|
|
2394
|
+
});
|
|
2395
|
+
},
|
|
2396
|
+
curveBytes: {
|
|
2397
|
+
'P-256': 32,
|
|
2398
|
+
'P-384': 48,
|
|
2399
|
+
'P-521': 66
|
|
1954
2400
|
},
|
|
1955
2401
|
import: function(data,optns) {
|
|
1956
2402
|
return libVES.Util.PEM.import(data,optns);
|
|
1957
2403
|
},
|
|
1958
2404
|
export: function(data,optns) {
|
|
1959
2405
|
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
|
-
});
|
|
2406
|
+
case 'private': return libVES.Util.PKCS8.encode(data, optns);
|
|
1985
2407
|
case 'public':
|
|
1986
|
-
return crypto.subtle.exportKey('spki',data).then(function(der) {
|
|
1987
|
-
|
|
2408
|
+
return crypto.subtle.exportKey('spki', data).then(function(der) {
|
|
2409
|
+
var asn = libVES.Util.ASN1.decode(new Uint8Array(der))[0];
|
|
2410
|
+
console.log(asn);
|
|
2411
|
+
switch (String(asn[0][0])) {
|
|
2412
|
+
case '1.2.840.10045.2.1':
|
|
2413
|
+
return der;
|
|
2414
|
+
case '1.3.132.1.12':
|
|
2415
|
+
case '1.3.132.112': // Firefox on Mac - apparently a misspelling of the former
|
|
2416
|
+
asn[0][0] = new libVES.Util.OID('1.2.840.10045.2.1');
|
|
2417
|
+
asn[1].ASN1type = 3;
|
|
2418
|
+
return libVES.Util.ASN1.encode([asn]);
|
|
2419
|
+
default:
|
|
2420
|
+
console.log(asn);
|
|
2421
|
+
throw new libVES.Error('Internal', 'Unexpected EC pubkey format');
|
|
2422
|
+
}
|
|
2423
|
+
return der;
|
|
2424
|
+
}).then(function(der) {
|
|
2425
|
+
return libVES.Util.PEM.encode(der, 'PUBLIC KEY');
|
|
1988
2426
|
});
|
|
1989
2427
|
}
|
|
2428
|
+
throw new libVES.Error('Internal', "Unknown type of key object");
|
|
2429
|
+
},
|
|
2430
|
+
generate: function(optns) {
|
|
2431
|
+
var op = {name:'ECDH', namedCurve:'P-384'};
|
|
2432
|
+
if (optns) for (var k in optns) op[k] = optns[k];
|
|
2433
|
+
return crypto.subtle.generateKey(op,true,['deriveKey','deriveBits']);
|
|
2434
|
+
},
|
|
2435
|
+
getPublic: function(priv) {
|
|
2436
|
+
return crypto.subtle.exportKey('jwk',priv).then(function(k) {
|
|
2437
|
+
return crypto.subtle.importKey('jwk',{
|
|
2438
|
+
crv: k.crv,
|
|
2439
|
+
ext: true,
|
|
2440
|
+
key_ops: [],
|
|
2441
|
+
kty: 'EC',
|
|
2442
|
+
x: k.x,
|
|
2443
|
+
y: k.y
|
|
2444
|
+
},{name:'ECDH'},true,[]);
|
|
2445
|
+
});
|
|
2446
|
+
}
|
|
2447
|
+
},
|
|
2448
|
+
RSA: {
|
|
2449
|
+
tag: 'RSA',
|
|
2450
|
+
decrypt: function(k,buf) {
|
|
2451
|
+
var self = libVES.Algo.RSA;
|
|
2452
|
+
var maxl = (k.algorithm.modulusLength + 7) >> 3;
|
|
2453
|
+
if (buf.byteLength <= maxl) return self.decryptRSA(k,buf);
|
|
2454
|
+
var b = new Uint8Array(buf);
|
|
2455
|
+
return self.decryptRSA(k,b.slice(0,maxl)).then(function(ck) {
|
|
2456
|
+
return self.cipher(ck).then(function(ci) {
|
|
2457
|
+
return ci.decrypt(b.slice(maxl),true);
|
|
2458
|
+
});
|
|
2459
|
+
});
|
|
2460
|
+
},
|
|
2461
|
+
decryptRSA: function(k,buf) {
|
|
2462
|
+
return crypto.subtle.decrypt('RSA-OAEP',k,buf).catch(function(e) {
|
|
2463
|
+
throw new libVES.Error('InvalidValue','Error decrypting RSA OAEP: Invalid ciphertext?',{error:e});
|
|
2464
|
+
});
|
|
2465
|
+
},
|
|
2466
|
+
encrypt: function(k,buf) {
|
|
2467
|
+
var self = libVES.Algo.RSA;
|
|
2468
|
+
var maxl = ((k.algorithm.modulusLength + 7) >> 3) - 48;
|
|
2469
|
+
if (buf.byteLength <= maxl) return self.encryptRSA(k,buf);
|
|
2470
|
+
return self.cipher().then(function(ci) {
|
|
2471
|
+
return Promise.all([
|
|
2472
|
+
ci.getSecret().then(function(sk) {
|
|
2473
|
+
return self.encryptRSA(k,sk);
|
|
2474
|
+
}),
|
|
2475
|
+
ci.encrypt(buf,true)
|
|
2476
|
+
]).then(function(bufs) {
|
|
2477
|
+
var rs = new Uint8Array(bufs[0].byteLength + bufs[1].byteLength);
|
|
2478
|
+
rs.set(new Uint8Array(bufs[0]),0);
|
|
2479
|
+
rs.set(new Uint8Array(bufs[1]),bufs[0].byteLength);
|
|
2480
|
+
return rs;
|
|
2481
|
+
});
|
|
2482
|
+
});
|
|
2483
|
+
},
|
|
2484
|
+
encryptRSA: function(k,buf) {
|
|
2485
|
+
return crypto.subtle.encrypt('RSA-OAEP',k,buf).catch(function(e) {
|
|
2486
|
+
throw new libVES.Error('InvalidValue','Error encrypting RSA OAEP: Buffer is too long?',{error:e});
|
|
2487
|
+
});;
|
|
2488
|
+
},
|
|
2489
|
+
cipher: function(secret) {
|
|
2490
|
+
return libVES.getModule(libVES.Cipher,'AES256GCMp').then(function(cls) {
|
|
2491
|
+
return new cls(secret);
|
|
2492
|
+
});
|
|
2493
|
+
},
|
|
2494
|
+
import: function(data,optns) {
|
|
2495
|
+
return libVES.Util.PEM.import(data,optns);
|
|
2496
|
+
},
|
|
2497
|
+
export: function(data,optns) {
|
|
2498
|
+
if (data instanceof CryptoKey) switch (data.type) {
|
|
2499
|
+
case 'private': return libVES.Util.PKCS8.encode(data,optns);
|
|
2500
|
+
case 'public': return libVES.Util.PKCS1.encode(data,optns);
|
|
2501
|
+
}
|
|
1990
2502
|
throw new libVES.Error('Internal',"Unknown type of key object");
|
|
1991
2503
|
},
|
|
1992
2504
|
generate: function(optns) {
|
|
@@ -2006,7 +2518,6 @@ libVES.Algo = {
|
|
|
2006
2518
|
},{name:'RSA-OAEP',hash:'SHA-1'},true,['encrypt']);
|
|
2007
2519
|
});
|
|
2008
2520
|
}
|
|
2009
|
-
|
|
2010
2521
|
},
|
|
2011
2522
|
RSA_PKCS1_15: {
|
|
2012
2523
|
tag: 'RSA_PKCS1_15',
|
|
@@ -2066,26 +2577,31 @@ libVES.Cipher.prototype = {
|
|
|
2066
2577
|
}
|
|
2067
2578
|
},
|
|
2068
2579
|
getSecret: function() {
|
|
2580
|
+
var self = this;
|
|
2069
2581
|
var meta = null;
|
|
2070
2582
|
if (this.meta) for (var k in this.meta) {
|
|
2071
2583
|
meta = libVES.Util.StringToByteArray(JSON.stringify(this.meta));
|
|
2072
2584
|
break;
|
|
2073
2585
|
}
|
|
2074
2586
|
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
|
-
|
|
2587
|
+
return Promise.all([(this.algo ? this.key.then(function(key) {
|
|
2588
|
+
return crypto.subtle.exportKey("raw", key);
|
|
2589
|
+
}) : this.key), this.IV]).then(function(data) {
|
|
2590
|
+
buf.set(new Uint8Array(data[0]), 0);
|
|
2591
|
+
buf.set(new Uint8Array(data[1]), data[0].byteLength);
|
|
2592
|
+
if (meta) buf.set(new Uint8Array(meta), data[0].byteLength + data[1].byteLength);
|
|
2593
|
+
return buf;
|
|
2082
2594
|
});
|
|
2083
2595
|
},
|
|
2596
|
+
getMeta: function() {
|
|
2597
|
+
return {a: this.a};
|
|
2598
|
+
},
|
|
2084
2599
|
buildKey: function(key) {
|
|
2085
2600
|
if (!this.algo) return Promise.resolve(key);
|
|
2086
2601
|
return crypto.subtle.importKey('raw',key,this.algo,true,['encrypt','decrypt']);
|
|
2087
2602
|
},
|
|
2088
|
-
process: function(buf,final,callbk,
|
|
2603
|
+
process: function(buf,final,callbk,sizefn) {
|
|
2604
|
+
var self = this;
|
|
2089
2605
|
buf = new Uint8Array(buf);
|
|
2090
2606
|
if (this.processBuf) {
|
|
2091
2607
|
var b = new Uint8Array(buf.byteLength + this.processBuf.byteLength);
|
|
@@ -2093,9 +2609,24 @@ libVES.Cipher.prototype = {
|
|
|
2093
2609
|
b.set(buf,this.processBuf.byteLength);
|
|
2094
2610
|
buf = b;
|
|
2095
2611
|
}
|
|
2096
|
-
var
|
|
2097
|
-
|
|
2098
|
-
|
|
2612
|
+
var over = !final;
|
|
2613
|
+
var fn = function(cprev) {
|
|
2614
|
+
var chunkSize = sizefn();
|
|
2615
|
+
if ((!buf.byteLength && over) || (!final && (!chunkSize || buf.byteLength < chunkSize))) {
|
|
2616
|
+
self.processBuf = buf.byteLength ? buf : null;
|
|
2617
|
+
return Promise.resolve(cprev);
|
|
2618
|
+
}
|
|
2619
|
+
var cl = (chunkSize && chunkSize < buf.byteLength) ? chunkSize : buf.byteLength;
|
|
2620
|
+
if (!chunkSize || cl < chunkSize) over = true;
|
|
2621
|
+
return callbk(buf.slice(0, cl)).then(function(ctext) {
|
|
2622
|
+
buf = buf.slice(cl);
|
|
2623
|
+
var r = new Uint8Array(cprev.byteLength + ctext.byteLength);
|
|
2624
|
+
r.set(cprev, 0);
|
|
2625
|
+
r.set(new Uint8Array(ctext), cprev.byteLength);
|
|
2626
|
+
return r;
|
|
2627
|
+
}).then(fn);
|
|
2628
|
+
};
|
|
2629
|
+
return fn(new Uint8Array(0));
|
|
2099
2630
|
},
|
|
2100
2631
|
encryptChunk: function(buf) {
|
|
2101
2632
|
return Promise.all([this.key,this.algoInfo()]).then(function(info) {
|
|
@@ -2111,37 +2642,60 @@ libVES.Cipher.prototype = {
|
|
|
2111
2642
|
return Promise.resolve(this.algo);
|
|
2112
2643
|
},
|
|
2113
2644
|
encrypt: function(buf,final) {
|
|
2114
|
-
return this.process(buf,final,this.encryptChunk.bind(this),this.chunkSizeP);
|
|
2645
|
+
return this.process(buf,final,this.encryptChunk.bind(this),(function() { return this.chunkSizeP; }).bind(this));
|
|
2115
2646
|
},
|
|
2116
2647
|
decrypt: function(buf,final) {
|
|
2117
|
-
return this.process(buf,final,this.decryptChunk.bind(this),this.chunkSizeC);
|
|
2648
|
+
return this.process(buf,final,this.decryptChunk.bind(this),(function() { return this.chunkSizeC; }).bind(this));
|
|
2118
2649
|
}
|
|
2119
2650
|
};
|
|
2120
2651
|
|
|
2121
|
-
libVES.Cipher.
|
|
2652
|
+
libVES.Cipher.NULL = function(rec) {
|
|
2122
2653
|
this.init(rec);
|
|
2654
|
+
}
|
|
2655
|
+
|
|
2656
|
+
libVES.Cipher.AES = function(data) {
|
|
2657
|
+
for (var k in data) this[k] = data[k];
|
|
2123
2658
|
};
|
|
2124
2659
|
|
|
2125
2660
|
libVES.Cipher.AES256CBC = function(rec) {
|
|
2126
2661
|
this.init(rec);
|
|
2127
2662
|
};
|
|
2128
2663
|
|
|
2129
|
-
libVES.Cipher.
|
|
2130
|
-
|
|
2131
|
-
|
|
2664
|
+
libVES.Cipher.AES256GCM = function(rec) {
|
|
2665
|
+
this.init(rec);
|
|
2666
|
+
};
|
|
2667
|
+
|
|
2668
|
+
libVES.Cipher.AES256GCMp = function(rec) {
|
|
2669
|
+
this.init(rec);
|
|
2670
|
+
};
|
|
2671
|
+
|
|
2672
|
+
libVES.Cipher.AES256GCM1K = function(rec) {
|
|
2673
|
+
this.init(rec);
|
|
2674
|
+
};
|
|
2675
|
+
|
|
2676
|
+
libVES.Cipher.NULL.prototype = new libVES.Cipher({
|
|
2677
|
+
a: 'NULL',
|
|
2678
|
+
keySize: 0,
|
|
2679
|
+
ivSize: 0
|
|
2132
2680
|
});
|
|
2133
2681
|
|
|
2134
|
-
libVES.Cipher.
|
|
2135
|
-
algo: 'AES-CBC',
|
|
2682
|
+
libVES.Cipher.AES.prototype = new libVES.Cipher({
|
|
2136
2683
|
keySize: 32,
|
|
2137
|
-
ivSize:
|
|
2684
|
+
ivSize: 32,
|
|
2138
2685
|
algoInfo: function() {
|
|
2686
|
+
var self = this;
|
|
2139
2687
|
return this.IV.then(function(iv) {
|
|
2140
|
-
return {name:
|
|
2688
|
+
return {name: self.algo, iv: iv};
|
|
2141
2689
|
});
|
|
2142
2690
|
}
|
|
2143
2691
|
});
|
|
2144
2692
|
|
|
2693
|
+
libVES.Cipher.AES256CBC.prototype = new libVES.Cipher.AES({
|
|
2694
|
+
algo: 'AES-CBC',
|
|
2695
|
+
keySize: 32,
|
|
2696
|
+
ivSize: 16
|
|
2697
|
+
});
|
|
2698
|
+
|
|
2145
2699
|
libVES.Cipher.AES256CBC.import = function(args,chain,optns) {
|
|
2146
2700
|
return chain('import').then(function(buf) {
|
|
2147
2701
|
return crypto.subtle.decrypt({name: 'AES-CBC', iv: args},optns.key,buf);
|
|
@@ -2160,6 +2714,88 @@ libVES.Cipher.AES256CBC.info = function(chain,optns) {
|
|
|
2160
2714
|
return Promise.resolve({algorithm: {name: 'AES-CBC', length: 256}});
|
|
2161
2715
|
};
|
|
2162
2716
|
|
|
2717
|
+
libVES.Cipher.AES256GCM.prototype = new libVES.Cipher.AES({
|
|
2718
|
+
algo: 'AES-GCM',
|
|
2719
|
+
keySize: 32,
|
|
2720
|
+
ivSize: 12
|
|
2721
|
+
});
|
|
2722
|
+
|
|
2723
|
+
libVES.Cipher.AES256GCMp.prototype = new libVES.Cipher.AES({
|
|
2724
|
+
algo: 'AES-GCM',
|
|
2725
|
+
keySize: 32,
|
|
2726
|
+
ivSize: 12,
|
|
2727
|
+
padSize: 32,
|
|
2728
|
+
encryptChunk: function(buf0) {
|
|
2729
|
+
var buf = new Uint8Array(buf0);
|
|
2730
|
+
var pad = this.padSize - (buf.byteLength % this.padSize) - 1;
|
|
2731
|
+
var bufp = new Uint8Array(buf.byteLength + pad + 1);
|
|
2732
|
+
bufp[0] = pad;
|
|
2733
|
+
bufp.set(buf,1);
|
|
2734
|
+
return libVES.Cipher.prototype.encryptChunk.call(this,bufp);
|
|
2735
|
+
},
|
|
2736
|
+
decryptChunk: function(buf) {
|
|
2737
|
+
return libVES.Cipher.prototype.decryptChunk.call(this,buf).then(function(bufp0) {
|
|
2738
|
+
var bufp = new Uint8Array(bufp0);
|
|
2739
|
+
return bufp.slice(1,bufp.byteLength - bufp[0]);
|
|
2740
|
+
});
|
|
2741
|
+
}
|
|
2742
|
+
});
|
|
2743
|
+
|
|
2744
|
+
libVES.Cipher.AES256GCM1K.prototype = new libVES.Cipher.AES({
|
|
2745
|
+
algo: 'AES-GCM',
|
|
2746
|
+
keySize: 32,
|
|
2747
|
+
ivSize: 12,
|
|
2748
|
+
chunkSizeP: 1024,
|
|
2749
|
+
chunkSizeC: 16,
|
|
2750
|
+
algoInfo: function() {
|
|
2751
|
+
var self = this;
|
|
2752
|
+
if (!this.lastGCM) throw new libVES.Error('Internal', 'GCM HMAC is not buffered');
|
|
2753
|
+
return this.IV.then(function(iv) {
|
|
2754
|
+
var buf = new Uint8Array(iv.byteLength + self.lastGCM.byteLength);
|
|
2755
|
+
buf.set(new Uint8Array(iv), 0);
|
|
2756
|
+
buf.set(new Uint8Array(self.lastGCM), iv.byteLength);
|
|
2757
|
+
return libVES.Util.Hash.SHA256.hash(buf).then(function(sha) {
|
|
2758
|
+
return { name: self.algo, iv: sha.slice(0, self.ivSize) };
|
|
2759
|
+
});
|
|
2760
|
+
});
|
|
2761
|
+
},
|
|
2762
|
+
encryptChunk: function(buf) {
|
|
2763
|
+
var self = this;
|
|
2764
|
+
var seed = null;
|
|
2765
|
+
if (!this.lastGCM) {
|
|
2766
|
+
seed = new Uint8Array(16);
|
|
2767
|
+
crypto.getRandomValues(seed);
|
|
2768
|
+
this.lastGCM = seed;
|
|
2769
|
+
}
|
|
2770
|
+
return Promise.all([this.key, this.algoInfo()]).then(function(info) {
|
|
2771
|
+
return crypto.subtle.encrypt(info[1], info[0], buf).then(function(ctext) {
|
|
2772
|
+
self.lastGCM = new Uint8Array(ctext.slice(-16));
|
|
2773
|
+
if (!seed) return ctext;
|
|
2774
|
+
var rs = new Uint8Array(seed.byteLength + ctext.byteLength);
|
|
2775
|
+
rs.set(seed, 0);
|
|
2776
|
+
rs.set(new Uint8Array(ctext), seed.byteLength);
|
|
2777
|
+
return rs;
|
|
2778
|
+
});
|
|
2779
|
+
});
|
|
2780
|
+
},
|
|
2781
|
+
decryptChunk: function(buf) {
|
|
2782
|
+
var self = this;
|
|
2783
|
+
if (buf.byteLength < 16) throw new libVES.Error('Crypto', 'Invalid ciphertext block size');
|
|
2784
|
+
var rs;
|
|
2785
|
+
if (this.lastGCM) {
|
|
2786
|
+
rs = Promise.all([this.key, this.algoInfo()]).then(function(info) {
|
|
2787
|
+
self.lastGCM = buf.slice(-16);
|
|
2788
|
+
return crypto.subtle.decrypt(info[1], info[0], buf);
|
|
2789
|
+
});
|
|
2790
|
+
} else {
|
|
2791
|
+
rs = Promise.resolve(new Uint8Array(0));
|
|
2792
|
+
this.chunkSizeC = 1040;
|
|
2793
|
+
this.lastGCM = buf;
|
|
2794
|
+
}
|
|
2795
|
+
return rs;
|
|
2796
|
+
}
|
|
2797
|
+
});
|
|
2798
|
+
|
|
2163
2799
|
libVES.Scramble = {
|
|
2164
2800
|
RDX: function(x) {
|
|
2165
2801
|
this.size = x;
|
|
@@ -2230,17 +2866,23 @@ libVES.Scramble.RDX.prototype = {
|
|
|
2230
2866
|
scramble: function(vec,b) {
|
|
2231
2867
|
return libVES.Math.mulv(vec,this.getCv(b));
|
|
2232
2868
|
},
|
|
2233
|
-
explode: function(sc,ct) {
|
|
2869
|
+
explode: function(sc,ct,optns) {
|
|
2234
2870
|
var self = this;
|
|
2235
2871
|
return this.toVector(sc).then(function(v) {
|
|
2236
2872
|
var bs = self.getBases(ct);
|
|
2237
2873
|
var rs = [];
|
|
2238
2874
|
for (i = 0; i < bs.length; i++) rs[i] = {
|
|
2239
|
-
meta: {
|
|
2875
|
+
meta: (function(m) {
|
|
2876
|
+
if (optns) {
|
|
2877
|
+
if (optns.t != null) m.t = optns.t;
|
|
2878
|
+
if (optns.shadow) for (var k in optns.shadow) m[k] = optns.shadow[k];
|
|
2879
|
+
}
|
|
2880
|
+
return m;
|
|
2881
|
+
})({
|
|
2240
2882
|
v: self.tag,
|
|
2241
2883
|
n: self.size,
|
|
2242
2884
|
b: bs[i]
|
|
2243
|
-
},
|
|
2885
|
+
}),
|
|
2244
2886
|
value: self.scramble(v,bs[i])
|
|
2245
2887
|
}
|
|
2246
2888
|
return rs;
|
|
@@ -2305,8 +2947,9 @@ libVES.Scramble.algo = {
|
|
|
2305
2947
|
'RDX1.2': libVES.Scramble.RDX
|
|
2306
2948
|
};
|
|
2307
2949
|
|
|
2308
|
-
libVES.Recovery = function(vaultKey) {
|
|
2950
|
+
libVES.Recovery = function(vaultKey, myItems) {
|
|
2309
2951
|
this.vaultKey = vaultKey;
|
|
2952
|
+
if (myItems) this.myItems = Promise.resolve(myItems);
|
|
2310
2953
|
};
|
|
2311
2954
|
|
|
2312
2955
|
libVES.Recovery.prototype = {
|
|
@@ -2315,7 +2958,7 @@ libVES.Recovery.prototype = {
|
|
|
2315
2958
|
var self = this;
|
|
2316
2959
|
return this.tokens = self.vaultKey.getType().then(function(t) {
|
|
2317
2960
|
switch (t) {
|
|
2318
|
-
case 'shadow': case 'recovery': return self.vaultKey.getField('vaultItems',{
|
|
2961
|
+
case 'shadow': case 'recovery': return (self.myItems ? self.myItems : self.vaultKey.getField('vaultItems',{
|
|
2319
2962
|
id: true,
|
|
2320
2963
|
meta: true,
|
|
2321
2964
|
type: true,
|
|
@@ -2326,7 +2969,7 @@ libVES.Recovery.prototype = {
|
|
|
2326
2969
|
type: true
|
|
2327
2970
|
}
|
|
2328
2971
|
}
|
|
2329
|
-
},true).then(function(vis) {
|
|
2972
|
+
},true)).then(function(vis) {
|
|
2330
2973
|
var frnds = {};
|
|
2331
2974
|
var fn = function() {
|
|
2332
2975
|
return self.vaultKey.getUser().then(function(my_u) {
|
|
@@ -2336,10 +2979,15 @@ libVES.Recovery.prototype = {
|
|
|
2336
2979
|
return Promise.all([
|
|
2337
2980
|
vi.getVaultEntries().then(function(ves) {
|
|
2338
2981
|
return Promise.all(ves.map(function(ve) {
|
|
2339
|
-
|
|
2982
|
+
var vk = new libVES.VaultKey(ve.vaultKey,self.vaultKey.VES);
|
|
2983
|
+
return vk.getUser().then(function(u) {
|
|
2340
2984
|
return u.getId().then(function(uid) {
|
|
2341
|
-
if (uid == my_uid)
|
|
2342
|
-
|
|
2985
|
+
if (uid == my_uid) {
|
|
2986
|
+
frnd.assisted = true;
|
|
2987
|
+
return vk.getType().then(function(type) {
|
|
2988
|
+
if (type == 'current') frnd.current = true;
|
|
2989
|
+
});
|
|
2990
|
+
} else {
|
|
2343
2991
|
frnd.user = u;
|
|
2344
2992
|
frnds[uid] = frnd;
|
|
2345
2993
|
}
|
|
@@ -2398,10 +3046,10 @@ libVES.Recovery.prototype = {
|
|
|
2398
3046
|
return Promise.all(tkns.map(function(v,i) {
|
|
2399
3047
|
return v.user.getId();
|
|
2400
3048
|
})).then(function(uids) {
|
|
2401
|
-
|
|
2402
|
-
|
|
2403
|
-
|
|
2404
|
-
|
|
3049
|
+
return user.getId().then(function(uid) {
|
|
3050
|
+
for (var i = 0; i < uids.length; i++) if (uids[i] == uid) return tkns[i];
|
|
3051
|
+
throw new libVES.Error('InvalidValue','Not a friend: ' + uid);
|
|
3052
|
+
});
|
|
2405
3053
|
});
|
|
2406
3054
|
});
|
|
2407
3055
|
},
|
|
@@ -2424,22 +3072,11 @@ libVES.Recovery.prototype = {
|
|
|
2424
3072
|
getFriendsAssisted: function() {
|
|
2425
3073
|
var self = this;
|
|
2426
3074
|
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
|
-
});
|
|
3075
|
+
var a = 0;
|
|
3076
|
+
tkns.map(function(t, i) {
|
|
3077
|
+
if (t.assisted) a++;
|
|
2441
3078
|
});
|
|
2442
|
-
return
|
|
3079
|
+
return a;
|
|
2443
3080
|
});
|
|
2444
3081
|
},
|
|
2445
3082
|
getFriendsToGo: function() {
|
|
@@ -2464,7 +3101,10 @@ libVES.Recovery.prototype = {
|
|
|
2464
3101
|
});
|
|
2465
3102
|
},
|
|
2466
3103
|
assist: function() {
|
|
2467
|
-
|
|
3104
|
+
var self = this;
|
|
3105
|
+
return self.vaultKey.getType().then(function(t) {
|
|
3106
|
+
return t == 'recovery' ? self._assist(true) : null;
|
|
3107
|
+
});
|
|
2468
3108
|
},
|
|
2469
3109
|
revoke: function() {
|
|
2470
3110
|
return this._assist(false);
|
|
@@ -2484,7 +3124,9 @@ libVES.Recovery.prototype = {
|
|
|
2484
3124
|
_recover: function() {
|
|
2485
3125
|
var self = this;
|
|
2486
3126
|
return self.unlock().then(function() {
|
|
2487
|
-
return self.vaultKey.
|
|
3127
|
+
return self.vaultKey.VES.elevateAuth({authVaultKey: self.vaultKey}).then(function(optns) {
|
|
3128
|
+
return self.vaultKey.rekey(optns);
|
|
3129
|
+
});
|
|
2488
3130
|
});
|
|
2489
3131
|
},
|
|
2490
3132
|
recover: function() {
|
|
@@ -2500,11 +3142,14 @@ libVES.Delegate = {
|
|
|
2500
3142
|
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
3143
|
+ '<div style="display:table-row;"><div style="display:table-cell;vertical-align:middle;text-align:center;">'
|
|
2502
3144
|
+ '<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>'
|
|
3145
|
+
+ '{$content}'
|
|
2507
3146
|
+ '</div></div></div></div>',
|
|
3147
|
+
htmlDlg: '<p>Use the VESvault popup window to grant access to the App Vault</p>'
|
|
3148
|
+
+ '<p class="VESvaultDelegateBlockerMsg" style="color: #bf7f00; font-style:italic;"> </p>'
|
|
3149
|
+
+ '<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>'
|
|
3150
|
+
+ '<p><a class="VESvaultDelegateCancelLnk" href="#" onclick="libVES.Delegate.cancel(); return false;">Cancel</a></p>',
|
|
3151
|
+
htmlFlw: '<p>Authorizing VES Access</p>'
|
|
3152
|
+
+ '<iframe style="width: 100%; height: 48px; border: none;" src="{$url}"></iframe>',
|
|
2508
3153
|
htmlBlockerMsg: 'Looks like your browser is using a popup blocker...',
|
|
2509
3154
|
name: 'VESvaultDelegate',
|
|
2510
3155
|
login: function(VES,challenge,optns) {
|
|
@@ -2518,11 +3163,10 @@ libVES.Delegate = {
|
|
|
2518
3163
|
return this.response = new Promise(function(resolve,reject) {
|
|
2519
3164
|
self.reject = reject;
|
|
2520
3165
|
self.resolve = resolve;
|
|
2521
|
-
var url = VES.wwwUrl + '
|
|
2522
|
-
|
|
2523
|
-
self.
|
|
2524
|
-
self.
|
|
2525
|
-
document.getElementsByTagName('BODY')[0].appendChild(self.popup);
|
|
3166
|
+
var url = VES.wwwUrl + 'vv/unlock?via=delegate&url=' + encodeURIComponent(document.location.href) + '&domain=' + encodeURIComponent(VES.domain);
|
|
3167
|
+
if (optns) for (var k in optns) if (optns[k] != null) url += '&' + encodeURIComponent(k) + '=' + encodeURIComponent(optns[k]);
|
|
3168
|
+
self.setOrigin(url);
|
|
3169
|
+
self.showOverlay(self.htmlDlg.replace('{$url}',url));
|
|
2526
3170
|
self.retryPopupCalled = 0;
|
|
2527
3171
|
try {
|
|
2528
3172
|
document.getElementsByClassName('VESvaultDelegateRetryLnk')[0].onclick = function() {
|
|
@@ -2545,6 +3189,35 @@ libVES.Delegate = {
|
|
|
2545
3189
|
self.popupInterval = window.setInterval(self.chkCancel.bind(self),1000);
|
|
2546
3190
|
});
|
|
2547
3191
|
},
|
|
3192
|
+
flow: function(VES, start, optns) {
|
|
3193
|
+
if (this.response) return this.response;
|
|
3194
|
+
this.VES = VES;
|
|
3195
|
+
var self = this;
|
|
3196
|
+
var unlk = VES.wwwUrl + 'vv/unlock';
|
|
3197
|
+
if (start || (!sessionStorage['libVES.flowStarted'] && document.referrer.substr(0, unlk.length).toLowerCase() == unlk.toLowerCase())) {
|
|
3198
|
+
return self.response = new Promise(function(resolve, reject) {
|
|
3199
|
+
self.reject = reject;
|
|
3200
|
+
self.resolve = resolve;
|
|
3201
|
+
var ifrm = VES.wwwUrl + 'vv/flowin?url=' + encodeURIComponent(document.location.href) + '&domain=' + encodeURIComponent(VES.domain);
|
|
3202
|
+
if (optns) for (var k in optns) if (optns[k] != null) ifrm += '&' + encodeURIComponent(k) + '=' + encodeURIComponent(optns[k]);
|
|
3203
|
+
self.setOrigin(ifrm);
|
|
3204
|
+
window.addEventListener('message',self.listener.bind(self));
|
|
3205
|
+
self.showOverlay(self.htmlFlw.replace('{$url}', ifrm));
|
|
3206
|
+
if (start) delete(sessionStorage['libVES.flowStarted'])
|
|
3207
|
+
else sessionStorage['libVES.flowStarted'] = true;
|
|
3208
|
+
});
|
|
3209
|
+
} else {
|
|
3210
|
+
return new Promise(function(){});
|
|
3211
|
+
}
|
|
3212
|
+
},
|
|
3213
|
+
showOverlay: function(cont) {
|
|
3214
|
+
this.popup = document.createElement('DIV');
|
|
3215
|
+
this.popup.innerHTML = this.html.replace('{$content}', cont);
|
|
3216
|
+
document.getElementsByTagName('BODY')[0].appendChild(this.popup);
|
|
3217
|
+
},
|
|
3218
|
+
setOrigin: function(url) {
|
|
3219
|
+
this.matchOrigin = (function(m) { return m ? m[0] : document.location.protocol + '//' + document.location.host; })(url.match(/^(https\:\/\/[^\/\?\#]+)/));
|
|
3220
|
+
},
|
|
2548
3221
|
openPopup: function(url) {
|
|
2549
3222
|
return this.popupWindow = window.open(url,this.name,"width=600,height=600,top=100,left=100");
|
|
2550
3223
|
},
|
|
@@ -2558,30 +3231,13 @@ libVES.Delegate = {
|
|
|
2558
3231
|
return !f && this.openPopup(url);
|
|
2559
3232
|
},
|
|
2560
3233
|
listener: function(evnt) {
|
|
2561
|
-
if (this.
|
|
3234
|
+
if (this.popup && evnt.origin == this.matchOrigin) try {
|
|
2562
3235
|
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;
|
|
3236
|
+
if (msg.redirect) {
|
|
3237
|
+
document.location.replace(msg.redirect);
|
|
3238
|
+
} else {
|
|
3239
|
+
this.resolve(this.VES.authorize(msg));
|
|
3240
|
+
}
|
|
2585
3241
|
this.close();
|
|
2586
3242
|
if (!evnt.source.closed) evnt.source.close();
|
|
2587
3243
|
} catch(e) {}
|
|
@@ -2598,7 +3254,7 @@ libVES.Delegate = {
|
|
|
2598
3254
|
this.popupInterval = null;
|
|
2599
3255
|
this.popup.parentNode.removeChild(this.popup);
|
|
2600
3256
|
this.popup = null;
|
|
2601
|
-
return
|
|
3257
|
+
return this.response;
|
|
2602
3258
|
}
|
|
2603
3259
|
},
|
|
2604
3260
|
cancel: function() {
|
|
@@ -2611,4 +3267,255 @@ libVES.Delegate = {
|
|
|
2611
3267
|
}
|
|
2612
3268
|
};
|
|
2613
3269
|
|
|
3270
|
+
|
|
3271
|
+
libVES.Flow = function(name, optns) {
|
|
3272
|
+
this.name = name;
|
|
3273
|
+
this.origin = document.location.origin;
|
|
3274
|
+
this.url = this.origin + '/VESflow';
|
|
3275
|
+
if (optns) for (var k in optns) this[k] = optns[k];
|
|
3276
|
+
return this;
|
|
3277
|
+
};
|
|
3278
|
+
|
|
3279
|
+
libVES.Flow.algo = {name: 'ECDH', namedCurve: 'P-256'};
|
|
3280
|
+
|
|
3281
|
+
libVES.Flow.keyAlgo = function(jwk) {
|
|
3282
|
+
if (jwk && jwk.kty == 'EC') return {name: 'ECDH', namedCurve: jwk.crv};
|
|
3283
|
+
return null;
|
|
3284
|
+
};
|
|
3285
|
+
|
|
3286
|
+
libVES.Flow.toOrigin = function(url) {
|
|
3287
|
+
var a = document.createElement('a');
|
|
3288
|
+
a.href = url;
|
|
3289
|
+
return a.origin;
|
|
3290
|
+
};
|
|
3291
|
+
|
|
3292
|
+
libVES.Flow.jwkPub = function(jwk) {
|
|
3293
|
+
delete(jwk.d);
|
|
3294
|
+
delete(jwk.key_ops);
|
|
3295
|
+
delete(jwk.ext);
|
|
3296
|
+
return jwk;
|
|
3297
|
+
};
|
|
3298
|
+
|
|
3299
|
+
libVES.Flow.parseToken = function(src, callbk) {
|
|
3300
|
+
src = src.replace(/\#VESflow\.(\w+)=([^\#\&\=]+)/g, function(s, k, v) {
|
|
3301
|
+
var tk;
|
|
3302
|
+
try {
|
|
3303
|
+
tk = JSON.parse(decodeURIComponent(v));
|
|
3304
|
+
if (callbk(decodeURIComponent(k), tk)) return '';
|
|
3305
|
+
} catch(e) {
|
|
3306
|
+
console.log(e);
|
|
3307
|
+
}
|
|
3308
|
+
return s;
|
|
3309
|
+
});
|
|
3310
|
+
return src;
|
|
3311
|
+
};
|
|
3312
|
+
|
|
3313
|
+
libVES.Flow.logout = function() {
|
|
3314
|
+
for (var k in sessionStorage) if (k.match(/^VESflow\b/)) delete(sessionStorage[k]);
|
|
3315
|
+
};
|
|
3316
|
+
|
|
3317
|
+
libVES.Flow.prototype.source = function(src) {
|
|
3318
|
+
if (src != null) history.replaceState(null, '', src);
|
|
3319
|
+
return document.location.href;
|
|
3320
|
+
};
|
|
3321
|
+
|
|
3322
|
+
libVES.Flow.prototype.privKey = function(algo) {
|
|
3323
|
+
if (!algo) algo = libVES.Flow.algo;
|
|
3324
|
+
var a = JSON.stringify(algo);
|
|
3325
|
+
return Promise.resolve(sessionStorage['VESflow' + a]).then(function(k) {
|
|
3326
|
+
if (!k) throw null;
|
|
3327
|
+
return crypto.subtle.importKey('jwk', JSON.parse(k), algo, true, ['deriveBits', 'deriveKey']);
|
|
3328
|
+
}).catch(function(e) {
|
|
3329
|
+
return crypto.subtle.generateKey(algo, true, ['deriveBits', 'deriveKey']).then(function(pair) {
|
|
3330
|
+
return crypto.subtle.exportKey('jwk', pair.privateKey).then(function(jwk) {
|
|
3331
|
+
sessionStorage['VESflow' + a] = JSON.stringify(jwk);
|
|
3332
|
+
return pair.privateKey;
|
|
3333
|
+
});
|
|
3334
|
+
});
|
|
3335
|
+
});
|
|
3336
|
+
};
|
|
3337
|
+
|
|
3338
|
+
libVES.Flow.prototype.pubJWK = function(org) {
|
|
3339
|
+
return ((!org || org == this.origin) ? this.privKey().then(function(priv) {
|
|
3340
|
+
return crypto.subtle.exportKey('jwk', priv).then(function(jwk) {
|
|
3341
|
+
return libVES.Flow.jwkPub(jwk);
|
|
3342
|
+
});
|
|
3343
|
+
}) : Promise.resolve(sessionStorage['VESflow|' + org]).then(function(k) {
|
|
3344
|
+
if (!k) throw {code: 'NotFound', message: 'No public key stored for ' + org};
|
|
3345
|
+
return JSON.parse(k);
|
|
3346
|
+
}));
|
|
3347
|
+
};
|
|
3348
|
+
|
|
3349
|
+
libVES.Flow.prototype.pubKey = function(org) {
|
|
3350
|
+
return this.pubJWK(org).then(function(jwk) {
|
|
3351
|
+
return crypto.subtle.importKey('jwk', jwk, libVES.Flow.keyAlgo(jwk), true, []);
|
|
3352
|
+
});
|
|
3353
|
+
};
|
|
3354
|
+
|
|
3355
|
+
libVES.Flow.prototype.cipher = function(url) {
|
|
3356
|
+
var self = this;
|
|
3357
|
+
return self.pubKey(libVES.Flow.toOrigin(url)).then(function(pub) {
|
|
3358
|
+
return self.privKey(pub.algorithm).then(function(priv) {
|
|
3359
|
+
return crypto.subtle.deriveBits({name: 'ECDH', public: pub}, priv, 8 * libVES.Algo.ECDH.curveBytes[pub.algorithm.namedCurve]);
|
|
3360
|
+
});
|
|
3361
|
+
}).then(function(raw) {
|
|
3362
|
+
return crypto.subtle.digest({name: 'SHA-256'}, raw).then(function(buf) {
|
|
3363
|
+
return crypto.subtle.importKey('raw', buf, 'AES-GCM', false, ['encrypt', 'decrypt']);
|
|
3364
|
+
});
|
|
3365
|
+
});
|
|
3366
|
+
};
|
|
3367
|
+
|
|
3368
|
+
libVES.Flow.prototype.encrypt = function(url, val) {
|
|
3369
|
+
var self = this;
|
|
3370
|
+
return Promise.resolve(val || this.value()).then(function(val) {
|
|
3371
|
+
if (val == null) throw {code: 'NoData', message: 'Empty value'};
|
|
3372
|
+
return self.cipher(url).then(function(ci) {
|
|
3373
|
+
var iv = new Uint8Array(12);
|
|
3374
|
+
crypto.getRandomValues(iv);
|
|
3375
|
+
return crypto.subtle.encrypt({name: 'AES-GCM', iv: iv.buffer}, ci, libVES.Util.StringToByteArray(JSON.stringify(val))).then(function(ctext) {
|
|
3376
|
+
return libVES.Util.ByteArrayToB64W(iv) + '.' + libVES.Util.ByteArrayToB64W(ctext);
|
|
3377
|
+
});
|
|
3378
|
+
});
|
|
3379
|
+
});
|
|
3380
|
+
};
|
|
3381
|
+
|
|
3382
|
+
libVES.Flow.prototype.token = function(url) {
|
|
3383
|
+
var self = this;
|
|
3384
|
+
return this.pubJWK().then(function(jwk) {
|
|
3385
|
+
return {url: self.url, key: jwk};
|
|
3386
|
+
}).then(function(tk) {
|
|
3387
|
+
return self.encrypt(url).then(function(ctext) {
|
|
3388
|
+
tk.enc = ctext;
|
|
3389
|
+
self.erase(url);
|
|
3390
|
+
self.sent = true;
|
|
3391
|
+
return tk;
|
|
3392
|
+
}).catch(function(e) {
|
|
3393
|
+
self.store(url).catch(function(e) {});
|
|
3394
|
+
return tk;
|
|
3395
|
+
});
|
|
3396
|
+
});
|
|
3397
|
+
};
|
|
3398
|
+
|
|
3399
|
+
libVES.Flow.prototype.addToken = function(url) {
|
|
3400
|
+
var self = this;
|
|
3401
|
+
return self.token(url).then(function(tk) {
|
|
3402
|
+
return url + '#VESflow.' + self.name + '=' + encodeURIComponent(JSON.stringify(tk));
|
|
3403
|
+
});
|
|
3404
|
+
};
|
|
3405
|
+
|
|
3406
|
+
libVES.Flow.prototype.decrypt = function(ctext, url) {
|
|
3407
|
+
var self = this;
|
|
3408
|
+
var c = ctext.split('.');
|
|
3409
|
+
return self.cipher(url).then(function(ci) {
|
|
3410
|
+
return crypto.subtle.decrypt({name: 'AES-GCM', iv: libVES.Util.B64ToByteArray(c[0])}, ci, libVES.Util.B64ToByteArray(c[1])).then(function(ptext) {
|
|
3411
|
+
return JSON.parse(libVES.Util.ByteArrayToString(ptext));
|
|
3412
|
+
});
|
|
3413
|
+
});
|
|
3414
|
+
};
|
|
3415
|
+
|
|
3416
|
+
libVES.Flow.prototype.value = function() {
|
|
3417
|
+
var self = this;
|
|
3418
|
+
return Promise.resolve(history.state && history.state['VESflow.' + self.name]).then(function(ctext) {
|
|
3419
|
+
return self.decrypt(ctext);
|
|
3420
|
+
});
|
|
3421
|
+
};
|
|
3422
|
+
|
|
3423
|
+
libVES.Flow.prototype.setValue = function(val) {
|
|
3424
|
+
var self = this;
|
|
3425
|
+
return Promise.resolve(val? self.encrypt(null, val) : null).then(function(ctext) {
|
|
3426
|
+
var s = {};
|
|
3427
|
+
if (history.state) for (var k in history.state) s[k] = history.state[k];
|
|
3428
|
+
if (ctext) s['VESflow.' + self.name] = ctext;
|
|
3429
|
+
else delete(s['VESflow.' + self.name]);
|
|
3430
|
+
history.replaceState(s, '');
|
|
3431
|
+
return val;
|
|
3432
|
+
});
|
|
3433
|
+
};
|
|
3434
|
+
|
|
3435
|
+
libVES.Flow.prototype.click = function(a) {
|
|
3436
|
+
var self = this;
|
|
3437
|
+
(a.origin == this.origin ? self.store() : self.addToken(a.href).then(function(url) {
|
|
3438
|
+
a.href = url;
|
|
3439
|
+
})).then(function() {
|
|
3440
|
+
document.location.href = a.href;
|
|
3441
|
+
});
|
|
3442
|
+
return false;
|
|
3443
|
+
};
|
|
3444
|
+
|
|
3445
|
+
libVES.Flow.prototype.reload = function(e) {
|
|
3446
|
+
if (!this.sent) this.store().catch(function(e) {});
|
|
3447
|
+
};
|
|
3448
|
+
|
|
3449
|
+
libVES.Flow.prototype.recv = function(dval) {
|
|
3450
|
+
var self = this;
|
|
3451
|
+
return Promise.resolve(self.source()).then(function(src) {
|
|
3452
|
+
var tk = null;
|
|
3453
|
+
src = libVES.Flow.parseToken(src, function(k, t) {
|
|
3454
|
+
if (k != self.name) return false;
|
|
3455
|
+
tk = t;
|
|
3456
|
+
return true;
|
|
3457
|
+
});
|
|
3458
|
+
if (tk == null) throw {code: 'NotFound', message: 'No valid token in the source url'};
|
|
3459
|
+
return Promise.resolve(self.source(src)).then(function() {
|
|
3460
|
+
if (dval) for (var k in dval) if (tk[k] === undefined) tk[k] = dval[k];
|
|
3461
|
+
return self.recvToken(tk);
|
|
3462
|
+
});
|
|
3463
|
+
});
|
|
3464
|
+
};
|
|
3465
|
+
|
|
3466
|
+
libVES.Flow.prototype.recvToken = function(tk) {
|
|
3467
|
+
var org = libVES.Flow.toOrigin(tk.url);
|
|
3468
|
+
if (org != this.origin && tk.key) sessionStorage['VESflow|' + org] = JSON.stringify(tk.key);
|
|
3469
|
+
if (!tk.enc) return Promise.reject({url: tk.url, code: 'Incomplete', message: 'Missing encrypted data'});
|
|
3470
|
+
return this.decrypt(tk.enc, org);
|
|
3471
|
+
};
|
|
3472
|
+
|
|
3473
|
+
libVES.Flow.prototype.get = function() {
|
|
3474
|
+
var self = this;
|
|
3475
|
+
return self.fetch().catch(function(e) {
|
|
3476
|
+
if (!e || e.code != 'NotFound') console.log(e);
|
|
3477
|
+
return null;
|
|
3478
|
+
}).then(function(data) {
|
|
3479
|
+
return self.recv().catch(function(e) {
|
|
3480
|
+
if (e && e.code == 'Incomplete') {
|
|
3481
|
+
self.url = document.location.href;
|
|
3482
|
+
return self.addToken(e.url).then(function(url) {
|
|
3483
|
+
document.location.replace(url);
|
|
3484
|
+
throw {code: 'Reload', message: 'Completing the key exchange'};
|
|
3485
|
+
});
|
|
3486
|
+
}
|
|
3487
|
+
if (!data) throw e;
|
|
3488
|
+
return data;
|
|
3489
|
+
});
|
|
3490
|
+
});
|
|
3491
|
+
};
|
|
3492
|
+
|
|
3493
|
+
libVES.Flow.prototype.store = function(url) {
|
|
3494
|
+
if (history.state && history.state['VESflow.' + this.name]) {
|
|
3495
|
+
this.sent = 1;
|
|
3496
|
+
return Promise.resolve(sessionStorage['VESflow.' + this.name + '>' + libVES.Flow.toOrigin(url)] = history.state['VESflow.' + this.name]);
|
|
3497
|
+
}
|
|
3498
|
+
return Promise.reject({code: 'NotFound', message: 'Value is not set'});
|
|
3499
|
+
};
|
|
3500
|
+
|
|
3501
|
+
libVES.Flow.prototype.fetch = function(url) {
|
|
3502
|
+
var self = this;
|
|
3503
|
+
return Promise.resolve(sessionStorage['VESflow.' + self.name + '>' + libVES.Flow.toOrigin(url)]).then(function(ctext) {
|
|
3504
|
+
if (!ctext) throw {code: 'NotFound', message: 'Not in the session storage'};
|
|
3505
|
+
return self.decrypt(ctext).then(function(data) {
|
|
3506
|
+
self.erase(url);
|
|
3507
|
+
return data;
|
|
3508
|
+
});
|
|
3509
|
+
});
|
|
3510
|
+
};
|
|
3511
|
+
|
|
3512
|
+
libVES.Flow.prototype.erase = function(url) {
|
|
3513
|
+
delete(sessionStorage['VESflow.' + this.name + '>' + libVES.Flow.toOrigin(url)]);
|
|
3514
|
+
};
|
|
3515
|
+
|
|
3516
|
+
libVES.Flow.prototype.logout = function() {
|
|
3517
|
+
this.setValue(undefined);
|
|
3518
|
+
return libVES.Flow.logout();
|
|
3519
|
+
};
|
|
3520
|
+
|
|
2614
3521
|
module.exports = libVES;
|