libves 2.6.0 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +398 -20
- package/libVES.node.js +1663 -245
- package/libves-3.0.0.tgz +0 -0
- package/package.json +4 -2
- package/libves-2.6.0.tgz +0 -0
package/libVES.node.js
CHANGED
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
*
|
|
28
28
|
* @title libVES
|
|
29
29
|
* @dev A JavaScript end-to-end encryption interface to VESvault REST API
|
|
30
|
-
* @version
|
|
30
|
+
* @version 3.00
|
|
31
31
|
*
|
|
32
32
|
* @dev Official source code: https://github.com/vesvault/libVES
|
|
33
33
|
*
|
|
@@ -51,20 +51,25 @@ if (typeof(libVES) != 'function') function libVES(optns) {
|
|
|
51
51
|
else if (this.user) this.type = 'primary';
|
|
52
52
|
else throw new libVES.Error('InvalidValue','Required parameters: user || domain');
|
|
53
53
|
this.unlockedKeys = {};
|
|
54
|
+
this.pendingKeys = {};
|
|
54
55
|
}
|
|
55
56
|
|
|
56
57
|
libVES.prototype = {
|
|
58
|
+
constructor: libVES,
|
|
57
59
|
apiUrl: 'https://api.ves.host/v1/',
|
|
60
|
+
pollUrl: 'https://poll.ves.host/v1/',
|
|
58
61
|
wwwUrl: 'https://www.vesvault.com/',
|
|
59
62
|
keyAlgo: 'ECDH',
|
|
63
|
+
keyOptions: {namedCurve: 'P-521'},
|
|
60
64
|
textCipher: 'AES256GCMp',
|
|
61
65
|
defaultHash: 'SHA256',
|
|
62
|
-
|
|
66
|
+
propagators: [],
|
|
63
67
|
request: function(method,uri,body,optns) {
|
|
68
|
+
var self = this;
|
|
64
69
|
if (!optns) optns = {};
|
|
65
70
|
return new Promise(function(resolve,reject) {
|
|
66
71
|
var xhr = new XMLHttpRequest();
|
|
67
|
-
xhr.open(method,this.apiUrl + uri);
|
|
72
|
+
xhr.open(method, (uri.match(/^https\:/) ? uri : this.apiUrl + uri));
|
|
68
73
|
if (optns.abortFn) optns.abortFn(function() {
|
|
69
74
|
return xhr.abort();
|
|
70
75
|
});
|
|
@@ -77,8 +82,13 @@ libVES.prototype = {
|
|
|
77
82
|
return new libVES.Error(e.type,e.message,e);
|
|
78
83
|
});
|
|
79
84
|
if (errs.length) {
|
|
85
|
+
var retry = function(o) { return self.request(method, uri, body, (o || optns)); };
|
|
80
86
|
if (optns && optns.onerror) try {
|
|
81
|
-
resolve(optns.onerror(errs));
|
|
87
|
+
resolve(optns.onerror(errs, optns, retry));
|
|
88
|
+
} catch (e) {
|
|
89
|
+
reject(e);
|
|
90
|
+
} else if (self.onerror) try {
|
|
91
|
+
resolve(self.onerror(errs, optns, retry));
|
|
82
92
|
} catch (e) {
|
|
83
93
|
reject(e);
|
|
84
94
|
}
|
|
@@ -92,7 +102,7 @@ libVES.prototype = {
|
|
|
92
102
|
if (body != null) xhr.setRequestHeader('Content-Type','application/json');
|
|
93
103
|
xhr.setRequestHeader('Accept','application/json');
|
|
94
104
|
if (this.user && optns.password) xhr.setRequestHeader('Authorization','Basic ' + btoa(this.user + ':' + optns.password));
|
|
95
|
-
else if (optns.token
|
|
105
|
+
else if (optns.token ?? this.token) xhr.setRequestHeader('Authorization','Bearer ' + (optns.token ? optns.token : this.token));
|
|
96
106
|
xhr.responseType = 'json';
|
|
97
107
|
xhr.send(body);
|
|
98
108
|
}.bind(this));
|
|
@@ -117,6 +127,10 @@ libVES.prototype = {
|
|
|
117
127
|
}
|
|
118
128
|
return '';
|
|
119
129
|
},
|
|
130
|
+
mergeFieldList: function(flds, flds2) {
|
|
131
|
+
for (var k in flds2) if (flds[k] instanceof Object) flds[k] = this.mergeFieldList(flds[k], flds2[k]); else flds[k] = flds2[k];
|
|
132
|
+
return flds;
|
|
133
|
+
},
|
|
120
134
|
elevateAuth: function(optns) {
|
|
121
135
|
var self = this;
|
|
122
136
|
if (optns && (optns.password || optns.token)) return Promise.resolve(optns);
|
|
@@ -183,7 +197,7 @@ libVES.prototype = {
|
|
|
183
197
|
return flow.setValue(undefined).then(function() {
|
|
184
198
|
return flow.addToken(url).then(function(url) {
|
|
185
199
|
document.location.replace(url);
|
|
186
|
-
throw
|
|
200
|
+
throw new libVES.Error('Redirect', 'Starting VES Authorization...');
|
|
187
201
|
});
|
|
188
202
|
});
|
|
189
203
|
});
|
|
@@ -233,7 +247,7 @@ libVES.prototype = {
|
|
|
233
247
|
unlock: function(veskey) {
|
|
234
248
|
var self = this;
|
|
235
249
|
return this.getVaultKey().then(function(vkey) {
|
|
236
|
-
return vkey.unlock(
|
|
250
|
+
return vkey.unlock(veskey).then(function(cryptoKey) {
|
|
237
251
|
if (self.VESkey === null) self.VESkey = veskey;
|
|
238
252
|
if (!self.token && self.type == 'secondary') return vkey.getSessionToken().then(function(tkn) {
|
|
239
253
|
self.token = tkn;
|
|
@@ -248,8 +262,13 @@ libVES.prototype = {
|
|
|
248
262
|
});
|
|
249
263
|
},
|
|
250
264
|
lock: function() {
|
|
251
|
-
|
|
252
|
-
|
|
265
|
+
var lock = [];
|
|
266
|
+
for (var kid in this.unlockedKeys) lock.push(this.unlockedKeys[kid].then(function(k) {
|
|
267
|
+
return k.lock();
|
|
268
|
+
}).catch(function() {}));
|
|
269
|
+
return Promise.all(lock).then(function() {
|
|
270
|
+
return true;
|
|
271
|
+
});
|
|
253
272
|
},
|
|
254
273
|
reset: function(val) {
|
|
255
274
|
this.userMe = undefined;
|
|
@@ -290,18 +309,22 @@ libVES.prototype = {
|
|
|
290
309
|
});
|
|
291
310
|
});
|
|
292
311
|
},
|
|
293
|
-
getItems: function() {
|
|
312
|
+
getItems: function(flds) {
|
|
294
313
|
var self = this;
|
|
295
314
|
return this.getVaultKey().then(function(k) {
|
|
296
315
|
return k.getId().then(function(kid) {
|
|
297
|
-
return k.getVaultEntries().then(function(ves) {
|
|
316
|
+
return k.getVaultEntries(self.mergeFieldList({type: true, deleted: true, file: {creator: true, externals: true}, vaultKey: {type: true, user: true}}, flds)).then(function(ves) {
|
|
298
317
|
var vis = {};
|
|
299
318
|
var vlst = [];
|
|
300
319
|
for (var i = 0; i < ves.length; i++) {
|
|
301
320
|
var viid = ves[i].vaultItem.id;
|
|
302
321
|
if (!vis[viid]) {
|
|
303
|
-
var vi =
|
|
322
|
+
var vi = ves[i].vaultItem;
|
|
323
|
+
if (!vi.file) vi.file = undefined;
|
|
324
|
+
if (!vi.vaultKey) vi.vaultKey = undefined;
|
|
325
|
+
vi = vis[viid] = self.getItem(vi);
|
|
304
326
|
vlst.push(vi);
|
|
327
|
+
if (!ves[i].vaultKey) ves[i].vaultKey = {id: kid};
|
|
305
328
|
vi.vaultEntryByKey[kid] = ves[i];
|
|
306
329
|
}
|
|
307
330
|
}
|
|
@@ -340,7 +363,7 @@ libVES.prototype = {
|
|
|
340
363
|
_matchUser: function(u) {
|
|
341
364
|
if (typeof(u) == 'object') {
|
|
342
365
|
if (u instanceof libVES.User) return u;
|
|
343
|
-
else return new libVES.User(u,this);
|
|
366
|
+
else return new libVES.User((u.id ? {id: u.id} : {email: u.email}), this);
|
|
344
367
|
} else if (typeof(u) == 'string' && u.match(/^\S+\@\S+$/)) return new libVES.User({email: u},this);
|
|
345
368
|
throw new libVES.Error('BadUser',"Cannot match user: " + u,{value: u});
|
|
346
369
|
},
|
|
@@ -356,7 +379,7 @@ libVES.prototype = {
|
|
|
356
379
|
},
|
|
357
380
|
vaultRefToUser: function(ext) {
|
|
358
381
|
var email = ext.externalId ? ext.externalId.replace(/\!.*/, '') : '';
|
|
359
|
-
if (!email.match(/\@/)) throw
|
|
382
|
+
if (!email.match(/\@/)) throw new libVES.Error('NotFound', 'externalId is not an email for non-existing vault');
|
|
360
383
|
return new libVES.User({email: email}, self);
|
|
361
384
|
}
|
|
362
385
|
};
|
|
@@ -371,11 +394,14 @@ libVES.prototype = {
|
|
|
371
394
|
}).catch(function(e) {
|
|
372
395
|
throw new libVES.Error('NotFound', 'Cannot match externalId for domain:' + ext.domain + ', user:' + user + '. Define libVES.Domain.' + ext.domain + '.userToVaultRef(user) to return a valid reference.',{error: e});
|
|
373
396
|
})).then(function(exts) {
|
|
374
|
-
|
|
397
|
+
var keyref = {externals: exts};
|
|
398
|
+
if (self.externalId && self.externalId[0] != '!') keyref.creator = self.me();
|
|
399
|
+
var vkey = new libVES.VaultKey(keyref, self);
|
|
375
400
|
return vkey.getId().then(function() {
|
|
376
401
|
return vkey;
|
|
377
402
|
}).catch(function(e) {
|
|
378
403
|
if (e.code != 'NotFound') throw e;
|
|
404
|
+
if (!keyref.creator) throw new libVES.Error.InvalidKey('Anonymous vaults are not authorized to create temp keys');
|
|
379
405
|
return Promise.resolve(user || m().then(function(dom) {
|
|
380
406
|
return dom.vaultRefToUser(exts[0]);
|
|
381
407
|
})).catch(function(e) {
|
|
@@ -426,14 +452,15 @@ libVES.prototype = {
|
|
|
426
452
|
var key = new libVES.VaultKey({type: 'temp', algo: this.keyAlgo, user: usr}, self);
|
|
427
453
|
var veskey = this.generateVESkey(usr);
|
|
428
454
|
return key.generate(veskey, optns).then(function(k) {
|
|
429
|
-
if (self.e2e && self.e2e.length) usr.e2e = self.getVESkeyE2E(veskey, usr);
|
|
430
455
|
key.setField('vaultItems', veskey.then(function(v) {
|
|
431
456
|
var vi = new libVES.VaultItem({type: 'password'}, self);
|
|
432
|
-
return usr.getActiveVaultKeys().then(function() {
|
|
433
|
-
return [self.me(), self.getVaultKey()
|
|
457
|
+
return usr.getActiveVaultKeys().then(function(akeys) {
|
|
458
|
+
return [self.me(), self.getVaultKey()].concat(akeys);
|
|
434
459
|
}).catch(function(e) {
|
|
435
460
|
if (e.code != 'NotFound') throw e;
|
|
436
|
-
|
|
461
|
+
var sh = self.type == 'secondary' ? [self.me(), self.getVaultKey()] : [self.me()];
|
|
462
|
+
if (self.propagators) for (var i = 0; i < self.propagators.length; i++) sh.push(self.propagators[i]);
|
|
463
|
+
return sh;
|
|
437
464
|
}).then(function(sh) {
|
|
438
465
|
return Promise.all(sh);
|
|
439
466
|
}).then(function(sh) {
|
|
@@ -451,18 +478,6 @@ libVES.prototype = {
|
|
|
451
478
|
crypto.getRandomValues(buf);
|
|
452
479
|
return Promise.resolve(libVES.Util.ByteArrayToB64(buf));
|
|
453
480
|
},
|
|
454
|
-
getVESkeyE2E: function(veskey,usr) {
|
|
455
|
-
var self = this;
|
|
456
|
-
return veskey.then(function(v) {
|
|
457
|
-
return libVES.getModule(libVES.E2E,['Dialog','TempKey']).then(function(cls) {
|
|
458
|
-
return new cls({
|
|
459
|
-
user: usr,
|
|
460
|
-
e2e: self.e2e,
|
|
461
|
-
tempKey: v
|
|
462
|
-
});
|
|
463
|
-
});
|
|
464
|
-
});
|
|
465
|
-
},
|
|
466
481
|
setVESkey: function(veskey,lost,options) {
|
|
467
482
|
var self = this;
|
|
468
483
|
return this.me().then(function(me) {
|
|
@@ -578,6 +593,9 @@ libVES.prototype = {
|
|
|
578
593
|
}).catch(function(e) {
|
|
579
594
|
if (!e || e.code != 'Unauthorized') throw e;
|
|
580
595
|
}).then(function() {
|
|
596
|
+
self.vaultKey = k.lock().then(function() {
|
|
597
|
+
return k;
|
|
598
|
+
});
|
|
581
599
|
return self.unlock(veskey);
|
|
582
600
|
});
|
|
583
601
|
});
|
|
@@ -658,7 +676,7 @@ libVES.prototype = {
|
|
|
658
676
|
return Promise.resolve(shareWith || self.getFileItem(fileRef).then(function(vi) {
|
|
659
677
|
return vi.getShareList();
|
|
660
678
|
}).catch(function(e) {
|
|
661
|
-
return self.usersToKeys([{domain:
|
|
679
|
+
return self.usersToKeys([{domain: VES.domain, externalId: VES.externalId}]);
|
|
662
680
|
})).then(function(shareWith) {
|
|
663
681
|
return vaultItem.shareWith(shareWith,value);
|
|
664
682
|
});
|
|
@@ -681,8 +699,8 @@ libVES.prototype = {
|
|
|
681
699
|
});
|
|
682
700
|
},
|
|
683
701
|
deleteFile: function(fileRef) {
|
|
684
|
-
return this.
|
|
685
|
-
return
|
|
702
|
+
return this.getFileItem(fileRef).then(function(item) {
|
|
703
|
+
return item.delete();
|
|
686
704
|
});
|
|
687
705
|
},
|
|
688
706
|
newSecret: function(cls) {
|
|
@@ -812,7 +830,7 @@ libVES.prototype = {
|
|
|
812
830
|
return self.getVaultKey().then(function(vk) {
|
|
813
831
|
return vk.getField('unlockableVaultKeys').then(function(vks) {
|
|
814
832
|
var rs = {};
|
|
815
|
-
return Promise.all(vks.map(function(e, i) {
|
|
833
|
+
return Promise.all((vks || []).map(function(e, i) {
|
|
816
834
|
return e.getId().then(function(id) {
|
|
817
835
|
rs[id] = e;
|
|
818
836
|
});
|
|
@@ -857,9 +875,11 @@ libVES.prototype = {
|
|
|
857
875
|
return vkey.rekey(optns);
|
|
858
876
|
});
|
|
859
877
|
else return vkey.getVaultItems().then(function(vis) {
|
|
860
|
-
return
|
|
861
|
-
return
|
|
862
|
-
|
|
878
|
+
return self.elevateAuth().then(function(optns) {
|
|
879
|
+
return Promise.all(vis.map(function(vi, i) {
|
|
880
|
+
return vi.reshareWith([user], undefined, optns);
|
|
881
|
+
}));
|
|
882
|
+
});
|
|
863
883
|
});
|
|
864
884
|
});
|
|
865
885
|
});
|
|
@@ -871,11 +891,27 @@ libVES.prototype = {
|
|
|
871
891
|
}
|
|
872
892
|
});
|
|
873
893
|
}));
|
|
894
|
+
},
|
|
895
|
+
setKeyAlgo: function(optns) {
|
|
896
|
+
if (typeof(optns) == 'string') {
|
|
897
|
+
this.keyOptions = null;
|
|
898
|
+
return this.keyAlgo = optns;
|
|
899
|
+
}
|
|
900
|
+
var algo = libVES.Algo.fromKeyOptions(optns);
|
|
901
|
+
if (algo) {
|
|
902
|
+
this.keyOptions = optns;
|
|
903
|
+
return this.keyAlgo = algo;
|
|
904
|
+
}
|
|
874
905
|
}
|
|
875
906
|
};
|
|
876
907
|
|
|
877
|
-
libVES.Error = function(code,msg,optns) {
|
|
908
|
+
libVES.Error = function(code, msg, optns) {
|
|
909
|
+
if (libVES.Error[code] && (libVES.Error[code].prototype instanceof libVES.Error)) return new (libVES.Error[code])(msg, optns);
|
|
878
910
|
this.code = code;
|
|
911
|
+
this.init(msg, optns);
|
|
912
|
+
};
|
|
913
|
+
|
|
914
|
+
libVES.Error.prototype.init = function(msg, optns) {
|
|
879
915
|
this.message = msg;
|
|
880
916
|
if (optns) for (var k in optns) this[k] = optns[k];
|
|
881
917
|
};
|
|
@@ -884,6 +920,37 @@ libVES.Error.prototype.toString = function() {
|
|
|
884
920
|
return this.message || this.code;
|
|
885
921
|
};
|
|
886
922
|
|
|
923
|
+
libVES.Error.NotFound = function(msg, optns) {
|
|
924
|
+
this.init(msg, optns);
|
|
925
|
+
};
|
|
926
|
+
libVES.Error.NotFound.prototype = new libVES.Error('NotFound');
|
|
927
|
+
|
|
928
|
+
libVES.Error.InvalidValue = function(msg, optns) {
|
|
929
|
+
this.init(msg, optns);
|
|
930
|
+
};
|
|
931
|
+
libVES.Error.InvalidValue.prototype = new libVES.Error('InvalidValue');
|
|
932
|
+
|
|
933
|
+
libVES.Error.InvalidKey = function(msg, optns) {
|
|
934
|
+
this.init(msg, optns);
|
|
935
|
+
};
|
|
936
|
+
libVES.Error.InvalidKey.prototype = new libVES.Error('InvalidKey');
|
|
937
|
+
|
|
938
|
+
libVES.Error.Redirect = function(msg, optns) {
|
|
939
|
+
this.init(msg, optns);
|
|
940
|
+
};
|
|
941
|
+
libVES.Error.Redirect.prototype = new libVES.Error('Redirect');
|
|
942
|
+
|
|
943
|
+
libVES.Error.Unauthorized = function(msg, optns) {
|
|
944
|
+
this.init(msg, optns);
|
|
945
|
+
};
|
|
946
|
+
libVES.Error.Unauthorized.prototype = new libVES.Error('Unauthorized');
|
|
947
|
+
|
|
948
|
+
libVES.Error.Internal = function(msg, optns) {
|
|
949
|
+
this.init(msg, optns);
|
|
950
|
+
};
|
|
951
|
+
libVES.Error.Internal.prototype = new libVES.Error('Internal');
|
|
952
|
+
|
|
953
|
+
|
|
887
954
|
libVES.getModule = function(sectn,mods) {
|
|
888
955
|
var mod;
|
|
889
956
|
if (mods instanceof Array) mod = mods[0];
|
|
@@ -904,6 +971,9 @@ libVES.getModuleFunc = function(sectn,mod,then) {
|
|
|
904
971
|
libVES.loadModule = function(sectn,mod) {
|
|
905
972
|
return Promise.reject(new libVES.Error('Internal',"Cannot load " + sectn + '.' + mod));
|
|
906
973
|
};
|
|
974
|
+
libVES.maxKeyLen = 48896;
|
|
975
|
+
libVES.maxEncDataLen = 32768;
|
|
976
|
+
|
|
907
977
|
|
|
908
978
|
if (!libVES.Domain) libVES.Domain = {};
|
|
909
979
|
|
|
@@ -982,6 +1052,24 @@ libVES.Util = {
|
|
|
982
1052
|
}
|
|
983
1053
|
return rs;
|
|
984
1054
|
},
|
|
1055
|
+
fillUndefs: function(data, defs) {
|
|
1056
|
+
if (data instanceof Array) data.map((d) => libVES.Util.fillUndefs(d, defs));
|
|
1057
|
+
else if (data && defs) for (var k in defs) if (defs[k]) {
|
|
1058
|
+
if (data[k] === undefined) data[k] = undefined;
|
|
1059
|
+
else if (data[k] instanceof Object) libVES.Util.fillUndefs(data[k], defs[k]);
|
|
1060
|
+
}
|
|
1061
|
+
return data;
|
|
1062
|
+
},
|
|
1063
|
+
loadWasm: function(src) {
|
|
1064
|
+
return new Promise(function(resolve, reject) {
|
|
1065
|
+
var sc = document.createElement('script');
|
|
1066
|
+
sc.async = false;
|
|
1067
|
+
sc.src = src;
|
|
1068
|
+
sc.onload = resolve;
|
|
1069
|
+
sc.onerror = reject;
|
|
1070
|
+
document.getElementsByTagName('head')[0].appendChild(sc);
|
|
1071
|
+
});
|
|
1072
|
+
},
|
|
985
1073
|
PEM: {
|
|
986
1074
|
toDER: function(pem) {
|
|
987
1075
|
var pp = pem.match(/-----BEGIN.*?-----\s*\r?\n([A-Za-z0-9\/\+\=\s\r\n]*)-----END/);
|
|
@@ -1136,6 +1224,43 @@ libVES.Util = {
|
|
|
1136
1224
|
this.value = rs.join('.');
|
|
1137
1225
|
} else this.value = s;
|
|
1138
1226
|
},
|
|
1227
|
+
Key: {
|
|
1228
|
+
fromDER: function(der, callbk) {
|
|
1229
|
+
var asn = libVES.Util.ASN1.decode(der)[0];
|
|
1230
|
+
if (typeof(asn[0]) == 'number') {
|
|
1231
|
+
var asn2 = libVES.Util.ASN1.decode(asn[2])[0];
|
|
1232
|
+
var pub = libVES.Util.ASN1.decode(asn2[2]);
|
|
1233
|
+
console.log('pub', pub);
|
|
1234
|
+
if (pub) return callbk(pub[0].slice(1), asn2[1], pub[0][0]);
|
|
1235
|
+
else callbk(null, asn2[1]);
|
|
1236
|
+
} else return callbk(asn[1].slice(1), null, asn[1][0]);
|
|
1237
|
+
},
|
|
1238
|
+
pubASN1: function(pub, optns) {
|
|
1239
|
+
var p = new Uint8Array(pub.byteLength + 1);
|
|
1240
|
+
p[0] = optns && optns.pubBits ? optns.pubBits : 0;
|
|
1241
|
+
p.set(new Uint8Array(pub), 1);
|
|
1242
|
+
p.ASN1type = 3;
|
|
1243
|
+
return p;
|
|
1244
|
+
},
|
|
1245
|
+
toPKCS: function(pub, priv, asn1hdr, optns) {
|
|
1246
|
+
if (priv) {
|
|
1247
|
+
var seq = [1, priv];
|
|
1248
|
+
if (pub) {
|
|
1249
|
+
p = libVES.Util.ASN1.encode([libVES.Util.Key.pubASN1(pub, optns)]);
|
|
1250
|
+
p.ASN1type = 0xa1;
|
|
1251
|
+
seq.push(p);
|
|
1252
|
+
}
|
|
1253
|
+
var buf = libVES.Util.ASN1.encode([seq]);
|
|
1254
|
+
return libVES.Util.ASN1.encode([[0, asn1hdr, buf]]);
|
|
1255
|
+
}
|
|
1256
|
+
return libVES.Util.ASN1.encode([[asn1hdr, libVES.Util.Key.pubASN1(pub, optns)]]);
|
|
1257
|
+
},
|
|
1258
|
+
export: function(pub, priv, asn1hdr, optns) {
|
|
1259
|
+
var pkcs = libVES.Util.Key.toPKCS(pub, priv, asn1hdr, optns);
|
|
1260
|
+
if (priv) return libVES.Util.PKCS8.encode8(pkcs, optns);
|
|
1261
|
+
return libVES.Util.PEM.encode(pkcs, 'PUBLIC KEY');
|
|
1262
|
+
}
|
|
1263
|
+
},
|
|
1139
1264
|
PKCS1: {
|
|
1140
1265
|
import: function(args,chain,optns) {
|
|
1141
1266
|
return chain('container',optns).then(function(der) {
|
|
@@ -1318,13 +1443,18 @@ libVES.Util = {
|
|
|
1318
1443
|
EC: {
|
|
1319
1444
|
import: function(args,chain,optns) {
|
|
1320
1445
|
return chain('container',optns).then(function(der) {
|
|
1321
|
-
var
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1446
|
+
var oid = String(args);
|
|
1447
|
+
var curve = libVES.Util.EC.namedCurves[oid] || oid;
|
|
1448
|
+
var a = {name:'ECDH',namedCurve: curve};
|
|
1449
|
+
return crypto.subtle.importKey('spki',der,a,true,[]).catch(function() {
|
|
1450
|
+
return crypto.subtle.importKey('pkcs8',der,a,true,['deriveKey','deriveBits']);
|
|
1451
|
+
}).catch(function(e) {
|
|
1452
|
+
console.log('PKCS8 failed, trying JWK...');
|
|
1453
|
+
var jwk = libVES.Util.PKCS8.toJWK(der);
|
|
1454
|
+
return crypto.subtle.importKey('jwk', jwk, a, true, jwk.key_ops);
|
|
1455
|
+
}).catch(function(e) {
|
|
1456
|
+
console.log('trying WasmECDH...');
|
|
1457
|
+
return libVES.Algo.ECDH.importWasm(curve, der);
|
|
1328
1458
|
});
|
|
1329
1459
|
});
|
|
1330
1460
|
},
|
|
@@ -1618,30 +1748,20 @@ libVES.Object.prototype = {
|
|
|
1618
1748
|
this.setFields(data,data.id == null);
|
|
1619
1749
|
if (refs) for (var k in refs) this[k] = Promise.resolve(refs[k]);
|
|
1620
1750
|
},
|
|
1621
|
-
setFields: function(
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
else if (v instanceof Array) return v.map(function(vv) { return clsf(vv); });
|
|
1636
|
-
else return new (self.fieldClass[k])(v,self.VES);
|
|
1637
|
-
})(v);
|
|
1638
|
-
return v;
|
|
1639
|
-
};
|
|
1640
|
-
})(k));
|
|
1641
|
-
else return Promise.reject(new libVES.Error('Internal',"Unknown field: " + k));
|
|
1642
|
-
}
|
|
1643
|
-
if (chg && self.trigger) self.trigger.resolve(self);
|
|
1644
|
-
return Promise.resolve(self);
|
|
1751
|
+
setFields: function(flds, up) {
|
|
1752
|
+
var res = Promise.resolve(null);
|
|
1753
|
+
for (var fld in flds) ((fld) => {
|
|
1754
|
+
if (up === undefined || up) this.fieldUpdate[fld] = true;
|
|
1755
|
+
var cls = this.fieldClass[fld];
|
|
1756
|
+
var cur = this[fld];
|
|
1757
|
+
res = this[fld] = res.then(() => Promise.resolve(flds[fld]).then((val) => Promise.resolve(cur).catch((er) => undefined).then((cur) => {
|
|
1758
|
+
if (!cls || !val) return val;
|
|
1759
|
+
else if (val instanceof Array) return val.map((v) => ((v instanceof libVES.Object) ? v : new cls(v, this.VES)));
|
|
1760
|
+
else if (cur instanceof cls) return cur.setFields(val, up);
|
|
1761
|
+
else return (val instanceof libVES.Object) ? val : new cls(val, this.VES);
|
|
1762
|
+
})));
|
|
1763
|
+
})(fld);
|
|
1764
|
+
return res.then(() => this);
|
|
1645
1765
|
},
|
|
1646
1766
|
setField: function(fld,val,upd) {
|
|
1647
1767
|
var flds = {};
|
|
@@ -1650,26 +1770,78 @@ libVES.Object.prototype = {
|
|
|
1650
1770
|
return self[fld];
|
|
1651
1771
|
});
|
|
1652
1772
|
},
|
|
1773
|
+
unsetField: function(fld) {
|
|
1774
|
+
delete(this[fld]);
|
|
1775
|
+
},
|
|
1776
|
+
_fieldsToLoad: function(fldlst, force, ld) {
|
|
1777
|
+
var flds = {};
|
|
1778
|
+
for (var k in fldlst) flds[k] ||= fldlst[k];
|
|
1779
|
+
for (var i = 0; i < this.fieldSets.length; i++) {
|
|
1780
|
+
for (var k in this.fieldSets[i]) if (fldlst[k]) {
|
|
1781
|
+
for (var k in this.fieldSets[i]) if ((force || !this[k]) && !(flds[k] instanceof Object)) (flds ||= {})[k] = this.fieldSets[i][k];
|
|
1782
|
+
break;
|
|
1783
|
+
}
|
|
1784
|
+
}
|
|
1785
|
+
var res = Promise.resolve(null);
|
|
1786
|
+
for (var fld in flds) ((fld) => {
|
|
1787
|
+
var cur = this[fld];
|
|
1788
|
+
var na = (cur === undefined);
|
|
1789
|
+
var cls = this.fieldClass[fld];
|
|
1790
|
+
res = res.then((res) => Promise.resolve(cur).catch((er) => null).then((cur) => {
|
|
1791
|
+
var lst = null;
|
|
1792
|
+
if (force || na) lst = flds[fld];
|
|
1793
|
+
else if (cls) {
|
|
1794
|
+
if (cur instanceof Array) lst = ((cur[0] instanceof cls) ? cur[0]._fieldsToLoad(flds[fld], force, ld.then((vals) => vals[fld])) : Promise.resolve(null)).then((lst) => (lst && flds[fld]));
|
|
1795
|
+
else if (cur instanceof cls) lst = cur._fieldsToLoad(flds[fld], force, ld.then((vals) => vals[fld]));
|
|
1796
|
+
}
|
|
1797
|
+
return Promise.resolve(lst).then((lst) => {
|
|
1798
|
+
if (lst) (res ||= {})[fld] = lst;
|
|
1799
|
+
return res;
|
|
1800
|
+
});
|
|
1801
|
+
}));
|
|
1802
|
+
if (na || (!cls && force)) (this[fld] = ld.then((vals) => (vals?.hasOwnProperty(fld) ? (cls && vals[fld] ? ((vals[fld] instanceof Array) ? vals[fld].map((e) => new cls(e, this.VES)) : new cls(vals[fld], this.VES)) : vals[fld]) : cur))).catch(() => null);
|
|
1803
|
+
})(fld);
|
|
1804
|
+
ld.then((vals) => {
|
|
1805
|
+
for (var fld in vals) if (!flds[fld] && !this[fld]) this.setField(fld, vals[fld], false);
|
|
1806
|
+
}).catch((er) => null);
|
|
1807
|
+
return res.then((res) => {
|
|
1808
|
+
if (res) for (var k in fldlst) if (res[k]) return res;
|
|
1809
|
+
return null;
|
|
1810
|
+
});
|
|
1811
|
+
},
|
|
1812
|
+
getFields: function(fldlst, force) {
|
|
1813
|
+
var ldf;
|
|
1814
|
+
var ld = new Promise((resolve, reject) => ldf = [resolve, reject]);
|
|
1815
|
+
this._fieldsToLoad(fldlst, force, ld).then((flds) => this.loadFields(flds, force)).then((vals) => ldf[0](vals)).catch((er) => ldf[1](er));
|
|
1816
|
+
var plst = [];
|
|
1817
|
+
for (var k in fldlst) ((k) => {
|
|
1818
|
+
plst.push(ld.then(() => this[k]).then(function rslv(v) {
|
|
1819
|
+
if (v instanceof Array) return Promise.all(v.map(function(e, i) {
|
|
1820
|
+
return rslv(e);
|
|
1821
|
+
}));
|
|
1822
|
+
if (!(v instanceof libVES.Object)) return v;
|
|
1823
|
+
return v.getFields(fldlst[k]);
|
|
1824
|
+
}));
|
|
1825
|
+
})(k);
|
|
1826
|
+
var rs = {};
|
|
1827
|
+
return Promise.all(plst).then((lst) => {
|
|
1828
|
+
var i = 0;
|
|
1829
|
+
for (var k in fldlst) rs[k] = lst[i++];
|
|
1830
|
+
return rs;
|
|
1831
|
+
});
|
|
1832
|
+
},
|
|
1653
1833
|
getField: function(fld,fldlst,force) {
|
|
1654
|
-
var self = this;
|
|
1655
1834
|
if (!this[fld] || force) {
|
|
1656
1835
|
var flds = {};
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
break;
|
|
1660
|
-
}
|
|
1661
|
-
if (fldlst) flds[fld] = fldlst;
|
|
1662
|
-
if (!flds[fld]) {
|
|
1663
|
-
var cls = self.fieldClass[fld];
|
|
1664
|
-
flds[fld] = cls ? cls.prototype.fieldList : true;
|
|
1665
|
-
}
|
|
1666
|
-
this.loadFields(flds,force);
|
|
1836
|
+
flds[fld] = fldlst || true;
|
|
1837
|
+
this.getFields(flds, force).catch(() => null);
|
|
1667
1838
|
}
|
|
1668
1839
|
return this[fld];
|
|
1669
1840
|
},
|
|
1670
1841
|
loadFields: function(flds,force,optns) {
|
|
1842
|
+
if (!flds) return Promise.resolve({});
|
|
1671
1843
|
var self = this;
|
|
1672
|
-
|
|
1844
|
+
return (this.id && !flds.id ? this.id.then(function(id) { return self.VES.get(self.apiUri + '/' + id,flds,optns); }) : self.postData().then(function(data) {
|
|
1673
1845
|
data['$op'] = 'fetch';
|
|
1674
1846
|
return self.VES.post(self.apiUri,data,flds,optns);
|
|
1675
1847
|
}).then(function(data) {
|
|
@@ -1678,21 +1850,10 @@ libVES.Object.prototype = {
|
|
|
1678
1850
|
self.fieldUpdate = {id: true};
|
|
1679
1851
|
}
|
|
1680
1852
|
return data;
|
|
1681
|
-
});
|
|
1682
|
-
for (var k in flds) if (force || this[k] === undefined) {
|
|
1683
|
-
this[k] = req.then((function(fld) {
|
|
1684
|
-
var cls = self.fieldClass[fld];
|
|
1685
|
-
return function(data) {
|
|
1686
|
-
if (cls && data[fld]) return ((data[fld] instanceof Array) ? data[fld].map(function(v) {
|
|
1687
|
-
return new cls(v,self.VES);
|
|
1688
|
-
}) : new cls(data[fld],self.VES));
|
|
1689
|
-
return data[fld];
|
|
1690
|
-
};
|
|
1691
|
-
})(k));
|
|
1692
|
-
}
|
|
1853
|
+
})).then((data) => libVES.Util.fillUndefs(data, flds));
|
|
1693
1854
|
},
|
|
1694
1855
|
reset: function() {
|
|
1695
|
-
for (var k in this.fieldClass)
|
|
1856
|
+
for (var k in this.fieldClass) this.unsetField(k);
|
|
1696
1857
|
return Promise.resolve();
|
|
1697
1858
|
},
|
|
1698
1859
|
getId: function() {
|
|
@@ -1766,6 +1927,23 @@ libVES.Object.prototype = {
|
|
|
1766
1927
|
},
|
|
1767
1928
|
resolveError: function(e,field) {
|
|
1768
1929
|
throw e;
|
|
1930
|
+
},
|
|
1931
|
+
setUpdate: function(flds) {
|
|
1932
|
+
var rs = [];
|
|
1933
|
+
for (var k in flds) {
|
|
1934
|
+
if (flds[k]) this.fieldUpdate[k] = true;
|
|
1935
|
+
else delete(this.fieldUpdate[k]);
|
|
1936
|
+
if (this[k] && (flds[k] instanceof Object)) (function(p, k) {
|
|
1937
|
+
rs.push(p.then(function rslv(obj) {
|
|
1938
|
+
if (obj instanceof Array) return Promise.all(obj.map(rslv));
|
|
1939
|
+
if (obj instanceof libVES.Object) return obj.setUpdate(flds[k]);
|
|
1940
|
+
}));
|
|
1941
|
+
})(this[k], k);
|
|
1942
|
+
}
|
|
1943
|
+
return Promise.all(rs);
|
|
1944
|
+
},
|
|
1945
|
+
toJSON: function() {
|
|
1946
|
+
return String(this);
|
|
1769
1947
|
}
|
|
1770
1948
|
};
|
|
1771
1949
|
|
|
@@ -1791,6 +1969,22 @@ libVES.File = function(data,VES,refs) {
|
|
|
1791
1969
|
this.init(data,VES,refs);
|
|
1792
1970
|
};
|
|
1793
1971
|
|
|
1972
|
+
libVES.Event = function(data, VES, refs) {
|
|
1973
|
+
this.init(data, VES, refs);
|
|
1974
|
+
};
|
|
1975
|
+
|
|
1976
|
+
libVES.Session = function(data, VES, refs) {
|
|
1977
|
+
this.init(data, VES, refs);
|
|
1978
|
+
};
|
|
1979
|
+
|
|
1980
|
+
libVES.oldDomain = libVES.Domain;
|
|
1981
|
+
libVES.Domain = function(dom, VES) {
|
|
1982
|
+
this.init({id: (dom ? dom : VES.domain)}, VES);
|
|
1983
|
+
};
|
|
1984
|
+
(function(old) {
|
|
1985
|
+
if (old) for (var k in old) libVES.Domain[k] = old[k];
|
|
1986
|
+
})(libVES.oldDomain);
|
|
1987
|
+
|
|
1794
1988
|
libVES.User.prototype = new libVES.Object({
|
|
1795
1989
|
apiUri: 'users',
|
|
1796
1990
|
fieldList: {id: true, email: true, type: true, firstName: true, lastName: true},
|
|
@@ -1902,10 +2096,16 @@ libVES.VaultKey.prototype = new libVES.Object({
|
|
|
1902
2096
|
case 'lost':
|
|
1903
2097
|
return self.getVaultItems().then(function(vis) {
|
|
1904
2098
|
var f = function(vis) {
|
|
1905
|
-
if (!vis.length) throw new libVES.Error('InvalidKey','Cannot unlock the secondary key');
|
|
2099
|
+
if (!vis || !vis.length) throw new libVES.Error('InvalidKey','Cannot unlock the secondary key');
|
|
1906
2100
|
return vis[0].getType().then(function(t) {
|
|
1907
2101
|
switch (t) {
|
|
1908
|
-
case 'password': return
|
|
2102
|
+
case 'password': return self.getId().then(function(kid) {
|
|
2103
|
+
if (!self.VES.pendingKeys) self.VES.pendingKeys = {};
|
|
2104
|
+
if (kid) self.VES.pendingKeys[kid] = true;
|
|
2105
|
+
return vis[0].get().finally(function() {
|
|
2106
|
+
self.VES.pendingKeys[kid] = false;
|
|
2107
|
+
});
|
|
2108
|
+
});
|
|
1909
2109
|
default: return f(vis.slice(1));
|
|
1910
2110
|
}
|
|
1911
2111
|
});
|
|
@@ -1916,26 +2116,57 @@ libVES.VaultKey.prototype = new libVES.Object({
|
|
|
1916
2116
|
}
|
|
1917
2117
|
});
|
|
1918
2118
|
},
|
|
2119
|
+
invalidVESkey: function() {
|
|
2120
|
+
var self = this;
|
|
2121
|
+
return self.getVaultItems().then(function(vis) {
|
|
2122
|
+
return Promise.all(vis.map(function(vi) {
|
|
2123
|
+
return vi.getVaultEntries().then(function(entries) {
|
|
2124
|
+
if (entries) for (let i = 0; i < entries.length; i++) if (self.VES.unlockedKeys[entries[i].vaultKey.id]) return Promise.resolve(self.VES.unlockedKeys[entries[i].vaultKey.id]).then(function(key) {
|
|
2125
|
+
return key.getFields({user: {email: true}, extrenals: {domain: true, externalId: true}}).then(function(flds) {
|
|
2126
|
+
return vi.unshareWith([flds.externals && flds.externals[0] ? flds.externals[0] : flds.user.email]);
|
|
2127
|
+
});
|
|
2128
|
+
});
|
|
2129
|
+
});
|
|
2130
|
+
}));
|
|
2131
|
+
});
|
|
2132
|
+
},
|
|
1919
2133
|
unlock: function(veskey) {
|
|
1920
2134
|
var self = this;
|
|
1921
|
-
if (self.wcPriv)
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
|
|
2135
|
+
if (!self.wcPriv) self.wcPriv = self.getId().then(function(id) {
|
|
2136
|
+
return Promise.resolve(self.VES.unlockedKeys[id]).then(function(k) {
|
|
2137
|
+
return k.wcPriv;
|
|
2138
|
+
}).catch(function(e) {
|
|
2139
|
+
let un = self.engine().then(function(m) {
|
|
2140
|
+
return self.resolveVESkey(veskey).then(function(v) {
|
|
2141
|
+
return self.getPrivateKey().then(function(prk) {
|
|
2142
|
+
return m.import(prk, {password: v}).catch(function(e) {
|
|
2143
|
+
if (e && e.code == 'InvalidKey' && !veskey) {
|
|
2144
|
+
console.log('Bad key propagated for ' + id + ', unsharing...');
|
|
2145
|
+
return self.invalidVESkey().catch(function(e2) {
|
|
2146
|
+
console.log(e2);
|
|
2147
|
+
}).then(function(r) {
|
|
2148
|
+
console.log(r);
|
|
2149
|
+
throw e;
|
|
2150
|
+
});
|
|
2151
|
+
}
|
|
2152
|
+
throw e;
|
|
2153
|
+
});
|
|
2154
|
+
});
|
|
1931
2155
|
});
|
|
1932
2156
|
});
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
|
|
2157
|
+
let vk = self.VES.unlockedKeys[id] = un.then(function() {
|
|
2158
|
+
return self;
|
|
2159
|
+
}).catch(function(e) {
|
|
2160
|
+
if (self.VES.unlockedKeys[id] === vk) delete(self.VES.unlockedKeys[id]);
|
|
2161
|
+
});
|
|
2162
|
+
return un;
|
|
1937
2163
|
});
|
|
1938
2164
|
});
|
|
2165
|
+
else if (veskey) self.wcPriv = self.wcPriv.catch(function(e) {
|
|
2166
|
+
delete(self.wcPriv);
|
|
2167
|
+
return self.unlock(veskey);
|
|
2168
|
+
});
|
|
2169
|
+
return self.wcPriv;
|
|
1939
2170
|
},
|
|
1940
2171
|
lock: function() {
|
|
1941
2172
|
var self = this;
|
|
@@ -1962,12 +2193,14 @@ libVES.VaultKey.prototype = new libVES.Object({
|
|
|
1962
2193
|
});
|
|
1963
2194
|
},
|
|
1964
2195
|
generate: function(veskey,optns) {
|
|
2196
|
+
if (!optns) optns = this.VES.keyOptions;
|
|
1965
2197
|
var self = this;
|
|
2198
|
+
var a;
|
|
1966
2199
|
var wc = optns && optns.privateKey ? libVES.Algo.acquire(optns.privateKey).then(function(wc) {
|
|
1967
2200
|
self.setField('algo',wc.engine.tag);
|
|
1968
2201
|
if (!wc.privateKey) throw new libVES.Error('InvalidValue','Private key expected');
|
|
1969
2202
|
return wc;
|
|
1970
|
-
}) : (optns && optns
|
|
2203
|
+
}) : (optns && (a = libVES.Algo.fromKeyOptions(optns)) ? self.setField('algo', a) : Promise.resolve()).then(function() {
|
|
1971
2204
|
return self.engine().then(function(e) {
|
|
1972
2205
|
return e.generate(optns).then(function(ks) {
|
|
1973
2206
|
ks.engine = e;
|
|
@@ -2111,8 +2344,28 @@ libVES.VaultKey.prototype = new libVES.Object({
|
|
|
2111
2344
|
});
|
|
2112
2345
|
});
|
|
2113
2346
|
},
|
|
2114
|
-
matchVaults: function(
|
|
2115
|
-
|
|
2347
|
+
matchVaults: function(shares) {
|
|
2348
|
+
return this.getFields({id: true, externals: {domain: true, externalId: true}, user: {email: true}}).then((flds) => (shares || []).reduce((res, sh) => res.then((res) => Promise.resolve(sh).then((sh) => {
|
|
2349
|
+
if (res) return res;
|
|
2350
|
+
var ext = flds.externals?.[0];
|
|
2351
|
+
if (sh instanceof libVES.Object) {
|
|
2352
|
+
if (sh instanceof libVES.VaultKey) return sh.getId().then((id) => (id == flds.id ? sh : res));
|
|
2353
|
+
else if ((sh instanceof libVES.External) && ext) return sh.getFields({domain: true, externalId: true}).then((xflds) => (xflds.domain == ext.domain && xflds.externalId == ext.externalId ? sh : res));
|
|
2354
|
+
else if ((sh instanceof libVES.User) && flds.user && !ext) return sh.getEmail().then((email) => (email == flds.user.email ? sh : res));
|
|
2355
|
+
} else if (sh instanceof Object) {
|
|
2356
|
+
if (sh.externalId && sh.externalId == ext?.externalId && (sh.domain || this.VES.domain) == ext.domain) return sh;
|
|
2357
|
+
else if (sh.email && sh.email == flds.user?.email && !ext) return sh;
|
|
2358
|
+
} else if (sh && flds.user?.email == sh && !ext) return sh;
|
|
2359
|
+
return res;
|
|
2360
|
+
})), Promise.resolve(false)));
|
|
2361
|
+
},
|
|
2362
|
+
getKeyOptions: function() {
|
|
2363
|
+
var self = this;
|
|
2364
|
+
return self.engine().then(function(e) {
|
|
2365
|
+
return self.getPublicCryptoKey().then(function(pub) {
|
|
2366
|
+
return e.getKeyOptions(pub);
|
|
2367
|
+
});
|
|
2368
|
+
});
|
|
2116
2369
|
}
|
|
2117
2370
|
});
|
|
2118
2371
|
|
|
@@ -2120,7 +2373,7 @@ libVES.VaultItem.prototype = new libVES.Object({
|
|
|
2120
2373
|
apiUri: 'vaultItems',
|
|
2121
2374
|
fieldList: {id: true, deleted: true, file: true},
|
|
2122
2375
|
fieldClass: {vaultKey: libVES.VaultKey, file: libVES.File},
|
|
2123
|
-
fieldSets: [{type: true, meta: true},{vaultEntries: {id: true, encData: true, vaultKey: {id: true, type: true, user: {id: true}, algo: true, externals: {id: true}}}},{vaultKey: true, file: true}],
|
|
2376
|
+
fieldSets: [{type: true, meta: true},{vaultEntries: {id: true, encData: true, vaultKey: {id: true, type: true, user: {id: true, email: true}, algo: true, externals: {id: true, domain: true, externalId: true}}}},{vaultKey: true, file: true}],
|
|
2124
2377
|
defaultCipher: 'AES256GCM',
|
|
2125
2378
|
getRaw: function() {
|
|
2126
2379
|
var self = this;
|
|
@@ -2129,9 +2382,11 @@ libVES.VaultItem.prototype = new libVES.Object({
|
|
|
2129
2382
|
var fn = function() {
|
|
2130
2383
|
if (vaultEntries) for (; i < vaultEntries.length; i++) {
|
|
2131
2384
|
var k, d;
|
|
2132
|
-
if ((d = vaultEntries[i].encData) != null &&
|
|
2385
|
+
if ((d = vaultEntries[i].encData) != null && (k = vaultKeys[vaultEntries[i].vaultKey.id]) && (!self.VES.pendingKeys || !self.VES.pendingKeys[vaultEntries[i].vaultKey.id])) {
|
|
2133
2386
|
i++;
|
|
2134
|
-
return
|
|
2387
|
+
return Promise.resolve(k).then(function(k) {
|
|
2388
|
+
return k.decrypt(d).catch(fn);
|
|
2389
|
+
});
|
|
2135
2390
|
}
|
|
2136
2391
|
}
|
|
2137
2392
|
return Promise.reject(new libVES.Error('InvalidKey',"No unlocked key to decrypt the item",{vaultItem: self}));
|
|
@@ -2190,7 +2445,10 @@ libVES.VaultItem.prototype = new libVES.Object({
|
|
|
2190
2445
|
},
|
|
2191
2446
|
build: function(data) {
|
|
2192
2447
|
var self = this;
|
|
2193
|
-
return this.getType().
|
|
2448
|
+
return this.getType().catch(function(e) {
|
|
2449
|
+
if (e && e.code == 'NotFound') return self.setField('type', libVES.VaultItem.Type._detect(data));
|
|
2450
|
+
throw e;
|
|
2451
|
+
}).then(function(type) {
|
|
2194
2452
|
return libVES.getModule(libVES.VaultItem.Type,type).then(function(m) {
|
|
2195
2453
|
return m.build.call(self,data);
|
|
2196
2454
|
});
|
|
@@ -2202,12 +2460,12 @@ libVES.VaultItem.prototype = new libVES.Object({
|
|
|
2202
2460
|
shareWith: function(usrs,val,save) {
|
|
2203
2461
|
var self = this;
|
|
2204
2462
|
return self.VES.usersToKeys(usrs).then(function(ks) {
|
|
2205
|
-
return (val == null
|
|
2463
|
+
return (val == null ? self.getVaultEntries().then(function(ves) {
|
|
2206
2464
|
var k_ves = {};
|
|
2207
2465
|
var k_used = {};
|
|
2208
2466
|
for (var j = 0; j < ves.length; j++) k_ves[ves[j].vaultKey.id] = ves[j];
|
|
2209
2467
|
return Promise.all(ks.map(function(k,j) {
|
|
2210
|
-
return k.getId().then(function(k_id) {
|
|
2468
|
+
if (!k.fieldUpdate.privateKey) return k.getId().then(function(k_id) {
|
|
2211
2469
|
k_used[k_id] = true;
|
|
2212
2470
|
return k_ves[k_id];
|
|
2213
2471
|
}).catch(function(){});
|
|
@@ -2219,21 +2477,26 @@ libVES.VaultItem.prototype = new libVES.Object({
|
|
|
2219
2477
|
var new_ves = [];
|
|
2220
2478
|
var set_ves = [];
|
|
2221
2479
|
var valr = null;
|
|
2480
|
+
var key_ids = {};
|
|
2222
2481
|
return Promise.all(ks.map(function(k,j) {
|
|
2223
2482
|
return new_ves[j] = (old_ves[j] || (valr != null ? valr : valr = self.resolveRaw(val)).then(function(v) {
|
|
2224
|
-
return
|
|
2225
|
-
|
|
2226
|
-
|
|
2227
|
-
|
|
2228
|
-
|
|
2483
|
+
return (function(refs) {
|
|
2484
|
+
if (refs) for (var i in refs) if (refs[i] === k) return Promise.resolve({'$ref':i});
|
|
2485
|
+
return k.postData(null,refs);
|
|
2486
|
+
})(libVES.Object._refs).then(function(pd) {
|
|
2487
|
+
if (pd.id) {
|
|
2488
|
+
if (key_ids[pd.id]) return;
|
|
2489
|
+
key_ids[pd.id] = true;
|
|
2490
|
+
}
|
|
2491
|
+
return k.encrypt(v).then(function(ctext) {
|
|
2229
2492
|
return set_ves.push({vaultKey: pd, encData: ctext});
|
|
2230
2493
|
});
|
|
2231
2494
|
});
|
|
2232
2495
|
}));
|
|
2233
2496
|
})).then(function() {
|
|
2234
2497
|
return Promise.all(old_ves.slice(ks.length).map(function(ve,j) {
|
|
2235
|
-
return (new libVES.VaultKey(ve.vaultKey,self.VES)).matchVaults(
|
|
2236
|
-
if (f
|
|
2498
|
+
return (new libVES.VaultKey(ve.vaultKey,self.VES)).matchVaults(usrs).then(function(f) {
|
|
2499
|
+
if (!f) set_ves.push({vaultKey: {id: ve.vaultKey.id}, '$op': 'delete'});
|
|
2237
2500
|
});
|
|
2238
2501
|
}));
|
|
2239
2502
|
}).then(function() {
|
|
@@ -2242,11 +2505,20 @@ libVES.VaultItem.prototype = new libVES.Object({
|
|
|
2242
2505
|
});
|
|
2243
2506
|
});
|
|
2244
2507
|
}).then(function() {
|
|
2245
|
-
if (
|
|
2508
|
+
if (self.id && val != null) return self.setUpdate({id: false, type: true, file: {id: false, externals: {id: false, domain: true, externalId: true}}});
|
|
2509
|
+
}).then(function() {
|
|
2510
|
+
if (save || save === undefined) return self.post(undefined, undefined, ((save instanceof Object) ? save : undefined)).then(function(flds) {
|
|
2511
|
+
self.vaultEntryByKey = {};
|
|
2512
|
+
self.setFields(flds, false);
|
|
2246
2513
|
return self;
|
|
2514
|
+
}).finally(function() {
|
|
2515
|
+
delete(self.vaultEntries);
|
|
2247
2516
|
});
|
|
2248
2517
|
return self;
|
|
2249
|
-
})
|
|
2518
|
+
}).catch(function(er) {
|
|
2519
|
+
delete(self.vaultEntries);
|
|
2520
|
+
throw er;
|
|
2521
|
+
});
|
|
2250
2522
|
},
|
|
2251
2523
|
reshareWith: function(share,val,save) {
|
|
2252
2524
|
var self = this;
|
|
@@ -2269,6 +2541,15 @@ libVES.VaultItem.prototype = new libVES.Object({
|
|
|
2269
2541
|
});
|
|
2270
2542
|
});
|
|
2271
2543
|
},
|
|
2544
|
+
unshareWith: function(share, save) {
|
|
2545
|
+
return this.getShareVaultKeys().then((vkeys) => Promise.all(vkeys.map((vkey) => vkey.matchVaults(share))).then((del) => this.shareWith(vkeys.filter((vkey, i) => !del[i]), undefined, save)));
|
|
2546
|
+
},
|
|
2547
|
+
set: function(val, save) {
|
|
2548
|
+
var self = this;
|
|
2549
|
+
return self.getShareList().then(function(sh) {
|
|
2550
|
+
return self.shareWith(sh, val, save);
|
|
2551
|
+
});
|
|
2552
|
+
},
|
|
2272
2553
|
getShareVaultKeys: function() {
|
|
2273
2554
|
var self = this;
|
|
2274
2555
|
return this.getVaultEntries().then(function(vaultEntries) {
|
|
@@ -2281,12 +2562,17 @@ libVES.VaultItem.prototype = new libVES.Object({
|
|
|
2281
2562
|
var self = this;
|
|
2282
2563
|
return this.getShareVaultKeys().then(function(vaultKeys) {
|
|
2283
2564
|
var uids = {};
|
|
2565
|
+
var xids = {};
|
|
2284
2566
|
return Promise.all(vaultKeys.map(function(e,i) {
|
|
2285
2567
|
return e.getExternals().then(function(exts) {
|
|
2286
|
-
if (exts && exts.length) return exts[0]
|
|
2568
|
+
if (exts && exts.length) return exts[0].getId().then(function(xid) {
|
|
2569
|
+
if (!xid || xids[xid]) return null;
|
|
2570
|
+
xids[xid] = true;
|
|
2571
|
+
return exts[0];
|
|
2572
|
+
});
|
|
2287
2573
|
return e.getUser().then(function(u) {
|
|
2288
2574
|
return u.getId().then(function(uid) {
|
|
2289
|
-
if (uids[uid]) return null;
|
|
2575
|
+
if (!uid || uids[uid]) return null;
|
|
2290
2576
|
uids[uid] = true;
|
|
2291
2577
|
return u;
|
|
2292
2578
|
});
|
|
@@ -2298,6 +2584,12 @@ libVES.VaultItem.prototype = new libVES.Object({
|
|
|
2298
2584
|
return rs;
|
|
2299
2585
|
});
|
|
2300
2586
|
});
|
|
2587
|
+
},
|
|
2588
|
+
delete: function() {
|
|
2589
|
+
var self = this;
|
|
2590
|
+
return self.getId().then(function(id) {
|
|
2591
|
+
return self.VES.post(self.apiUri + '/' + id, {'$op': 'delete'});
|
|
2592
|
+
});
|
|
2301
2593
|
}
|
|
2302
2594
|
});
|
|
2303
2595
|
libVES.VaultItem.Type = {
|
|
@@ -2372,9 +2664,70 @@ libVES.External.prototype = new libVES.Object({
|
|
|
2372
2664
|
}
|
|
2373
2665
|
});
|
|
2374
2666
|
|
|
2667
|
+
|
|
2668
|
+
libVES.Event.prototype = new libVES.Object({
|
|
2669
|
+
apiUri: 'events',
|
|
2670
|
+
fieldList: {id: true, recordedAt: true, vaultKey: true, vaultItem: true, user: true},
|
|
2671
|
+
fieldClass: {vaultKey: libVES.VaultKey, vaultItem: libVES.VaultItem, user: libVES.User, creator: libVES.User, session: libVES.Session},
|
|
2672
|
+
getType: function() {
|
|
2673
|
+
return this.getField('type');
|
|
2674
|
+
},
|
|
2675
|
+
getVaultKey: function() {
|
|
2676
|
+
return this.getField('vaultKey');
|
|
2677
|
+
},
|
|
2678
|
+
getVaultItem: function() {
|
|
2679
|
+
return this.getField('vaultItem');
|
|
2680
|
+
},
|
|
2681
|
+
getUser: function() {
|
|
2682
|
+
return this.getField('user');
|
|
2683
|
+
},
|
|
2684
|
+
getCreator: function() {
|
|
2685
|
+
return this.getField('creator');
|
|
2686
|
+
},
|
|
2687
|
+
getSession: function() {
|
|
2688
|
+
return this.getField('session');
|
|
2689
|
+
}
|
|
2690
|
+
});
|
|
2691
|
+
|
|
2692
|
+
libVES.Session.prototype = new libVES.Object({
|
|
2693
|
+
apiUri: 'sessions',
|
|
2694
|
+
fieldList: {id: true, createdAt: true, expiresAt: true, vaultKey: true, user: true},
|
|
2695
|
+
fieldClass: {vaultKey: libVES.VaultKey, user: libVES.User},
|
|
2696
|
+
getVaultKey: function() {
|
|
2697
|
+
return this.getField('vaultKey');
|
|
2698
|
+
},
|
|
2699
|
+
getUser: function() {
|
|
2700
|
+
return this.getField('user');
|
|
2701
|
+
},
|
|
2702
|
+
getRemote: function() {
|
|
2703
|
+
return this.getField('remote');
|
|
2704
|
+
},
|
|
2705
|
+
getUserAgent: function() {
|
|
2706
|
+
return this.getField('userAgent');
|
|
2707
|
+
}
|
|
2708
|
+
});
|
|
2709
|
+
|
|
2710
|
+
libVES.Domain.prototype = new libVES.Object({
|
|
2711
|
+
apiUri: 'domains',
|
|
2712
|
+
fieldList: {id: true},
|
|
2713
|
+
fieldClass: {vaultKeys: libVES.VaultKey, vaultItems: libVES.VaultItem, creator: libVES.User},
|
|
2714
|
+
fieldSets: [{vaultItems: {id: true, type: true, file: {creator: true, externals: true}, deleted: true}, vaultKeys: {id: true, type: true, user: {id: true}, algo: true, externals: {id: true}}}],
|
|
2715
|
+
getCreator: function() {
|
|
2716
|
+
return this.getField('creator');
|
|
2717
|
+
},
|
|
2718
|
+
getVaultKeys: function() {
|
|
2719
|
+
return this.getField('vaultKeys');
|
|
2720
|
+
},
|
|
2721
|
+
getVaultItems: function() {
|
|
2722
|
+
return this.getField('vaultItems');
|
|
2723
|
+
}
|
|
2724
|
+
});
|
|
2725
|
+
|
|
2726
|
+
|
|
2375
2727
|
libVES.Algo = {
|
|
2376
2728
|
ECDH: {
|
|
2377
2729
|
tag: 'ECDH',
|
|
2730
|
+
defaultCurve: 'P-521',
|
|
2378
2731
|
decrypt: function(k,buf) {
|
|
2379
2732
|
var b = new Uint8Array(buf);
|
|
2380
2733
|
var data = libVES.Util.ASN1.decode(b);
|
|
@@ -2398,7 +2751,12 @@ libVES.Algo = {
|
|
|
2398
2751
|
return libVES.Algo.ECDH.eKey(k).then(function(eKey) {
|
|
2399
2752
|
return libVES.Algo.ECDH.cipher(eKey.privateKey,k).then(function(ci) {
|
|
2400
2753
|
return Promise.all([
|
|
2401
|
-
|
|
2754
|
+
((k instanceof CryptoKey)
|
|
2755
|
+
? crypto.subtle.exportKey('spki',eKey.publicKey)
|
|
2756
|
+
: libVES.Algo.ECDH.wasm().then(function(wasm) {
|
|
2757
|
+
return libVES.Util.Key.toPKCS(wasm.getpub(eKey.publicKey), null, libVES.Algo.ECDH.asn1hdr(wasm.getoid(eKey.publicKey)));
|
|
2758
|
+
})
|
|
2759
|
+
),
|
|
2402
2760
|
ci.encrypt(buf,true)
|
|
2403
2761
|
]).then(function(bufs) {
|
|
2404
2762
|
var buf = new Uint8Array(bufs[0].byteLength + bufs[1].byteLength);
|
|
@@ -2413,21 +2771,32 @@ libVES.Algo = {
|
|
|
2413
2771
|
});
|
|
2414
2772
|
},
|
|
2415
2773
|
eKey: function(pub) {
|
|
2416
|
-
return crypto.subtle.exportKey('jwk',pub).then(function(kdata) {
|
|
2774
|
+
if (pub instanceof CryptoKey) return crypto.subtle.exportKey('jwk',pub).then(function(kdata) {
|
|
2417
2775
|
return crypto.subtle.generateKey({name:'ECDH',namedCurve: kdata.crv},true,['deriveKey','deriveBits']).catch(function(e) {
|
|
2418
2776
|
throw new libVES.Error('InvalidValue','Error generating ECIES ephemeral',{error: e});
|
|
2419
2777
|
});
|
|
2420
2778
|
});
|
|
2779
|
+
return this.wasm().then(function(wasm) {
|
|
2780
|
+
var k = wasm.init(pub.curve);
|
|
2781
|
+
wasm.generate(k);
|
|
2782
|
+
return wasm.privpub(k);
|
|
2783
|
+
});
|
|
2421
2784
|
},
|
|
2422
|
-
|
|
2785
|
+
derive: function(priv, pub) {
|
|
2786
|
+
if (pub instanceof CryptoKey) return Promise.resolve(libVES.Algo.ECDH.curveBytes[pub.algorithm.namedCurve] || crypto.subtle.exportKey('jwk', pub).then(function(jwk) {
|
|
2787
|
+
return jwk.x.length * 3 / 4;
|
|
2788
|
+
})).then(function(len) {
|
|
2789
|
+
return crypto.subtle.deriveBits({name: 'ECDH', public: pub}, priv, 8 * len);
|
|
2790
|
+
});
|
|
2791
|
+
return this.wasm().then(function(wasm) {
|
|
2792
|
+
return wasm.derive(priv, pub);
|
|
2793
|
+
});
|
|
2794
|
+
},
|
|
2795
|
+
cipher: function(priv, pub) {
|
|
2423
2796
|
return libVES.getModule(libVES.Cipher,'AES256GCMp').then(function(m) {
|
|
2424
|
-
return
|
|
2425
|
-
return
|
|
2426
|
-
|
|
2427
|
-
return crypto.subtle.deriveBits({name:'ECDH',public:pub},priv,8 * len).then(function(raw) {
|
|
2428
|
-
return crypto.subtle.digest({name:'SHA-384'},raw).then(function(buf) {
|
|
2429
|
-
return new m(new Uint8Array(buf).slice(0,m.prototype.keySize + m.prototype.ivSize));
|
|
2430
|
-
});
|
|
2797
|
+
return libVES.Algo.ECDH.derive(priv, pub).then(function(raw) {
|
|
2798
|
+
return crypto.subtle.digest({name:'SHA-384'},raw).then(function(buf) {
|
|
2799
|
+
return new m(new Uint8Array(buf).slice(0,m.prototype.keySize + m.prototype.ivSize));
|
|
2431
2800
|
});
|
|
2432
2801
|
});
|
|
2433
2802
|
});
|
|
@@ -2462,13 +2831,22 @@ libVES.Algo = {
|
|
|
2462
2831
|
}).then(function(der) {
|
|
2463
2832
|
return libVES.Util.PEM.encode(der, 'PUBLIC KEY');
|
|
2464
2833
|
});
|
|
2465
|
-
}
|
|
2834
|
+
} else return this.wasm().then(function(wasm) {
|
|
2835
|
+
return libVES.Util.Key.export(wasm.getpub(data), wasm.getpriv(data), libVES.Algo.ECDH.asn1hdr(wasm.getoid(data)), optns);
|
|
2836
|
+
});
|
|
2466
2837
|
throw new libVES.Error('Internal', "Unknown type of key object");
|
|
2467
2838
|
},
|
|
2468
2839
|
generate: function(optns) {
|
|
2469
|
-
var op = {name:'ECDH', namedCurve:
|
|
2840
|
+
var op = {name: 'ECDH', namedCurve: this.defaultCurve};
|
|
2470
2841
|
if (optns) for (var k in optns) op[k] = optns[k];
|
|
2471
|
-
return crypto.subtle.generateKey(op,true,['deriveKey','deriveBits'])
|
|
2842
|
+
return crypto.subtle.generateKey(op, true, ['deriveKey', 'deriveBits']).catch(function(e) {
|
|
2843
|
+
console.log('ECDH generateKey failed, trying wasm...', e, op);
|
|
2844
|
+
return libVES.Algo.ECDH.wasm().then(function(wasm) {
|
|
2845
|
+
var k = wasm.init(op.namedCurve);
|
|
2846
|
+
if (!k || !wasm.generate(k)) throw new libVES.Error('InvalidValue', 'WasmECDH key generation error (unsupported curve?)');
|
|
2847
|
+
return wasm.privpub(k);
|
|
2848
|
+
});
|
|
2849
|
+
});
|
|
2472
2850
|
},
|
|
2473
2851
|
getPublic: function(priv) {
|
|
2474
2852
|
return crypto.subtle.exportKey('jwk',priv).then(function(k) {
|
|
@@ -2481,7 +2859,48 @@ libVES.Algo = {
|
|
|
2481
2859
|
y: k.y
|
|
2482
2860
|
},{name:'ECDH'},true,[]);
|
|
2483
2861
|
});
|
|
2484
|
-
}
|
|
2862
|
+
},
|
|
2863
|
+
getKeyOptions: function(key) {
|
|
2864
|
+
if (key instanceof CryptoKey) return crypto.subtle.exportKey('jwk', key).then(function(k) {
|
|
2865
|
+
return {namedCurve: k.crv};
|
|
2866
|
+
});
|
|
2867
|
+
return {namedCurve: k.curve};
|
|
2868
|
+
},
|
|
2869
|
+
asn1hdr: function(oid) {
|
|
2870
|
+
return [new libVES.Util.OID(this.OID), new libVES.Util.OID(oid)];
|
|
2871
|
+
},
|
|
2872
|
+
wasm: function() {
|
|
2873
|
+
if (!this.wasmP) this.wasmP = (typeof(WasmECDH) == 'function' ? Promise.resolve()
|
|
2874
|
+
: libVES.Util.loadWasm(WasmECDHinit.baseUrl + 'WasmECDH.js')
|
|
2875
|
+
).then(function() {
|
|
2876
|
+
return WasmECDH(WasmECDHinit);
|
|
2877
|
+
});
|
|
2878
|
+
return this.wasmP;
|
|
2879
|
+
},
|
|
2880
|
+
importWasm: function(curve, der) {
|
|
2881
|
+
return libVES.Algo.ECDH.wasm().then(function(wasm) {
|
|
2882
|
+
return libVES.Util.Key.fromDER(der, function(pub, priv, pubBits) {
|
|
2883
|
+
var k = wasm.init(curve);
|
|
2884
|
+
if (!k) return null;
|
|
2885
|
+
if (pub) wasm.setpub(k, pub);
|
|
2886
|
+
if (priv) wasm.setpriv(k, priv);
|
|
2887
|
+
return k;
|
|
2888
|
+
});
|
|
2889
|
+
});
|
|
2890
|
+
},
|
|
2891
|
+
getMethods: function() {
|
|
2892
|
+
var crvs = ['P-256', 'P-384', 'P-521'];
|
|
2893
|
+
return this.wasm().then(function(wasm) {
|
|
2894
|
+
return crvs.concat(wasm.getcurves());
|
|
2895
|
+
}).catch(function(e) {
|
|
2896
|
+
return crvs;
|
|
2897
|
+
}).then(function(crvs) {
|
|
2898
|
+
return crvs.map(function(algo) {
|
|
2899
|
+
return {namedCurve: algo};
|
|
2900
|
+
});
|
|
2901
|
+
});
|
|
2902
|
+
},
|
|
2903
|
+
OID: '1.2.840.10045.2.1'
|
|
2485
2904
|
},
|
|
2486
2905
|
RSA: {
|
|
2487
2906
|
tag: 'RSA',
|
|
@@ -2540,7 +2959,7 @@ libVES.Algo = {
|
|
|
2540
2959
|
throw new libVES.Error('Internal',"Unknown type of key object");
|
|
2541
2960
|
},
|
|
2542
2961
|
generate: function(optns) {
|
|
2543
|
-
var op = {name:'RSA-OAEP', modulusLength:
|
|
2962
|
+
var op = {name:'RSA-OAEP', modulusLength:4096, publicExponent:new Uint8Array([1,0,1]), hash:'SHA-256'};
|
|
2544
2963
|
if (optns) for (var k in optns) op[k] = optns[k];
|
|
2545
2964
|
return crypto.subtle.generateKey(op,true,['decrypt','encrypt']);
|
|
2546
2965
|
},
|
|
@@ -2553,9 +2972,25 @@ libVES.Algo = {
|
|
|
2553
2972
|
key_ops: ['encrypt'],
|
|
2554
2973
|
kty: 'RSA',
|
|
2555
2974
|
n: k.n
|
|
2556
|
-
},{name:'RSA-OAEP',hash:'SHA-
|
|
2975
|
+
},{name:'RSA-OAEP',hash:'SHA-256'},true,['encrypt']);
|
|
2557
2976
|
});
|
|
2558
|
-
}
|
|
2977
|
+
},
|
|
2978
|
+
getKeyOptions: function(key) {
|
|
2979
|
+
return crypto.subtle.exportKey('jwk', key).then(function(k) {
|
|
2980
|
+
return {modulusLength: ((k.n.length * 6) >> 3) * 8, publicExponent: libVES.Util.B64ToByteArray(k.e)};
|
|
2981
|
+
});
|
|
2982
|
+
},
|
|
2983
|
+
getMethods: function() {
|
|
2984
|
+
var bits = [];
|
|
2985
|
+
var s = 128;
|
|
2986
|
+
for (var i = 640; i <= 16384; i += s) {
|
|
2987
|
+
bits.push(i);
|
|
2988
|
+
if (i / s >= 8) s <<= 1;
|
|
2989
|
+
}
|
|
2990
|
+
return Promise.resolve(bits.map(function(b) {
|
|
2991
|
+
return {modulusLength: b};
|
|
2992
|
+
}));
|
|
2993
|
+
},
|
|
2559
2994
|
},
|
|
2560
2995
|
RSA_PKCS1_15: {
|
|
2561
2996
|
tag: 'RSA_PKCS1_15',
|
|
@@ -2592,9 +3027,107 @@ libVES.Algo = {
|
|
|
2592
3027
|
}
|
|
2593
3028
|
});
|
|
2594
3029
|
},
|
|
3030
|
+
fromKeyOptions: function(optns) {
|
|
3031
|
+
if (optns.namedCurve) return 'ECDH';
|
|
3032
|
+
if (optns.oqsAlgo) return 'OQS';
|
|
3033
|
+
if (optns.modulusLength) return 'RSA';
|
|
3034
|
+
},
|
|
2595
3035
|
toString: function() {
|
|
2596
3036
|
return 'libVES.Algo';
|
|
2597
|
-
}
|
|
3037
|
+
},
|
|
3038
|
+
all: ['RSA', 'ECDH']
|
|
3039
|
+
};
|
|
3040
|
+
|
|
3041
|
+
WasmECDHinit = {
|
|
3042
|
+
Key: function() {},
|
|
3043
|
+
init: function(curve) {
|
|
3044
|
+
var a = new Uint8Array(libVES.Util.StringToByteArray(curve));
|
|
3045
|
+
var arg1 = this.buf(a.byteLength + 1);
|
|
3046
|
+
arg1.set(a);
|
|
3047
|
+
arg1.set([0], a.byteLength);
|
|
3048
|
+
var ptr = this._WasmECDH_new(arg1.byteOffset);
|
|
3049
|
+
if (!ptr) return null;
|
|
3050
|
+
var key = new this.Key();
|
|
3051
|
+
key.ptr = ptr;
|
|
3052
|
+
key.curve = this.getcurve(key);
|
|
3053
|
+
return key;
|
|
3054
|
+
},
|
|
3055
|
+
buf: function(len) {
|
|
3056
|
+
return new Uint8Array(this.asm.memory.buffer, this._WasmECDH_buf, len);
|
|
3057
|
+
},
|
|
3058
|
+
str: function(ptr) {
|
|
3059
|
+
if (!ptr) return null;
|
|
3060
|
+
var b = new Uint8Array(this.asm.memory.buffer, ptr);
|
|
3061
|
+
return libVES.Util.ByteArrayToString(b.slice(0, b.indexOf(0)));
|
|
3062
|
+
},
|
|
3063
|
+
generate: function(key) {
|
|
3064
|
+
key.private = true;
|
|
3065
|
+
return this._WasmECDH_generate(key.ptr);
|
|
3066
|
+
},
|
|
3067
|
+
setpub: function(key, pub) {
|
|
3068
|
+
var arg1 = this.buf(pub.byteLength);
|
|
3069
|
+
arg1.set(pub);
|
|
3070
|
+
return this._WasmECDH_setpub(key.ptr, arg1.byteOffset, arg1.byteLength);
|
|
3071
|
+
},
|
|
3072
|
+
setpriv: function(key, priv) {
|
|
3073
|
+
key.private = true;
|
|
3074
|
+
var arg1 = this.buf(priv.byteLength);
|
|
3075
|
+
arg1.set(priv);
|
|
3076
|
+
return this._WasmECDH_setpriv(key.ptr, arg1.byteOffset, arg1.byteLength);
|
|
3077
|
+
},
|
|
3078
|
+
getpub: function(key) {
|
|
3079
|
+
var l = this._WasmECDH_getpub(key.ptr);
|
|
3080
|
+
if (l <= 0) return null;
|
|
3081
|
+
var rs = new Uint8Array(l);
|
|
3082
|
+
rs.set(this.buf(l));
|
|
3083
|
+
return rs;
|
|
3084
|
+
},
|
|
3085
|
+
getpriv: function(key) {
|
|
3086
|
+
if (!key.private) return null;
|
|
3087
|
+
var l = this._WasmECDH_getpriv(key.ptr);
|
|
3088
|
+
if (l <= 0) return null;
|
|
3089
|
+
var rs = new Uint8Array(l);
|
|
3090
|
+
rs.set(this.buf(l));
|
|
3091
|
+
return rs;
|
|
3092
|
+
},
|
|
3093
|
+
getcurve: function(key) {
|
|
3094
|
+
return this.str(this._WasmECDH_getcurve(key.ptr));
|
|
3095
|
+
},
|
|
3096
|
+
getoid: function(key) {
|
|
3097
|
+
return this.str(this._WasmECDH_getoid(key.ptr));
|
|
3098
|
+
},
|
|
3099
|
+
derive: function(priv, pub) {
|
|
3100
|
+
var l = this._WasmECDH_derive(priv.ptr, pub.ptr);
|
|
3101
|
+
if (l <= 0) return null;
|
|
3102
|
+
var rs = new Uint8Array(l);
|
|
3103
|
+
rs.set(this.buf(l));
|
|
3104
|
+
return rs;
|
|
3105
|
+
},
|
|
3106
|
+
privpub: function(priv) {
|
|
3107
|
+
var pub = new this.Key();
|
|
3108
|
+
pub.ptr = priv.ptr;
|
|
3109
|
+
pub.curve = priv.curve;
|
|
3110
|
+
return {privateKey: priv, publicKey: pub};
|
|
3111
|
+
},
|
|
3112
|
+
free: function(key) {
|
|
3113
|
+
this._WasmECDH_free(key.ptr);
|
|
3114
|
+
},
|
|
3115
|
+
getcurves: function() {
|
|
3116
|
+
var lst = this._WasmECDH_listinit(1024);
|
|
3117
|
+
var crvs = [];
|
|
3118
|
+
var c;
|
|
3119
|
+
for (var i = 0; (c = this._WasmECDH_listget(lst, i)); i++) {
|
|
3120
|
+
var crv = this.str(c);
|
|
3121
|
+
if (crv == '') continue;
|
|
3122
|
+
crvs.push(crv);
|
|
3123
|
+
}
|
|
3124
|
+
this._WasmECDH_listfree(lst);
|
|
3125
|
+
return crvs;
|
|
3126
|
+
},
|
|
3127
|
+
locateFile: function(file) {
|
|
3128
|
+
return this.baseUrl + file;
|
|
3129
|
+
},
|
|
3130
|
+
baseUrl: 'https://ves.host/pub/'
|
|
2598
3131
|
};
|
|
2599
3132
|
|
|
2600
3133
|
libVES.Cipher = function(data) {
|
|
@@ -3142,10 +3675,14 @@ libVES.Recovery.prototype = {
|
|
|
3142
3675
|
return this.getMyToken().then(function(tkn) {
|
|
3143
3676
|
if (!tkn) throw new libVES.Error('InvalidValue','No assistance available');
|
|
3144
3677
|
return self.vaultKey.getUser().then(function(user) {
|
|
3145
|
-
return
|
|
3146
|
-
|
|
3147
|
-
|
|
3148
|
-
return
|
|
3678
|
+
return self.vaultKey.VES.elevateAuth().catch(function(e) {
|
|
3679
|
+
return undefined;
|
|
3680
|
+
}).then(function(optns) {
|
|
3681
|
+
return tkn.vaultItem.shareWith((assist ? [tkn.user,user] : [tkn.user]), undefined, optns).then(function() {
|
|
3682
|
+
self.tokens = undefined;
|
|
3683
|
+
self.vaultKey.vaultItems = undefined;
|
|
3684
|
+
return true;
|
|
3685
|
+
});
|
|
3149
3686
|
});
|
|
3150
3687
|
});
|
|
3151
3688
|
});
|
|
@@ -3394,7 +3931,7 @@ libVES.Flow.prototype.pubJWK = function(org) {
|
|
|
3394
3931
|
return libVES.Flow.jwkPub(jwk);
|
|
3395
3932
|
});
|
|
3396
3933
|
}) : Promise.resolve(sessionStorage['VESflow|' + org]).then(function(k) {
|
|
3397
|
-
if (!k) throw
|
|
3934
|
+
if (!k) throw new libVES.Error('NotFound', 'No public key stored for ' + org);
|
|
3398
3935
|
return JSON.parse(k);
|
|
3399
3936
|
}));
|
|
3400
3937
|
};
|
|
@@ -3421,7 +3958,7 @@ libVES.Flow.prototype.cipher = function(url) {
|
|
|
3421
3958
|
libVES.Flow.prototype.encrypt = function(url, val) {
|
|
3422
3959
|
var self = this;
|
|
3423
3960
|
return Promise.resolve(val || this.value()).then(function(val) {
|
|
3424
|
-
if (val == null) throw
|
|
3961
|
+
if (val == null) throw new libVES.Error('NoData', 'Empty value');
|
|
3425
3962
|
return self.cipher(url).then(function(ci) {
|
|
3426
3963
|
var iv = new Uint8Array(12);
|
|
3427
3964
|
crypto.getRandomValues(iv);
|
|
@@ -3512,7 +4049,7 @@ libVES.Flow.prototype.recv = function(dval) {
|
|
|
3512
4049
|
tk = t;
|
|
3513
4050
|
return true;
|
|
3514
4051
|
});
|
|
3515
|
-
if (tk == null) throw
|
|
4052
|
+
if (tk == null) throw new libVES.Error('NotFound', 'No valid token in the source url');
|
|
3516
4053
|
return Promise.resolve(self.source(src)).then(function() {
|
|
3517
4054
|
if (dval) for (var k in dval) if (tk[k] === undefined) tk[k] = dval[k];
|
|
3518
4055
|
return self.recvToken(tk);
|
|
@@ -3523,7 +4060,7 @@ libVES.Flow.prototype.recv = function(dval) {
|
|
|
3523
4060
|
libVES.Flow.prototype.recvToken = function(tk) {
|
|
3524
4061
|
var org = libVES.Flow.toOrigin(tk.url);
|
|
3525
4062
|
if (org != this.origin && tk.key) sessionStorage['VESflow|' + org] = JSON.stringify(tk.key);
|
|
3526
|
-
if (!tk.enc) return Promise.reject(
|
|
4063
|
+
if (!tk.enc) return Promise.reject(new libVES.Error('Incomplete', 'Missing encrypted data', {url: tk.url}));
|
|
3527
4064
|
return this.decrypt(tk.enc, org);
|
|
3528
4065
|
};
|
|
3529
4066
|
|
|
@@ -3538,7 +4075,7 @@ libVES.Flow.prototype.get = function() {
|
|
|
3538
4075
|
self.url = document.location.href;
|
|
3539
4076
|
return self.addToken(e.url).then(function(url) {
|
|
3540
4077
|
document.location.replace(url);
|
|
3541
|
-
throw
|
|
4078
|
+
throw new libVES.Error('Redirect', 'Completing the key exchange');
|
|
3542
4079
|
});
|
|
3543
4080
|
}
|
|
3544
4081
|
if (!data) throw e;
|
|
@@ -3552,13 +4089,13 @@ libVES.Flow.prototype.store = function(url) {
|
|
|
3552
4089
|
this.sent = 1;
|
|
3553
4090
|
return Promise.resolve(sessionStorage['VESflow.' + this.name + '>' + libVES.Flow.toOrigin(url)] = history.state['VESflow.' + this.name]);
|
|
3554
4091
|
}
|
|
3555
|
-
return Promise.reject(
|
|
4092
|
+
return Promise.reject(new libVES.Error('NotFound', 'Value is not set'));
|
|
3556
4093
|
};
|
|
3557
4094
|
|
|
3558
4095
|
libVES.Flow.prototype.fetch = function(url) {
|
|
3559
4096
|
var self = this;
|
|
3560
4097
|
return Promise.resolve(sessionStorage['VESflow.' + self.name + '>' + libVES.Flow.toOrigin(url)]).then(function(ctext) {
|
|
3561
|
-
if (!ctext) throw
|
|
4098
|
+
if (!ctext) throw new libVES.Error('NotFound', 'Not in the session storage');
|
|
3562
4099
|
return self.decrypt(ctext).then(function(data) {
|
|
3563
4100
|
self.erase(url);
|
|
3564
4101
|
return data;
|
|
@@ -3678,19 +4215,16 @@ libVES.Auth.prototype.verify = function(token, auth) {
|
|
|
3678
4215
|
libVES.Algo.OQS = {
|
|
3679
4216
|
tag: 'OQS',
|
|
3680
4217
|
wasm: function() {
|
|
3681
|
-
if (!this.wasmP) this.wasmP =
|
|
3682
|
-
|
|
3683
|
-
|
|
3684
|
-
sc.async = false;
|
|
3685
|
-
sc.src = WasmOQSinit.baseUrl + 'WasmOQS.js';
|
|
3686
|
-
sc.onload = resolve;
|
|
3687
|
-
sc.onerror = reject;
|
|
3688
|
-
document.getElementsByTagName('head')[0].appendChild(sc);
|
|
3689
|
-
}).then(function() {
|
|
4218
|
+
if (!this.wasmP) this.wasmP = (typeof(WasmOQS) == 'function' ? Promise.resolve()
|
|
4219
|
+
: libVES.Util.loadWasm(WasmOQSinit.baseUrl + 'WasmOQS.js')
|
|
4220
|
+
).then(function() {
|
|
3690
4221
|
return WasmOQS(WasmOQSinit);
|
|
3691
4222
|
});
|
|
3692
4223
|
return this.wasmP;
|
|
3693
4224
|
},
|
|
4225
|
+
checkLimits: function(k) {
|
|
4226
|
+
return k.pub.byteLength + k.priv.byteLength <= libVES.maxKeyLen && k.ctextlen + 64 <= libVES.maxEncDataLen;
|
|
4227
|
+
},
|
|
3694
4228
|
decrypt: function(k,buf) {
|
|
3695
4229
|
return this.wasm().then(function(wasm) {
|
|
3696
4230
|
var b = new Uint8Array(buf);
|
|
@@ -3737,56 +4271,54 @@ libVES.Algo.OQS = {
|
|
|
3737
4271
|
},
|
|
3738
4272
|
export: function(data, optns) {
|
|
3739
4273
|
if (!data || !data.ptr) throw new libVES.Error('Internal', "Unknown type of key object");
|
|
3740
|
-
var pub = new Uint8Array(data.pub.byteLength + 1);
|
|
3741
|
-
pub[0] = 0;
|
|
3742
|
-
pub.set(new Uint8Array(data.pub), 1);
|
|
3743
|
-
pub.ASN1type = 3;
|
|
3744
4274
|
var oid = [new libVES.Util.OID(libVES.Algo.OQS.OID), libVES.Util.StringToByteArray(data.algo)];
|
|
3745
|
-
|
|
3746
|
-
pub = libVES.Util.ASN1.encode([pub]);
|
|
3747
|
-
pub.ASN1type = 0xa1;
|
|
3748
|
-
var buf = libVES.Util.ASN1.encode([[1, data.priv, pub]]);
|
|
3749
|
-
var pkcs8 = libVES.Util.ASN1.encode([[0, oid, buf]]);
|
|
3750
|
-
return libVES.Util.PKCS8.encode8(pkcs8, optns);
|
|
3751
|
-
}
|
|
3752
|
-
return libVES.Util.PEM.encode(libVES.Util.ASN1.encode([[oid, pub]]), 'PUBLIC KEY');
|
|
4275
|
+
return libVES.Util.Key.export(data.pub, data.priv, oid, optns);
|
|
3753
4276
|
},
|
|
3754
4277
|
generate: function(optns) {
|
|
3755
|
-
var algo = optns ? optns.
|
|
4278
|
+
var algo = optns ? optns.oqsAlgo : null;
|
|
3756
4279
|
if (!algo) algo = this.defaultAlgo;
|
|
3757
4280
|
return this.wasm().then(function(wasm) {
|
|
3758
4281
|
var k = wasm.init(algo, true);
|
|
3759
4282
|
if (!k) throw new libVES.Error('InvalidValue', 'OQS key init failed');
|
|
3760
|
-
if (!
|
|
3761
|
-
|
|
4283
|
+
if (!libVES.Algo.OQS.checkLimits(k)) throw wasm.free(k), new libVES.Error('Internal', 'OQS key is too large for VES');
|
|
4284
|
+
if (!wasm.generate(k)) throw wasm.free(k), new libVES.Error('Internal', 'OQS generate failed');
|
|
4285
|
+
var pub = new wasm.Key(k.algo);
|
|
3762
4286
|
for (var i in k) if (i != 'priv') pub[i] = k[i];
|
|
3763
4287
|
return {privateKey: k, publicKey: pub};
|
|
3764
4288
|
});
|
|
3765
4289
|
},
|
|
4290
|
+
getKeyOptions: function(key) {
|
|
4291
|
+
return {oqsAlgo: k.algo};
|
|
4292
|
+
},
|
|
4293
|
+
getMethods: function() {
|
|
4294
|
+
return this.wasm().then(function(wasm) {
|
|
4295
|
+
return wasm.getalgos().filter(function(algo) {
|
|
4296
|
+
var k = wasm.init(algo, true);
|
|
4297
|
+
if (!k) return false;
|
|
4298
|
+
var f = libVES.Algo.OQS.checkLimits(k);
|
|
4299
|
+
wasm.free(k);
|
|
4300
|
+
return f;
|
|
4301
|
+
}).map(function(algo) {
|
|
4302
|
+
return {oqsAlgo: algo};
|
|
4303
|
+
});
|
|
4304
|
+
});
|
|
4305
|
+
},
|
|
3766
4306
|
Util: {
|
|
3767
4307
|
import: function(args,chain,optns) {
|
|
3768
4308
|
var algo = libVES.Util.ByteArrayToString(args);
|
|
3769
4309
|
return chain('container').then(function(der) {
|
|
3770
|
-
|
|
3771
|
-
|
|
3772
|
-
|
|
3773
|
-
|
|
3774
|
-
|
|
3775
|
-
|
|
3776
|
-
|
|
3777
|
-
|
|
3778
|
-
|
|
3779
|
-
|
|
3780
|
-
|
|
3781
|
-
|
|
3782
|
-
if (!dst || !src || dst.byteLength != src.byteLength - dif) throw new libVES.Error('InvalidValue', 'Incorrect OQS key size');
|
|
3783
|
-
dst.set(src.slice(dif), 0);
|
|
3784
|
-
};
|
|
3785
|
-
if (pub) {
|
|
3786
|
-
s(k.priv, pkey, 0);
|
|
3787
|
-
s(k.pub, pub, 1);
|
|
3788
|
-
} else s(k.pub, pkey, 1);
|
|
3789
|
-
return k;
|
|
4310
|
+
return libVES.Util.Key.fromDER(der, function(pub, priv, pubBits) {
|
|
4311
|
+
return libVES.Algo.OQS.wasm().then(function(wasm) {
|
|
4312
|
+
var k = wasm.init(algo, !!priv);
|
|
4313
|
+
if (!k) throw new libVES.Error('InvalidValue', 'OQS key init failed (bad algo?)');
|
|
4314
|
+
var s = function(dst, src) {
|
|
4315
|
+
if (!dst || !src || dst.byteLength != src.byteLength) throw wasm.free(k), new libVES.Error('InvalidValue', 'Incorrect OQS key size');
|
|
4316
|
+
dst.set(src, 0);
|
|
4317
|
+
};
|
|
4318
|
+
if (priv) s(k.priv, priv);
|
|
4319
|
+
s(k.pub, pub);
|
|
4320
|
+
return k;
|
|
4321
|
+
});
|
|
3790
4322
|
});
|
|
3791
4323
|
});
|
|
3792
4324
|
}
|
|
@@ -3794,59 +4326,76 @@ libVES.Algo.OQS = {
|
|
|
3794
4326
|
OID: '1.3.6.1.4.1.53675.3.5',
|
|
3795
4327
|
defaultAlgo: 'Kyber768'
|
|
3796
4328
|
};
|
|
4329
|
+
libVES.Algo.all.push('OQS');
|
|
3797
4330
|
|
|
3798
4331
|
var WasmOQSinit = {
|
|
3799
|
-
|
|
3800
|
-
|
|
3801
|
-
|
|
3802
|
-
|
|
3803
|
-
|
|
3804
|
-
|
|
3805
|
-
|
|
3806
|
-
|
|
3807
|
-
|
|
3808
|
-
|
|
3809
|
-
|
|
3810
|
-
|
|
3811
|
-
|
|
3812
|
-
|
|
3813
|
-
|
|
4332
|
+
Key: function(algo) {
|
|
4333
|
+
this.algo = algo;
|
|
4334
|
+
},
|
|
4335
|
+
init: function(algo, fpriv) {
|
|
4336
|
+
var a = new Uint8Array(libVES.Util.StringToByteArray(algo));
|
|
4337
|
+
var arg1 = new Uint8Array(this.asm.memory.buffer, 16, 48);
|
|
4338
|
+
arg1.set(a);
|
|
4339
|
+
arg1.set([0], a.byteLength);
|
|
4340
|
+
var ptr = this._WasmOQS_new(arg1.byteOffset, fpriv);
|
|
4341
|
+
if (!ptr) return null;
|
|
4342
|
+
var key = new this.Key(algo);
|
|
4343
|
+
key.ptr = ptr;
|
|
4344
|
+
var priv = this._WasmOQS_priv(ptr);
|
|
4345
|
+
if (priv) key.priv = new Uint8Array(this.asm.memory.buffer, priv, this._WasmOQS_privlen(ptr));
|
|
4346
|
+
key.pub = new Uint8Array(this.asm.memory.buffer, this._WasmOQS_pub(ptr), this._WasmOQS_publen(ptr));
|
|
4347
|
+
key.secretlen = this._WasmOQS_decaps(key.ptr, null, null);
|
|
4348
|
+
key.ctextlen = this._WasmOQS_encaps(key.ptr, null, null);
|
|
4349
|
+
return key;
|
|
3814
4350
|
},
|
|
3815
4351
|
generate: function(key) {
|
|
3816
|
-
|
|
4352
|
+
return this._WasmOQS_generate(key.ptr) >= 0;
|
|
3817
4353
|
},
|
|
3818
4354
|
encaps: function(key) {
|
|
3819
|
-
|
|
3820
|
-
|
|
3821
|
-
|
|
3822
|
-
|
|
3823
|
-
|
|
3824
|
-
|
|
3825
|
-
|
|
3826
|
-
|
|
4355
|
+
var arg1 = new Uint8Array(this.asm.memory.buffer, this._WasmOQS_secretbuf, this._WasmOQS_decaps(key.ptr, null, null));
|
|
4356
|
+
var arg2 = new Uint8Array(this.asm.memory.buffer, this._WasmOQS_ctextbuf, this._WasmOQS_encaps(key.ptr, null, null));
|
|
4357
|
+
if (this._WasmOQS_encaps(key.ptr, arg2.byteOffset, arg1.byteOffset) <= 0) return null;
|
|
4358
|
+
key.secret = new Uint8Array(arg1.byteLength);
|
|
4359
|
+
key.secret.set(arg1);
|
|
4360
|
+
var ctext = new Uint8Array(arg2.byteLength);
|
|
4361
|
+
ctext.set(arg2);
|
|
4362
|
+
return ctext;
|
|
3827
4363
|
},
|
|
3828
4364
|
decaps: function(key, ctext) {
|
|
3829
|
-
|
|
3830
|
-
|
|
3831
|
-
|
|
3832
|
-
|
|
3833
|
-
|
|
3834
|
-
|
|
3835
|
-
|
|
3836
|
-
|
|
3837
|
-
|
|
4365
|
+
var arg1 = new Uint8Array(this.asm.memory.buffer, this._WasmOQS_secretbuf, this._WasmOQS_decaps(key.ptr, null, null));
|
|
4366
|
+
if (ctext) {
|
|
4367
|
+
if (ctext.byteLength != this._WasmOQS_encaps(key.ptr, null, null)) return null;
|
|
4368
|
+
var arg2 = new Uint8Array(this.asm.memory.buffer, this._WasmOQS_ctextbuf, ctext.byteLength);
|
|
4369
|
+
arg2.set(ctext);
|
|
4370
|
+
if (this._WasmOQS_decaps(key.ptr, arg1.byteOffset, arg2.byteOffset) <= 0) return null;
|
|
4371
|
+
}
|
|
4372
|
+
var secret = new Uint8Array(arg1.byteLength);
|
|
4373
|
+
secret.set(arg1);
|
|
4374
|
+
return secret;
|
|
3838
4375
|
},
|
|
3839
4376
|
free: function(key) {
|
|
3840
|
-
|
|
4377
|
+
this._WasmOQS_free(key.ptr);
|
|
4378
|
+
delete(key.ptr);
|
|
4379
|
+
},
|
|
4380
|
+
getalgos: function() {
|
|
4381
|
+
var algos = [];
|
|
4382
|
+
var a;
|
|
4383
|
+
for (var i = 0; a = this._WasmOQS_enumalgo(i); i++) {
|
|
4384
|
+
var s = new Uint8Array(this.asm.memory.buffer, a);
|
|
4385
|
+
var p = s.indexOf(0);
|
|
4386
|
+
if (!p) continue;
|
|
4387
|
+
algos.push(libVES.Util.ByteArrayToString(s.slice(0, p)));
|
|
4388
|
+
}
|
|
4389
|
+
return algos;
|
|
3841
4390
|
},
|
|
3842
4391
|
test: function(algo) {
|
|
3843
|
-
|
|
3844
|
-
|
|
3845
|
-
|
|
3846
|
-
|
|
3847
|
-
|
|
3848
|
-
|
|
3849
|
-
|
|
4392
|
+
var k = this.init(algo, 1);
|
|
4393
|
+
this.generate(k);
|
|
4394
|
+
var ctext = this.encaps(k);
|
|
4395
|
+
var secret = this.decaps(k);
|
|
4396
|
+
console.log(secret);
|
|
4397
|
+
var secret2 = this.decaps(k, ctext);
|
|
4398
|
+
console.log(secret2);
|
|
3850
4399
|
},
|
|
3851
4400
|
locateFile: function(file) {
|
|
3852
4401
|
return this.baseUrl + file;
|
|
@@ -3854,4 +4403,873 @@ var WasmOQSinit = {
|
|
|
3854
4403
|
baseUrl: 'https://ves.host/pub/'
|
|
3855
4404
|
};
|
|
3856
4405
|
|
|
4406
|
+
|
|
4407
|
+
|
|
4408
|
+
libVES.Watch = function(obj, optns) {
|
|
4409
|
+
if (obj instanceof libVES) obj = obj.domain ? (obj.externalId ? obj.getVaultKey() : new libVES.Domain(null, obj)) : obj.me();
|
|
4410
|
+
var self = this;
|
|
4411
|
+
this.object = Promise.resolve(obj).then(function(o) {
|
|
4412
|
+
if (o instanceof libVES.VaultKey) {
|
|
4413
|
+
self.uri = 'vaultKeys/';
|
|
4414
|
+
} else if (o instanceof libVES.VaultItem) {
|
|
4415
|
+
self.uri = 'vaultItems/';
|
|
4416
|
+
} else if (o instanceof libVES.User) {
|
|
4417
|
+
self.uri = 'users/';
|
|
4418
|
+
} else if (o instanceof libVES.Domain) {
|
|
4419
|
+
self.uri = 'domains/';
|
|
4420
|
+
} else {
|
|
4421
|
+
throw new libVES.Error('Internal', 'Watchable object expected');
|
|
4422
|
+
}
|
|
4423
|
+
self.VES = o.VES;
|
|
4424
|
+
return o;
|
|
4425
|
+
});
|
|
4426
|
+
if (optns) for (var k in optns) this[k] = optns[k];
|
|
4427
|
+
};
|
|
4428
|
+
|
|
4429
|
+
libVES.Watch.prototype = {
|
|
4430
|
+
fields: {vaultKey: {id: true, user: true, externals: true, creator: true}, vaultItem: {id: true, vaultKey: true, file: {externals: true, creator: true}}, session: {id: true, userAgent: true, remote: true, createdAt: true, expiresAt: true}},
|
|
4431
|
+
state: 'idle',
|
|
4432
|
+
timeout: 900,
|
|
4433
|
+
getEvents: function(start, ct, poll) {
|
|
4434
|
+
var self = this;
|
|
4435
|
+
return self.object.then(function(o) {
|
|
4436
|
+
return o.getId().then(function(id) {
|
|
4437
|
+
return (poll ? self.VES.pollUrl : '') + self.uri + id
|
|
4438
|
+
+ '?fields=events(' + self.VES.uriListFields(self.fields) + ')%5B' + start + (ct >= 0 ? '%2B' : '') + ct + '%5D'
|
|
4439
|
+
+ (poll ? '&poll=' + self.timeout : '');
|
|
4440
|
+
});
|
|
4441
|
+
}).then(function(url) {
|
|
4442
|
+
return self.VES.get(url);
|
|
4443
|
+
}).then(function(res) {
|
|
4444
|
+
if (!res.events) return null;
|
|
4445
|
+
return res.events.map(function(e, i) {
|
|
4446
|
+
return new libVES.Event(libVES.Util.fillUndefs(e, self.fields), self.VES);
|
|
4447
|
+
});
|
|
4448
|
+
});
|
|
4449
|
+
},
|
|
4450
|
+
setState: function(st) {
|
|
4451
|
+
if (this.statefn) try {
|
|
4452
|
+
this.statefn(st, this);
|
|
4453
|
+
} catch(e) {}
|
|
4454
|
+
this.state = st;
|
|
4455
|
+
},
|
|
4456
|
+
setBusy: function(busy) {
|
|
4457
|
+
this.busy = busy;
|
|
4458
|
+
if (!busy && this.state == 'stop') this.setState('idle');
|
|
4459
|
+
},
|
|
4460
|
+
start: function(pos) {
|
|
4461
|
+
if (!this.eventfn) return Promise.reject(new libVES.Error('InvalidValue', 'eventfn is not set'));
|
|
4462
|
+
if (this.busy) return Promise.reject(new libVES.Error('Internal', 'Watch instance is busy'));
|
|
4463
|
+
var self = this;
|
|
4464
|
+
self.setBusy(true);
|
|
4465
|
+
this.setState('read');
|
|
4466
|
+
if (pos < 0) {
|
|
4467
|
+
this.next = 0;
|
|
4468
|
+
return this.getEvents(0, pos).then(function(evs) {
|
|
4469
|
+
self.setBusy(false);
|
|
4470
|
+
return self.received(evs ? evs.reverse() : null);
|
|
4471
|
+
}).finally(function() {
|
|
4472
|
+
self.setBusy(false);
|
|
4473
|
+
});
|
|
4474
|
+
} else {
|
|
4475
|
+
this.next = pos;
|
|
4476
|
+
return this.getEvents(pos, 0).then(function(evs) {
|
|
4477
|
+
self.setBusy(false);
|
|
4478
|
+
return self.received(evs);
|
|
4479
|
+
}).finally(function() {
|
|
4480
|
+
self.setBusy(false);
|
|
4481
|
+
});
|
|
4482
|
+
}
|
|
4483
|
+
},
|
|
4484
|
+
active: function() {
|
|
4485
|
+
return this.state == 'read' || this.state == 'poll';
|
|
4486
|
+
},
|
|
4487
|
+
received: function(evs) {
|
|
4488
|
+
var self = this;
|
|
4489
|
+
var p;
|
|
4490
|
+
if (!evs) return null;
|
|
4491
|
+
if (evs.length) return evs.reduce(function(v, ev) {
|
|
4492
|
+
if (self.active()) try {
|
|
4493
|
+
self.eventfn(ev, self);
|
|
4494
|
+
} catch(e) {
|
|
4495
|
+
console.log(e);
|
|
4496
|
+
}
|
|
4497
|
+
return ev;
|
|
4498
|
+
}, null).getId().then(function(id) {
|
|
4499
|
+
self.next = id + 1;
|
|
4500
|
+
return self.request();
|
|
4501
|
+
});
|
|
4502
|
+
else {
|
|
4503
|
+
if (this.state == 'read') this.setState('poll');
|
|
4504
|
+
return self.request(), true;
|
|
4505
|
+
}
|
|
4506
|
+
},
|
|
4507
|
+
request: function() {
|
|
4508
|
+
if (this.busy || !this.active()) return true;
|
|
4509
|
+
var self = this;
|
|
4510
|
+
self.setBusy(true);
|
|
4511
|
+
return self.getEvents(self.next, 0, (self.state == 'poll')).then(function(evs) {
|
|
4512
|
+
self.setBusy(false);
|
|
4513
|
+
return self.received(evs);
|
|
4514
|
+
}).catch(function(e) {
|
|
4515
|
+
self.setBusy(false);
|
|
4516
|
+
if (self.errorfn) try {
|
|
4517
|
+
self.errorfn(e, self);
|
|
4518
|
+
} catch(e) {
|
|
4519
|
+
console.log(e);
|
|
4520
|
+
}
|
|
4521
|
+
return self.retry();
|
|
4522
|
+
});
|
|
4523
|
+
},
|
|
4524
|
+
retry: function() {
|
|
4525
|
+
var self = this;
|
|
4526
|
+
return new Promise(function(resolve, reject) {
|
|
4527
|
+
window.setTimeout(function() {
|
|
4528
|
+
resolve(self.request());
|
|
4529
|
+
}, 1000);
|
|
4530
|
+
});
|
|
4531
|
+
},
|
|
4532
|
+
stop: function() {
|
|
4533
|
+
this.setState(this.busy ? 'stop' : 'idle');
|
|
4534
|
+
}
|
|
4535
|
+
};
|
|
4536
|
+
|
|
4537
|
+
|
|
4538
|
+
|
|
4539
|
+
libVES.subtle = function(optns) {
|
|
4540
|
+
if (!(optns instanceof Object)) {
|
|
4541
|
+
let uri = String(optns);
|
|
4542
|
+
optns = uri.includes('/') ? libVES.Vault.toRef(uri) : {domain: uri};
|
|
4543
|
+
}
|
|
4544
|
+
return new libVES(optns).subtle();
|
|
4545
|
+
};
|
|
4546
|
+
|
|
4547
|
+
libVES.prototype.subtle = function(ref) {
|
|
4548
|
+
return new libVES.Vault((ref || this), this);
|
|
4549
|
+
};
|
|
4550
|
+
|
|
4551
|
+
libVES.EventTarget = class extends EventTarget {
|
|
4552
|
+
watchFields() {
|
|
4553
|
+
return {vaultKey: {id: true, user: {id: true, email: true}, externals: {domain: true, externalId: true}}, vaultItem: {id: true, type: true, deleted: true, vaultKey: {id: true, type: true, externals: {domain: true, externalId: true}, user: {id: true, email: true}}, file: {externals: {domain: true, externalId: true}, creator: true}}, authorSession: {id: true, vaultKey: {id: true, type: true, externals: {domain: true, externalId: true}}, domain: true, user: {email: true}, remote: true, userAgent: true}, session: {id: true, vaultKey: {id: true}, user: {id: true}, remote: true, userAgent: true}};
|
|
4554
|
+
}
|
|
4555
|
+
|
|
4556
|
+
dispatchEvent(ev) {
|
|
4557
|
+
if (!ev) return;
|
|
4558
|
+
super.dispatchEvent(ev);
|
|
4559
|
+
if (this['on' + ev.type]) try { this['on' + ev.type](ev) } catch (er) { console.log(er); }
|
|
4560
|
+
}
|
|
4561
|
+
|
|
4562
|
+
start(optns) {
|
|
4563
|
+
if (!this.watch) {
|
|
4564
|
+
let tr = this._eventTracker();
|
|
4565
|
+
if (optns === false) optns = {replay: true};
|
|
4566
|
+
else if (optns != null && !isNaN(optns)) optns = {startEvent: Number(optns)};
|
|
4567
|
+
else if (!(optns instanceof Object)) optns = {};
|
|
4568
|
+
if (optns.startEvent == null) optns.startEvent = -1;
|
|
4569
|
+
this.watch = this.createWatch(optns);
|
|
4570
|
+
this.watch.eventfn = (ev) => (this.eventClear = this.eventClear.then(() => tr._event(ev).then((ev) => this.dispatchEvent(ev)).catch((er) => console.log(er))));
|
|
4571
|
+
this.eventClear = optns.replay ? this.replay((optns.replay instanceof Object) ? optns.replay : optns).then((evs) => Promise.all(evs.map((ev) => this.dispatchEvent(ev)))) : Promise.resolve();
|
|
4572
|
+
return this.watch.start(optns.startEvent).then((v) => (v || this.badauth().then(() => this.watch.start(startEvent)))).catch((er) => {
|
|
4573
|
+
this.watch = null;
|
|
4574
|
+
throw er;
|
|
4575
|
+
});
|
|
4576
|
+
} else throw new libVES.Error.InvalidValue('The watch is already started');
|
|
4577
|
+
}
|
|
4578
|
+
|
|
4579
|
+
stop() {
|
|
4580
|
+
if (this.watch) return Promise.resolve(this.watch.stop()).then(() => this.eventClear).then(() => true).finally(() => this.watch = null);
|
|
4581
|
+
return Promise.resolve(null);
|
|
4582
|
+
}
|
|
4583
|
+
|
|
4584
|
+
events(optns) {
|
|
4585
|
+
let tr = this._eventTracker();
|
|
4586
|
+
return this.createWatch(optns).getEvents(0, 0).then((evs) => (evs ? evs.reduce((res, ev) => res.then((res) => tr._event(ev, false).then((ev) => ((ev && res.push(ev)), res))), Promise.resolve([])) : this.badauth().then(() => this.events())));
|
|
4587
|
+
}
|
|
4588
|
+
|
|
4589
|
+
toJSON() {
|
|
4590
|
+
return this.uri();
|
|
4591
|
+
}
|
|
4592
|
+
};
|
|
4593
|
+
|
|
4594
|
+
libVES.Vault = class extends libVES.EventTarget {
|
|
4595
|
+
constructor(ref, ves, fields) {
|
|
4596
|
+
super();
|
|
4597
|
+
this.init(libVES.Vault.toRef(ref, ves), ves, fields);
|
|
4598
|
+
}
|
|
4599
|
+
|
|
4600
|
+
init(ref, ves, fields) {
|
|
4601
|
+
fields ||= {};
|
|
4602
|
+
if (ref.externalId) fields.externals = [{domain: (this.domain = String(ref.domain)), externalId: (this.externalId = String(ref.externalId))}];
|
|
4603
|
+
this.email = ref.email || '';
|
|
4604
|
+
if (ref.email) fields.email = this.email;
|
|
4605
|
+
if (ref.version) this.version = fields.id = Number(ref.version);
|
|
4606
|
+
if (!fields.id) fields.type = this.externalId ? 'secondary' : 'current';
|
|
4607
|
+
this.vaultKey = new libVES.VaultKey(fields, ves);
|
|
4608
|
+
delete(this.admin);
|
|
4609
|
+
};
|
|
4610
|
+
|
|
4611
|
+
item(ref) {
|
|
4612
|
+
return new libVES.Item(ref, this);
|
|
4613
|
+
};
|
|
4614
|
+
|
|
4615
|
+
vault(ref) {
|
|
4616
|
+
if (!ref) return null;
|
|
4617
|
+
return new libVES.Vault(ref, this.vaultKey.VES);
|
|
4618
|
+
}
|
|
4619
|
+
|
|
4620
|
+
entries(optns) {
|
|
4621
|
+
const flds = {encData: true, vaultItem: {type: true, file: {externals: true, creator: {id: true, email: true}}, deleted: true, vaultKey: {type: true, externals: true, user: true}, type: true, meta: true}};
|
|
4622
|
+
const getfn = () => this.vaultKey.getField('vaultEntries', flds, true).then((data) => libVES.Util.fillUndefs(data, flds));
|
|
4623
|
+
if (!this._entriesCache) (this._entriesCache = getfn().then((entries) => (entries || this.badauth().then(getfn)))).catch(() => null).finally(() => this._entriesCache = null);
|
|
4624
|
+
return this._entriesCache;
|
|
4625
|
+
};
|
|
4626
|
+
|
|
4627
|
+
objects(optns) {
|
|
4628
|
+
let found = {items: {}, vaults: {}};
|
|
4629
|
+
return this.entries(optns).then((entries) => Promise.all((entries || []).map((entry) => {
|
|
4630
|
+
const ext = entry.vaultItem?.file?.externals?.[0];
|
|
4631
|
+
if (ext) {
|
|
4632
|
+
if (entry.vaultItem.deleted) return null;
|
|
4633
|
+
let d = (found.items[ext.domain] ||= {});
|
|
4634
|
+
return d[ext.externalId] ? null : (d[ext.externalId] = new libVES.Item(ext, this, entry.vaultItem));
|
|
4635
|
+
}
|
|
4636
|
+
const vkey = entry.vaultItem?.vaultKey;
|
|
4637
|
+
const kext = vkey?.externals?.[0];
|
|
4638
|
+
if (kext && vkey.type == 'secondary' && entry.vaultItem.type == 'password') {
|
|
4639
|
+
let d = (found.vaults[kext.domain] ||= {});
|
|
4640
|
+
return d[kext.externalId] ? null : (d[kext.externalId] = new libVES.Vault(kext, this.vaultKey.VES, vkey));
|
|
4641
|
+
}
|
|
4642
|
+
}))).then((objs) => objs.filter((obj) => obj));
|
|
4643
|
+
};
|
|
4644
|
+
|
|
4645
|
+
items(optns) {
|
|
4646
|
+
return this.objects(optns).then((objs) => objs.filter((obj) => (obj instanceof libVES.Item)));
|
|
4647
|
+
}
|
|
4648
|
+
|
|
4649
|
+
vaults(optns) {
|
|
4650
|
+
return this.objects(optns).then((objs) => objs.filter((obj) => (obj instanceof libVES.Vault)));
|
|
4651
|
+
}
|
|
4652
|
+
|
|
4653
|
+
_setunlock(reauth) {
|
|
4654
|
+
this.current = true;
|
|
4655
|
+
this.owner = this.externalId[0] != '!';
|
|
4656
|
+
this.lock(600);
|
|
4657
|
+
let rf;
|
|
4658
|
+
if (reauth !== false) (rf = (tmout) => {
|
|
4659
|
+
this.refreshTmout = setTimeout(() => {
|
|
4660
|
+
this.vaultKey.loadFields({encSessionToken: true}, true, {token: ''}).then((flds) => this.vaultKey.setFields(flds)).then(() => this.vaultKey.getSessionToken()).then((tk) => {
|
|
4661
|
+
this.vaultKey.VES.token = tk;
|
|
4662
|
+
rf();
|
|
4663
|
+
}).catch((er) => {
|
|
4664
|
+
console.log(er);
|
|
4665
|
+
rf(60000);
|
|
4666
|
+
});
|
|
4667
|
+
}, (tmout || 14400000));
|
|
4668
|
+
})();
|
|
4669
|
+
return this;
|
|
4670
|
+
}
|
|
4671
|
+
|
|
4672
|
+
unlock(optns) {
|
|
4673
|
+
if (this.lockInProgress) return this.lock().then(() => this.unlock(optns));
|
|
4674
|
+
if (optns && !(optns instanceof Object)) optns = libVES.Vault.toRef(optns, this.vaultKey.VES);
|
|
4675
|
+
if (optns?.veskey) return this.vaultKey.VES.logout().then(() => {
|
|
4676
|
+
let ves = new libVES(optns);
|
|
4677
|
+
delete(ves.veskey);
|
|
4678
|
+
return ((reauth) => ves.unlock(String(optns.veskey)).then(() => this.init(ves, ves)).then(() => this._setunlock(reauth)))(!this.vaultKey.VES.token);
|
|
4679
|
+
});
|
|
4680
|
+
return this.vaultKey.VES.unlock().catch((er) => {
|
|
4681
|
+
let mode = optns?.mode || 'delegate';
|
|
4682
|
+
switch (mode) {
|
|
4683
|
+
case 'delegate': return this.vaultKey.VES.delegate(optns).then((ves) => this.init(ves, ves));
|
|
4684
|
+
case 'flow': return this.vaultKey.VES.flow(true, optns).then((ves) => this.init(ves, ves));
|
|
4685
|
+
case 'veskey': throw new libVES.Error.InvalidValue('No veskey provided');
|
|
4686
|
+
default: throw new libVES.Error.InvalidValue('Unknown unlock mode: ' + mode + ', expected: delegate|flow');
|
|
4687
|
+
}
|
|
4688
|
+
}).then(() => this._setunlock());
|
|
4689
|
+
}
|
|
4690
|
+
|
|
4691
|
+
unlocked(optns) {
|
|
4692
|
+
return this.vaultKey.VES.unlock().catch((er) => {
|
|
4693
|
+
if (optns?.mode != 'flow') throw er;
|
|
4694
|
+
return this.vaultKey.VES.flow(false, optns).then((ves) => this.init(ves, ves)).then(() => this._setunlock());
|
|
4695
|
+
}).then(() => true).catch((er) => false);
|
|
4696
|
+
}
|
|
4697
|
+
|
|
4698
|
+
anonymous(optns) {
|
|
4699
|
+
if (!(optns instanceof Object)) {
|
|
4700
|
+
if (optns && typeof(optns) == 'string') optns = {veskey: optns};
|
|
4701
|
+
else optns = {};
|
|
4702
|
+
}
|
|
4703
|
+
if (!optns.veskey) return Promise.reject(libVES.Error.InvalidValue('Required: veskey'));
|
|
4704
|
+
if (!this.vaultKey.VES.domain) return Promise.reject(libVES.Error.InvalidValue('Cannot create an anonymous vault without a VES domain'));
|
|
4705
|
+
this.vaultKey.VES.logout();
|
|
4706
|
+
return (optns.externalId ? Promise.resolve(this.vaultKey.VES.externalId = optns.externalId) : crypto.subtle.digest('sha-256', libVES.Util.StringToByteArray('libVES.subtle\0' + this.vaultKey.VES.domain + '\0' + optns.veskey)).then((hash) => {
|
|
4707
|
+
const hex = '0123456789abcdef';
|
|
4708
|
+
let xid = new Uint8Array(hash).reduce(((v, e) => v + hex[e >> 4] + hex[e & 0x0f]), '!');
|
|
4709
|
+
this.vaultKey.VES.externalId = xid;
|
|
4710
|
+
})).then(() => this.vaultKey.VES.unlock(optns.veskey).catch((er) => {
|
|
4711
|
+
if (er?.code == 'NotFound') return this.vaultKey.VES.setAnonymousKey(optns.veskey, optns);
|
|
4712
|
+
else throw er;
|
|
4713
|
+
})).then(() => this.init(this.vaultKey.VES, this.vaultKey.VES)).then(() => this._setunlock());
|
|
4714
|
+
}
|
|
4715
|
+
|
|
4716
|
+
lock(tmout) {
|
|
4717
|
+
this.lockInProgress = false;
|
|
4718
|
+
clearTimeout(this.lockTmout);
|
|
4719
|
+
this.lockTmout = null;
|
|
4720
|
+
if (tmout > 0) {
|
|
4721
|
+
if (tmout > 3600) tmout = 3600;
|
|
4722
|
+
this.lockTmout = setTimeout(() => {
|
|
4723
|
+
this.lockInProgress = true;
|
|
4724
|
+
this.dispatchEvent(new libVES.CustomEvent('authexpire', {detail: {vault: this}}));
|
|
4725
|
+
if (this.lockInProgress) this.lock();
|
|
4726
|
+
}, tmout * 1000);
|
|
4727
|
+
return Promise.resolve(true);
|
|
4728
|
+
}
|
|
4729
|
+
clearTimeout(this.refreshTmout);
|
|
4730
|
+
this.refreshTmout = null;
|
|
4731
|
+
this.stop();
|
|
4732
|
+
return this.vaultKey.VES.logout();
|
|
4733
|
+
}
|
|
4734
|
+
|
|
4735
|
+
random() {
|
|
4736
|
+
return this.vaultKey.VES.generateVESkey();
|
|
4737
|
+
}
|
|
4738
|
+
|
|
4739
|
+
static toRef(value, ves) {
|
|
4740
|
+
switch (typeof(value)) {
|
|
4741
|
+
case 'object':
|
|
4742
|
+
return value;
|
|
4743
|
+
case 'number':
|
|
4744
|
+
value = String(value);
|
|
4745
|
+
case 'string':
|
|
4746
|
+
let uri = new URL(value, "ves://" + (ves && ves.domain ? ves.domain : ''));
|
|
4747
|
+
if (uri.protocol != 'ves:') throw new libVES.Error.InvalidValue("Invalid schema: '" + uri.protocol + "', expected 'ves:'");
|
|
4748
|
+
let p = uri.pathname.split('/');
|
|
4749
|
+
let id = p.length > 1 ? decodeURIComponent(p[1]) : '';
|
|
4750
|
+
let ref = uri.host ? {domain: uri.host, externalId: id} : {version: Number(id)};
|
|
4751
|
+
if (p[2] != null) ref.email = decodeURIComponent(p[2]);
|
|
4752
|
+
if (uri.password) ref.veskey = uri.password;
|
|
4753
|
+
return ref;
|
|
4754
|
+
}
|
|
4755
|
+
};
|
|
4756
|
+
|
|
4757
|
+
static toRefs(refs, ves, owner) {
|
|
4758
|
+
if (!refs) return [];
|
|
4759
|
+
if (!(refs instanceof Array)) refs = [refs];
|
|
4760
|
+
refs = refs.map((ref) => libVES.Vault.toRef(ref, ves)).filter((ref) => ref);
|
|
4761
|
+
if (owner) {
|
|
4762
|
+
if (!ves.externalId) throw new libVES.Error.Unauthorized('The vault is locked');
|
|
4763
|
+
refs.push({domain: ves.domain, externalId: ves.externalId});
|
|
4764
|
+
}
|
|
4765
|
+
return refs;
|
|
4766
|
+
}
|
|
4767
|
+
|
|
4768
|
+
static toUri(ref, short) {
|
|
4769
|
+
if (ref.externalId && short) return (ref.domain == short ? '' : '//' + encodeURIComponent(ref.domain) + '/') + encodeURIComponent(ref.externalId).replaceAll('%40', '@');
|
|
4770
|
+
let uri = ref.externalId ? "ves://" + encodeURIComponent(ref.domain) + "/" + encodeURIComponent(ref.externalId) : "ves://" + (ref.version ? "/" + String(Number(ref.version)) : encodeURIComponent(ref.domain ?? '') + "/");
|
|
4771
|
+
if (ref.email != null) uri += '/' + encodeURIComponent(ref.email);
|
|
4772
|
+
return uri;
|
|
4773
|
+
}
|
|
4774
|
+
|
|
4775
|
+
uri() {
|
|
4776
|
+
if (!this.externalId && !this.version && !this.email) return null;
|
|
4777
|
+
return libVES.Vault.toUri(this);
|
|
4778
|
+
}
|
|
4779
|
+
|
|
4780
|
+
short() {
|
|
4781
|
+
return libVES.Vault.toUri(this, this.vaultKey.VES.domain);
|
|
4782
|
+
}
|
|
4783
|
+
|
|
4784
|
+
badauth() {
|
|
4785
|
+
const ves = this.vaultKey.VES;
|
|
4786
|
+
if (!this.externalId || (this.externalId == ves.externalId && this.domain == ves.domain)) return Promise.reject(new libVES.Error.InvalidKey('Not authorized for this key'));
|
|
4787
|
+
return this.vaultKey.getFields({encSessionToken: true, type: true, algo: true, publicKey: true, privateKey: true, vaultItems: {type: true, vaultEntries: {vaultKey : {id: true}, encData: true}, meta: true}}).then(() => {
|
|
4788
|
+
const ves2 = new libVES({domain: this.domain, externalId: this.externalId});
|
|
4789
|
+
ves2.vaultKey = Promise.resolve(this.vaultKey);
|
|
4790
|
+
ves2.unlockedKeys = ves.unlockedKeys;
|
|
4791
|
+
ves2.pendingKeys = ves.pendingKeys;
|
|
4792
|
+
this.vaultKey.VES = ves2;
|
|
4793
|
+
return ves2.unlock();
|
|
4794
|
+
});
|
|
4795
|
+
}
|
|
4796
|
+
|
|
4797
|
+
createWatch() {
|
|
4798
|
+
let w = new libVES.Watch(this.vaultKey);
|
|
4799
|
+
w.fields = {vaultItem: {id: true, type: true, deleted: true, vaultKey: {id: true, type: true, algo: true, publicKey: true, externals: {domain: true, externalId: true}, user: {id: true, email: true}}, file: {externals: {domain: true, externalId: true}, creator: true}, meta: true}, authorSession: {vaultKey: {id: true, externals: {domain: true, externalId: true}, user: {email: true}, type: true}, domain: true, user: {email: true}, remote: true, userAgent: true}, session: {id: true, remote: true, userAgent: true, vaultKey: {id: true}, user: {id: true}}};
|
|
4800
|
+
return w;
|
|
4801
|
+
}
|
|
4802
|
+
|
|
4803
|
+
replay(optns) {
|
|
4804
|
+
return this.objects(optns).then((objs) => Promise.all(objs.map((obj) => {
|
|
4805
|
+
if (obj instanceof libVES.Item) return new libVES.CustomEvent('itemadd', {detail: {replay: true, item: obj, share: this}});
|
|
4806
|
+
else if (obj instanceof libVES.Vault) return new libVES.CustomEvent('vaultadd', {detail: {replay: true, vault: obj, share: this}});
|
|
4807
|
+
})));
|
|
4808
|
+
}
|
|
4809
|
+
|
|
4810
|
+
password() {
|
|
4811
|
+
return this.vaultKey.getVaultItems().then((vitems) => {
|
|
4812
|
+
if (!vitems) return this.badauth().then(() => this.password());
|
|
4813
|
+
return vitems.reduce((p, vitem) => p.catch((e) => vitem.getType().then((type) => (type == 'password' ? vitem.getId().then((id) => this.item({version: id})) : Promise.reject(e)))), Promise.reject(new libVES.Error.NotFound('No password item found')));
|
|
4814
|
+
});
|
|
4815
|
+
}
|
|
4816
|
+
|
|
4817
|
+
verify() {
|
|
4818
|
+
if (this.current !== undefined) return Promise.resolve(this);
|
|
4819
|
+
return this.vaultKey.VES.usersToKeys([(this.externalId ? {domain: this.domain, externalId: this.externalId} : this.email)]).then((vkeys) => Promise.all(vkeys.map((vkey) => vkey.getFields(vkey.id ? {id: true, type: true} : {type: true}))).then((flds) => flds.reduce((res, fld, idx) => {
|
|
4820
|
+
if (res) return res;
|
|
4821
|
+
if (this.version) return this.version == fld.id ? vkeys[idx] : null;
|
|
4822
|
+
switch (fld.type) {
|
|
4823
|
+
case 'secondary': case 'current': case 'temp': return vkeys[idx];
|
|
4824
|
+
}
|
|
4825
|
+
}, null))).then((vkey) => {
|
|
4826
|
+
if (!vkey) throw new libVES.Error.NotFound('Cannot find or create a matching key');
|
|
4827
|
+
return vkey.getType().then((type) => {
|
|
4828
|
+
this.current = (type == 'current' || type == 'secondary');
|
|
4829
|
+
this.owner = (this.externalId != null && this.externalId == vkey.VES.externalId && this.domain == vkey.VES.domain) || (!!this.email && this.email == vkey.VES.email);
|
|
4830
|
+
this.vaultKey = vkey;
|
|
4831
|
+
return this;
|
|
4832
|
+
});
|
|
4833
|
+
});
|
|
4834
|
+
}
|
|
4835
|
+
|
|
4836
|
+
_eventTracker() {
|
|
4837
|
+
return new libVES.EventTracker(this);
|
|
4838
|
+
}
|
|
4839
|
+
|
|
4840
|
+
toString() {
|
|
4841
|
+
return 'libVES.Vault(' + (this.uri() ?? '[pending]') + ')';
|
|
4842
|
+
}
|
|
4843
|
+
|
|
4844
|
+
};
|
|
4845
|
+
|
|
4846
|
+
libVES.Author = class {
|
|
4847
|
+
constructor(sess, ves) {
|
|
4848
|
+
this.sessid = sess.id;
|
|
4849
|
+
if (sess.vaultKey?.externals?.[0]) this.vault = new libVES.Vault(sess.vaultKey.externals[0], ves);
|
|
4850
|
+
else if (sess.user?.email) this.vault = new libVES.Vault({email: sess.user.email}, ves);
|
|
4851
|
+
this.remote = sess.remote;
|
|
4852
|
+
this.userAgent = sess.userAgent;
|
|
4853
|
+
}
|
|
4854
|
+
toString() {
|
|
4855
|
+
return 'libVES.Author(' + (this.sessid ?? '') + ')';
|
|
4856
|
+
}
|
|
4857
|
+
toJSON() {
|
|
4858
|
+
return this.sessid;
|
|
4859
|
+
}
|
|
4860
|
+
};
|
|
4861
|
+
|
|
4862
|
+
libVES.CustomEvent = class extends CustomEvent {
|
|
4863
|
+
toString() {
|
|
4864
|
+
return 'libVES.CustomEvent(' + this.type + (this.detail?.id ? '[' + this.detail.id + ']' : '') + (this.detail?.at ? ' @' + this.detail.at : '') + ')';
|
|
4865
|
+
}
|
|
4866
|
+
toJSON() {
|
|
4867
|
+
return this.detail?.id;
|
|
4868
|
+
}
|
|
4869
|
+
};
|
|
4870
|
+
|
|
4871
|
+
libVES.EventTracker = class {
|
|
4872
|
+
constructor(vault, share) {
|
|
4873
|
+
this.vault = vault;
|
|
4874
|
+
this.share = share;
|
|
4875
|
+
this.items = {};
|
|
4876
|
+
}
|
|
4877
|
+
|
|
4878
|
+
_event(e, attn) {
|
|
4879
|
+
const event = (type, detail) => {
|
|
4880
|
+
detail.event = e;
|
|
4881
|
+
return e.getFields({id: true, recordedAt: true, authorSession: {vaultKey: {id: true, externals: {domain: true, externalId: true}, user: {email: true}}, user: {email: true}, domain: true, remote: true, userAgent: true}}).then((flds) => {
|
|
4882
|
+
detail.id = flds?.id;
|
|
4883
|
+
if (flds?.recordedAt) detail.at = new Date(flds.recordedAt);
|
|
4884
|
+
detail.author = new libVES.Author((flds?.authorSession ?? {}), this.vault.vaultKey.VES);
|
|
4885
|
+
}).catch(() => null).then(() => new libVES.CustomEvent(type, {detail: detail}));
|
|
4886
|
+
}
|
|
4887
|
+
return e.getType().then((type) => {
|
|
4888
|
+
const itemfn = (ac, attn, sh) => e.getVaultItem().then((vitem) => vitem.getType().then((itype) => {
|
|
4889
|
+
switch (itype) {
|
|
4890
|
+
case 'string': case 'file':
|
|
4891
|
+
return vitem.getFields({id: true, file: {externals: {domain: true, externalId: true}}, deleted: true, type: true, meta: true}).then((flds) => {
|
|
4892
|
+
let ext = flds?.file?.externals?.[0];
|
|
4893
|
+
if (!ext) return null;
|
|
4894
|
+
let item = new libVES.Item({domain: ext.domain, externalId: ext.externalId, version: flds.id}, this.vault, flds);
|
|
4895
|
+
let ids = (this.items[item.uri()] ||= []);
|
|
4896
|
+
let idx = ids.indexOf(flds.id);
|
|
4897
|
+
if (idx < 0 && (flds.deleted === false || (ac == 'create' || ac == 'add'))) ids.unshift(flds.id), idx = 0;
|
|
4898
|
+
return event((idx == 0 ? '' : 'old') + 'item' + ac, {item: item, share: sh});
|
|
4899
|
+
});
|
|
4900
|
+
case 'password':
|
|
4901
|
+
return vitem.getFields({vaultKey: {type: true, externals: {domain: true, externalId: true}}}).then((flds) => {
|
|
4902
|
+
switch (flds?.vaultKey?.type) {
|
|
4903
|
+
case 'secondary':
|
|
4904
|
+
return event('vault' + ac, {vault: this.vault.vault(flds.vaultKey.externals?.[0]), share: sh});
|
|
4905
|
+
default:
|
|
4906
|
+
if (attn) return vitem.getVaultKey().then((vkey) => this.vault.vaultKey.VES.attnVaultKeys([vkey])).catch((e) => console.log(e)).then(() => null);
|
|
4907
|
+
}
|
|
4908
|
+
});
|
|
4909
|
+
}
|
|
4910
|
+
}));
|
|
4911
|
+
const sharefn = () => (this.share ? e.getVaultKey().then((vkey) => vkey.getFields({id: true, type: true, externals: {domain: true, externalId: true}, user: {id: true, email: true}}).then((flds) => {
|
|
4912
|
+
let f = flds?.externals?.[0] ? flds.externals[0] : (flds?.user?.email ? {email: flds.user.email} : {});
|
|
4913
|
+
f.version = flds.id;
|
|
4914
|
+
let vault = this.vault.vault(f);
|
|
4915
|
+
vault.current = (f.externals && flds.type == 'secondary') || (f.email && flds.type == 'current');
|
|
4916
|
+
return vault;
|
|
4917
|
+
})) : Promise.resolve(this.vault));
|
|
4918
|
+
switch (type) {
|
|
4919
|
+
case 'vaultEntry.deleted':
|
|
4920
|
+
return sharefn().then((sh) => itemfn('remove', false, sh));
|
|
4921
|
+
case 'vaultEntry.created':
|
|
4922
|
+
return sharefn().then((sh) => itemfn('add', attn !== false, sh));
|
|
4923
|
+
case 'vaultItem.deleted':
|
|
4924
|
+
return itemfn('delete');
|
|
4925
|
+
case 'vaultItem.created':
|
|
4926
|
+
return itemfn('create');
|
|
4927
|
+
case 'vaultItem.listening':
|
|
4928
|
+
return itemfn('change');
|
|
4929
|
+
case 'session.created':
|
|
4930
|
+
return e.getFields({session: {id: true, remote: true, userAgent: true, vaultKey: {id: true}, user: {id: true}}}).then((flds) => {
|
|
4931
|
+
if (!flds?.session) return null;
|
|
4932
|
+
let ses = new libVES.Author(flds.session, this.vault.vaultKey.VES);
|
|
4933
|
+
ses.vault = this.vault;
|
|
4934
|
+
return event('sessioncreate', {vault: this.vault, session: ses});
|
|
4935
|
+
});
|
|
4936
|
+
}
|
|
4937
|
+
}).catch((er) => (console.log(er), event('error', {error: er})));
|
|
4938
|
+
}
|
|
4939
|
+
};
|
|
4940
|
+
|
|
4941
|
+
|
|
4942
|
+
|
|
4943
|
+
libVES.Item = class extends libVES.EventTarget {
|
|
4944
|
+
constructor(ref, vault, fields) {
|
|
4945
|
+
const ves = vault.vaultKey.VES;
|
|
4946
|
+
super();
|
|
4947
|
+
if (ref == null || typeof(ref) == 'function') {
|
|
4948
|
+
this.provisional = {share: [vault], ref: (ref || libVES.Item.newRef)};
|
|
4949
|
+
} else {
|
|
4950
|
+
ref = libVES.Vault.toRef(ref, ves);
|
|
4951
|
+
if ((!ref.domain || !ref.externalId) && !ref.version) throw new libVES.Error.InvalidValue('Bad item reference');
|
|
4952
|
+
this.domain = ref.domain;
|
|
4953
|
+
this.externalId = ref.externalId;
|
|
4954
|
+
this.version = ref.version || null;
|
|
4955
|
+
}
|
|
4956
|
+
this.vault = vault;
|
|
4957
|
+
this._vaultItem(ves, fields);
|
|
4958
|
+
};
|
|
4959
|
+
|
|
4960
|
+
static newRef() {
|
|
4961
|
+
let d = new Date();
|
|
4962
|
+
return ((d.getFullYear() * 100 + d.getMonth() + 1) * 100 + d.getDate()).toFixed(0) + '.' + (((d.getHours() + 100) * 100 + d.getMinutes()) * 100 + d.getSeconds() + d.getMilliseconds() / 1000).toFixed(3).slice(-10);
|
|
4963
|
+
}
|
|
4964
|
+
|
|
4965
|
+
_vaultItem(ves, fields) {
|
|
4966
|
+
if (this.vaultItem && this._entriesCache !== null) return this.vaultItem;
|
|
4967
|
+
ves ||= this.vaultItem.VES;
|
|
4968
|
+
if (!fields) {
|
|
4969
|
+
fields = this.externalId ? {file: {externals: [{domain: this.domain, externalId: this.externalId}]}} : {};
|
|
4970
|
+
if (this.version) fields.id = this.version;
|
|
4971
|
+
} else if (fields.vaultEntries) this._entriesCache = Promise.resolve(fields).finally(() => this._entriesCache = null);
|
|
4972
|
+
return this.vaultItem = new libVES.VaultItem(fields, ves);
|
|
4973
|
+
};
|
|
4974
|
+
|
|
4975
|
+
_entries() {
|
|
4976
|
+
if (this.provisional) return Promise.reject(new libVES.Error.NotFound('Not available for a provisional item'));
|
|
4977
|
+
if (this._entriesCache) return this._entriesCache;
|
|
4978
|
+
this._entriesCache = this._vaultItem().getFields({vaultEntries: {encData: true, vaultKey: {id: true, type: true, algo: true, privateKey: true, publicKey: true, user: {id: true, email: true}, externals: {domain: true, externalId: true}}}, file: {creator: {id: true}}, vaultKey: {user: {id: true}}, deleted: true}).then((flds) => {
|
|
4979
|
+
if (!flds?.vaultEntries) return Promise.reject(new libVES.Error.InvalidKey('Not authorized to access this item'));
|
|
4980
|
+
return flds;
|
|
4981
|
+
});
|
|
4982
|
+
this._entriesCache.catch((er) => null).finally(() => this._entriesCache = null);
|
|
4983
|
+
return this._entriesCache;
|
|
4984
|
+
};
|
|
4985
|
+
|
|
4986
|
+
_get() {
|
|
4987
|
+
return this._entries().then(() => this.vaultItem.get());
|
|
4988
|
+
};
|
|
4989
|
+
|
|
4990
|
+
_reset() {
|
|
4991
|
+
this._entriesCache = null;
|
|
4992
|
+
};
|
|
4993
|
+
|
|
4994
|
+
latest() {
|
|
4995
|
+
return this.externalId && this.version ? this.vault.item({domain: this.domain, externalId: this.externalId}) : this;
|
|
4996
|
+
};
|
|
4997
|
+
|
|
4998
|
+
get() {
|
|
4999
|
+
return this._get().then((val) => {
|
|
5000
|
+
if (typeof(val) != 'string') throw new libVES.Error.InvalidValue('The item value is not a string');
|
|
5001
|
+
return val;
|
|
5002
|
+
});
|
|
5003
|
+
};
|
|
5004
|
+
|
|
5005
|
+
put(value, shares) {
|
|
5006
|
+
if (value == null) return Promise.reject(new libVES.Error.InvalidValue('The item value cannot be empty'));
|
|
5007
|
+
let prref;
|
|
5008
|
+
return (shares ? Promise.resolve(libVES.Vault.toRefs(shares, this.vaultItem.VES, true)) : this.share().then((shares) => {
|
|
5009
|
+
let owner = shares.reduce((cur, sh) => (cur || ((sh.owner && sh.externalId?.match(/@/)) ? sh : null)), null);
|
|
5010
|
+
if (owner && owner.uri() != this.vault.uri()) shares.push(this.vault.vault({domain: '.admin', externalId: owner.externalId}));
|
|
5011
|
+
return shares;
|
|
5012
|
+
}).catch((e) => {
|
|
5013
|
+
if (e && e.code == 'NotFound') return libVES.Vault.toRefs([], this.vaultItem.VES, true);
|
|
5014
|
+
throw e;
|
|
5015
|
+
})).then((shares) => {
|
|
5016
|
+
if (!this.provisional) return shares;
|
|
5017
|
+
prref = libVES.Vault.toRef(this.provisional.ref(), this.vaultItem.VES);
|
|
5018
|
+
if (!prref?.externalId) return Promise.reject(new libVES.Error.InvalidValue('Bad provisional reference generated by the supplied function'));
|
|
5019
|
+
return this.vaultItem.setFields({file: {externals: [prref]}}).then(() => shares);
|
|
5020
|
+
}).then((shares) => this.vaultItem.shareWith(shares, value)).then(() => {
|
|
5021
|
+
if (prref) {
|
|
5022
|
+
this.externalId = prref.externalId;
|
|
5023
|
+
this.domain = prref.domain;
|
|
5024
|
+
delete(this.provisional);
|
|
5025
|
+
}
|
|
5026
|
+
this.version = null;
|
|
5027
|
+
this._reset();
|
|
5028
|
+
return value;
|
|
5029
|
+
});
|
|
5030
|
+
};
|
|
5031
|
+
|
|
5032
|
+
cipher(optns, shares) {
|
|
5033
|
+
return this._get().then((val) => {
|
|
5034
|
+
if (!(val instanceof libVES.Cipher)) throw new libVES.Error.InvalidValue('The item value is not a cipher');
|
|
5035
|
+
return (shares ? this.share(shares) : Promise.resolve(null)).then(() => val);
|
|
5036
|
+
}).catch((e) => {
|
|
5037
|
+
if (e && e.code == 'NotFound') {
|
|
5038
|
+
let algo = optns?.algo || this.vaultItem.VES.cipherAlgo || 'AES256GCM1K';
|
|
5039
|
+
if (!libVES.Cipher[algo]) throw new libVES.Error.InvalidValue('Unsupported cipher: ' + algo);
|
|
5040
|
+
let ci = new libVES.Cipher[algo]();
|
|
5041
|
+
return this.put(ci, shares);
|
|
5042
|
+
}
|
|
5043
|
+
throw e;
|
|
5044
|
+
}).then((ci) => new libVES.ItemCipher(ci, this));
|
|
5045
|
+
};
|
|
5046
|
+
|
|
5047
|
+
json(val, shares) {
|
|
5048
|
+
if (val === undefined) return this.get().then((val) => JSON.parse(val));
|
|
5049
|
+
return this.put(JSON.stringify(val), shares).then(() => val);
|
|
5050
|
+
};
|
|
5051
|
+
|
|
5052
|
+
exists() {
|
|
5053
|
+
return this._entries().then((flds) => !flds?.deleted).catch((e) => {
|
|
5054
|
+
if (e?.code == 'NotFound') return false;
|
|
5055
|
+
if (e?.code == 'InvalidKey') return true;
|
|
5056
|
+
throw e;
|
|
5057
|
+
});
|
|
5058
|
+
};
|
|
5059
|
+
|
|
5060
|
+
_provShare(shares, del) {
|
|
5061
|
+
return new Promise((resolve, reject) => {
|
|
5062
|
+
let uris = libVES.Vault.toRefs(shares, this.vaultItem.VES).map((ref) => this.vault.vault(ref).uri());
|
|
5063
|
+
let prov = {};
|
|
5064
|
+
this.provisional.share.map((sh) => prov[sh.uri()] = sh);
|
|
5065
|
+
resolve(this.vaultItem.VES.usersToKeys(libVES.Vault.toRefs(uris.filter((uri) => !prov[uri]))));
|
|
5066
|
+
}).then((vkeys) => Promise.all(vkeys.map((vkey => vkey.getFields({user: {email: true}, externals: {domain: true, externalId: true}, type: true}).then((flds) => {
|
|
5067
|
+
let sh = new libVES.Vault((flds?.externals?.[0] ?? flds?.user?.email), this.vaultItem.VES, flds);
|
|
5068
|
+
if (sh) return sh.verify();
|
|
5069
|
+
}))))).then((shares) => shares.filter((sh) => sh)).then((shares) => {
|
|
5070
|
+
this.provisional.share = this.provisional.share.concat(shares);
|
|
5071
|
+
if (del) {
|
|
5072
|
+
let uris = {};
|
|
5073
|
+
shares.map((sh) => uris[sh.uri()] = sh);
|
|
5074
|
+
uris[this.vault.uri()] = this.vault;
|
|
5075
|
+
this.provisional.share = this.provisional.share.filter((sh) => uris[sh.uri()]);
|
|
5076
|
+
}
|
|
5077
|
+
return this.provisional.share;
|
|
5078
|
+
});
|
|
5079
|
+
}
|
|
5080
|
+
|
|
5081
|
+
share(shares) {
|
|
5082
|
+
if (this.provisional) {
|
|
5083
|
+
if (shares) return this._provShare(shares, true);
|
|
5084
|
+
return Promise.resolve(this.provisional.share);
|
|
5085
|
+
}
|
|
5086
|
+
return (shares ? (this._reset(), this.vaultItem.shareWith(libVES.Vault.toRefs(shares, this.vaultItem.VES, true))) : Promise.resolve(null)).then(() => {
|
|
5087
|
+
let result = [];
|
|
5088
|
+
let found = {};
|
|
5089
|
+
let admins = {};
|
|
5090
|
+
return this._entries().then((flds) => flds.vaultEntries.map((entry) => {
|
|
5091
|
+
let vkey = entry?.vaultKey;
|
|
5092
|
+
let ref = vkey?.externals?.[0];
|
|
5093
|
+
if (!ref) {
|
|
5094
|
+
const email = vkey?.user?.email;
|
|
5095
|
+
ref = email ? {email: email} : {version: vkey?.id};
|
|
5096
|
+
}
|
|
5097
|
+
let vault = new libVES.Vault(ref, this.vaultItem.VES);
|
|
5098
|
+
let uri = vault.uri();
|
|
5099
|
+
if (!found[uri]) {
|
|
5100
|
+
result.push(found[uri] = vault);
|
|
5101
|
+
let uid = vkey?.user?.id;
|
|
5102
|
+
vault.owner = !!uid && uid == (flds.file?.creator?.id ?? flds.vaultKey?.user?.id);
|
|
5103
|
+
if (vault.domain == '.admin') admins[vault.externalId] = true;
|
|
5104
|
+
}
|
|
5105
|
+
switch (vkey?.type) {
|
|
5106
|
+
case 'current': case 'secondary':
|
|
5107
|
+
found[uri].current = true;
|
|
5108
|
+
break;
|
|
5109
|
+
default:
|
|
5110
|
+
vault.current = false;
|
|
5111
|
+
}
|
|
5112
|
+
})).then(() => {
|
|
5113
|
+
result.map((sh) => sh.admin = !!admins[sh.externalId]);
|
|
5114
|
+
return result;
|
|
5115
|
+
});
|
|
5116
|
+
});
|
|
5117
|
+
};
|
|
5118
|
+
|
|
5119
|
+
add(shares) {
|
|
5120
|
+
if (this.provisional) return this._provShare(shares, false).then(() => true);
|
|
5121
|
+
return this._entries().then(() => this.vaultItem.getShareVaultKeys()).then((vkeys) => {
|
|
5122
|
+
if (!vkeys) throw new libVES.Error.InvalidKey('Not authorized to share this item');
|
|
5123
|
+
if (!shares) return true;
|
|
5124
|
+
libVES.Vault.toRefs(shares, this.vaultItem.VES).map((share) => vkeys.push(share));
|
|
5125
|
+
this._reset();
|
|
5126
|
+
return this.vaultItem.shareWith(vkeys);
|
|
5127
|
+
}).then(() => true);
|
|
5128
|
+
};
|
|
5129
|
+
|
|
5130
|
+
remove(shares) {
|
|
5131
|
+
shares = libVES.Vault.toRefs(shares, this.vaultItem.VES);
|
|
5132
|
+
if (!shares || !shares.length) return Promise.resolve(true);
|
|
5133
|
+
if (this.provisional) return new Promise((resolve, reject) => {
|
|
5134
|
+
let uris = {};
|
|
5135
|
+
shares.map((sh) => uris[this.vault.vault(sh).uri()] = true);
|
|
5136
|
+
this.provisional.share = this.provisional.share.filter((sh) => !uris[sh.uri()]);
|
|
5137
|
+
resolve(true);
|
|
5138
|
+
});
|
|
5139
|
+
return this._entries().then(() => this.vaultItem.unshareWith(shares)).then(() => (this._reset(), true));
|
|
5140
|
+
};
|
|
5141
|
+
|
|
5142
|
+
refuse() {
|
|
5143
|
+
return this.remove(this.vault);
|
|
5144
|
+
};
|
|
5145
|
+
|
|
5146
|
+
delete() {
|
|
5147
|
+
this._reset();
|
|
5148
|
+
return this.vaultItem.delete();
|
|
5149
|
+
}
|
|
5150
|
+
|
|
5151
|
+
badauth() {
|
|
5152
|
+
return (this.vaultItem.VES == this.vault.vaultKey.VES ? this.vault.badauth() : Promise.resolve(null)).then(() => this.vaultItem.VES = this.vault.vaultKey.VES);
|
|
5153
|
+
}
|
|
5154
|
+
|
|
5155
|
+
shareFor(share) {
|
|
5156
|
+
let uri = this.vault.vault(share).uri();
|
|
5157
|
+
return uri ? this.share().then((shares) => shares.reduce((res, sh) => (res ?? (sh.uri() == uri ? sh : null)), null)) : null;
|
|
5158
|
+
}
|
|
5159
|
+
|
|
5160
|
+
uri() {
|
|
5161
|
+
if (!this.externalId && !this.version) return null;
|
|
5162
|
+
return libVES.Vault.toUri(this);
|
|
5163
|
+
}
|
|
5164
|
+
|
|
5165
|
+
short() {
|
|
5166
|
+
if (!this.externalId) return null;
|
|
5167
|
+
return libVES.Vault.toUri(this, this.vaultItem.VES.domain);
|
|
5168
|
+
}
|
|
5169
|
+
|
|
5170
|
+
_eventTracker() {
|
|
5171
|
+
return new libVES.EventTracker(this.vault, true);
|
|
5172
|
+
}
|
|
5173
|
+
|
|
5174
|
+
createWatch() {
|
|
5175
|
+
let w = new libVES.Watch(this.vaultItem);
|
|
5176
|
+
w.fields = {vaultKey: {id: true, type: true, algo: true, publicKey: true, externals: {domain: true, externalId: true}, user: {id: true, email: true}}, vaultItem: {id: true, type: true, meta: true, deleted: true, vaultKey: {id: true, type: true, algo: true, publicKey: true, externals: {domain: true, externalId: true}, user: {id: true, email: true}}, file: {externals: {domain: true, externalId: true}, creator: true}}, authorSession: {vaultKey: {id: true, type: true, externals: {domain: true, externalId: true}}, domain: true, user: {email: true}, remote: true, userAgent: true}};
|
|
5177
|
+
return w;
|
|
5178
|
+
}
|
|
5179
|
+
|
|
5180
|
+
replay() {
|
|
5181
|
+
return this.share().then((vaults) => Promise.all(vaults.map((vault) => {
|
|
5182
|
+
if (this.externalId) return new libVES.CustomEvent('itemadd', {detail: {replay: true, item: this, share: vault}});
|
|
5183
|
+
else return new libVES.CustomEvent('vaultadd', {detail: {replay: true, vault: this.vault, share: vault}});
|
|
5184
|
+
})));
|
|
5185
|
+
}
|
|
5186
|
+
|
|
5187
|
+
readable() {
|
|
5188
|
+
return this._get().then(() => true).catch((er) => {
|
|
5189
|
+
switch (er?.code) {
|
|
5190
|
+
case 'NotFound':
|
|
5191
|
+
case 'InvalidKey': return false;
|
|
5192
|
+
default: throw er;
|
|
5193
|
+
}
|
|
5194
|
+
});
|
|
5195
|
+
}
|
|
5196
|
+
|
|
5197
|
+
writable() {
|
|
5198
|
+
return this.shareFor(this.vault).then((sh) => sh && (sh.owner || sh.admin)).catch((er) => {
|
|
5199
|
+
switch (er?.code) {
|
|
5200
|
+
case 'NotFound': return true;
|
|
5201
|
+
case 'InvalidKey': return false;
|
|
5202
|
+
default: throw er;
|
|
5203
|
+
}
|
|
5204
|
+
});
|
|
5205
|
+
}
|
|
5206
|
+
|
|
5207
|
+
toString() {
|
|
5208
|
+
return 'libVES.Item(' + (this.uri() ?? '[provisional]') + ')';
|
|
5209
|
+
}
|
|
5210
|
+
|
|
5211
|
+
};
|
|
5212
|
+
|
|
5213
|
+
libVES.ItemCipher = class {
|
|
5214
|
+
constructor(ci, item) {
|
|
5215
|
+
this.cipher = ci;
|
|
5216
|
+
this.item = item;
|
|
5217
|
+
}
|
|
5218
|
+
|
|
5219
|
+
meta(val) {
|
|
5220
|
+
if (val == null) return Promise.resolve(this.cipher.meta);
|
|
5221
|
+
if (!(val instanceof Object)) return Promise.reject(new libVES.Error.InvalidValue('Cipher metadata must be an object'));
|
|
5222
|
+
this.cipher.meta = val;
|
|
5223
|
+
return this.item.put(this.cipher).then(() => this.cipher.meta);
|
|
5224
|
+
}
|
|
5225
|
+
|
|
5226
|
+
reset(final) {
|
|
5227
|
+
if (final && !this.final) return Promise.resolve(null);
|
|
5228
|
+
this.final = false;
|
|
5229
|
+
return this.item.vaultItem.get().then((ci) => this.cipher = ci);
|
|
5230
|
+
}
|
|
5231
|
+
|
|
5232
|
+
encrypt(data, optns) {
|
|
5233
|
+
return this.reset(true).then(() => {
|
|
5234
|
+
this.final = optns?.final !== false;
|
|
5235
|
+
if (data instanceof Blob) {
|
|
5236
|
+
return data.arrayBuffer().then((buf) => this.cipher.encrypt(buf, this.final)).then((ctext) => {
|
|
5237
|
+
const op = {type: 'application/vnd.ves.encrypted'};
|
|
5238
|
+
if (optns) optns.type = data.type;
|
|
5239
|
+
if (data instanceof File) {
|
|
5240
|
+
if (optns) optns.name = data.name;
|
|
5241
|
+
return new File([ctext], this.item.externalId, op);
|
|
5242
|
+
}
|
|
5243
|
+
return new Blob([ctext], op);
|
|
5244
|
+
});
|
|
5245
|
+
} else if (data instanceof ArrayBuffer) return this.cipher.encrypt(data, this.final).then((ctext) => ctext.buffer);
|
|
5246
|
+
else if ((data instanceof Object) && (data.buffer instanceof ArrayBuffer)) return this.cipher.encrypt(data.buffer, this.final).then((ctext) => new data.constructor(ctext.buffer));
|
|
5247
|
+
else return this.cipher.encrypt(libVES.Util.StringToByteArray(String(data)), this.final).then((ctext) => libVES.Util.ByteArrayToB64(ctext));
|
|
5248
|
+
});
|
|
5249
|
+
}
|
|
5250
|
+
|
|
5251
|
+
decrypt(data, optns) {
|
|
5252
|
+
return this.reset(true).then(() => {
|
|
5253
|
+
this.final = optns?.final !== false;
|
|
5254
|
+
if (data instanceof Blob) {
|
|
5255
|
+
return data.arrayBuffer().then((buf) => this.cipher.decrypt(buf, this.final)).then((ctext) => {
|
|
5256
|
+
if (data instanceof File) return new File([ctext], (optns?.name || ''), optns);
|
|
5257
|
+
return new Blob([ctext], optns);
|
|
5258
|
+
});
|
|
5259
|
+
} else if (data instanceof ArrayBuffer) return this.cipher.decrypt(data, this.final).then((ctext) => ctext.buffer);
|
|
5260
|
+
else if ((data instanceof Object) && (data.buffer instanceof ArrayBuffer)) return this.cipher.decrypt(data.buffer, this.final).then((ctext) => new data.constructor(ctext.buffer));
|
|
5261
|
+
else return this.cipher.decrypt(libVES.Util.B64ToByteArray(String(data)), this.final).then((ctext) => libVES.Util.ByteArrayToString(ctext));
|
|
5262
|
+
});
|
|
5263
|
+
}
|
|
5264
|
+
|
|
5265
|
+
toString() {
|
|
5266
|
+
return 'libVES.ItemCipher(' + String(this.item) + ')';
|
|
5267
|
+
}
|
|
5268
|
+
|
|
5269
|
+
toJSON() {
|
|
5270
|
+
return this.item?.uri();
|
|
5271
|
+
}
|
|
5272
|
+
};
|
|
5273
|
+
libVES.version = '3.00';
|
|
5274
|
+
|
|
3857
5275
|
module.exports = libVES;
|