libves 2.16.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.16
30
+ * @version 3.00
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 = {
@@ -64,6 +65,7 @@ libVES.prototype = {
64
65
  defaultHash: 'SHA256',
65
66
  propagators: [],
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,13 @@ 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
+ return Promise.all(lock).then(function() {
270
+ return true;
271
+ });
256
272
  },
257
273
  reset: function(val) {
258
274
  this.userMe = undefined;
@@ -293,11 +309,11 @@ libVES.prototype = {
293
309
  });
294
310
  });
295
311
  },
296
- getItems: function() {
312
+ getItems: function(flds) {
297
313
  var self = this;
298
314
  return this.getVaultKey().then(function(k) {
299
315
  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) {
316
+ return k.getVaultEntries(self.mergeFieldList({type: true, deleted: true, file: {creator: true, externals: true}, vaultKey: {type: true, user: true}}, flds)).then(function(ves) {
301
317
  var vis = {};
302
318
  var vlst = [];
303
319
  for (var i = 0; i < ves.length; i++) {
@@ -308,6 +324,7 @@ libVES.prototype = {
308
324
  if (!vi.vaultKey) vi.vaultKey = undefined;
309
325
  vi = vis[viid] = self.getItem(vi);
310
326
  vlst.push(vi);
327
+ if (!ves[i].vaultKey) ves[i].vaultKey = {id: kid};
311
328
  vi.vaultEntryByKey[kid] = ves[i];
312
329
  }
313
330
  }
@@ -346,7 +363,7 @@ libVES.prototype = {
346
363
  _matchUser: function(u) {
347
364
  if (typeof(u) == 'object') {
348
365
  if (u instanceof libVES.User) return u;
349
- else return new libVES.User(u,this);
366
+ else return new libVES.User((u.id ? {id: u.id} : {email: u.email}), this);
350
367
  } else if (typeof(u) == 'string' && u.match(/^\S+\@\S+$/)) return new libVES.User({email: u},this);
351
368
  throw new libVES.Error('BadUser',"Cannot match user: " + u,{value: u});
352
369
  },
@@ -377,11 +394,14 @@ libVES.prototype = {
377
394
  }).catch(function(e) {
378
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});
379
396
  })).then(function(exts) {
380
- 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);
381
400
  return vkey.getId().then(function() {
382
401
  return vkey;
383
402
  }).catch(function(e) {
384
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');
385
405
  return Promise.resolve(user || m().then(function(dom) {
386
406
  return dom.vaultRefToUser(exts[0]);
387
407
  })).catch(function(e) {
@@ -434,8 +454,8 @@ libVES.prototype = {
434
454
  return key.generate(veskey, optns).then(function(k) {
435
455
  key.setField('vaultItems', veskey.then(function(v) {
436
456
  var vi = new libVES.VaultItem({type: 'password'}, self);
437
- return usr.getActiveVaultKeys().then(function() {
438
- return [self.me(), self.getVaultKey(), usr];
457
+ return usr.getActiveVaultKeys().then(function(akeys) {
458
+ return [self.me(), self.getVaultKey()].concat(akeys);
439
459
  }).catch(function(e) {
440
460
  if (e.code != 'NotFound') throw e;
441
461
  var sh = self.type == 'secondary' ? [self.me(), self.getVaultKey()] : [self.me()];
@@ -573,6 +593,9 @@ libVES.prototype = {
573
593
  }).catch(function(e) {
574
594
  if (!e || e.code != 'Unauthorized') throw e;
575
595
  }).then(function() {
596
+ self.vaultKey = k.lock().then(function() {
597
+ return k;
598
+ });
576
599
  return self.unlock(veskey);
577
600
  });
578
601
  });
@@ -807,7 +830,7 @@ libVES.prototype = {
807
830
  return self.getVaultKey().then(function(vk) {
808
831
  return vk.getField('unlockableVaultKeys').then(function(vks) {
809
832
  var rs = {};
810
- return Promise.all(vks.map(function(e, i) {
833
+ return Promise.all((vks || []).map(function(e, i) {
811
834
  return e.getId().then(function(id) {
812
835
  rs[id] = e;
813
836
  });
@@ -917,6 +940,11 @@ libVES.Error.Redirect = function(msg, optns) {
917
940
  };
918
941
  libVES.Error.Redirect.prototype = new libVES.Error('Redirect');
919
942
 
943
+ libVES.Error.Unauthorized = function(msg, optns) {
944
+ this.init(msg, optns);
945
+ };
946
+ libVES.Error.Unauthorized.prototype = new libVES.Error('Unauthorized');
947
+
920
948
  libVES.Error.Internal = function(msg, optns) {
921
949
  this.init(msg, optns);
922
950
  };
@@ -1024,6 +1052,14 @@ libVES.Util = {
1024
1052
  }
1025
1053
  return rs;
1026
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
+ },
1027
1063
  loadWasm: function(src) {
1028
1064
  return new Promise(function(resolve, reject) {
1029
1065
  var sc = document.createElement('script');
@@ -1712,30 +1748,20 @@ libVES.Object.prototype = {
1712
1748
  this.setFields(data,data.id == null);
1713
1749
  if (refs) for (var k in refs) this[k] = Promise.resolve(refs[k]);
1714
1750
  },
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);
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);
1739
1765
  },
1740
1766
  setField: function(fld,val,upd) {
1741
1767
  var flds = {};
@@ -1744,54 +1770,78 @@ libVES.Object.prototype = {
1744
1770
  return self[fld];
1745
1771
  });
1746
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
+ },
1747
1812
  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
- }
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));
1761
1816
  var plst = [];
1762
- for (var k in fldlst) {
1763
- plst.push(Promise.resolve(this[k]).then(function(v) {
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
+ }));
1764
1822
  if (!(v instanceof libVES.Object)) return v;
1765
- return v.getFields(fldlst[k], force);
1823
+ return v.getFields(fldlst[k]);
1766
1824
  }));
1767
- }
1825
+ })(k);
1768
1826
  var rs = {};
1769
- return Promise.all(plst).then(function(lst) {
1827
+ return Promise.all(plst).then((lst) => {
1770
1828
  var i = 0;
1771
1829
  for (var k in fldlst) rs[k] = lst[i++];
1772
1830
  return rs;
1773
1831
  });
1774
1832
  },
1775
1833
  getField: function(fld,fldlst,force) {
1776
- var self = this;
1777
1834
  if (!this[fld] || force) {
1778
1835
  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);
1836
+ flds[fld] = fldlst || true;
1837
+ this.getFields(flds, force).catch(() => null);
1789
1838
  }
1790
1839
  return this[fld];
1791
1840
  },
1792
1841
  loadFields: function(flds,force,optns) {
1842
+ if (!flds) return Promise.resolve({});
1793
1843
  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) {
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) {
1795
1845
  data['$op'] = 'fetch';
1796
1846
  return self.VES.post(self.apiUri,data,flds,optns);
1797
1847
  }).then(function(data) {
@@ -1800,21 +1850,10 @@ libVES.Object.prototype = {
1800
1850
  self.fieldUpdate = {id: true};
1801
1851
  }
1802
1852
  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
- }
1853
+ })).then((data) => libVES.Util.fillUndefs(data, flds));
1815
1854
  },
1816
1855
  reset: function() {
1817
- for (var k in this.fieldClass) delete(this[k]);
1856
+ for (var k in this.fieldClass) this.unsetField(k);
1818
1857
  return Promise.resolve();
1819
1858
  },
1820
1859
  getId: function() {
@@ -1888,6 +1927,23 @@ libVES.Object.prototype = {
1888
1927
  },
1889
1928
  resolveError: function(e,field) {
1890
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);
1891
1947
  }
1892
1948
  };
1893
1949
 
@@ -2040,10 +2096,16 @@ libVES.VaultKey.prototype = new libVES.Object({
2040
2096
  case 'lost':
2041
2097
  return self.getVaultItems().then(function(vis) {
2042
2098
  var f = function(vis) {
2043
- 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');
2044
2100
  return vis[0].getType().then(function(t) {
2045
2101
  switch (t) {
2046
- 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
+ });
2047
2109
  default: return f(vis.slice(1));
2048
2110
  }
2049
2111
  });
@@ -2054,26 +2116,57 @@ libVES.VaultKey.prototype = new libVES.Object({
2054
2116
  }
2055
2117
  });
2056
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
+ },
2057
2133
  unlock: function(veskey) {
2058
2134
  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);
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
+ });
2069
2155
  });
2070
2156
  });
2071
- });
2072
- else return self.VES.unlockedKeys[id].catch(function(e) {
2073
- self.VES.unlockedKeys[id] = null;
2074
- 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;
2075
2163
  });
2076
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;
2077
2170
  },
2078
2171
  lock: function() {
2079
2172
  var self = this;
@@ -2251,8 +2344,20 @@ libVES.VaultKey.prototype = new libVES.Object({
2251
2344
  });
2252
2345
  });
2253
2346
  },
2254
- matchVaults: function(vaultKeys) {
2255
- 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)));
2256
2361
  },
2257
2362
  getKeyOptions: function() {
2258
2363
  var self = this;
@@ -2268,7 +2373,7 @@ libVES.VaultItem.prototype = new libVES.Object({
2268
2373
  apiUri: 'vaultItems',
2269
2374
  fieldList: {id: true, deleted: true, file: true},
2270
2375
  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}],
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}],
2272
2377
  defaultCipher: 'AES256GCM',
2273
2378
  getRaw: function() {
2274
2379
  var self = this;
@@ -2277,9 +2382,11 @@ libVES.VaultItem.prototype = new libVES.Object({
2277
2382
  var fn = function() {
2278
2383
  if (vaultEntries) for (; i < vaultEntries.length; i++) {
2279
2384
  var k, d;
2280
- 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])) {
2281
2386
  i++;
2282
- 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
+ });
2283
2390
  }
2284
2391
  }
2285
2392
  return Promise.reject(new libVES.Error('InvalidKey',"No unlocked key to decrypt the item",{vaultItem: self}));
@@ -2338,7 +2445,10 @@ libVES.VaultItem.prototype = new libVES.Object({
2338
2445
  },
2339
2446
  build: function(data) {
2340
2447
  var self = this;
2341
- 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) {
2342
2452
  return libVES.getModule(libVES.VaultItem.Type,type).then(function(m) {
2343
2453
  return m.build.call(self,data);
2344
2454
  });
@@ -2350,12 +2460,12 @@ libVES.VaultItem.prototype = new libVES.Object({
2350
2460
  shareWith: function(usrs,val,save) {
2351
2461
  var self = this;
2352
2462
  return self.VES.usersToKeys(usrs).then(function(ks) {
2353
- return (val == null || self.id ? self.getVaultEntries().then(function(ves) {
2463
+ return (val == null ? self.getVaultEntries().then(function(ves) {
2354
2464
  var k_ves = {};
2355
2465
  var k_used = {};
2356
2466
  for (var j = 0; j < ves.length; j++) k_ves[ves[j].vaultKey.id] = ves[j];
2357
2467
  return Promise.all(ks.map(function(k,j) {
2358
- return k.getId().then(function(k_id) {
2468
+ if (!k.fieldUpdate.privateKey) return k.getId().then(function(k_id) {
2359
2469
  k_used[k_id] = true;
2360
2470
  return k_ves[k_id];
2361
2471
  }).catch(function(){});
@@ -2367,21 +2477,26 @@ libVES.VaultItem.prototype = new libVES.Object({
2367
2477
  var new_ves = [];
2368
2478
  var set_ves = [];
2369
2479
  var valr = null;
2480
+ var key_ids = {};
2370
2481
  return Promise.all(ks.map(function(k,j) {
2371
2482
  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) {
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) {
2377
2492
  return set_ves.push({vaultKey: pd, encData: ctext});
2378
2493
  });
2379
2494
  });
2380
2495
  }));
2381
2496
  })).then(function() {
2382
2497
  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'});
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'});
2385
2500
  });
2386
2501
  }));
2387
2502
  }).then(function() {
@@ -2390,12 +2505,20 @@ libVES.VaultItem.prototype = new libVES.Object({
2390
2505
  });
2391
2506
  });
2392
2507
  }).then(function() {
2393
- if (save || save === undefined) return self.post(undefined, undefined, ((save instanceof Object) ? save : undefined)).then(function() {
2394
- delete(self.vaultEntries);
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);
2395
2513
  return self;
2514
+ }).finally(function() {
2515
+ delete(self.vaultEntries);
2396
2516
  });
2397
2517
  return self;
2398
- });
2518
+ }).catch(function(er) {
2519
+ delete(self.vaultEntries);
2520
+ throw er;
2521
+ });
2399
2522
  },
2400
2523
  reshareWith: function(share,val,save) {
2401
2524
  var self = this;
@@ -2418,6 +2541,15 @@ libVES.VaultItem.prototype = new libVES.Object({
2418
2541
  });
2419
2542
  });
2420
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
+ },
2421
2553
  getShareVaultKeys: function() {
2422
2554
  var self = this;
2423
2555
  return this.getVaultEntries().then(function(vaultEntries) {
@@ -2430,12 +2562,17 @@ libVES.VaultItem.prototype = new libVES.Object({
2430
2562
  var self = this;
2431
2563
  return this.getShareVaultKeys().then(function(vaultKeys) {
2432
2564
  var uids = {};
2565
+ var xids = {};
2433
2566
  return Promise.all(vaultKeys.map(function(e,i) {
2434
2567
  return e.getExternals().then(function(exts) {
2435
- 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
+ });
2436
2573
  return e.getUser().then(function(u) {
2437
2574
  return u.getId().then(function(uid) {
2438
- if (uids[uid]) return null;
2575
+ if (!uid || uids[uid]) return null;
2439
2576
  uids[uid] = true;
2440
2577
  return u;
2441
2578
  });
@@ -2451,7 +2588,7 @@ libVES.VaultItem.prototype = new libVES.Object({
2451
2588
  delete: function() {
2452
2589
  var self = this;
2453
2590
  return self.getId().then(function(id) {
2454
- return this.VES.post(self.apiUri + '/' + id, {'$op': 'delete'});
2591
+ return self.VES.post(self.apiUri + '/' + id, {'$op': 'delete'});
2455
2592
  });
2456
2593
  }
2457
2594
  });
@@ -4306,7 +4443,7 @@ libVES.Watch.prototype = {
4306
4443
  }).then(function(res) {
4307
4444
  if (!res.events) return null;
4308
4445
  return res.events.map(function(e, i) {
4309
- return new libVES.Event(e, self.VES);
4446
+ return new libVES.Event(libVES.Util.fillUndefs(e, self.fields), self.VES);
4310
4447
  });
4311
4448
  });
4312
4449
  },
@@ -4321,8 +4458,8 @@ libVES.Watch.prototype = {
4321
4458
  if (!busy && this.state == 'stop') this.setState('idle');
4322
4459
  },
4323
4460
  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');
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'));
4326
4463
  var self = this;
4327
4464
  self.setBusy(true);
4328
4465
  this.setState('read');
@@ -4330,13 +4467,17 @@ libVES.Watch.prototype = {
4330
4467
  this.next = 0;
4331
4468
  return this.getEvents(0, pos).then(function(evs) {
4332
4469
  self.setBusy(false);
4333
- return self.received(evs.reverse());
4334
- });
4470
+ return self.received(evs ? evs.reverse() : null);
4471
+ }).finally(function() {
4472
+ self.setBusy(false);
4473
+ });
4335
4474
  } else {
4336
4475
  this.next = pos;
4337
4476
  return this.getEvents(pos, 0).then(function(evs) {
4338
4477
  self.setBusy(false);
4339
4478
  return self.received(evs);
4479
+ }).finally(function() {
4480
+ self.setBusy(false);
4340
4481
  });
4341
4482
  }
4342
4483
  },
@@ -4346,31 +4487,30 @@ libVES.Watch.prototype = {
4346
4487
  received: function(evs) {
4347
4488
  var self = this;
4348
4489
  var p;
4349
- if (evs && evs.length) p = evs.reduce(function(v, e) {
4490
+ if (!evs) return null;
4491
+ if (evs.length) return evs.reduce(function(v, ev) {
4350
4492
  if (self.active()) try {
4351
- self.eventfn(e, self);
4493
+ self.eventfn(ev, self);
4352
4494
  } catch(e) {
4353
4495
  console.log(e);
4354
4496
  }
4355
- return e;
4497
+ return ev;
4356
4498
  }, null).getId().then(function(id) {
4357
4499
  self.next = id + 1;
4500
+ return self.request();
4358
4501
  });
4359
4502
  else {
4360
- p = Promise.resolve(null);
4361
4503
  if (this.state == 'read') this.setState('poll');
4504
+ return self.request(), true;
4362
4505
  }
4363
- return p.then(function() {
4364
- return self.request();
4365
- });
4366
4506
  },
4367
4507
  request: function() {
4368
- if (this.busy || !this.active()) return;
4508
+ if (this.busy || !this.active()) return true;
4369
4509
  var self = this;
4370
4510
  self.setBusy(true);
4371
4511
  return self.getEvents(self.next, 0, (self.state == 'poll')).then(function(evs) {
4372
4512
  self.setBusy(false);
4373
- self.received(evs);
4513
+ return self.received(evs);
4374
4514
  }).catch(function(e) {
4375
4515
  self.setBusy(false);
4376
4516
  if (self.errorfn) try {
@@ -4393,6 +4533,743 @@ libVES.Watch.prototype = {
4393
4533
  this.setState(this.busy ? 'stop' : 'idle');
4394
4534
  }
4395
4535
  };
4396
- libVES.version = '2.16';
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';
4397
5274
 
4398
5275
  module.exports = libVES;