libves 2.16.0 → 3.0.2

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.16
30
+ * @version 3.02
31
31
  *
32
32
  * @dev Official source code: https://github.com/vesvault/libVES
33
33
  *
@@ -51,6 +51,7 @@ 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 = {
@@ -62,8 +63,9 @@ libVES.prototype = {
62
63
  keyOptions: {namedCurve: 'P-521'},
63
64
  textCipher: 'AES256GCMp',
64
65
  defaultHash: 'SHA256',
65
- propagators: [],
66
+ propagators: null,
66
67
  request: function(method,uri,body,optns) {
68
+ var self = this;
67
69
  if (!optns) optns = {};
68
70
  return new Promise(function(resolve,reject) {
69
71
  var xhr = new XMLHttpRequest();
@@ -80,8 +82,13 @@ libVES.prototype = {
80
82
  return new libVES.Error(e.type,e.message,e);
81
83
  });
82
84
  if (errs.length) {
85
+ var retry = function(o) { return self.request(method, uri, body, (o || optns)); };
83
86
  if (optns && optns.onerror) try {
84
- 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));
85
92
  } catch (e) {
86
93
  reject(e);
87
94
  }
@@ -95,7 +102,7 @@ libVES.prototype = {
95
102
  if (body != null) xhr.setRequestHeader('Content-Type','application/json');
96
103
  xhr.setRequestHeader('Accept','application/json');
97
104
  if (this.user && optns.password) xhr.setRequestHeader('Authorization','Basic ' + btoa(this.user + ':' + optns.password));
98
- 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));
99
106
  xhr.responseType = 'json';
100
107
  xhr.send(body);
101
108
  }.bind(this));
@@ -120,6 +127,10 @@ libVES.prototype = {
120
127
  }
121
128
  return '';
122
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
+ },
123
134
  elevateAuth: function(optns) {
124
135
  var self = this;
125
136
  if (optns && (optns.password || optns.token)) return Promise.resolve(optns);
@@ -236,7 +247,7 @@ libVES.prototype = {
236
247
  unlock: function(veskey) {
237
248
  var self = this;
238
249
  return this.getVaultKey().then(function(vkey) {
239
- return vkey.unlock(Promise.resolve(veskey)).then(function(cryptoKey) {
250
+ return vkey.unlock(veskey).then(function(cryptoKey) {
240
251
  if (self.VESkey === null) self.VESkey = veskey;
241
252
  if (!self.token && self.type == 'secondary') return vkey.getSessionToken().then(function(tkn) {
242
253
  self.token = tkn;
@@ -251,8 +262,14 @@ libVES.prototype = {
251
262
  });
252
263
  },
253
264
  lock: function() {
254
- this.unlockedKeys = {};
255
- 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
+ this.propagators = null;
270
+ return Promise.all(lock).then(function() {
271
+ return true;
272
+ });
256
273
  },
257
274
  reset: function(val) {
258
275
  this.userMe = undefined;
@@ -293,11 +310,11 @@ libVES.prototype = {
293
310
  });
294
311
  });
295
312
  },
296
- getItems: function() {
313
+ getItems: function(flds) {
297
314
  var self = this;
298
315
  return this.getVaultKey().then(function(k) {
299
316
  return k.getId().then(function(kid) {
300
- return k.getVaultEntries({type: true, deleted: true, file: {creator: true, externals: true}, vaultKey: {type: true, user: true}}).then(function(ves) {
317
+ return k.getVaultEntries(self.mergeFieldList({type: true, deleted: true, file: {creator: true, externals: true}, vaultKey: {type: true, user: true}}, flds)).then(function(ves) {
301
318
  var vis = {};
302
319
  var vlst = [];
303
320
  for (var i = 0; i < ves.length; i++) {
@@ -308,6 +325,7 @@ libVES.prototype = {
308
325
  if (!vi.vaultKey) vi.vaultKey = undefined;
309
326
  vi = vis[viid] = self.getItem(vi);
310
327
  vlst.push(vi);
328
+ if (!ves[i].vaultKey) ves[i].vaultKey = {id: kid};
311
329
  vi.vaultEntryByKey[kid] = ves[i];
312
330
  }
313
331
  }
@@ -346,7 +364,7 @@ libVES.prototype = {
346
364
  _matchUser: function(u) {
347
365
  if (typeof(u) == 'object') {
348
366
  if (u instanceof libVES.User) return u;
349
- else return new libVES.User(u,this);
367
+ else return new libVES.User((u.id ? {id: u.id} : {email: u.email}), this);
350
368
  } else if (typeof(u) == 'string' && u.match(/^\S+\@\S+$/)) return new libVES.User({email: u},this);
351
369
  throw new libVES.Error('BadUser',"Cannot match user: " + u,{value: u});
352
370
  },
@@ -377,11 +395,14 @@ libVES.prototype = {
377
395
  }).catch(function(e) {
378
396
  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});
379
397
  })).then(function(exts) {
380
- var vkey = new libVES.VaultKey({externals: exts, creator: self.me()},self);
398
+ var keyref = {externals: exts};
399
+ if (self.externalId && self.externalId[0] != '!') keyref.creator = self.me();
400
+ var vkey = new libVES.VaultKey(keyref, self);
381
401
  return vkey.getId().then(function() {
382
402
  return vkey;
383
403
  }).catch(function(e) {
384
404
  if (e.code != 'NotFound') throw e;
405
+ if (!keyref.creator) throw new libVES.Error.InvalidKey('Anonymous vaults are not authorized to create temp keys');
385
406
  return Promise.resolve(user || m().then(function(dom) {
386
407
  return dom.vaultRefToUser(exts[0]);
387
408
  })).catch(function(e) {
@@ -405,6 +426,20 @@ libVES.prototype = {
405
426
  });
406
427
  });
407
428
  },
429
+ getPropagators: function() {
430
+ if (!this.propagators) {
431
+ let xid = (this.externalId ?? this.email);
432
+ this.propagators = (xid?.match(/^[^\!]+\@\w/) ? Promise.resolve(xid.replace(/\!.*/, '')) : this.me().then((me) => me.getEmail())).then((xid) => {
433
+ if (!xid) return [];
434
+ let prop = new libVES.VaultKey({externals: {domain: '.propagate', externalId: xid.toLowerCase()}}, this);
435
+ return prop.getId().then(() => [prop]);
436
+ }).catch((er) => {
437
+ if (er?.code == 'NotFound' || er?.code == 'Unauthorized') return [];
438
+ throw er;
439
+ });
440
+ }
441
+ return Promise.resolve(this.propagators);
442
+ },
408
443
  getUserKeys: function(usr) {
409
444
  var self = this;
410
445
  return usr.getActiveVaultKeys().catch(function(e) {
@@ -434,13 +469,12 @@ libVES.prototype = {
434
469
  return key.generate(veskey, optns).then(function(k) {
435
470
  key.setField('vaultItems', veskey.then(function(v) {
436
471
  var vi = new libVES.VaultItem({type: 'password'}, self);
437
- return usr.getActiveVaultKeys().then(function() {
438
- return [self.me(), self.getVaultKey(), usr];
472
+ return usr.getActiveVaultKeys().then(function(akeys) {
473
+ return [self.me(), self.getVaultKey()].concat(akeys);
439
474
  }).catch(function(e) {
440
475
  if (e.code != 'NotFound') throw e;
441
476
  var sh = self.type == 'secondary' ? [self.me(), self.getVaultKey()] : [self.me()];
442
- if (self.propagators) for (var i = 0; i < self.propagators.length; i++) sh.push(self.propagators[i]);
443
- return sh;
477
+ return self.getPropagators().then((props) => sh.concat(props)).catch((er) => sh);
444
478
  }).then(function(sh) {
445
479
  return Promise.all(sh);
446
480
  }).then(function(sh) {
@@ -573,6 +607,9 @@ libVES.prototype = {
573
607
  }).catch(function(e) {
574
608
  if (!e || e.code != 'Unauthorized') throw e;
575
609
  }).then(function() {
610
+ self.vaultKey = k.lock().then(function() {
611
+ return k;
612
+ });
576
613
  return self.unlock(veskey);
577
614
  });
578
615
  });
@@ -807,7 +844,7 @@ libVES.prototype = {
807
844
  return self.getVaultKey().then(function(vk) {
808
845
  return vk.getField('unlockableVaultKeys').then(function(vks) {
809
846
  var rs = {};
810
- return Promise.all(vks.map(function(e, i) {
847
+ return Promise.all((vks || []).map(function(e, i) {
811
848
  return e.getId().then(function(id) {
812
849
  rs[id] = e;
813
850
  });
@@ -852,11 +889,20 @@ libVES.prototype = {
852
889
  return vkey.rekey(optns);
853
890
  });
854
891
  else return vkey.getVaultItems().then(function(vis) {
855
- return self.elevateAuth().then(function(optns) {
856
- return Promise.all(vis.map(function(vi, i) {
857
- return vi.reshareWith([user], undefined, optns);
858
- }));
859
- });
892
+ return Promise.all([user.getActiveVaultKeys(), vkey.getExternals().then((exts) => {
893
+ let ckey = new libVES.VaultKey({externals: exts}, self);
894
+ return ckey.getType().then(() => [ckey]).catch((er) => {
895
+ if (er?.code != 'NotFound') throw er;
896
+ return [];
897
+ });
898
+ })]).then((klists) => {
899
+ let ks = (klists[0] ?? []).concat(klists[1]);
900
+ return Promise.all(ks.map((k) => k.getType())).then((ktypes) => ks.filter((k, i) => ktypes[i] != 'temp'));
901
+ }).then((ks) => self.elevateAuth().then(function(optns) {
902
+ return Promise.all(vis.map(function(vi, i) {
903
+ return vi.reshareWith(ks, undefined, optns);
904
+ }));
905
+ }));
860
906
  });
861
907
  });
862
908
  });
@@ -917,6 +963,11 @@ libVES.Error.Redirect = function(msg, optns) {
917
963
  };
918
964
  libVES.Error.Redirect.prototype = new libVES.Error('Redirect');
919
965
 
966
+ libVES.Error.Unauthorized = function(msg, optns) {
967
+ this.init(msg, optns);
968
+ };
969
+ libVES.Error.Unauthorized.prototype = new libVES.Error('Unauthorized');
970
+
920
971
  libVES.Error.Internal = function(msg, optns) {
921
972
  this.init(msg, optns);
922
973
  };
@@ -1024,6 +1075,14 @@ libVES.Util = {
1024
1075
  }
1025
1076
  return rs;
1026
1077
  },
1078
+ fillUndefs: function(data, defs) {
1079
+ if (data instanceof Array) data.map((d) => libVES.Util.fillUndefs(d, defs));
1080
+ else if (data && defs) for (var k in defs) if (defs[k]) {
1081
+ if (data[k] === undefined) data[k] = undefined;
1082
+ else if (data[k] instanceof Object) libVES.Util.fillUndefs(data[k], defs[k]);
1083
+ }
1084
+ return data;
1085
+ },
1027
1086
  loadWasm: function(src) {
1028
1087
  return new Promise(function(resolve, reject) {
1029
1088
  var sc = document.createElement('script');
@@ -1712,30 +1771,20 @@ libVES.Object.prototype = {
1712
1771
  this.setFields(data,data.id == null);
1713
1772
  if (refs) for (var k in refs) this[k] = Promise.resolve(refs[k]);
1714
1773
  },
1715
- setFields: function(data,up) {
1716
- var self = this;
1717
- var chg = false;
1718
- for (var k in data) {
1719
- if (up === undefined || up) this.fieldUpdate[k] = true;
1720
- if (this[k] instanceof Promise) {
1721
- this[k] = undefined;
1722
- chg = true;
1723
- }
1724
- if (this[k] === undefined) this[k] = Promise.resolve(data[k]).then((function(k) {
1725
- return function(v) {
1726
- var clsf;
1727
- if (self.fieldClass[k]) return (clsf = function(v) {
1728
- if (v instanceof libVES.Object) return v;
1729
- else if (v instanceof Array) return v.map(function(vv) { return clsf(vv); });
1730
- else if (v) return new (self.fieldClass[k])(v,self.VES);
1731
- })(v);
1732
- return v;
1733
- };
1734
- })(k));
1735
- else return Promise.reject(new libVES.Error('Internal',"Unknown field: " + k));
1736
- }
1737
- if (chg && self.trigger) self.trigger.resolve(self);
1738
- return Promise.resolve(self);
1774
+ setFields: function(flds, up) {
1775
+ var res = Promise.resolve(null);
1776
+ for (var fld in flds) ((fld) => {
1777
+ if (up === undefined || up) this.fieldUpdate[fld] = true;
1778
+ var cls = this.fieldClass[fld];
1779
+ var cur = this[fld];
1780
+ res = this[fld] = res.then(() => Promise.resolve(flds[fld]).then((val) => Promise.resolve(cur).catch((er) => undefined).then((cur) => {
1781
+ if (!cls || !val) return val;
1782
+ else if (val instanceof Array) return val.map((v) => ((v instanceof libVES.Object) ? v : new cls(v, this.VES)));
1783
+ else if (cur instanceof cls) return cur.setFields(val, up);
1784
+ else return (val instanceof libVES.Object) ? val : new cls(val, this.VES);
1785
+ })));
1786
+ })(fld);
1787
+ return res.then(() => this);
1739
1788
  },
1740
1789
  setField: function(fld,val,upd) {
1741
1790
  var flds = {};
@@ -1744,54 +1793,78 @@ libVES.Object.prototype = {
1744
1793
  return self[fld];
1745
1794
  });
1746
1795
  },
1796
+ unsetField: function(fld) {
1797
+ delete(this[fld]);
1798
+ },
1799
+ _fieldsToLoad: function(fldlst, force, ld) {
1800
+ var flds = {};
1801
+ for (var k in fldlst) flds[k] ||= fldlst[k];
1802
+ for (var i = 0; i < this.fieldSets.length; i++) {
1803
+ for (var k in this.fieldSets[i]) if (fldlst[k]) {
1804
+ for (var k in this.fieldSets[i]) if ((force || !this[k]) && !(flds[k] instanceof Object)) (flds ||= {})[k] = this.fieldSets[i][k];
1805
+ break;
1806
+ }
1807
+ }
1808
+ var res = Promise.resolve(null);
1809
+ for (var fld in flds) ((fld) => {
1810
+ var cur = this[fld];
1811
+ var na = (cur === undefined);
1812
+ var cls = this.fieldClass[fld];
1813
+ res = res.then((res) => Promise.resolve(cur).catch((er) => null).then((cur) => {
1814
+ var lst = null;
1815
+ if (force || na) lst = flds[fld];
1816
+ else if (cls) {
1817
+ 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]));
1818
+ else if (cur instanceof cls) lst = cur._fieldsToLoad(flds[fld], force, ld.then((vals) => vals[fld]));
1819
+ }
1820
+ return Promise.resolve(lst).then((lst) => {
1821
+ if (lst) (res ||= {})[fld] = lst;
1822
+ return res;
1823
+ });
1824
+ }));
1825
+ 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);
1826
+ })(fld);
1827
+ ld.then((vals) => {
1828
+ for (var fld in vals) if (!flds[fld] && !this[fld]) this.setField(fld, vals[fld], false);
1829
+ }).catch((er) => null);
1830
+ return res.then((res) => {
1831
+ if (res) for (var k in fldlst) if (res[k]) return res;
1832
+ return null;
1833
+ });
1834
+ },
1747
1835
  getFields: function(fldlst, force) {
1748
- var self = this;
1749
- var flds = {};
1750
- for (var i = 0; i < this.fieldSets.length; i++) {
1751
- for (var k in this.fieldSets[i]) if (fldlst[k]) {
1752
- for (var k in this.fieldSets[i]) if ((force || !this[k]) && !(flds[k] instanceof Object)) flds[k] = this.fieldSets[i][k];
1753
- break;
1754
- }
1755
- }
1756
- for (var k in fldlst) if ((force || !this[k]) && !(flds[k] instanceof Object)) flds[k] = fldlst[k];
1757
- for (var k in flds) {
1758
- this.loadFields(flds);
1759
- break;
1760
- }
1836
+ var ldf;
1837
+ var ld = new Promise((resolve, reject) => ldf = [resolve, reject]);
1838
+ this._fieldsToLoad(fldlst, force, ld).then((flds) => this.loadFields(flds, force)).then((vals) => ldf[0](vals)).catch((er) => ldf[1](er));
1761
1839
  var plst = [];
1762
- for (var k in fldlst) {
1763
- plst.push(Promise.resolve(this[k]).then(function(v) {
1840
+ for (var k in fldlst) ((k) => {
1841
+ plst.push(ld.then(() => this[k]).then(function rslv(v) {
1842
+ if (v instanceof Array) return Promise.all(v.map(function(e, i) {
1843
+ return rslv(e);
1844
+ }));
1764
1845
  if (!(v instanceof libVES.Object)) return v;
1765
- return v.getFields(fldlst[k], force);
1846
+ return v.getFields(fldlst[k]);
1766
1847
  }));
1767
- }
1848
+ })(k);
1768
1849
  var rs = {};
1769
- return Promise.all(plst).then(function(lst) {
1850
+ return Promise.all(plst).then((lst) => {
1770
1851
  var i = 0;
1771
1852
  for (var k in fldlst) rs[k] = lst[i++];
1772
1853
  return rs;
1773
1854
  });
1774
1855
  },
1775
1856
  getField: function(fld,fldlst,force) {
1776
- var self = this;
1777
1857
  if (!this[fld] || force) {
1778
1858
  var flds = {};
1779
- for (var i = 0; i < this.fieldSets.length; i++) if (this.fieldSets[i][fld]) {
1780
- for (var k in this.fieldSets[i]) flds[k] = this.fieldSets[i][k];
1781
- break;
1782
- }
1783
- if (fldlst) flds[fld] = fldlst;
1784
- if (!flds[fld]) {
1785
- var cls = self.fieldClass[fld];
1786
- flds[fld] = cls ? cls.prototype.fieldList : true;
1787
- }
1788
- this.loadFields(flds,force);
1859
+ flds[fld] = fldlst || true;
1860
+ this.getFields(flds, force).catch(() => null);
1789
1861
  }
1790
1862
  return this[fld];
1791
1863
  },
1792
1864
  loadFields: function(flds,force,optns) {
1865
+ if (!flds) return Promise.resolve({});
1793
1866
  var self = this;
1794
- var req = this.id ? this.id.then(function(id) { return self.VES.get(self.apiUri + '/' + id,flds,optns); }) : self.postData().then(function(data) {
1867
+ return (this.id && !flds.id ? this.id.then(function(id) { return self.VES.get(self.apiUri + '/' + id,flds,optns); }) : self.postData().then(function(data) {
1795
1868
  data['$op'] = 'fetch';
1796
1869
  return self.VES.post(self.apiUri,data,flds,optns);
1797
1870
  }).then(function(data) {
@@ -1800,21 +1873,10 @@ libVES.Object.prototype = {
1800
1873
  self.fieldUpdate = {id: true};
1801
1874
  }
1802
1875
  return data;
1803
- });
1804
- for (var k in flds) if (force || this[k] === undefined) {
1805
- this[k] = req.then((function(fld) {
1806
- var cls = self.fieldClass[fld];
1807
- return function(data) {
1808
- if (cls && data[fld]) return ((data[fld] instanceof Array) ? data[fld].map(function(v) {
1809
- return new cls(v,self.VES);
1810
- }) : new cls(data[fld],self.VES));
1811
- return data[fld];
1812
- };
1813
- })(k));
1814
- }
1876
+ })).then((data) => libVES.Util.fillUndefs(data, flds));
1815
1877
  },
1816
1878
  reset: function() {
1817
- for (var k in this.fieldClass) delete(this[k]);
1879
+ for (var k in this.fieldClass) this.unsetField(k);
1818
1880
  return Promise.resolve();
1819
1881
  },
1820
1882
  getId: function() {
@@ -1888,6 +1950,23 @@ libVES.Object.prototype = {
1888
1950
  },
1889
1951
  resolveError: function(e,field) {
1890
1952
  throw e;
1953
+ },
1954
+ setUpdate: function(flds) {
1955
+ var rs = [];
1956
+ for (var k in flds) {
1957
+ if (flds[k]) this.fieldUpdate[k] = true;
1958
+ else delete(this.fieldUpdate[k]);
1959
+ if (this[k] && (flds[k] instanceof Object)) (function(p, k) {
1960
+ rs.push(p.then(function rslv(obj) {
1961
+ if (obj instanceof Array) return Promise.all(obj.map(rslv));
1962
+ if (obj instanceof libVES.Object) return obj.setUpdate(flds[k]);
1963
+ }));
1964
+ })(this[k], k);
1965
+ }
1966
+ return Promise.all(rs);
1967
+ },
1968
+ toJSON: function() {
1969
+ return String(this);
1891
1970
  }
1892
1971
  };
1893
1972
 
@@ -2040,10 +2119,16 @@ libVES.VaultKey.prototype = new libVES.Object({
2040
2119
  case 'lost':
2041
2120
  return self.getVaultItems().then(function(vis) {
2042
2121
  var f = function(vis) {
2043
- if (!vis.length) throw new libVES.Error('InvalidKey','Cannot unlock the secondary key');
2122
+ if (!vis || !vis.length) throw new libVES.Error('InvalidKey','Cannot unlock the secondary key');
2044
2123
  return vis[0].getType().then(function(t) {
2045
2124
  switch (t) {
2046
- case 'password': return vis[0].get();
2125
+ case 'password': return self.getId().then(function(kid) {
2126
+ if (!self.VES.pendingKeys) self.VES.pendingKeys = {};
2127
+ if (kid) self.VES.pendingKeys[kid] = true;
2128
+ return vis[0].get().finally(function() {
2129
+ self.VES.pendingKeys[kid] = false;
2130
+ });
2131
+ });
2047
2132
  default: return f(vis.slice(1));
2048
2133
  }
2049
2134
  });
@@ -2054,26 +2139,57 @@ libVES.VaultKey.prototype = new libVES.Object({
2054
2139
  }
2055
2140
  });
2056
2141
  },
2142
+ invalidVESkey: function() {
2143
+ var self = this;
2144
+ return self.getVaultItems().then(function(vis) {
2145
+ return Promise.all(vis.map(function(vi) {
2146
+ return vi.getVaultEntries().then(function(entries) {
2147
+ 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) {
2148
+ return key.getFields({user: {email: true}, extrenals: {domain: true, externalId: true}}).then(function(flds) {
2149
+ return vi.unshareWith([flds.externals && flds.externals[0] ? flds.externals[0] : flds.user.email]);
2150
+ });
2151
+ });
2152
+ });
2153
+ }));
2154
+ });
2155
+ },
2057
2156
  unlock: function(veskey) {
2058
2157
  var self = this;
2059
- if (self.wcPriv) return self.wcPriv;
2060
- return self.getId().then(function(id) {
2061
- if (!self.VES.unlockedKeys[id]) return self.VES.unlockedKeys[id] = self.engine().then(function(m) {
2062
- return self.resolveVESkey(veskey).then(function(v) {
2063
- return self.getPrivateKey().then(function(prk) {
2064
- return m.import(prk,{password: v});
2065
- }).catch(function(e) {
2066
- if (e.code != 'Legacy' || !self.VES.unlockLegacyKey) throw e;
2067
- delete(self.VES.unlockedKeys[id]);
2068
- return self.VES.unlockLegacyKey(self,veskey);
2158
+ if (!self.wcPriv) self.wcPriv = self.getId().then(function(id) {
2159
+ return Promise.resolve(self.VES.unlockedKeys[id]).then(function(k) {
2160
+ return k.wcPriv;
2161
+ }).catch(function(e) {
2162
+ let un = self.engine().then(function(m) {
2163
+ return self.resolveVESkey(veskey).then(function(v) {
2164
+ return self.getPrivateKey().then(function(prk) {
2165
+ return m.import(prk, {password: v}).catch(function(e) {
2166
+ if (e && e.code == 'InvalidKey' && !veskey) {
2167
+ console.log('Bad key propagated for ' + id + ', unsharing...');
2168
+ return self.invalidVESkey().catch(function(e2) {
2169
+ console.log(e2);
2170
+ }).then(function(r) {
2171
+ console.log(r);
2172
+ throw e;
2173
+ });
2174
+ }
2175
+ throw e;
2176
+ });
2177
+ });
2069
2178
  });
2070
2179
  });
2071
- });
2072
- else return self.VES.unlockedKeys[id].catch(function(e) {
2073
- self.VES.unlockedKeys[id] = null;
2074
- return self.unlock(veskey);
2180
+ let vk = self.VES.unlockedKeys[id] = un.then(function() {
2181
+ return self;
2182
+ }).catch(function(e) {
2183
+ if (self.VES.unlockedKeys[id] === vk) delete(self.VES.unlockedKeys[id]);
2184
+ });
2185
+ return un;
2075
2186
  });
2076
2187
  });
2188
+ else if (veskey) self.wcPriv = self.wcPriv.catch(function(e) {
2189
+ delete(self.wcPriv);
2190
+ return self.unlock(veskey);
2191
+ });
2192
+ return self.wcPriv;
2077
2193
  },
2078
2194
  lock: function() {
2079
2195
  var self = this;
@@ -2251,8 +2367,20 @@ libVES.VaultKey.prototype = new libVES.Object({
2251
2367
  });
2252
2368
  });
2253
2369
  },
2254
- matchVaults: function(vaultKeys) {
2255
- return Promise.resolve(false);
2370
+ matchVaults: function(shares) {
2371
+ 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) => {
2372
+ if (res) return res;
2373
+ var ext = flds.externals?.[0];
2374
+ if (sh instanceof libVES.Object) {
2375
+ if (sh instanceof libVES.VaultKey) return sh.getId().then((id) => (id == flds.id ? sh : res));
2376
+ 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));
2377
+ else if ((sh instanceof libVES.User) && flds.user && !ext) return sh.getEmail().then((email) => (email == flds.user.email ? sh : res));
2378
+ } else if (sh instanceof Object) {
2379
+ if (sh.externalId && sh.externalId == ext?.externalId && (sh.domain || this.VES.domain) == ext.domain) return sh;
2380
+ else if (sh.email && sh.email == flds.user?.email && !ext) return sh;
2381
+ } else if (sh && flds.user?.email == sh && !ext) return sh;
2382
+ return res;
2383
+ })), Promise.resolve(false)));
2256
2384
  },
2257
2385
  getKeyOptions: function() {
2258
2386
  var self = this;
@@ -2268,7 +2396,7 @@ libVES.VaultItem.prototype = new libVES.Object({
2268
2396
  apiUri: 'vaultItems',
2269
2397
  fieldList: {id: true, deleted: true, file: true},
2270
2398
  fieldClass: {vaultKey: libVES.VaultKey, file: libVES.File},
2271
- 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}],
2399
+ 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}],
2272
2400
  defaultCipher: 'AES256GCM',
2273
2401
  getRaw: function() {
2274
2402
  var self = this;
@@ -2277,9 +2405,11 @@ libVES.VaultItem.prototype = new libVES.Object({
2277
2405
  var fn = function() {
2278
2406
  if (vaultEntries) for (; i < vaultEntries.length; i++) {
2279
2407
  var k, d;
2280
- if ((d = vaultEntries[i].encData) != null && vaultKeys[(k = vaultEntries[i].vaultKey).id]) {
2408
+ if ((d = vaultEntries[i].encData) != null && (k = vaultKeys[vaultEntries[i].vaultKey.id]) && (!self.VES.pendingKeys || !self.VES.pendingKeys[vaultEntries[i].vaultKey.id])) {
2281
2409
  i++;
2282
- return new libVES.VaultKey(k, self.VES).decrypt(d).catch(fn);
2410
+ return Promise.resolve(k).then(function(k) {
2411
+ return k.decrypt(d).catch(fn);
2412
+ });
2283
2413
  }
2284
2414
  }
2285
2415
  return Promise.reject(new libVES.Error('InvalidKey',"No unlocked key to decrypt the item",{vaultItem: self}));
@@ -2338,7 +2468,10 @@ libVES.VaultItem.prototype = new libVES.Object({
2338
2468
  },
2339
2469
  build: function(data) {
2340
2470
  var self = this;
2341
- return this.getType().then(function(type) {
2471
+ return this.getType().catch(function(e) {
2472
+ if (e && e.code == 'NotFound') return self.setField('type', libVES.VaultItem.Type._detect(data));
2473
+ throw e;
2474
+ }).then(function(type) {
2342
2475
  return libVES.getModule(libVES.VaultItem.Type,type).then(function(m) {
2343
2476
  return m.build.call(self,data);
2344
2477
  });
@@ -2350,12 +2483,12 @@ libVES.VaultItem.prototype = new libVES.Object({
2350
2483
  shareWith: function(usrs,val,save) {
2351
2484
  var self = this;
2352
2485
  return self.VES.usersToKeys(usrs).then(function(ks) {
2353
- return (val == null || self.id ? self.getVaultEntries().then(function(ves) {
2486
+ return (val == null ? self.getVaultEntries().then(function(ves) {
2354
2487
  var k_ves = {};
2355
2488
  var k_used = {};
2356
2489
  for (var j = 0; j < ves.length; j++) k_ves[ves[j].vaultKey.id] = ves[j];
2357
2490
  return Promise.all(ks.map(function(k,j) {
2358
- return k.getId().then(function(k_id) {
2491
+ if (!k.fieldUpdate.privateKey) return k.getId().then(function(k_id) {
2359
2492
  k_used[k_id] = true;
2360
2493
  return k_ves[k_id];
2361
2494
  }).catch(function(){});
@@ -2367,21 +2500,26 @@ libVES.VaultItem.prototype = new libVES.Object({
2367
2500
  var new_ves = [];
2368
2501
  var set_ves = [];
2369
2502
  var valr = null;
2503
+ var key_ids = {};
2370
2504
  return Promise.all(ks.map(function(k,j) {
2371
2505
  return new_ves[j] = (old_ves[j] || (valr != null ? valr : valr = self.resolveRaw(val)).then(function(v) {
2372
- return k.encrypt(v).then(function(ctext) {
2373
- return (function(refs) {
2374
- if (refs) for (var i in refs) if (refs[i] === k) return Promise.resolve({'$ref':i});
2375
- return k.postData(null,refs);
2376
- })(libVES.Object._refs).then(function(pd) {
2506
+ return (function(refs) {
2507
+ if (refs) for (var i in refs) if (refs[i] === k) return Promise.resolve({'$ref':i});
2508
+ return k.postData(null,refs);
2509
+ })(libVES.Object._refs).then(function(pd) {
2510
+ if (pd.id) {
2511
+ if (key_ids[pd.id]) return;
2512
+ key_ids[pd.id] = true;
2513
+ }
2514
+ return k.encrypt(v).then(function(ctext) {
2377
2515
  return set_ves.push({vaultKey: pd, encData: ctext});
2378
2516
  });
2379
2517
  });
2380
2518
  }));
2381
2519
  })).then(function() {
2382
2520
  return Promise.all(old_ves.slice(ks.length).map(function(ve,j) {
2383
- return (new libVES.VaultKey(ve.vaultKey,self.VES)).matchVaults(ks).then(function(f) {
2384
- if (f === false) set_ves.push({vaultKey: {id: ve.vaultKey.id}, '$op': 'delete'});
2521
+ return (new libVES.VaultKey(ve.vaultKey,self.VES)).matchVaults(usrs).then(function(f) {
2522
+ if (!f) set_ves.push({vaultKey: {id: ve.vaultKey.id}, '$op': 'delete'});
2385
2523
  });
2386
2524
  }));
2387
2525
  }).then(function() {
@@ -2390,12 +2528,20 @@ libVES.VaultItem.prototype = new libVES.Object({
2390
2528
  });
2391
2529
  });
2392
2530
  }).then(function() {
2393
- if (save || save === undefined) return self.post(undefined, undefined, ((save instanceof Object) ? save : undefined)).then(function() {
2394
- delete(self.vaultEntries);
2531
+ if (self.id && val != null) return self.setUpdate({id: false, type: true, file: {id: false, externals: {id: false, domain: true, externalId: true}}});
2532
+ }).then(function() {
2533
+ if (save || save === undefined) return self.post(undefined, undefined, ((save instanceof Object) ? save : undefined)).then(function(flds) {
2534
+ self.vaultEntryByKey = {};
2535
+ self.setFields(flds, false);
2395
2536
  return self;
2537
+ }).finally(function() {
2538
+ delete(self.vaultEntries);
2396
2539
  });
2397
2540
  return self;
2398
- });
2541
+ }).catch(function(er) {
2542
+ delete(self.vaultEntries);
2543
+ throw er;
2544
+ });
2399
2545
  },
2400
2546
  reshareWith: function(share,val,save) {
2401
2547
  var self = this;
@@ -2418,6 +2564,15 @@ libVES.VaultItem.prototype = new libVES.Object({
2418
2564
  });
2419
2565
  });
2420
2566
  },
2567
+ unshareWith: function(share, save) {
2568
+ 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)));
2569
+ },
2570
+ set: function(val, save) {
2571
+ var self = this;
2572
+ return self.getShareList().then(function(sh) {
2573
+ return self.shareWith(sh, val, save);
2574
+ });
2575
+ },
2421
2576
  getShareVaultKeys: function() {
2422
2577
  var self = this;
2423
2578
  return this.getVaultEntries().then(function(vaultEntries) {
@@ -2430,12 +2585,17 @@ libVES.VaultItem.prototype = new libVES.Object({
2430
2585
  var self = this;
2431
2586
  return this.getShareVaultKeys().then(function(vaultKeys) {
2432
2587
  var uids = {};
2588
+ var xids = {};
2433
2589
  return Promise.all(vaultKeys.map(function(e,i) {
2434
2590
  return e.getExternals().then(function(exts) {
2435
- if (exts && exts.length) return exts[0];
2591
+ if (exts && exts.length) return exts[0].getId().then(function(xid) {
2592
+ if (!xid || xids[xid]) return null;
2593
+ xids[xid] = true;
2594
+ return exts[0];
2595
+ });
2436
2596
  return e.getUser().then(function(u) {
2437
2597
  return u.getId().then(function(uid) {
2438
- if (uids[uid]) return null;
2598
+ if (!uid || uids[uid]) return null;
2439
2599
  uids[uid] = true;
2440
2600
  return u;
2441
2601
  });
@@ -2451,7 +2611,7 @@ libVES.VaultItem.prototype = new libVES.Object({
2451
2611
  delete: function() {
2452
2612
  var self = this;
2453
2613
  return self.getId().then(function(id) {
2454
- return this.VES.post(self.apiUri + '/' + id, {'$op': 'delete'});
2614
+ return self.VES.post(self.apiUri + '/' + id, {'$op': 'delete'});
2455
2615
  });
2456
2616
  }
2457
2617
  });
@@ -4306,7 +4466,7 @@ libVES.Watch.prototype = {
4306
4466
  }).then(function(res) {
4307
4467
  if (!res.events) return null;
4308
4468
  return res.events.map(function(e, i) {
4309
- return new libVES.Event(e, self.VES);
4469
+ return new libVES.Event(libVES.Util.fillUndefs(e, self.fields), self.VES);
4310
4470
  });
4311
4471
  });
4312
4472
  },
@@ -4321,8 +4481,8 @@ libVES.Watch.prototype = {
4321
4481
  if (!busy && this.state == 'stop') this.setState('idle');
4322
4482
  },
4323
4483
  start: function(pos) {
4324
- if (!this.eventfn) throw new libVES.Error('InvalidValue', 'eventfn is not set');
4325
- if (this.busy) throw new libVES.Error('Internal', 'Watch instance is busy');
4484
+ if (!this.eventfn) return Promise.reject(new libVES.Error('InvalidValue', 'eventfn is not set'));
4485
+ if (this.busy) return Promise.reject(new libVES.Error('Internal', 'Watch instance is busy'));
4326
4486
  var self = this;
4327
4487
  self.setBusy(true);
4328
4488
  this.setState('read');
@@ -4330,13 +4490,17 @@ libVES.Watch.prototype = {
4330
4490
  this.next = 0;
4331
4491
  return this.getEvents(0, pos).then(function(evs) {
4332
4492
  self.setBusy(false);
4333
- return self.received(evs.reverse());
4334
- });
4493
+ return self.received(evs ? evs.reverse() : null);
4494
+ }).finally(function() {
4495
+ self.setBusy(false);
4496
+ });
4335
4497
  } else {
4336
4498
  this.next = pos;
4337
4499
  return this.getEvents(pos, 0).then(function(evs) {
4338
4500
  self.setBusy(false);
4339
4501
  return self.received(evs);
4502
+ }).finally(function() {
4503
+ self.setBusy(false);
4340
4504
  });
4341
4505
  }
4342
4506
  },
@@ -4346,31 +4510,30 @@ libVES.Watch.prototype = {
4346
4510
  received: function(evs) {
4347
4511
  var self = this;
4348
4512
  var p;
4349
- if (evs && evs.length) p = evs.reduce(function(v, e) {
4513
+ if (!evs) return null;
4514
+ if (evs.length) return evs.reduce(function(v, ev) {
4350
4515
  if (self.active()) try {
4351
- self.eventfn(e, self);
4516
+ self.eventfn(ev, self);
4352
4517
  } catch(e) {
4353
4518
  console.log(e);
4354
4519
  }
4355
- return e;
4520
+ return ev;
4356
4521
  }, null).getId().then(function(id) {
4357
4522
  self.next = id + 1;
4523
+ return self.request();
4358
4524
  });
4359
4525
  else {
4360
- p = Promise.resolve(null);
4361
4526
  if (this.state == 'read') this.setState('poll');
4527
+ return self.request(), true;
4362
4528
  }
4363
- return p.then(function() {
4364
- return self.request();
4365
- });
4366
4529
  },
4367
4530
  request: function() {
4368
- if (this.busy || !this.active()) return;
4531
+ if (this.busy || !this.active()) return true;
4369
4532
  var self = this;
4370
4533
  self.setBusy(true);
4371
4534
  return self.getEvents(self.next, 0, (self.state == 'poll')).then(function(evs) {
4372
4535
  self.setBusy(false);
4373
- self.received(evs);
4536
+ return self.received(evs);
4374
4537
  }).catch(function(e) {
4375
4538
  self.setBusy(false);
4376
4539
  if (self.errorfn) try {
@@ -4393,6 +4556,761 @@ libVES.Watch.prototype = {
4393
4556
  this.setState(this.busy ? 'stop' : 'idle');
4394
4557
  }
4395
4558
  };
4396
- libVES.version = '2.16';
4559
+
4560
+
4561
+
4562
+ libVES.subtle = function(optns) {
4563
+ if (!(optns instanceof Object)) {
4564
+ let uri = String(optns);
4565
+ optns = uri.includes('/') ? libVES.Vault.toRef(uri) : {domain: uri};
4566
+ }
4567
+ return new libVES(optns).subtle();
4568
+ };
4569
+
4570
+ libVES.prototype.subtle = function(ref) {
4571
+ return new libVES.Vault((ref || this), this);
4572
+ };
4573
+
4574
+ libVES.EventTarget = class extends EventTarget {
4575
+ watchFields() {
4576
+ 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}};
4577
+ }
4578
+
4579
+ dispatchEvent(ev) {
4580
+ if (!ev) return;
4581
+ super.dispatchEvent(ev);
4582
+ if (this['on' + ev.type]) try { this['on' + ev.type](ev) } catch (er) { console.log(er); }
4583
+ }
4584
+
4585
+ start(optns) {
4586
+ if (!this.watch) {
4587
+ let tr = this._eventTracker();
4588
+ if (optns === false) optns = {replay: true};
4589
+ else if (optns != null && !isNaN(optns)) optns = {startEvent: Number(optns)};
4590
+ else if (!(optns instanceof Object)) optns = {};
4591
+ if (optns.startEvent == null) optns.startEvent = -1;
4592
+ this.watch = this.createWatch(optns);
4593
+ this.watch.eventfn = (ev) => (this.eventClear = this.eventClear.then(() => tr._event(ev).then((ev) => this.dispatchEvent(ev)).catch((er) => console.log(er))));
4594
+ 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();
4595
+ return this.watch.start(optns.startEvent).then((v) => (v || this.badauth().then(() => this.watch.start(startEvent)))).catch((er) => {
4596
+ this.watch = null;
4597
+ throw er;
4598
+ });
4599
+ } else throw new libVES.Error.InvalidValue('The watch is already started');
4600
+ }
4601
+
4602
+ stop() {
4603
+ if (this.watch) return Promise.resolve(this.watch.stop()).then(() => this.eventClear).then(() => true).finally(() => this.watch = null);
4604
+ return Promise.resolve(null);
4605
+ }
4606
+
4607
+ events(optns) {
4608
+ let tr = this._eventTracker();
4609
+ 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())));
4610
+ }
4611
+
4612
+ toJSON() {
4613
+ return this.uri();
4614
+ }
4615
+ };
4616
+
4617
+ libVES.Vault = class extends libVES.EventTarget {
4618
+ constructor(ref, ves, fields) {
4619
+ super();
4620
+ this.init(libVES.Vault.toRef(ref, ves), ves, fields);
4621
+ }
4622
+
4623
+ init(ref, ves, fields) {
4624
+ fields ||= {};
4625
+ if (ref.externalId) fields.externals = [{domain: (this.domain = String(ref.domain)), externalId: (this.externalId = String(ref.externalId))}];
4626
+ this.email = ref.email || '';
4627
+ if (ref.email) fields.user = {email: this.email};
4628
+ if (ref.version) this.version = fields.id = Number(ref.version);
4629
+ if (!fields.id) fields.type = this.externalId ? 'secondary' : 'current';
4630
+ this.vaultKey = new libVES.VaultKey(fields, ves);
4631
+ delete(this.admin);
4632
+ };
4633
+
4634
+ item(ref) {
4635
+ return new libVES.Item(ref, this);
4636
+ };
4637
+
4638
+ vault(ref) {
4639
+ if (!ref) return null;
4640
+ return new libVES.Vault(ref, this.vaultKey.VES);
4641
+ }
4642
+
4643
+ entries(optns) {
4644
+ 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}};
4645
+ const getfn = () => this.vaultKey.getField('vaultEntries', flds, true).then((data) => libVES.Util.fillUndefs(data, flds));
4646
+ if (!this._entriesCache) (this._entriesCache = getfn().then((entries) => (entries || this.badauth().then(getfn)))).catch(() => null).finally(() => this._entriesCache = null);
4647
+ return this._entriesCache;
4648
+ };
4649
+
4650
+ objects(optns) {
4651
+ let found = {items: {}, vaults: {}};
4652
+ return this.entries(optns).then((entries) => Promise.all((entries || []).map((entry) => {
4653
+ const ext = entry.vaultItem?.file?.externals?.[0];
4654
+ if (ext) {
4655
+ if (entry.vaultItem.deleted) return null;
4656
+ let d = (found.items[ext.domain] ||= {});
4657
+ return d[ext.externalId] ? null : (d[ext.externalId] = new libVES.Item(ext, this, entry.vaultItem));
4658
+ }
4659
+ const vkey = entry.vaultItem?.vaultKey;
4660
+ const kext = vkey?.externals?.[0];
4661
+ if (kext && vkey.type == 'secondary' && entry.vaultItem.type == 'password') {
4662
+ let d = (found.vaults[kext.domain] ||= {});
4663
+ return d[kext.externalId] ? null : (d[kext.externalId] = new libVES.Vault(kext, this.vaultKey.VES, vkey));
4664
+ }
4665
+ }))).then((objs) => objs.filter((obj) => obj));
4666
+ };
4667
+
4668
+ items(optns) {
4669
+ return this.objects(optns).then((objs) => objs.filter((obj) => (obj instanceof libVES.Item)));
4670
+ }
4671
+
4672
+ vaults(optns) {
4673
+ return this.objects(optns).then((objs) => objs.filter((obj) => (obj instanceof libVES.Vault)));
4674
+ }
4675
+
4676
+ reauth() {
4677
+ clearTimeout(this.refreshTmout);
4678
+ return this.vaultKey.loadFields({encSessionToken: true}, true, {token: ''}).then((flds) => this.vaultKey.setFields(flds)).then(() => this.vaultKey.getSessionToken()).then((tk) => {
4679
+ this.vaultKey.VES.token = tk;
4680
+ return this;
4681
+ });
4682
+ }
4683
+
4684
+ _setunlock(reauth) {
4685
+ this.current = true;
4686
+ this.owner = this.externalId?.[0] != '!';
4687
+ this.lock(600);
4688
+ let rf;
4689
+ if (reauth !== false && this.externalId) (rf = (tmout) => {
4690
+ this.refreshTmout = setTimeout(() => {
4691
+ this.reauth().then(() => rf()).catch((er) => {
4692
+ console.log(er);
4693
+ rf(60000);
4694
+ });
4695
+ }, (tmout || 14400000));
4696
+ })();
4697
+ if (this.appUrl === undefined) try {
4698
+ this.appUrl = document.location.origin;
4699
+ } catch(er) {}
4700
+ return this;
4701
+ }
4702
+
4703
+ unlock(optns) {
4704
+ if (this.lockInProgress) return this.lock().then(() => this.unlock(optns));
4705
+ if (optns && !(optns instanceof Object)) optns = libVES.Vault.toRef(optns, this.vaultKey.VES);
4706
+ if (optns?.veskey) return this.vaultKey.VES.logout().then(() => {
4707
+ let ves = new libVES(optns);
4708
+ delete(ves.veskey);
4709
+ return ((reauth) => ves.unlock(String(optns.veskey)).then(() => this.init(ves, ves)).then(() => this._setunlock(reauth)))(!this.vaultKey.VES.token);
4710
+ });
4711
+ return this.vaultKey.VES.unlock().catch((er) => {
4712
+ let mode = optns?.mode || 'delegate';
4713
+ switch (mode) {
4714
+ case 'delegate': return this.vaultKey.VES.delegate(optns).then((ves) => this.init(ves, ves));
4715
+ case 'flow': return this.vaultKey.VES.flow(true, optns).then((ves) => this.init(ves, ves));
4716
+ case 'veskey': throw new libVES.Error.InvalidValue('No veskey provided');
4717
+ default: throw new libVES.Error.InvalidValue('Unknown unlock mode: ' + mode + ', expected: delegate|flow');
4718
+ }
4719
+ }).then(() => this._setunlock());
4720
+ }
4721
+
4722
+ unlocked(optns) {
4723
+ return this.vaultKey.VES.unlock().catch((er) => {
4724
+ if (optns?.mode != 'flow') throw er;
4725
+ return this.vaultKey.VES.flow(false, optns).then((ves) => this.init(ves, ves)).then(() => this._setunlock());
4726
+ }).then(() => true).catch((er) => false);
4727
+ }
4728
+
4729
+ anonymous(optns) {
4730
+ if (!(optns instanceof Object)) {
4731
+ if (optns && typeof(optns) == 'string') optns = {veskey: optns};
4732
+ else optns = {};
4733
+ }
4734
+ if (!optns.veskey) return Promise.reject(libVES.Error.InvalidValue('Required: veskey'));
4735
+ if (!this.vaultKey.VES.domain) return Promise.reject(libVES.Error.InvalidValue('Cannot create an anonymous vault without a VES domain'));
4736
+ this.vaultKey.VES.logout();
4737
+ 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) => {
4738
+ const hex = '0123456789abcdef';
4739
+ let xid = new Uint8Array(hash).reduce(((v, e) => v + hex[e >> 4] + hex[e & 0x0f]), '!');
4740
+ this.vaultKey.VES.externalId = xid;
4741
+ })).then(() => this.vaultKey.VES.unlock(optns.veskey).catch((er) => {
4742
+ if (er?.code == 'NotFound') return this.vaultKey.VES.setAnonymousKey(optns.veskey, optns);
4743
+ else throw er;
4744
+ })).then(() => this.init(this.vaultKey.VES, this.vaultKey.VES)).then(() => this._setunlock());
4745
+ }
4746
+
4747
+ lock(tmout) {
4748
+ this.lockInProgress = false;
4749
+ clearTimeout(this.lockTmout);
4750
+ this.lockTmout = null;
4751
+ if (tmout > 0) {
4752
+ if (tmout > 3600) tmout = 3600;
4753
+ this.lockTmout = setTimeout(() => {
4754
+ this.lockInProgress = true;
4755
+ this.dispatchEvent(new libVES.CustomEvent('authexpire', {detail: {vault: this}}));
4756
+ if (this.lockInProgress) this.lock();
4757
+ }, tmout * 1000);
4758
+ return Promise.resolve(true);
4759
+ }
4760
+ clearTimeout(this.refreshTmout);
4761
+ this.refreshTmout = null;
4762
+ this.stop();
4763
+ return this.vaultKey.VES.logout();
4764
+ }
4765
+
4766
+ random() {
4767
+ return this.vaultKey.VES.generateVESkey();
4768
+ }
4769
+
4770
+ static toRef(value, ves) {
4771
+ switch (typeof(value)) {
4772
+ case 'object':
4773
+ return value;
4774
+ case 'number':
4775
+ value = String(value);
4776
+ case 'string':
4777
+ let uri = new URL(value, "ves://" + (ves && ves.domain ? ves.domain : ''));
4778
+ if (uri.protocol != 'ves:') throw new libVES.Error.InvalidValue("Invalid schema: '" + uri.protocol + "', expected 'ves:'");
4779
+ let p = uri.pathname.split('/');
4780
+ let id = p.length > 1 ? decodeURIComponent(p[1]) : '';
4781
+ let ref = uri.host ? {domain: uri.host, externalId: id} : {version: Number(id)};
4782
+ if (p[2] != null) ref.email = decodeURIComponent(p[2]);
4783
+ if (uri.password) ref.veskey = uri.password;
4784
+ return ref;
4785
+ }
4786
+ };
4787
+
4788
+ static toRefs(refs, ves, owner) {
4789
+ if (!refs) return [];
4790
+ if (!(refs instanceof Array)) refs = [refs];
4791
+ refs = refs.map((ref) => libVES.Vault.toRef(ref, ves)).filter((ref) => ref);
4792
+ if (owner) {
4793
+ if (ves.externalId) refs.push({domain: ves.domain, externalId: ves.externalId});
4794
+ else if (ves.user) refs.push({email: ves.user});
4795
+ else throw new libVES.Error.Unauthorized('The vault is locked');
4796
+ }
4797
+ return refs;
4798
+ }
4799
+
4800
+ static toUri(ref, short) {
4801
+ if (ref.externalId && short) return (ref.domain == short ? '' : '//' + encodeURIComponent(ref.domain) + '/') + encodeURIComponent(ref.externalId).replaceAll('%40', '@');
4802
+ let uri = ref.externalId ? "ves://" + encodeURIComponent(ref.domain) + "/" + encodeURIComponent(ref.externalId) : "ves://" + (ref.version ? "/" + String(Number(ref.version)) : encodeURIComponent(ref.domain ?? '') + "/");
4803
+ if (ref.email != null) uri += '/' + encodeURIComponent(ref.email);
4804
+ return uri;
4805
+ }
4806
+
4807
+ uri() {
4808
+ if (!this.externalId && !this.version && !this.email) return null;
4809
+ return libVES.Vault.toUri(this);
4810
+ }
4811
+
4812
+ short() {
4813
+ return libVES.Vault.toUri(this, this.vaultKey.VES.domain);
4814
+ }
4815
+
4816
+ badauth() {
4817
+ const ves = this.vaultKey.VES;
4818
+ if (!this.externalId || (this.externalId == ves.externalId && this.domain == ves.domain)) return Promise.reject(new libVES.Error.InvalidKey('Not authorized for this key'));
4819
+ 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(() => {
4820
+ const ves2 = new libVES({domain: this.domain, externalId: this.externalId});
4821
+ ves2.vaultKey = Promise.resolve(this.vaultKey);
4822
+ ves2.unlockedKeys = ves.unlockedKeys;
4823
+ ves2.pendingKeys = ves.pendingKeys;
4824
+ this.vaultKey.VES = ves2;
4825
+ return ves2.unlock();
4826
+ });
4827
+ }
4828
+
4829
+ createWatch() {
4830
+ let w = new libVES.Watch(this.vaultKey);
4831
+ 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}}};
4832
+ return w;
4833
+ }
4834
+
4835
+ replay(optns) {
4836
+ return this.objects(optns).then((objs) => Promise.all(objs.map((obj) => {
4837
+ if (obj instanceof libVES.Item) return new libVES.CustomEvent('itemadd', {detail: {replay: true, item: obj, share: this}});
4838
+ else if (obj instanceof libVES.Vault) return new libVES.CustomEvent('vaultadd', {detail: {replay: true, vault: obj, share: this}});
4839
+ })));
4840
+ }
4841
+
4842
+ password() {
4843
+ return this.vaultKey.getVaultItems().then((vitems) => {
4844
+ if (!vitems) return this.badauth().then(() => this.password());
4845
+ 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')));
4846
+ });
4847
+ }
4848
+
4849
+ verify() {
4850
+ if (this.current !== undefined) return Promise.resolve(this);
4851
+ 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) => {
4852
+ if (res) return res;
4853
+ if (this.version) return this.version == fld.id ? vkeys[idx] : null;
4854
+ switch (fld.type) {
4855
+ case 'secondary': case 'current': case 'temp': return vkeys[idx];
4856
+ }
4857
+ }, null))).then((vkey) => {
4858
+ if (!vkey) throw new libVES.Error.NotFound('Cannot find or create a matching key');
4859
+ return vkey.getType().then((type) => {
4860
+ this.current = (type == 'current' || type == 'secondary');
4861
+ this.owner = (this.externalId != null && this.externalId == vkey.VES.externalId && this.domain == vkey.VES.domain) || (!!this.email && this.email == vkey.VES.email);
4862
+ this.vaultKey = vkey;
4863
+ return this;
4864
+ });
4865
+ });
4866
+ }
4867
+
4868
+ _eventTracker() {
4869
+ return new libVES.EventTracker(this);
4870
+ }
4871
+
4872
+ toAppRefs(refs, ves, owner) {
4873
+ let shares = libVES.Vault.toRefs(refs, ves, owner);
4874
+ if (this.appUrl !== undefined) shares.map((share) => {
4875
+ if (share.appUrl === undefined) share.appUrl = this.appUrl;
4876
+ });
4877
+ return shares;
4878
+ }
4879
+
4880
+ toString() {
4881
+ return 'libVES.Vault(' + (this.uri() ?? '[pending]') + ')';
4882
+ }
4883
+
4884
+ };
4885
+
4886
+ libVES.Author = class {
4887
+ constructor(sess, ves) {
4888
+ this.sessid = sess.id;
4889
+ if (sess.vaultKey?.externals?.[0]) this.vault = new libVES.Vault(sess.vaultKey.externals[0], ves);
4890
+ else if (sess.user?.email) this.vault = new libVES.Vault({email: sess.user.email}, ves);
4891
+ this.remote = sess.remote;
4892
+ this.userAgent = sess.userAgent;
4893
+ }
4894
+ toString() {
4895
+ return 'libVES.Author(' + (this.sessid ?? '') + ')';
4896
+ }
4897
+ toJSON() {
4898
+ return this.sessid;
4899
+ }
4900
+ };
4901
+
4902
+ libVES.CustomEvent = class extends CustomEvent {
4903
+ toString() {
4904
+ return 'libVES.CustomEvent(' + this.type + (this.detail?.id ? '[' + this.detail.id + ']' : '') + (this.detail?.at ? ' @' + this.detail.at : '') + ')';
4905
+ }
4906
+ toJSON() {
4907
+ return this.detail?.id;
4908
+ }
4909
+ };
4910
+
4911
+ libVES.EventTracker = class {
4912
+ constructor(vault, share) {
4913
+ this.vault = vault;
4914
+ this.share = share;
4915
+ this.items = {};
4916
+ }
4917
+
4918
+ _event(e, attn) {
4919
+ const event = (type, detail) => {
4920
+ detail.event = e;
4921
+ 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) => {
4922
+ detail.id = flds?.id;
4923
+ if (flds?.recordedAt) detail.at = new Date(flds.recordedAt);
4924
+ detail.author = new libVES.Author((flds?.authorSession ?? {}), this.vault.vaultKey.VES);
4925
+ }).catch(() => null).then(() => new libVES.CustomEvent(type, {detail: detail}));
4926
+ }
4927
+ return e.getType().then((type) => {
4928
+ const itemfn = (ac, attn, sh) => e.getVaultItem().then((vitem) => vitem.getType().then((itype) => {
4929
+ switch (itype) {
4930
+ case 'string': case 'file':
4931
+ return vitem.getFields({id: true, file: {externals: {domain: true, externalId: true}}, deleted: true, type: true, meta: true}).then((flds) => {
4932
+ let ext = flds?.file?.externals?.[0];
4933
+ if (!ext) return null;
4934
+ let item = new libVES.Item({domain: ext.domain, externalId: ext.externalId, version: flds.id}, this.vault, flds);
4935
+ let ids = (this.items[item.uri()] ||= []);
4936
+ let idx = ids.indexOf(flds.id);
4937
+ if (idx < 0 && (flds.deleted === false || (ac == 'create' || ac == 'add'))) ids.unshift(flds.id), idx = 0;
4938
+ return event((idx == 0 ? '' : 'old') + 'item' + ac, {item: item, share: sh});
4939
+ });
4940
+ case 'password':
4941
+ return vitem.getFields({vaultKey: {type: true, externals: {domain: true, externalId: true}}}).then((flds) => {
4942
+ switch (flds?.vaultKey?.type) {
4943
+ case 'secondary':
4944
+ return event('vault' + ac, {vault: this.vault.vault(flds.vaultKey.externals?.[0]), share: sh});
4945
+ default:
4946
+ if (attn) return vitem.getVaultKey().then((vkey) => this.vault.vaultKey.VES.attnVaultKeys([vkey])).catch((e) => console.log(e)).then(() => null);
4947
+ }
4948
+ });
4949
+ }
4950
+ }));
4951
+ 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) => {
4952
+ let f = flds?.externals?.[0] ? flds.externals[0] : (flds?.user?.email ? {email: flds.user.email} : {});
4953
+ f.version = flds.id;
4954
+ let vault = this.vault.vault(f);
4955
+ vault.current = (f.externals && flds.type == 'secondary') || (f.email && flds.type == 'current');
4956
+ return vault;
4957
+ })) : Promise.resolve(this.vault));
4958
+ switch (type) {
4959
+ case 'vaultEntry.deleted':
4960
+ return sharefn().then((sh) => itemfn('remove', false, sh));
4961
+ case 'vaultEntry.created':
4962
+ return sharefn().then((sh) => itemfn('add', attn !== false, sh));
4963
+ case 'vaultItem.deleted':
4964
+ return itemfn('delete');
4965
+ case 'vaultItem.created':
4966
+ return itemfn('create');
4967
+ case 'vaultItem.listening':
4968
+ case 'vaultKey.listening':
4969
+ return itemfn('change', attn !== false);
4970
+ case 'session.created':
4971
+ return e.getFields({session: {id: true, remote: true, userAgent: true, vaultKey: {id: true}, user: {id: true}}}).then((flds) => {
4972
+ if (!flds?.session) return null;
4973
+ let ses = new libVES.Author(flds.session, this.vault.vaultKey.VES);
4974
+ ses.vault = this.vault;
4975
+ return event('sessioncreate', {vault: this.vault, session: ses});
4976
+ });
4977
+ }
4978
+ }).catch((er) => (console.log(er), event('error', {error: er})));
4979
+ }
4980
+ };
4981
+
4982
+
4983
+
4984
+ libVES.Item = class extends libVES.EventTarget {
4985
+ constructor(ref, vault, fields) {
4986
+ const ves = vault.vaultKey.VES;
4987
+ super();
4988
+ if (ref == null || typeof(ref) == 'function') {
4989
+ this.provisional = {share: [vault], ref: (ref || libVES.Item.newRef)};
4990
+ } else {
4991
+ ref = libVES.Vault.toRef(ref, ves);
4992
+ if ((!ref.domain || !ref.externalId) && !ref.version) throw new libVES.Error.InvalidValue('Bad item reference');
4993
+ this.domain = ref.domain;
4994
+ this.externalId = ref.externalId;
4995
+ this.version = ref.version || null;
4996
+ }
4997
+ this.vault = vault;
4998
+ this._vaultItem(ves, fields);
4999
+ };
5000
+
5001
+ static newRef() {
5002
+ let d = new Date();
5003
+ 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);
5004
+ }
5005
+
5006
+ _vaultItem(ves, fields) {
5007
+ if (this.vaultItem && this._entriesCache !== null) return this.vaultItem;
5008
+ ves ||= this.vaultItem.VES;
5009
+ if (!fields) {
5010
+ fields = this.externalId ? {file: {externals: [{domain: this.domain, externalId: this.externalId}]}} : {};
5011
+ if (this.version) fields.id = this.version;
5012
+ } else if (fields.vaultEntries) this._entriesCache = Promise.resolve(fields).finally(() => this._entriesCache = null);
5013
+ return this.vaultItem = new libVES.VaultItem(fields, ves);
5014
+ };
5015
+
5016
+ _entries() {
5017
+ if (this.provisional) return Promise.reject(new libVES.Error.NotFound('Not available for a provisional item'));
5018
+ if (this._entriesCache) return this._entriesCache;
5019
+ 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) => {
5020
+ if (!flds?.vaultEntries) return Promise.reject(new libVES.Error.InvalidKey('Not authorized to access this item'));
5021
+ return flds;
5022
+ });
5023
+ this._entriesCache.catch((er) => null).finally(() => this._entriesCache = null);
5024
+ return this._entriesCache;
5025
+ };
5026
+
5027
+ _get() {
5028
+ return this._entries().then(() => this.vaultItem.get());
5029
+ };
5030
+
5031
+ _reset() {
5032
+ this._entriesCache = null;
5033
+ };
5034
+
5035
+ latest() {
5036
+ return this.externalId && this.version ? this.vault.item({domain: this.domain, externalId: this.externalId}) : this;
5037
+ };
5038
+
5039
+ get() {
5040
+ return this._get().then((val) => {
5041
+ if (typeof(val) != 'string') throw new libVES.Error.InvalidValue('The item value is not a string');
5042
+ return val;
5043
+ });
5044
+ };
5045
+
5046
+ put(value, shares) {
5047
+ if (value == null) return Promise.reject(new libVES.Error.InvalidValue('The item value cannot be empty'));
5048
+ let prref;
5049
+ return (shares ? Promise.resolve(this.vault.toAppRefs(shares, this.vaultItem.VES, true)) : this.share().then((shares) => {
5050
+ let owner = shares.reduce((cur, sh) => (cur || ((sh.owner && sh.externalId?.match(/@/)) ? sh : null)), null);
5051
+ if (owner && owner.uri() != this.vault.uri()) shares.push(this.vault.vault({domain: '.admin', externalId: owner.externalId}));
5052
+ return shares;
5053
+ }).catch((e) => {
5054
+ if (e && e.code == 'NotFound') return libVES.Vault.toRefs([], this.vaultItem.VES, true);
5055
+ throw e;
5056
+ })).then((shares) => {
5057
+ if (!this.provisional) return shares;
5058
+ prref = libVES.Vault.toRef(this.provisional.ref(), this.vaultItem.VES);
5059
+ if (!prref?.externalId) return Promise.reject(new libVES.Error.InvalidValue('Bad provisional reference generated by the supplied function'));
5060
+ return this.vaultItem.setFields({file: {externals: [prref]}}).then(() => shares);
5061
+ }).then((shares) => this.vaultItem.shareWith(shares, value)).then(() => {
5062
+ if (prref) {
5063
+ this.externalId = prref.externalId;
5064
+ this.domain = prref.domain;
5065
+ delete(this.provisional);
5066
+ }
5067
+ this.version = null;
5068
+ this._reset();
5069
+ return value;
5070
+ });
5071
+ };
5072
+
5073
+ cipher(optns, shares) {
5074
+ return this._get().then((val) => {
5075
+ if (!(val instanceof libVES.Cipher)) throw new libVES.Error.InvalidValue('The item value is not a cipher');
5076
+ return (shares ? this.share(shares) : Promise.resolve(null)).then(() => val);
5077
+ }).catch((e) => {
5078
+ if (e && e.code == 'NotFound') {
5079
+ let algo = optns?.algo || this.vaultItem.VES.cipherAlgo || 'AES256GCM1K';
5080
+ if (!libVES.Cipher[algo]) throw new libVES.Error.InvalidValue('Unsupported cipher: ' + algo);
5081
+ let ci = new libVES.Cipher[algo]();
5082
+ return this.put(ci, shares);
5083
+ }
5084
+ throw e;
5085
+ }).then((ci) => new libVES.ItemCipher(ci, this));
5086
+ };
5087
+
5088
+ json(val, shares) {
5089
+ if (val === undefined) return this.get().then((val) => JSON.parse(val));
5090
+ return this.put(JSON.stringify(val), shares).then(() => val);
5091
+ };
5092
+
5093
+ exists() {
5094
+ return this._entries().then((flds) => !flds?.deleted).catch((e) => {
5095
+ if (e?.code == 'NotFound') return false;
5096
+ if (e?.code == 'InvalidKey') return true;
5097
+ throw e;
5098
+ });
5099
+ };
5100
+
5101
+ _provShare(shares, del) {
5102
+ return new Promise((resolve, reject) => {
5103
+ let uris = libVES.Vault.toRefs(shares, this.vaultItem.VES).map((ref) => this.vault.vault(ref).uri());
5104
+ let prov = {};
5105
+ this.provisional.share.map((sh) => prov[sh.uri()] = sh);
5106
+ resolve(this.vaultItem.VES.usersToKeys(libVES.Vault.toRefs(uris.filter((uri) => !prov[uri]))));
5107
+ }).then((vkeys) => Promise.all(vkeys.map((vkey => vkey.getFields({user: {email: true}, externals: {domain: true, externalId: true}, type: true}).then((flds) => {
5108
+ let sh = new libVES.Vault((flds?.externals?.[0] ?? flds?.user?.email), this.vaultItem.VES, flds);
5109
+ if (sh) return sh.verify();
5110
+ }))))).then((shares) => shares.filter((sh) => sh)).then((shares) => {
5111
+ this.provisional.share = this.provisional.share.concat(this.vault.toAppRefs(shares));
5112
+ if (del) {
5113
+ let uris = {};
5114
+ shares.map((sh) => uris[sh.uri()] = sh);
5115
+ uris[this.vault.uri()] = this.vault;
5116
+ this.provisional.share = this.provisional.share.filter((sh) => uris[sh.uri()]);
5117
+ }
5118
+ return this.provisional.share;
5119
+ });
5120
+ }
5121
+
5122
+ share(shares) {
5123
+ if (this.provisional) {
5124
+ if (shares) return this._provShare(shares, true);
5125
+ return Promise.resolve(this.provisional.share);
5126
+ }
5127
+ return (shares ? (this._reset(), this.vaultItem.shareWith(this.vault.toAppRefs(shares, this.vaultItem.VES, true))) : Promise.resolve(null)).then(() => {
5128
+ let result = [];
5129
+ let found = {};
5130
+ let admins = {};
5131
+ return this._entries().then((flds) => flds.vaultEntries.map((entry) => {
5132
+ let vkey = entry?.vaultKey;
5133
+ let ref = vkey?.externals?.[0];
5134
+ if (!ref) {
5135
+ const email = vkey?.user?.email;
5136
+ ref = email ? {email: email} : {version: vkey?.id};
5137
+ }
5138
+ let vault = new libVES.Vault(ref, this.vaultItem.VES);
5139
+ let uri = vault.uri();
5140
+ if (!found[uri]) {
5141
+ result.push(found[uri] = vault);
5142
+ let uid = vkey?.user?.id;
5143
+ vault.owner = !!uid && uid == (flds.file?.creator?.id ?? flds.vaultKey?.user?.id);
5144
+ if (vault.domain == '.admin') admins[vault.externalId] = true;
5145
+ }
5146
+ switch (vkey?.type) {
5147
+ case 'current': case 'secondary':
5148
+ found[uri].current = true;
5149
+ break;
5150
+ default:
5151
+ vault.current = false;
5152
+ }
5153
+ })).then(() => {
5154
+ result.map((sh) => sh.admin = !!admins[sh.externalId]);
5155
+ return result;
5156
+ });
5157
+ });
5158
+ };
5159
+
5160
+ add(shares) {
5161
+ if (this.provisional) return this._provShare(shares, false).then(() => true);
5162
+ return this._entries().then(() => this.vaultItem.getShareVaultKeys()).then((vkeys) => {
5163
+ if (!vkeys) throw new libVES.Error.InvalidKey('Not authorized to share this item');
5164
+ if (!shares) return true;
5165
+ this.vault.toAppRefs(shares, this.vaultItem.VES).map((share) => vkeys.push(share));
5166
+ this._reset();
5167
+ return this.vaultItem.shareWith(vkeys);
5168
+ }).then(() => true);
5169
+ };
5170
+
5171
+ remove(shares) {
5172
+ shares = libVES.Vault.toRefs(shares, this.vaultItem.VES);
5173
+ if (!shares || !shares.length) return Promise.resolve(true);
5174
+ if (this.provisional) return new Promise((resolve, reject) => {
5175
+ let uris = {};
5176
+ shares.map((sh) => uris[this.vault.vault(sh).uri()] = true);
5177
+ this.provisional.share = this.provisional.share.filter((sh) => !uris[sh.uri()]);
5178
+ resolve(true);
5179
+ });
5180
+ return this._entries().then(() => this.vaultItem.unshareWith(shares)).then(() => (this._reset(), true));
5181
+ };
5182
+
5183
+ refuse() {
5184
+ return this.remove(this.vault);
5185
+ };
5186
+
5187
+ delete() {
5188
+ this._reset();
5189
+ return this.vaultItem.delete().then(() => true);
5190
+ }
5191
+
5192
+ badauth() {
5193
+ return (this.vaultItem.VES == this.vault.vaultKey.VES ? this.vault.badauth() : Promise.resolve(null)).then(() => this.vaultItem.VES = this.vault.vaultKey.VES);
5194
+ }
5195
+
5196
+ shareFor(share) {
5197
+ let uri = this.vault.vault(share).uri();
5198
+ return uri ? this.share().then((shares) => shares.reduce((res, sh) => (res ?? (sh.uri() == uri ? sh : null)), null)) : null;
5199
+ }
5200
+
5201
+ uri() {
5202
+ if (!this.externalId && !this.version) return null;
5203
+ return libVES.Vault.toUri(this);
5204
+ }
5205
+
5206
+ short() {
5207
+ if (!this.externalId) return null;
5208
+ return libVES.Vault.toUri(this, this.vaultItem.VES.domain);
5209
+ }
5210
+
5211
+ _eventTracker() {
5212
+ return new libVES.EventTracker(this.vault, true);
5213
+ }
5214
+
5215
+ createWatch() {
5216
+ let w = new libVES.Watch(this.vaultItem);
5217
+ 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}};
5218
+ return w;
5219
+ }
5220
+
5221
+ replay() {
5222
+ return this.share().then((vaults) => Promise.all(vaults.map((vault) => {
5223
+ if (this.externalId) return new libVES.CustomEvent('itemadd', {detail: {replay: true, item: this, share: vault}});
5224
+ else return new libVES.CustomEvent('vaultadd', {detail: {replay: true, vault: this.vault, share: vault}});
5225
+ })));
5226
+ }
5227
+
5228
+ readable() {
5229
+ return this._get().then(() => true).catch((er) => {
5230
+ switch (er?.code) {
5231
+ case 'NotFound':
5232
+ case 'InvalidKey': return false;
5233
+ default: throw er;
5234
+ }
5235
+ });
5236
+ }
5237
+
5238
+ writable() {
5239
+ return this.shareFor(this.vault).then((sh) => sh && (sh.owner || sh.admin)).catch((er) => {
5240
+ switch (er?.code) {
5241
+ case 'NotFound': return true;
5242
+ case 'InvalidKey': return false;
5243
+ default: throw er;
5244
+ }
5245
+ });
5246
+ }
5247
+
5248
+ toString() {
5249
+ return 'libVES.Item(' + (this.uri() ?? '[provisional]') + ')';
5250
+ }
5251
+
5252
+ };
5253
+
5254
+ libVES.ItemCipher = class {
5255
+ constructor(ci, item) {
5256
+ this.cipher = ci;
5257
+ this.item = item;
5258
+ }
5259
+
5260
+ meta(val) {
5261
+ if (val == null) return Promise.resolve(this.cipher.meta);
5262
+ if (!(val instanceof Object)) return Promise.reject(new libVES.Error.InvalidValue('Cipher metadata must be an object'));
5263
+ this.cipher.meta = val;
5264
+ return this.item.put(this.cipher).then(() => this.cipher.meta);
5265
+ }
5266
+
5267
+ reset(final) {
5268
+ if (final && !this.final) return Promise.resolve(null);
5269
+ this.final = false;
5270
+ return this.item.vaultItem.get().then((ci) => this.cipher = ci);
5271
+ }
5272
+
5273
+ encrypt(data, optns) {
5274
+ return this.reset(true).then(() => {
5275
+ this.final = optns?.final !== false;
5276
+ if (data instanceof Blob) {
5277
+ return data.arrayBuffer().then((buf) => this.cipher.encrypt(buf, this.final)).then((ctext) => {
5278
+ const op = {type: 'application/vnd.ves.encrypted'};
5279
+ if (optns) optns.type = data.type;
5280
+ if (data instanceof File) {
5281
+ if (optns) optns.name = data.name;
5282
+ return new File([ctext], this.item.externalId, op);
5283
+ }
5284
+ return new Blob([ctext], op);
5285
+ });
5286
+ } else if (data instanceof ArrayBuffer) return this.cipher.encrypt(data, this.final).then((ctext) => ctext.buffer);
5287
+ else if ((data instanceof Object) && (data.buffer instanceof ArrayBuffer)) return this.cipher.encrypt(data.buffer, this.final).then((ctext) => new data.constructor(ctext.buffer));
5288
+ else return this.cipher.encrypt(libVES.Util.StringToByteArray(String(data)), this.final).then((ctext) => libVES.Util.ByteArrayToB64(ctext));
5289
+ });
5290
+ }
5291
+
5292
+ decrypt(data, optns) {
5293
+ return this.reset(true).then(() => {
5294
+ this.final = optns?.final !== false;
5295
+ if (data instanceof Blob) {
5296
+ return data.arrayBuffer().then((buf) => this.cipher.decrypt(buf, this.final)).then((ctext) => {
5297
+ if (data instanceof File) return new File([ctext], (optns?.name || ''), optns);
5298
+ return new Blob([ctext], optns);
5299
+ });
5300
+ } else if (data instanceof ArrayBuffer) return this.cipher.decrypt(data, this.final).then((ctext) => ctext.buffer);
5301
+ else if ((data instanceof Object) && (data.buffer instanceof ArrayBuffer)) return this.cipher.decrypt(data.buffer, this.final).then((ctext) => new data.constructor(ctext.buffer));
5302
+ else return this.cipher.decrypt(libVES.Util.B64ToByteArray(String(data)), this.final).then((ctext) => libVES.Util.ByteArrayToString(ctext));
5303
+ });
5304
+ }
5305
+
5306
+ toString() {
5307
+ return 'libVES.ItemCipher(' + String(this.item) + ')';
5308
+ }
5309
+
5310
+ toJSON() {
5311
+ return this.item?.uri();
5312
+ }
5313
+ };
5314
+ libVES.version = '3.02';
4397
5315
 
4398
5316
  module.exports = libVES;