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/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 2.06
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 || this.token) xhr.setRequestHeader('Authorization','Bearer ' + (optns.token ? optns.token : this.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 {code: 'Redirect', message: 'Starting VES Authorization...'};
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(Promise.resolve(veskey)).then(function(cryptoKey) {
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
- this.unlockedKeys = {};
252
- return Promise.resolve(true);
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 = vis[viid] = self.getItem(ves[i].vaultItem);
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 {code: 'NotFound', message: 'externalId is not an email for non-existing vault'};
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
- var vkey = new libVES.VaultKey({externals: exts, creator: self.me()},self);
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(), usr];
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
- return self.type == 'secondary' ? [self.me(), self.getVaultKey()] : [self.me()];
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: (fileRef.domain || VES.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.getFile(fileRef).then(function(file) {
685
- return file.delete();
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 Promise.all(vis.map(function(vi, i) {
861
- return vi.reshareWith([user]);
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 a = {name:'ECDH',namedCurve:libVES.Util.EC.namedCurves[String(args)]};
1322
- return crypto.subtle.importKey('spki',der,a,true,[]).catch(function() {;
1323
- return crypto.subtle.importKey('pkcs8',der,a,true,['deriveKey','deriveBits']).catch(function(e) {
1324
- console.log('PKCS8 failed, trying JWK...');
1325
- var jwk = libVES.Util.PKCS8.toJWK(der);
1326
- return crypto.subtle.importKey('jwk', jwk, a, true, jwk.key_ops);
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(data,up) {
1622
- var self = this;
1623
- var chg = false;
1624
- for (var k in data) {
1625
- if (up === undefined || up) this.fieldUpdate[k] = true;
1626
- if (this[k] instanceof Promise) {
1627
- this[k] = undefined;
1628
- chg = true;
1629
- }
1630
- if (this[k] === undefined) this[k] = Promise.resolve(data[k]).then((function(k) {
1631
- return function(v) {
1632
- var clsf;
1633
- if (self.fieldClass[k]) return (clsf = function(v) {
1634
- if (v instanceof libVES.Object) return v;
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
- for (var i = 0; i < this.fieldSets.length; i++) if (this.fieldSets[i][fld]) {
1658
- for (var k in this.fieldSets[i]) flds[k] = this.fieldSets[i][k];
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
- var req = this.id ? this.id.then(function(id) { return self.VES.get(self.apiUri + '/' + id,flds,optns); }) : self.postData().then(function(data) {
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) delete(this[k]);
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 vis[0].get();
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) return self.wcPriv;
1922
- return self.getId().then(function(id) {
1923
- if (!self.VES.unlockedKeys[id]) return self.VES.unlockedKeys[id] = self.engine().then(function(m) {
1924
- return self.resolveVESkey(veskey).then(function(v) {
1925
- return self.getPrivateKey().then(function(prk) {
1926
- return m.import(prk,{password: v});
1927
- }).catch(function(e) {
1928
- if (e.code != 'Legacy' || !self.VES.unlockLegacyKey) throw e;
1929
- delete(self.VES.unlockedKeys[id]);
1930
- return self.VES.unlockLegacyKey(self,veskey);
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
- else return self.VES.unlockedKeys[id].catch(function(e) {
1935
- self.VES.unlockedKeys[id] = null;
1936
- return self.unlock(veskey);
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.algo ? self.setField('algo',optns.algo) : Promise.resolve()).then(function() {
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(vaultKeys) {
2115
- return Promise.resolve(false);
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 && vaultKeys[(k = vaultEntries[i].vaultKey).id]) {
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 new libVES.VaultKey(k, self.VES).decrypt(d).catch(fn);
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().then(function(type) {
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 || self.id ? self.getVaultEntries().then(function(ves) {
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 k.encrypt(v).then(function(ctext) {
2225
- return (function(refs) {
2226
- if (refs) for (var i in refs) if (refs[i] === k) return Promise.resolve({'$ref':i});
2227
- return k.postData(null,refs);
2228
- })(libVES.Object._refs).then(function(pd) {
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(ks).then(function(f) {
2236
- if (f === false) set_ves.push({vaultKey: {id: ve.vaultKey.id}, '$op': 'delete'});
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 (save || save === undefined) return self.post().then(function() {
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
- crypto.subtle.exportKey('spki',eKey.publicKey),
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
- cipher: function(priv,pub) {
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 Promise.resolve(libVES.Algo.ECDH.curveBytes[pub.algorithm.namedCurve] || crypto.subtle.exportKey('jwk',pub).then(function(jwk) {
2425
- return jwk.x.length * 3 / 4;
2426
- })).then(function(len) {
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:'P-384'};
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:2048, publicExponent:new Uint8Array([1,0,1]), hash:'SHA-1'};
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-1'},true,['encrypt']);
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 tkn.vaultItem.shareWith(assist ? [tkn.user,user] : [tkn.user]).then(function() {
3146
- self.tokens = undefined;
3147
- self.vaultKey.vaultItems = undefined;
3148
- return true;
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 {code: 'NotFound', message: 'No public key stored for ' + org};
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 {code: 'NoData', message: 'Empty value'};
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 {code: 'NotFound', message: 'No valid token in the source url'};
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({url: tk.url, code: 'Incomplete', message: 'Missing encrypted data'});
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 {code: 'Reload', message: 'Completing the key exchange'};
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({code: 'NotFound', message: 'Value is not set'});
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 {code: 'NotFound', message: 'Not in the session storage'};
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 = new Promise(function(resolve, reject) {
3682
- if (typeof(WasmOQS) == 'function') return resolve();
3683
- var sc = document.createElement('script');
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
- if (data.priv) {
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.algo : null;
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 (!wasm.generate(k)) throw new libVES.Error('Internal', 'OQS generate failed');
3761
- var pub = {};
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
- var asn = libVES.Util.ASN1.decode(der)[0];
3771
- var pkey = null;
3772
- var pub = null;
3773
- if (typeof(asn[0]) == 'number') {
3774
- var asn2 = libVES.Util.ASN1.decode(asn[2])[0];
3775
- pkey = asn2[1];
3776
- pub = libVES.Util.ASN1.decode(asn2[2])[0];
3777
- } else pkey = asn[1];
3778
- return libVES.Algo.OQS.wasm().then(function(wasm) {
3779
- var k = wasm.init(algo, !!pub);
3780
- if (!k) throw new libVES.Error('InvalidValue', 'OQS key init failed (bad algo?)');
3781
- var s = function(dst, src, dif) {
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
- init: function(algo, priv) {
3800
- var a = new Uint8Array(libVES.Util.StringToByteArray(algo));
3801
- var arg1 = new Uint8Array(this.asm.memory.buffer, 16, 48);
3802
- arg1.set(a);
3803
- arg1.set([0], a.byteLength);
3804
- var ptr = this._WasmOQS_new(arg1.byteOffset, priv);
3805
- if (!ptr) return null;
3806
- var key = { ptr: ptr };
3807
- var priv = this._WasmOQS_priv(ptr);
3808
- if (priv) key.priv = new Uint8Array(this.asm.memory.buffer, priv, this._WasmOQS_privlen(ptr));
3809
- key.pub = new Uint8Array(this.asm.memory.buffer, this._WasmOQS_pub(ptr), this._WasmOQS_publen(ptr));
3810
- key.secretlen = this._WasmOQS_decaps(key.ptr, null, null);
3811
- key.ctextlen = this._WasmOQS_encaps(key.ptr, null, null);
3812
- key.algo = algo;
3813
- return key;
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
- return this._WasmOQS_generate(key.ptr) >= 0;
4352
+ return this._WasmOQS_generate(key.ptr) >= 0;
3817
4353
  },
3818
4354
  encaps: function(key) {
3819
- var arg1 = new Uint8Array(this.asm.memory.buffer, this._WasmOQS_secretbuf, this._WasmOQS_decaps(key.ptr, null, null));
3820
- var arg2 = new Uint8Array(this.asm.memory.buffer, this._WasmOQS_ctextbuf, this._WasmOQS_encaps(key.ptr, null, null));
3821
- if (this._WasmOQS_encaps(key.ptr, arg2.byteOffset, arg1.byteOffset) <= 0) return null;
3822
- key.secret = new Uint8Array(arg1.byteLength);
3823
- key.secret.set(arg1);
3824
- var ctext = new Uint8Array(arg2.byteLength);
3825
- ctext.set(arg2);
3826
- return ctext;
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
- if (!ctext) return key.secret;
3830
- if (ctext.byteLength != this._WasmOQS_encaps(key.ptr, null, null)) return null;
3831
- var arg1 = new Uint8Array(this.asm.memory.buffer, this._WasmOQS_secretbuf, this._WasmOQS_decaps(key.ptr, null, null));
3832
- var arg2 = new Uint8Array(this.asm.memory.buffer, this._WasmOQS_ctextbuf, ctext.byteLength);
3833
- arg2.set(ctext);
3834
- if (this._WasmOQS_decaps(key.ptr, arg1.byteOffset, arg2.byteOffset) <= 0) return null;
3835
- key.secret = new Uint8Array(arg1.byteLength);
3836
- key.secret.set(arg1);
3837
- return key.secret;
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
- this._WasmOQS_free(key.ptr);
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
- var k = this.init(algo, 1);
3844
- this.generate(k);
3845
- console.log(k);
3846
- var ctext = this.encaps(k);
3847
- console.log(k.secret, ctext);
3848
- var secret = this.decaps(k);
3849
- console.log(secret);
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;