gun-eth 1.4.21 → 1.4.23
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/dist/gun-eth.cjs.js +1534 -68
- package/dist/gun-eth.cjs.js.map +1 -1
- package/dist/gun-eth.esm.js +1534 -68
- package/dist/gun-eth.esm.js.map +1 -1
- package/dist/gun-eth.min.js +1 -1
- package/dist/gun-eth.min.js.map +1 -1
- package/package.json +19 -21
- package/dist/gun-eth.js +0 -1382
- package/dist/gun-eth.js.map +0 -1
- package/src/abis/abis.js +0 -391
- package/src/config/contract-address.json +0 -4
- package/src/config/local.js +0 -29
- package/src/index.js +0 -953
package/dist/gun-eth.cjs.js
CHANGED
|
@@ -3,16 +3,1532 @@
|
|
|
3
3
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
4
|
|
|
5
5
|
var Gun = require('gun');
|
|
6
|
-
var SEA = require('gun/sea.js');
|
|
7
6
|
var ethers = require('ethers');
|
|
8
7
|
|
|
9
8
|
var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
|
|
10
|
-
var
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
9
|
+
var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
|
|
10
|
+
|
|
11
|
+
function getDefaultExportFromCjs (x) {
|
|
12
|
+
return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function commonjsRequire(path) {
|
|
16
|
+
throw new Error('Could not dynamically require "' + path + '". Please configure the dynamicRequireTargets or/and ignoreDynamicRequires option of @rollup/plugin-commonjs appropriately for this require call to work.');
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
var sea = {exports: {}};
|
|
20
|
+
|
|
21
|
+
sea.exports;
|
|
22
|
+
|
|
23
|
+
(function (module) {
|
|
24
|
+
(function(){
|
|
25
|
+
|
|
26
|
+
/* UNBUILD */
|
|
27
|
+
function USE(arg, req){
|
|
28
|
+
return req? commonjsRequire(arg) : arg.slice? USE[R(arg)] : function(mod, path){
|
|
29
|
+
arg(mod = {exports: {}});
|
|
30
|
+
USE[R(path)] = mod.exports;
|
|
31
|
+
}
|
|
32
|
+
function R(p){
|
|
33
|
+
return p.split('/').slice(-1).toString().replace('.js','');
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
{ var MODULE = module; }
|
|
37
|
+
USE(function(module){
|
|
38
|
+
// Security, Encryption, and Authorization: SEA.js
|
|
39
|
+
// MANDATORY READING: https://gun.eco/explainers/data/security.html
|
|
40
|
+
// IT IS IMPLEMENTED IN A POLYFILL/SHIM APPROACH.
|
|
41
|
+
// THIS IS AN EARLY ALPHA!
|
|
42
|
+
|
|
43
|
+
if(typeof self !== "undefined"){ module.window = self; } // should be safe for at least browser/worker/nodejs, need to check other envs like RN etc.
|
|
44
|
+
if(typeof window !== "undefined"){ module.window = window; }
|
|
45
|
+
|
|
46
|
+
var tmp = module.window || module, u;
|
|
47
|
+
var SEA = tmp.SEA || {};
|
|
48
|
+
|
|
49
|
+
if(SEA.window = module.window){ SEA.window.SEA = SEA; }
|
|
50
|
+
|
|
51
|
+
try{ if(u+'' !== typeof MODULE){ MODULE.exports = SEA; } }catch(e){}
|
|
52
|
+
module.exports = SEA;
|
|
53
|
+
})(USE, './root');
|
|
54
|
+
USE(function(module){
|
|
55
|
+
var SEA = USE('./root');
|
|
56
|
+
try{ if(SEA.window){
|
|
57
|
+
if(location.protocol.indexOf('s') < 0
|
|
58
|
+
&& location.host.indexOf('localhost') < 0
|
|
59
|
+
&& ! /^127\.\d+\.\d+\.\d+$/.test(location.hostname)
|
|
60
|
+
&& location.protocol.indexOf('file:') < 0){
|
|
61
|
+
console.warn('HTTPS needed for WebCrypto in SEA, redirecting...');
|
|
62
|
+
location.protocol = 'https:'; // WebCrypto does NOT work without HTTPS!
|
|
63
|
+
}
|
|
64
|
+
} }catch(e){}
|
|
65
|
+
})(USE, './https');
|
|
66
|
+
USE(function(module){
|
|
67
|
+
var u;
|
|
68
|
+
if(u+''== typeof btoa){
|
|
69
|
+
if(u+'' == typeof Buffer){
|
|
70
|
+
try{ commonjsGlobal.Buffer = USE("buffer", 1).Buffer; }catch(e){ console.log("Please `npm install buffer` or add it to your package.json !"); }
|
|
71
|
+
}
|
|
72
|
+
commonjsGlobal.btoa = function(data){ return Buffer.from(data, "binary").toString("base64") };
|
|
73
|
+
commonjsGlobal.atob = function(data){ return Buffer.from(data, "base64").toString("binary") };
|
|
74
|
+
}
|
|
75
|
+
})(USE, './base64');
|
|
76
|
+
USE(function(module){
|
|
77
|
+
USE('./base64');
|
|
78
|
+
// This is Array extended to have .toString(['utf8'|'hex'|'base64'])
|
|
79
|
+
function SeaArray() {}
|
|
80
|
+
Object.assign(SeaArray, { from: Array.from });
|
|
81
|
+
SeaArray.prototype = Object.create(Array.prototype);
|
|
82
|
+
SeaArray.prototype.toString = function(enc, start, end) { enc = enc || 'utf8'; start = start || 0;
|
|
83
|
+
const length = this.length;
|
|
84
|
+
if (enc === 'hex') {
|
|
85
|
+
const buf = new Uint8Array(this);
|
|
86
|
+
return [ ...Array(((end && (end + 1)) || length) - start).keys()]
|
|
87
|
+
.map((i) => buf[ i + start ].toString(16).padStart(2, '0')).join('')
|
|
88
|
+
}
|
|
89
|
+
if (enc === 'utf8') {
|
|
90
|
+
return Array.from(
|
|
91
|
+
{ length: (end || length) - start },
|
|
92
|
+
(_, i) => String.fromCharCode(this[ i + start])
|
|
93
|
+
).join('')
|
|
94
|
+
}
|
|
95
|
+
if (enc === 'base64') {
|
|
96
|
+
return btoa(this)
|
|
97
|
+
}
|
|
98
|
+
};
|
|
99
|
+
module.exports = SeaArray;
|
|
100
|
+
})(USE, './array');
|
|
101
|
+
USE(function(module){
|
|
102
|
+
USE('./base64');
|
|
103
|
+
// This is Buffer implementation used in SEA. Functionality is mostly
|
|
104
|
+
// compatible with NodeJS 'safe-buffer' and is used for encoding conversions
|
|
105
|
+
// between binary and 'hex' | 'utf8' | 'base64'
|
|
106
|
+
// See documentation and validation for safe implementation in:
|
|
107
|
+
// https://github.com/feross/safe-buffer#update
|
|
108
|
+
var SeaArray = USE('./array');
|
|
109
|
+
function SafeBuffer(...props) {
|
|
110
|
+
console.warn('new SafeBuffer() is depreciated, please use SafeBuffer.from()');
|
|
111
|
+
return SafeBuffer.from(...props)
|
|
112
|
+
}
|
|
113
|
+
SafeBuffer.prototype = Object.create(Array.prototype);
|
|
114
|
+
Object.assign(SafeBuffer, {
|
|
115
|
+
// (data, enc) where typeof data === 'string' then enc === 'utf8'|'hex'|'base64'
|
|
116
|
+
from() {
|
|
117
|
+
if (!Object.keys(arguments).length || arguments[0]==null) {
|
|
118
|
+
throw new TypeError('First argument must be a string, Buffer, ArrayBuffer, Array, or array-like object.')
|
|
119
|
+
}
|
|
120
|
+
const input = arguments[0];
|
|
121
|
+
let buf;
|
|
122
|
+
if (typeof input === 'string') {
|
|
123
|
+
const enc = arguments[1] || 'utf8';
|
|
124
|
+
if (enc === 'hex') {
|
|
125
|
+
const bytes = input.match(/([\da-fA-F]{2})/g)
|
|
126
|
+
.map((byte) => parseInt(byte, 16));
|
|
127
|
+
if (!bytes || !bytes.length) {
|
|
128
|
+
throw new TypeError('Invalid first argument for type \'hex\'.')
|
|
129
|
+
}
|
|
130
|
+
buf = SeaArray.from(bytes);
|
|
131
|
+
} else if (enc === 'utf8' || 'binary' === enc) { // EDIT BY MARK: I think this is safe, tested it against a couple "binary" strings. This lets SafeBuffer match NodeJS Buffer behavior more where it safely btoas regular strings.
|
|
132
|
+
const length = input.length;
|
|
133
|
+
const words = new Uint16Array(length);
|
|
134
|
+
Array.from({ length: length }, (_, i) => words[i] = input.charCodeAt(i));
|
|
135
|
+
buf = SeaArray.from(words);
|
|
136
|
+
} else if (enc === 'base64') {
|
|
137
|
+
const dec = atob(input);
|
|
138
|
+
const length = dec.length;
|
|
139
|
+
const bytes = new Uint8Array(length);
|
|
140
|
+
Array.from({ length: length }, (_, i) => bytes[i] = dec.charCodeAt(i));
|
|
141
|
+
buf = SeaArray.from(bytes);
|
|
142
|
+
} else if (enc === 'binary') { // deprecated by above comment
|
|
143
|
+
buf = SeaArray.from(input); // some btoas were mishandled.
|
|
144
|
+
} else {
|
|
145
|
+
console.info('SafeBuffer.from unknown encoding: '+enc);
|
|
146
|
+
}
|
|
147
|
+
return buf
|
|
148
|
+
}
|
|
149
|
+
input.byteLength; // what is going on here? FOR MARTTI
|
|
150
|
+
const length = input.byteLength ? input.byteLength : input.length;
|
|
151
|
+
if (length) {
|
|
152
|
+
let buf;
|
|
153
|
+
if (input instanceof ArrayBuffer) {
|
|
154
|
+
buf = new Uint8Array(input);
|
|
155
|
+
}
|
|
156
|
+
return SeaArray.from(buf || input)
|
|
157
|
+
}
|
|
158
|
+
},
|
|
159
|
+
// This is 'safe-buffer.alloc' sans encoding support
|
|
160
|
+
alloc(length, fill = 0 /*, enc*/ ) {
|
|
161
|
+
return SeaArray.from(new Uint8Array(Array.from({ length: length }, () => fill)))
|
|
162
|
+
},
|
|
163
|
+
// This is normal UNSAFE 'buffer.alloc' or 'new Buffer(length)' - don't use!
|
|
164
|
+
allocUnsafe(length) {
|
|
165
|
+
return SeaArray.from(new Uint8Array(Array.from({ length : length })))
|
|
166
|
+
},
|
|
167
|
+
// This puts together array of array like members
|
|
168
|
+
concat(arr) { // octet array
|
|
169
|
+
if (!Array.isArray(arr)) {
|
|
170
|
+
throw new TypeError('First argument must be Array containing ArrayBuffer or Uint8Array instances.')
|
|
171
|
+
}
|
|
172
|
+
return SeaArray.from(arr.reduce((ret, item) => ret.concat(Array.from(item)), []))
|
|
173
|
+
}
|
|
174
|
+
});
|
|
175
|
+
SafeBuffer.prototype.from = SafeBuffer.from;
|
|
176
|
+
SafeBuffer.prototype.toString = SeaArray.prototype.toString;
|
|
177
|
+
|
|
178
|
+
module.exports = SafeBuffer;
|
|
179
|
+
})(USE, './buffer');
|
|
180
|
+
USE(function(module){
|
|
181
|
+
const SEA = USE('./root');
|
|
182
|
+
const api = {Buffer: USE('./buffer')};
|
|
183
|
+
var o = {}, u;
|
|
184
|
+
|
|
185
|
+
// ideally we can move away from JSON entirely? unlikely due to compatibility issues... oh well.
|
|
186
|
+
JSON.parseAsync = JSON.parseAsync || function(t,cb,r){ var u; try{ cb(u, JSON.parse(t,r)); }catch(e){ cb(e); } };
|
|
187
|
+
JSON.stringifyAsync = JSON.stringifyAsync || function(v,cb,r,s){ var u; try{ cb(u, JSON.stringify(v,r,s)); }catch(e){ cb(e); } };
|
|
188
|
+
|
|
189
|
+
api.parse = function(t,r){ return new Promise(function(res, rej){
|
|
190
|
+
JSON.parseAsync(t,function(err, raw){ err? rej(err) : res(raw); },r);
|
|
191
|
+
})};
|
|
192
|
+
api.stringify = function(v,r,s){ return new Promise(function(res, rej){
|
|
193
|
+
JSON.stringifyAsync(v,function(err, raw){ err? rej(err) : res(raw); },r,s);
|
|
194
|
+
})};
|
|
195
|
+
|
|
196
|
+
if(SEA.window){
|
|
197
|
+
api.crypto = SEA.window.crypto || SEA.window.msCrypto;
|
|
198
|
+
api.subtle = (api.crypto||o).subtle || (api.crypto||o).webkitSubtle;
|
|
199
|
+
api.TextEncoder = SEA.window.TextEncoder;
|
|
200
|
+
api.TextDecoder = SEA.window.TextDecoder;
|
|
201
|
+
api.random = (len) => api.Buffer.from(api.crypto.getRandomValues(new Uint8Array(api.Buffer.alloc(len))));
|
|
202
|
+
}
|
|
203
|
+
if(!api.TextDecoder)
|
|
204
|
+
{
|
|
205
|
+
const { TextEncoder, TextDecoder } = USE((u+'' == typeof MODULE?'.':'')+'./lib/text-encoding', 1);
|
|
206
|
+
api.TextDecoder = TextDecoder;
|
|
207
|
+
api.TextEncoder = TextEncoder;
|
|
208
|
+
}
|
|
209
|
+
if(!api.crypto)
|
|
210
|
+
{
|
|
211
|
+
try
|
|
212
|
+
{
|
|
213
|
+
var crypto = USE('crypto', 1);
|
|
214
|
+
Object.assign(api, {
|
|
215
|
+
crypto,
|
|
216
|
+
random: (len) => api.Buffer.from(crypto.randomBytes(len))
|
|
217
|
+
});
|
|
218
|
+
const { Crypto: WebCrypto } = USE('@peculiar/webcrypto', 1);
|
|
219
|
+
api.ossl = api.subtle = new WebCrypto({directory: 'ossl'}).subtle; // ECDH
|
|
220
|
+
}
|
|
221
|
+
catch(e){
|
|
222
|
+
console.log("Please `npm install @peculiar/webcrypto` or add it to your package.json !");
|
|
223
|
+
}}
|
|
224
|
+
|
|
225
|
+
module.exports = api;
|
|
226
|
+
})(USE, './shim');
|
|
227
|
+
USE(function(module){
|
|
228
|
+
var SEA = USE('./root');
|
|
229
|
+
var shim = USE('./shim');
|
|
230
|
+
var s = {};
|
|
231
|
+
s.pbkdf2 = {hash: {name : 'SHA-256'}, iter: 100000, ks: 64};
|
|
232
|
+
s.ecdsa = {
|
|
233
|
+
pair: {name: 'ECDSA', namedCurve: 'P-256'},
|
|
234
|
+
sign: {name: 'ECDSA', hash: {name: 'SHA-256'}}
|
|
235
|
+
};
|
|
236
|
+
s.ecdh = {name: 'ECDH', namedCurve: 'P-256'};
|
|
237
|
+
|
|
238
|
+
// This creates Web Cryptography API compliant JWK for sign/verify purposes
|
|
239
|
+
s.jwk = function(pub, d){ // d === priv
|
|
240
|
+
pub = pub.split('.');
|
|
241
|
+
var x = pub[0], y = pub[1];
|
|
242
|
+
var jwk = {kty: "EC", crv: "P-256", x: x, y: y, ext: true};
|
|
243
|
+
jwk.key_ops = d ? ['sign'] : ['verify'];
|
|
244
|
+
if(d){ jwk.d = d; }
|
|
245
|
+
return jwk;
|
|
246
|
+
};
|
|
247
|
+
|
|
248
|
+
s.keyToJwk = function(keyBytes) {
|
|
249
|
+
const keyB64 = keyBytes.toString('base64');
|
|
250
|
+
const k = keyB64.replace(/\+/g, '-').replace(/\//g, '_').replace(/\=/g, '');
|
|
251
|
+
return { kty: 'oct', k: k, ext: false, alg: 'A256GCM' };
|
|
252
|
+
};
|
|
253
|
+
|
|
254
|
+
s.recall = {
|
|
255
|
+
validity: 12 * 60 * 60, // internally in seconds : 12 hours
|
|
256
|
+
hook: function(props){ return props } // { iat, exp, alias, remember } // or return new Promise((resolve, reject) => resolve(props)
|
|
257
|
+
};
|
|
258
|
+
|
|
259
|
+
s.check = function(t){ return (typeof t == 'string') && ('SEA{' === t.slice(0,4)) };
|
|
260
|
+
s.parse = async function p(t){ try {
|
|
261
|
+
var yes = (typeof t == 'string');
|
|
262
|
+
if(yes && 'SEA{' === t.slice(0,4)){ t = t.slice(3); }
|
|
263
|
+
return yes ? await shim.parse(t) : t;
|
|
264
|
+
} catch (e) {}
|
|
265
|
+
return t;
|
|
266
|
+
};
|
|
267
|
+
|
|
268
|
+
SEA.opt = s;
|
|
269
|
+
module.exports = s;
|
|
270
|
+
})(USE, './settings');
|
|
271
|
+
USE(function(module){
|
|
272
|
+
var shim = USE('./shim');
|
|
273
|
+
module.exports = async function(d, o){
|
|
274
|
+
var t = (typeof d == 'string')? d : await shim.stringify(d);
|
|
275
|
+
var hash = await shim.subtle.digest({name: o||'SHA-256'}, new shim.TextEncoder().encode(t));
|
|
276
|
+
return shim.Buffer.from(hash);
|
|
277
|
+
};
|
|
278
|
+
})(USE, './sha256');
|
|
279
|
+
USE(function(module){
|
|
280
|
+
// This internal func returns SHA-1 hashed data for KeyID generation
|
|
281
|
+
const __shim = USE('./shim');
|
|
282
|
+
const subtle = __shim.subtle;
|
|
283
|
+
const ossl = __shim.ossl ? __shim.ossl : subtle;
|
|
284
|
+
const sha1hash = (b) => ossl.digest({name: 'SHA-1'}, new ArrayBuffer(b));
|
|
285
|
+
module.exports = sha1hash;
|
|
286
|
+
})(USE, './sha1');
|
|
287
|
+
USE(function(module){
|
|
288
|
+
var SEA = USE('./root');
|
|
289
|
+
var shim = USE('./shim');
|
|
290
|
+
var S = USE('./settings');
|
|
291
|
+
var sha = USE('./sha256');
|
|
292
|
+
var u;
|
|
293
|
+
|
|
294
|
+
SEA.work = SEA.work || (async (data, pair, cb, opt) => { try { // used to be named `proof`
|
|
295
|
+
var salt = (pair||{}).epub || pair; // epub not recommended, salt should be random!
|
|
296
|
+
opt = opt || {};
|
|
297
|
+
if(salt instanceof Function){
|
|
298
|
+
cb = salt;
|
|
299
|
+
salt = u;
|
|
300
|
+
}
|
|
301
|
+
data = (typeof data == 'string')? data : await shim.stringify(data);
|
|
302
|
+
if('sha' === (opt.name||'').toLowerCase().slice(0,3)){
|
|
303
|
+
var rsha = shim.Buffer.from(await sha(data, opt.name), 'binary').toString(opt.encode || 'base64');
|
|
304
|
+
if(cb){ try{ cb(rsha); }catch(e){console.log(e);} }
|
|
305
|
+
return rsha;
|
|
306
|
+
}
|
|
307
|
+
salt = salt || shim.random(9);
|
|
308
|
+
var key = await (shim.ossl || shim.subtle).importKey('raw', new shim.TextEncoder().encode(data), {name: opt.name || 'PBKDF2'}, false, ['deriveBits']);
|
|
309
|
+
var work = await (shim.ossl || shim.subtle).deriveBits({
|
|
310
|
+
name: opt.name || 'PBKDF2',
|
|
311
|
+
iterations: opt.iterations || S.pbkdf2.iter,
|
|
312
|
+
salt: new shim.TextEncoder().encode(opt.salt || salt),
|
|
313
|
+
hash: opt.hash || S.pbkdf2.hash,
|
|
314
|
+
}, key, opt.length || (S.pbkdf2.ks * 8));
|
|
315
|
+
data = shim.random(data.length); // Erase data in case of passphrase
|
|
316
|
+
var r = shim.Buffer.from(work, 'binary').toString(opt.encode || 'base64');
|
|
317
|
+
if(cb){ try{ cb(r); }catch(e){console.log(e);} }
|
|
318
|
+
return r;
|
|
319
|
+
} catch(e) {
|
|
320
|
+
console.log(e);
|
|
321
|
+
SEA.err = e;
|
|
322
|
+
if(SEA.throw){ throw e }
|
|
323
|
+
if(cb){ cb(); }
|
|
324
|
+
return;
|
|
325
|
+
}});
|
|
326
|
+
|
|
327
|
+
module.exports = SEA.work;
|
|
328
|
+
})(USE, './work');
|
|
329
|
+
USE(function(module){
|
|
330
|
+
var SEA = USE('./root');
|
|
331
|
+
var shim = USE('./shim');
|
|
332
|
+
USE('./settings');
|
|
333
|
+
|
|
334
|
+
SEA.name = SEA.name || (async (cb, opt) => { try {
|
|
335
|
+
if(cb){ try{ cb(); }catch(e){console.log(e);} }
|
|
336
|
+
return;
|
|
337
|
+
} catch(e) {
|
|
338
|
+
console.log(e);
|
|
339
|
+
SEA.err = e;
|
|
340
|
+
if(SEA.throw){ throw e }
|
|
341
|
+
if(cb){ cb(); }
|
|
342
|
+
return;
|
|
343
|
+
}});
|
|
344
|
+
|
|
345
|
+
//SEA.pair = async (data, proof, cb) => { try {
|
|
346
|
+
SEA.pair = SEA.pair || (async (cb, opt) => { try {
|
|
347
|
+
|
|
348
|
+
var ecdhSubtle = shim.ossl || shim.subtle;
|
|
349
|
+
// First: ECDSA keys for signing/verifying...
|
|
350
|
+
var sa = await shim.subtle.generateKey({name: 'ECDSA', namedCurve: 'P-256'}, true, [ 'sign', 'verify' ])
|
|
351
|
+
.then(async (keys) => {
|
|
352
|
+
// privateKey scope doesn't leak out from here!
|
|
353
|
+
//const { d: priv } = await shim.subtle.exportKey('jwk', keys.privateKey)
|
|
354
|
+
var key = {};
|
|
355
|
+
key.priv = (await shim.subtle.exportKey('jwk', keys.privateKey)).d;
|
|
356
|
+
var pub = await shim.subtle.exportKey('jwk', keys.publicKey);
|
|
357
|
+
//const pub = Buff.from([ x, y ].join(':')).toString('base64') // old
|
|
358
|
+
key.pub = pub.x+'.'+pub.y; // new
|
|
359
|
+
// x and y are already base64
|
|
360
|
+
// pub is UTF8 but filename/URL safe (https://www.ietf.org/rfc/rfc3986.txt)
|
|
361
|
+
// but split on a non-base64 letter.
|
|
362
|
+
return key;
|
|
363
|
+
});
|
|
364
|
+
|
|
365
|
+
// To include PGPv4 kind of keyId:
|
|
366
|
+
// const pubId = await SEA.keyid(keys.pub)
|
|
367
|
+
// Next: ECDH keys for encryption/decryption...
|
|
368
|
+
|
|
369
|
+
try{
|
|
370
|
+
var dh = await ecdhSubtle.generateKey({name: 'ECDH', namedCurve: 'P-256'}, true, ['deriveKey'])
|
|
371
|
+
.then(async (keys) => {
|
|
372
|
+
// privateKey scope doesn't leak out from here!
|
|
373
|
+
var key = {};
|
|
374
|
+
key.epriv = (await ecdhSubtle.exportKey('jwk', keys.privateKey)).d;
|
|
375
|
+
var pub = await ecdhSubtle.exportKey('jwk', keys.publicKey);
|
|
376
|
+
//const epub = Buff.from([ ex, ey ].join(':')).toString('base64') // old
|
|
377
|
+
key.epub = pub.x+'.'+pub.y; // new
|
|
378
|
+
// ex and ey are already base64
|
|
379
|
+
// epub is UTF8 but filename/URL safe (https://www.ietf.org/rfc/rfc3986.txt)
|
|
380
|
+
// but split on a non-base64 letter.
|
|
381
|
+
return key;
|
|
382
|
+
});
|
|
383
|
+
}catch(e){
|
|
384
|
+
if(SEA.window){ throw e }
|
|
385
|
+
if(e == 'Error: ECDH is not a supported algorithm'){ console.log('Ignoring ECDH...'); }
|
|
386
|
+
else { throw e }
|
|
387
|
+
} dh = dh || {};
|
|
388
|
+
|
|
389
|
+
var r = { pub: sa.pub, priv: sa.priv, /* pubId, */ epub: dh.epub, epriv: dh.epriv };
|
|
390
|
+
if(cb){ try{ cb(r); }catch(e){console.log(e);} }
|
|
391
|
+
return r;
|
|
392
|
+
} catch(e) {
|
|
393
|
+
console.log(e);
|
|
394
|
+
SEA.err = e;
|
|
395
|
+
if(SEA.throw){ throw e }
|
|
396
|
+
if(cb){ cb(); }
|
|
397
|
+
return;
|
|
398
|
+
}});
|
|
399
|
+
|
|
400
|
+
module.exports = SEA.pair;
|
|
401
|
+
})(USE, './pair');
|
|
402
|
+
USE(function(module){
|
|
403
|
+
var SEA = USE('./root');
|
|
404
|
+
var shim = USE('./shim');
|
|
405
|
+
var S = USE('./settings');
|
|
406
|
+
var sha = USE('./sha256');
|
|
407
|
+
var u;
|
|
408
|
+
|
|
409
|
+
SEA.sign = SEA.sign || (async (data, pair, cb, opt) => { try {
|
|
410
|
+
opt = opt || {};
|
|
411
|
+
if(!(pair||opt).priv){
|
|
412
|
+
if(!SEA.I){ throw 'No signing key.' }
|
|
413
|
+
pair = await SEA.I(null, {what: data, how: 'sign', why: opt.why});
|
|
414
|
+
}
|
|
415
|
+
if(u === data){ throw '`undefined` not allowed.' }
|
|
416
|
+
var json = await S.parse(data);
|
|
417
|
+
var check = opt.check = opt.check || json;
|
|
418
|
+
if(SEA.verify && (SEA.opt.check(check) || (check && check.s && check.m))
|
|
419
|
+
&& u !== await SEA.verify(check, pair)){ // don't sign if we already signed it.
|
|
420
|
+
var r = await S.parse(check);
|
|
421
|
+
if(!opt.raw){ r = 'SEA' + await shim.stringify(r); }
|
|
422
|
+
if(cb){ try{ cb(r); }catch(e){console.log(e);} }
|
|
423
|
+
return r;
|
|
424
|
+
}
|
|
425
|
+
var pub = pair.pub;
|
|
426
|
+
var priv = pair.priv;
|
|
427
|
+
var jwk = S.jwk(pub, priv);
|
|
428
|
+
var hash = await sha(json);
|
|
429
|
+
var sig = await (shim.ossl || shim.subtle).importKey('jwk', jwk, {name: 'ECDSA', namedCurve: 'P-256'}, false, ['sign'])
|
|
430
|
+
.then((key) => (shim.ossl || shim.subtle).sign({name: 'ECDSA', hash: {name: 'SHA-256'}}, key, new Uint8Array(hash))); // privateKey scope doesn't leak out from here!
|
|
431
|
+
var r = {m: json, s: shim.Buffer.from(sig, 'binary').toString(opt.encode || 'base64')};
|
|
432
|
+
if(!opt.raw){ r = 'SEA' + await shim.stringify(r); }
|
|
433
|
+
|
|
434
|
+
if(cb){ try{ cb(r); }catch(e){console.log(e);} }
|
|
435
|
+
return r;
|
|
436
|
+
} catch(e) {
|
|
437
|
+
console.log(e);
|
|
438
|
+
SEA.err = e;
|
|
439
|
+
if(SEA.throw){ throw e }
|
|
440
|
+
if(cb){ cb(); }
|
|
441
|
+
return;
|
|
442
|
+
}});
|
|
443
|
+
|
|
444
|
+
module.exports = SEA.sign;
|
|
445
|
+
})(USE, './sign');
|
|
446
|
+
USE(function(module){
|
|
447
|
+
var SEA = USE('./root');
|
|
448
|
+
var shim = USE('./shim');
|
|
449
|
+
var S = USE('./settings');
|
|
450
|
+
var sha = USE('./sha256');
|
|
451
|
+
var u;
|
|
452
|
+
|
|
453
|
+
SEA.verify = SEA.verify || (async (data, pair, cb, opt) => { try {
|
|
454
|
+
var json = await S.parse(data);
|
|
455
|
+
if(false === pair){ // don't verify!
|
|
456
|
+
var raw = await S.parse(json.m);
|
|
457
|
+
if(cb){ try{ cb(raw); }catch(e){console.log(e);} }
|
|
458
|
+
return raw;
|
|
459
|
+
}
|
|
460
|
+
opt = opt || {};
|
|
461
|
+
// SEA.I // verify is free! Requires no user permission.
|
|
462
|
+
var pub = pair.pub || pair;
|
|
463
|
+
var key = SEA.opt.slow_leak? await SEA.opt.slow_leak(pub) : await (shim.ossl || shim.subtle).importKey('jwk', S.jwk(pub), {name: 'ECDSA', namedCurve: 'P-256'}, false, ['verify']);
|
|
464
|
+
var hash = await sha(json.m);
|
|
465
|
+
var buf, sig, check, tmp; try{
|
|
466
|
+
buf = shim.Buffer.from(json.s, opt.encode || 'base64'); // NEW DEFAULT!
|
|
467
|
+
sig = new Uint8Array(buf);
|
|
468
|
+
check = await (shim.ossl || shim.subtle).verify({name: 'ECDSA', hash: {name: 'SHA-256'}}, key, sig, new Uint8Array(hash));
|
|
469
|
+
if(!check){ throw "Signature did not match." }
|
|
470
|
+
}catch(e){
|
|
471
|
+
if(SEA.opt.fallback){
|
|
472
|
+
return await SEA.opt.fall_verify(data, pair, cb, opt);
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
var r = check? await S.parse(json.m) : u;
|
|
476
|
+
|
|
477
|
+
if(cb){ try{ cb(r); }catch(e){console.log(e);} }
|
|
478
|
+
return r;
|
|
479
|
+
} catch(e) {
|
|
480
|
+
console.log(e); // mismatched owner FOR MARTTI
|
|
481
|
+
SEA.err = e;
|
|
482
|
+
if(SEA.throw){ throw e }
|
|
483
|
+
if(cb){ cb(); }
|
|
484
|
+
return;
|
|
485
|
+
}});
|
|
486
|
+
|
|
487
|
+
module.exports = SEA.verify;
|
|
488
|
+
// legacy & ossl memory leak mitigation:
|
|
489
|
+
|
|
490
|
+
var knownKeys = {};
|
|
491
|
+
SEA.opt.slow_leak = pair => {
|
|
492
|
+
if (knownKeys[pair]) return knownKeys[pair];
|
|
493
|
+
var jwk = S.jwk(pair);
|
|
494
|
+
knownKeys[pair] = (shim.ossl || shim.subtle).importKey("jwk", jwk, {name: 'ECDSA', namedCurve: 'P-256'}, false, ["verify"]);
|
|
495
|
+
return knownKeys[pair];
|
|
496
|
+
};
|
|
497
|
+
|
|
498
|
+
var O = SEA.opt;
|
|
499
|
+
SEA.opt.fall_verify = async function(data, pair, cb, opt, f){
|
|
500
|
+
if(f === SEA.opt.fallback){ throw "Signature did not match" } f = f || 1;
|
|
501
|
+
var tmp = data||'';
|
|
502
|
+
data = SEA.opt.unpack(data) || data;
|
|
503
|
+
var json = await S.parse(data), pub = pair.pub || pair, key = await SEA.opt.slow_leak(pub);
|
|
504
|
+
var hash = (f <= SEA.opt.fallback)? shim.Buffer.from(await shim.subtle.digest({name: 'SHA-256'}, new shim.TextEncoder().encode(await S.parse(json.m)))) : await sha(json.m); // this line is old bad buggy code but necessary for old compatibility.
|
|
505
|
+
var buf; var sig; var check; try{
|
|
506
|
+
buf = shim.Buffer.from(json.s, opt.encode || 'base64'); // NEW DEFAULT!
|
|
507
|
+
sig = new Uint8Array(buf);
|
|
508
|
+
check = await (shim.ossl || shim.subtle).verify({name: 'ECDSA', hash: {name: 'SHA-256'}}, key, sig, new Uint8Array(hash));
|
|
509
|
+
if(!check){ throw "Signature did not match." }
|
|
510
|
+
}catch(e){ try{
|
|
511
|
+
buf = shim.Buffer.from(json.s, 'utf8'); // AUTO BACKWARD OLD UTF8 DATA!
|
|
512
|
+
sig = new Uint8Array(buf);
|
|
513
|
+
check = await (shim.ossl || shim.subtle).verify({name: 'ECDSA', hash: {name: 'SHA-256'}}, key, sig, new Uint8Array(hash));
|
|
514
|
+
}catch(e){
|
|
515
|
+
if(!check){ throw "Signature did not match." }
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
var r = check? await S.parse(json.m) : u;
|
|
519
|
+
O.fall_soul = tmp['#']; O.fall_key = tmp['.']; O.fall_val = data; O.fall_state = tmp['>'];
|
|
520
|
+
if(cb){ try{ cb(r); }catch(e){console.log(e);} }
|
|
521
|
+
return r;
|
|
522
|
+
};
|
|
523
|
+
SEA.opt.fallback = 2;
|
|
524
|
+
|
|
525
|
+
})(USE, './verify');
|
|
526
|
+
USE(function(module){
|
|
527
|
+
var shim = USE('./shim');
|
|
528
|
+
var S = USE('./settings');
|
|
529
|
+
var sha256hash = USE('./sha256');
|
|
530
|
+
|
|
531
|
+
const importGen = async (key, salt, opt) => {
|
|
532
|
+
const combo = key + (salt || shim.random(8)).toString('utf8'); // new
|
|
533
|
+
const hash = shim.Buffer.from(await sha256hash(combo), 'binary');
|
|
534
|
+
|
|
535
|
+
const jwkKey = S.keyToJwk(hash);
|
|
536
|
+
return await shim.subtle.importKey('jwk', jwkKey, {name:'AES-GCM'}, false, ['encrypt', 'decrypt'])
|
|
537
|
+
};
|
|
538
|
+
module.exports = importGen;
|
|
539
|
+
})(USE, './aeskey');
|
|
540
|
+
USE(function(module){
|
|
541
|
+
var SEA = USE('./root');
|
|
542
|
+
var shim = USE('./shim');
|
|
543
|
+
USE('./settings');
|
|
544
|
+
var aeskey = USE('./aeskey');
|
|
545
|
+
var u;
|
|
546
|
+
|
|
547
|
+
SEA.encrypt = SEA.encrypt || (async (data, pair, cb, opt) => { try {
|
|
548
|
+
opt = opt || {};
|
|
549
|
+
var key = (pair||opt).epriv || pair;
|
|
550
|
+
if(u === data){ throw '`undefined` not allowed.' }
|
|
551
|
+
if(!key){
|
|
552
|
+
if(!SEA.I){ throw 'No encryption key.' }
|
|
553
|
+
pair = await SEA.I(null, {what: data, how: 'encrypt', why: opt.why});
|
|
554
|
+
key = pair.epriv || pair;
|
|
555
|
+
}
|
|
556
|
+
var msg = (typeof data == 'string')? data : await shim.stringify(data);
|
|
557
|
+
var rand = {s: shim.random(9), iv: shim.random(15)}; // consider making this 9 and 15 or 18 or 12 to reduce == padding.
|
|
558
|
+
var ct = await aeskey(key, rand.s, opt).then((aes) => (/*shim.ossl ||*/ shim.subtle).encrypt({ // Keeping the AES key scope as private as possible...
|
|
559
|
+
name: opt.name || 'AES-GCM', iv: new Uint8Array(rand.iv)
|
|
560
|
+
}, aes, new shim.TextEncoder().encode(msg)));
|
|
561
|
+
var r = {
|
|
562
|
+
ct: shim.Buffer.from(ct, 'binary').toString(opt.encode || 'base64'),
|
|
563
|
+
iv: rand.iv.toString(opt.encode || 'base64'),
|
|
564
|
+
s: rand.s.toString(opt.encode || 'base64')
|
|
565
|
+
};
|
|
566
|
+
if(!opt.raw){ r = 'SEA' + await shim.stringify(r); }
|
|
567
|
+
|
|
568
|
+
if(cb){ try{ cb(r); }catch(e){console.log(e);} }
|
|
569
|
+
return r;
|
|
570
|
+
} catch(e) {
|
|
571
|
+
console.log(e);
|
|
572
|
+
SEA.err = e;
|
|
573
|
+
if(SEA.throw){ throw e }
|
|
574
|
+
if(cb){ cb(); }
|
|
575
|
+
return;
|
|
576
|
+
}});
|
|
577
|
+
|
|
578
|
+
module.exports = SEA.encrypt;
|
|
579
|
+
})(USE, './encrypt');
|
|
580
|
+
USE(function(module){
|
|
581
|
+
var SEA = USE('./root');
|
|
582
|
+
var shim = USE('./shim');
|
|
583
|
+
var S = USE('./settings');
|
|
584
|
+
var aeskey = USE('./aeskey');
|
|
585
|
+
|
|
586
|
+
SEA.decrypt = SEA.decrypt || (async (data, pair, cb, opt) => { try {
|
|
587
|
+
opt = opt || {};
|
|
588
|
+
var key = (pair||opt).epriv || pair;
|
|
589
|
+
if(!key){
|
|
590
|
+
if(!SEA.I){ throw 'No decryption key.' }
|
|
591
|
+
pair = await SEA.I(null, {what: data, how: 'decrypt', why: opt.why});
|
|
592
|
+
key = pair.epriv || pair;
|
|
593
|
+
}
|
|
594
|
+
var json = await S.parse(data);
|
|
595
|
+
var buf, bufiv, bufct; try{
|
|
596
|
+
buf = shim.Buffer.from(json.s, opt.encode || 'base64');
|
|
597
|
+
bufiv = shim.Buffer.from(json.iv, opt.encode || 'base64');
|
|
598
|
+
bufct = shim.Buffer.from(json.ct, opt.encode || 'base64');
|
|
599
|
+
var ct = await aeskey(key, buf, opt).then((aes) => (/*shim.ossl ||*/ shim.subtle).decrypt({ // Keeping aesKey scope as private as possible...
|
|
600
|
+
name: opt.name || 'AES-GCM', iv: new Uint8Array(bufiv), tagLength: 128
|
|
601
|
+
}, aes, new Uint8Array(bufct)));
|
|
602
|
+
}catch(e){
|
|
603
|
+
if('utf8' === opt.encode){ throw "Could not decrypt" }
|
|
604
|
+
if(SEA.opt.fallback){
|
|
605
|
+
opt.encode = 'utf8';
|
|
606
|
+
return await SEA.decrypt(data, pair, cb, opt);
|
|
607
|
+
}
|
|
608
|
+
}
|
|
609
|
+
var r = await S.parse(new shim.TextDecoder('utf8').decode(ct));
|
|
610
|
+
if(cb){ try{ cb(r); }catch(e){console.log(e);} }
|
|
611
|
+
return r;
|
|
612
|
+
} catch(e) {
|
|
613
|
+
console.log(e);
|
|
614
|
+
SEA.err = e;
|
|
615
|
+
if(SEA.throw){ throw e }
|
|
616
|
+
if(cb){ cb(); }
|
|
617
|
+
return;
|
|
618
|
+
}});
|
|
619
|
+
|
|
620
|
+
module.exports = SEA.decrypt;
|
|
621
|
+
})(USE, './decrypt');
|
|
622
|
+
USE(function(module){
|
|
623
|
+
var SEA = USE('./root');
|
|
624
|
+
var shim = USE('./shim');
|
|
625
|
+
USE('./settings');
|
|
626
|
+
// Derive shared secret from other's pub and my epub/epriv
|
|
627
|
+
SEA.secret = SEA.secret || (async (key, pair, cb, opt) => { try {
|
|
628
|
+
opt = opt || {};
|
|
629
|
+
if(!pair || !pair.epriv || !pair.epub){
|
|
630
|
+
if(!SEA.I){ throw 'No secret mix.' }
|
|
631
|
+
pair = await SEA.I(null, {what: key, how: 'secret', why: opt.why});
|
|
632
|
+
}
|
|
633
|
+
var pub = key.epub || key;
|
|
634
|
+
var epub = pair.epub;
|
|
635
|
+
var epriv = pair.epriv;
|
|
636
|
+
var ecdhSubtle = shim.ossl || shim.subtle;
|
|
637
|
+
var pubKeyData = keysToEcdhJwk(pub);
|
|
638
|
+
var props = Object.assign({ public: await ecdhSubtle.importKey(...pubKeyData, true, []) },{name: 'ECDH', namedCurve: 'P-256'}); // Thanks to @sirpy !
|
|
639
|
+
var privKeyData = keysToEcdhJwk(epub, epriv);
|
|
640
|
+
var derived = await ecdhSubtle.importKey(...privKeyData, false, ['deriveBits']).then(async (privKey) => {
|
|
641
|
+
// privateKey scope doesn't leak out from here!
|
|
642
|
+
var derivedBits = await ecdhSubtle.deriveBits(props, privKey, 256);
|
|
643
|
+
var rawBits = new Uint8Array(derivedBits);
|
|
644
|
+
var derivedKey = await ecdhSubtle.importKey('raw', rawBits,{ name: 'AES-GCM', length: 256 }, true, [ 'encrypt', 'decrypt' ]);
|
|
645
|
+
return ecdhSubtle.exportKey('jwk', derivedKey).then(({ k }) => k);
|
|
646
|
+
});
|
|
647
|
+
var r = derived;
|
|
648
|
+
if(cb){ try{ cb(r); }catch(e){console.log(e);} }
|
|
649
|
+
return r;
|
|
650
|
+
} catch(e) {
|
|
651
|
+
console.log(e);
|
|
652
|
+
SEA.err = e;
|
|
653
|
+
if(SEA.throw){ throw e }
|
|
654
|
+
if(cb){ cb(); }
|
|
655
|
+
return;
|
|
656
|
+
}});
|
|
657
|
+
|
|
658
|
+
// can this be replaced with settings.jwk?
|
|
659
|
+
var keysToEcdhJwk = (pub, d) => { // d === priv
|
|
660
|
+
//var [ x, y ] = shim.Buffer.from(pub, 'base64').toString('utf8').split(':') // old
|
|
661
|
+
var [ x, y ] = pub.split('.'); // new
|
|
662
|
+
var jwk = d ? { d: d } : {};
|
|
663
|
+
return [ // Use with spread returned value...
|
|
664
|
+
'jwk',
|
|
665
|
+
Object.assign(
|
|
666
|
+
jwk,
|
|
667
|
+
{ x: x, y: y, kty: 'EC', crv: 'P-256', ext: true }
|
|
668
|
+
), // ??? refactor
|
|
669
|
+
{name: 'ECDH', namedCurve: 'P-256'}
|
|
670
|
+
]
|
|
671
|
+
};
|
|
672
|
+
|
|
673
|
+
module.exports = SEA.secret;
|
|
674
|
+
})(USE, './secret');
|
|
675
|
+
USE(function(module){
|
|
676
|
+
var SEA = USE('./root');
|
|
677
|
+
// This is to certify that a group of "certificants" can "put" anything at a group of matched "paths" to the certificate authority's graph
|
|
678
|
+
SEA.certify = SEA.certify || (async (certificants, policy = {}, authority, cb, opt = {}) => { try {
|
|
679
|
+
/*
|
|
680
|
+
The Certify Protocol was made out of love by a Vietnamese code enthusiast. Vietnamese people around the world deserve respect!
|
|
681
|
+
IMPORTANT: A Certificate is like a Signature. No one knows who (authority) created/signed a cert until you put it into their graph.
|
|
682
|
+
"certificants": '*' or a String (Bob.pub) || an Object that contains "pub" as a key || an array of [object || string]. These people will have the rights.
|
|
683
|
+
"policy": A string ('inbox'), or a RAD/LEX object {'*': 'inbox'}, or an Array of RAD/LEX objects or strings. RAD/LEX object can contain key "?" with indexOf("*") > -1 to force key equals certificant pub. This rule is used to check against soul+'/'+key using Gun.text.match or String.match.
|
|
684
|
+
"authority": Key pair or priv of the certificate authority.
|
|
685
|
+
"cb": A callback function after all things are done.
|
|
686
|
+
"opt": If opt.expiry (a timestamp) is set, SEA won't sync data after opt.expiry. If opt.block is set, SEA will look for block before syncing.
|
|
687
|
+
*/
|
|
688
|
+
console.log('SEA.certify() is an early experimental community supported method that may change API behavior without warning in any future version.');
|
|
689
|
+
|
|
690
|
+
certificants = (() => {
|
|
691
|
+
var data = [];
|
|
692
|
+
if (certificants) {
|
|
693
|
+
if ((typeof certificants === 'string' || Array.isArray(certificants)) && certificants.indexOf('*') > -1) return '*'
|
|
694
|
+
if (typeof certificants === 'string') return certificants
|
|
695
|
+
if (Array.isArray(certificants)) {
|
|
696
|
+
if (certificants.length === 1 && certificants[0]) return typeof certificants[0] === 'object' && certificants[0].pub ? certificants[0].pub : typeof certificants[0] === 'string' ? certificants[0] : null
|
|
697
|
+
certificants.map(certificant => {
|
|
698
|
+
if (typeof certificant ==='string') data.push(certificant);
|
|
699
|
+
else if (typeof certificant === 'object' && certificant.pub) data.push(certificant.pub);
|
|
700
|
+
});
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
if (typeof certificants === 'object' && certificants.pub) return certificants.pub
|
|
704
|
+
return data.length > 0 ? data : null
|
|
705
|
+
}
|
|
706
|
+
return
|
|
707
|
+
})();
|
|
708
|
+
|
|
709
|
+
if (!certificants) return console.log("No certificant found.")
|
|
710
|
+
|
|
711
|
+
const expiry = opt.expiry && (typeof opt.expiry === 'number' || typeof opt.expiry === 'string') ? parseFloat(opt.expiry) : null;
|
|
712
|
+
const readPolicy = (policy || {}).read ? policy.read : null;
|
|
713
|
+
const writePolicy = (policy || {}).write ? policy.write : typeof policy === 'string' || Array.isArray(policy) || policy["+"] || policy["#"] || policy["."] || policy["="] || policy["*"] || policy[">"] || policy["<"] ? policy : null;
|
|
714
|
+
// The "blacklist" feature is now renamed to "block". Why ? BECAUSE BLACK LIVES MATTER!
|
|
715
|
+
// We can now use 3 keys: block, blacklist, ban
|
|
716
|
+
const block = (opt || {}).block || (opt || {}).blacklist || (opt || {}).ban || {};
|
|
717
|
+
const readBlock = block.read && (typeof block.read === 'string' || (block.read || {})['#']) ? block.read : null;
|
|
718
|
+
const writeBlock = typeof block === 'string' ? block : block.write && (typeof block.write === 'string' || block.write['#']) ? block.write : null;
|
|
719
|
+
|
|
720
|
+
if (!readPolicy && !writePolicy) return console.log("No policy found.")
|
|
721
|
+
|
|
722
|
+
// reserved keys: c, e, r, w, rb, wb
|
|
723
|
+
const data = JSON.stringify({
|
|
724
|
+
c: certificants,
|
|
725
|
+
...(expiry ? {e: expiry} : {}), // inject expiry if possible
|
|
726
|
+
...(readPolicy ? {r: readPolicy } : {}), // "r" stands for read, which means read permission.
|
|
727
|
+
...(writePolicy ? {w: writePolicy} : {}), // "w" stands for write, which means write permission.
|
|
728
|
+
...(readBlock ? {rb: readBlock} : {}), // inject READ block if possible
|
|
729
|
+
...(writeBlock ? {wb: writeBlock} : {}), // inject WRITE block if possible
|
|
730
|
+
});
|
|
731
|
+
|
|
732
|
+
const certificate = await SEA.sign(data, authority, null, {raw:1});
|
|
733
|
+
|
|
734
|
+
var r = certificate;
|
|
735
|
+
if(!opt.raw){ r = 'SEA'+JSON.stringify(r); }
|
|
736
|
+
if(cb){ try{ cb(r); }catch(e){console.log(e);} }
|
|
737
|
+
return r;
|
|
738
|
+
} catch(e) {
|
|
739
|
+
SEA.err = e;
|
|
740
|
+
if(SEA.throw){ throw e }
|
|
741
|
+
if(cb){ cb(); }
|
|
742
|
+
return;
|
|
743
|
+
}});
|
|
744
|
+
|
|
745
|
+
module.exports = SEA.certify;
|
|
746
|
+
})(USE, './certify');
|
|
747
|
+
USE(function(module){
|
|
748
|
+
var shim = USE('./shim');
|
|
749
|
+
// Practical examples about usage found in tests.
|
|
750
|
+
var SEA = USE('./root');
|
|
751
|
+
SEA.work = USE('./work');
|
|
752
|
+
SEA.sign = USE('./sign');
|
|
753
|
+
SEA.verify = USE('./verify');
|
|
754
|
+
SEA.encrypt = USE('./encrypt');
|
|
755
|
+
SEA.decrypt = USE('./decrypt');
|
|
756
|
+
SEA.certify = USE('./certify');
|
|
757
|
+
//SEA.opt.aeskey = USE('./aeskey'); // not official! // this causes problems in latest WebCrypto.
|
|
758
|
+
|
|
759
|
+
SEA.random = SEA.random || shim.random;
|
|
760
|
+
|
|
761
|
+
// This is Buffer used in SEA and usable from Gun/SEA application also.
|
|
762
|
+
// For documentation see https://nodejs.org/api/buffer.html
|
|
763
|
+
SEA.Buffer = SEA.Buffer || USE('./buffer');
|
|
764
|
+
|
|
765
|
+
// These SEA functions support now ony Promises or
|
|
766
|
+
// async/await (compatible) code, use those like Promises.
|
|
767
|
+
//
|
|
768
|
+
// Creates a wrapper library around Web Crypto API
|
|
769
|
+
// for various AES, ECDSA, PBKDF2 functions we called above.
|
|
770
|
+
// Calculate public key KeyID aka PGPv4 (result: 8 bytes as hex string)
|
|
771
|
+
SEA.keyid = SEA.keyid || (async (pub) => {
|
|
772
|
+
try {
|
|
773
|
+
// base64('base64(x):base64(y)') => shim.Buffer(xy)
|
|
774
|
+
const pb = shim.Buffer.concat(
|
|
775
|
+
pub.replace(/-/g, '+').replace(/_/g, '/').split('.')
|
|
776
|
+
.map((t) => shim.Buffer.from(t, 'base64'))
|
|
777
|
+
);
|
|
778
|
+
// id is PGPv4 compliant raw key
|
|
779
|
+
const id = shim.Buffer.concat([
|
|
780
|
+
shim.Buffer.from([0x99, pb.length / 0x100, pb.length % 0x100]), pb
|
|
781
|
+
]);
|
|
782
|
+
const sha1 = await sha1hash(id);
|
|
783
|
+
const hash = shim.Buffer.from(sha1, 'binary');
|
|
784
|
+
return hash.toString('hex', hash.length - 8) // 16-bit ID as hex
|
|
785
|
+
} catch (e) {
|
|
786
|
+
console.log(e);
|
|
787
|
+
throw e
|
|
788
|
+
}
|
|
789
|
+
});
|
|
790
|
+
// all done!
|
|
791
|
+
// Obviously it is missing MANY necessary features. This is only an alpha release.
|
|
792
|
+
// Please experiment with it, audit what I've done so far, and complain about what needs to be added.
|
|
793
|
+
// SEA should be a full suite that is easy and seamless to use.
|
|
794
|
+
// Again, scroll naer the top, where I provide an EXAMPLE of how to create a user and sign in.
|
|
795
|
+
// Once logged in, the rest of the code you just read handled automatically signing/validating data.
|
|
796
|
+
// But all other behavior needs to be equally easy, like opinionated ways of
|
|
797
|
+
// Adding friends (trusted public keys), sending private messages, etc.
|
|
798
|
+
// Cheers! Tell me what you think.
|
|
799
|
+
((SEA.window||{}).GUN||{}).SEA = SEA;
|
|
800
|
+
|
|
801
|
+
module.exports = SEA;
|
|
802
|
+
// -------------- END SEA MODULES --------------------
|
|
803
|
+
// -- BEGIN SEA+GUN MODULES: BUNDLED BY DEFAULT UNTIL OTHERS USE SEA ON OWN -------
|
|
804
|
+
})(USE, './sea');
|
|
805
|
+
USE(function(module){
|
|
806
|
+
var SEA = USE('./sea'), Gun, u;
|
|
807
|
+
if(SEA.window){
|
|
808
|
+
Gun = SEA.window.GUN || {chain:{}};
|
|
809
|
+
} else {
|
|
810
|
+
Gun = USE((u+'' == typeof MODULE?'.':'')+'./gun', 1);
|
|
811
|
+
}
|
|
812
|
+
SEA.GUN = Gun;
|
|
813
|
+
|
|
814
|
+
function User(root){
|
|
815
|
+
this._ = {$: this};
|
|
816
|
+
}
|
|
817
|
+
User.prototype = (function(){ function F(){} F.prototype = Gun.chain; return new F() }()); // Object.create polyfill
|
|
818
|
+
User.prototype.constructor = User;
|
|
819
|
+
|
|
820
|
+
// let's extend the gun chain with a `user` function.
|
|
821
|
+
// only one user can be logged in at a time, per gun instance.
|
|
822
|
+
Gun.chain.user = function(pub){
|
|
823
|
+
var gun = this, root = gun.back(-1), user;
|
|
824
|
+
if(pub){
|
|
825
|
+
pub = SEA.opt.pub((pub._||'')['#']) || pub;
|
|
826
|
+
return root.get('~'+pub);
|
|
827
|
+
}
|
|
828
|
+
if(user = root.back('user')){ return user }
|
|
829
|
+
var root = (root._), at = root, uuid = at.opt.uuid || lex;
|
|
830
|
+
(at = (user = at.user = gun.chain(new User))._).opt = {};
|
|
831
|
+
at.opt.uuid = function(cb){
|
|
832
|
+
var id = uuid(), pub = root.user;
|
|
833
|
+
if(!pub || !(pub = pub.is) || !(pub = pub.pub)){ return id }
|
|
834
|
+
id = '~' + pub + '/' + id;
|
|
835
|
+
if(cb && cb.call){ cb(null, id); }
|
|
836
|
+
return id;
|
|
837
|
+
};
|
|
838
|
+
return user;
|
|
839
|
+
};
|
|
840
|
+
function lex(){ return Gun.state().toString(36).replace('.','') }
|
|
841
|
+
Gun.User = User;
|
|
842
|
+
User.GUN = Gun;
|
|
843
|
+
User.SEA = Gun.SEA = SEA;
|
|
844
|
+
module.exports = User;
|
|
845
|
+
})(USE, './user');
|
|
846
|
+
USE(function(module){
|
|
847
|
+
var u, Gun = (''+u != typeof GUN)? (GUN||{chain:{}}) : USE((''+u === typeof MODULE?'.':'')+'./gun', 1);
|
|
848
|
+
Gun.chain.then = function(cb, opt){
|
|
849
|
+
var gun = this, p = (new Promise(function(res, rej){
|
|
850
|
+
gun.once(res, opt);
|
|
851
|
+
}));
|
|
852
|
+
return cb? p.then(cb) : p;
|
|
853
|
+
};
|
|
854
|
+
})(USE, './then');
|
|
855
|
+
USE(function(module){
|
|
856
|
+
var User = USE('./user'), SEA = User.SEA, Gun = User.GUN, noop = function(){};
|
|
857
|
+
|
|
858
|
+
// Well first we have to actually create a user. That is what this function does.
|
|
859
|
+
User.prototype.create = function(...args){
|
|
860
|
+
var pair = typeof args[0] === 'object' && (args[0].pub || args[0].epub) ? args[0] : typeof args[1] === 'object' && (args[1].pub || args[1].epub) ? args[1] : null;
|
|
861
|
+
var alias = pair && (pair.pub || pair.epub) ? pair.pub : typeof args[0] === 'string' ? args[0] : null;
|
|
862
|
+
var pass = pair && (pair.pub || pair.epub) ? pair : alias && typeof args[1] === 'string' ? args[1] : null;
|
|
863
|
+
var cb = args.filter(arg => typeof arg === 'function')[0] || null; // cb now can stand anywhere, after alias/pass or pair
|
|
864
|
+
var opt = args && args.length > 1 && typeof args[args.length-1] === 'object' ? args[args.length-1] : {}; // opt is always the last parameter which typeof === 'object' and stands after cb
|
|
865
|
+
|
|
866
|
+
var gun = this, cat = (gun._), root = gun.back(-1);
|
|
867
|
+
cb = cb || noop;
|
|
868
|
+
opt = opt || {};
|
|
869
|
+
if(false !== opt.check){
|
|
870
|
+
var err;
|
|
871
|
+
if(!alias){ err = "No user."; }
|
|
872
|
+
if((pass||'').length < 8){ err = "Password too short!"; }
|
|
873
|
+
if(err){
|
|
874
|
+
cb({err: Gun.log(err)});
|
|
875
|
+
return gun;
|
|
876
|
+
}
|
|
877
|
+
}
|
|
878
|
+
if(cat.ing){
|
|
879
|
+
(cb || noop)({err: Gun.log("User is already being created or authenticated!"), wait: true});
|
|
880
|
+
return gun;
|
|
881
|
+
}
|
|
882
|
+
cat.ing = true;
|
|
883
|
+
var act = {};
|
|
884
|
+
act.a = function(pubs){
|
|
885
|
+
act.pubs = pubs;
|
|
886
|
+
if(pubs && !opt.already){
|
|
887
|
+
// If we can enforce that a user name is already taken, it might be nice to try, but this is not guaranteed.
|
|
888
|
+
var ack = {err: Gun.log('User already created!')};
|
|
889
|
+
cat.ing = false;
|
|
890
|
+
(cb || noop)(ack);
|
|
891
|
+
gun.leave();
|
|
892
|
+
return;
|
|
893
|
+
}
|
|
894
|
+
act.salt = String.random(64); // pseudo-randomly create a salt, then use PBKDF2 function to extend the password with it.
|
|
895
|
+
SEA.work(pass, act.salt, act.b); // this will take some short amount of time to produce a proof, which slows brute force attacks.
|
|
896
|
+
};
|
|
897
|
+
act.b = function(proof){
|
|
898
|
+
act.proof = proof;
|
|
899
|
+
pair ? act.c(pair) : SEA.pair(act.c); // generate a brand new key pair or use the existing.
|
|
900
|
+
};
|
|
901
|
+
act.c = function(pair){
|
|
902
|
+
var tmp;
|
|
903
|
+
act.pair = pair || {};
|
|
904
|
+
if(tmp = cat.root.user){
|
|
905
|
+
tmp._.sea = pair;
|
|
906
|
+
tmp.is = {pub: pair.pub, epub: pair.epub, alias: alias};
|
|
907
|
+
}
|
|
908
|
+
// the user's public key doesn't need to be signed. But everything else needs to be signed with it! // we have now automated it! clean up these extra steps now!
|
|
909
|
+
act.data = {pub: pair.pub};
|
|
910
|
+
act.d();
|
|
911
|
+
};
|
|
912
|
+
act.d = function(){
|
|
913
|
+
act.data.alias = alias;
|
|
914
|
+
act.e();
|
|
915
|
+
};
|
|
916
|
+
act.e = function(){
|
|
917
|
+
act.data.epub = act.pair.epub;
|
|
918
|
+
SEA.encrypt({priv: act.pair.priv, epriv: act.pair.epriv}, act.proof, act.f, {raw:1}); // to keep the private key safe, we AES encrypt it with the proof of work!
|
|
919
|
+
};
|
|
920
|
+
act.f = function(auth){
|
|
921
|
+
act.data.auth = JSON.stringify({ek: auth, s: act.salt});
|
|
922
|
+
act.g(act.data.auth);
|
|
923
|
+
};
|
|
924
|
+
act.g = function(auth){ var tmp;
|
|
925
|
+
act.data.auth = act.data.auth || auth;
|
|
926
|
+
root.get(tmp = '~'+act.pair.pub).put(act.data).on(act.h); // awesome, now we can actually save the user with their public key as their ID.
|
|
927
|
+
var link = {}; link[tmp] = {'#': tmp}; root.get('~@'+alias).put(link).get(tmp).on(act.i); // next up, we want to associate the alias with the public key. So we add it to the alias list.
|
|
928
|
+
};
|
|
929
|
+
act.h = function(data, key, msg, eve){
|
|
930
|
+
eve.off(); act.h.ok = 1; act.i();
|
|
931
|
+
};
|
|
932
|
+
act.i = function(data, key, msg, eve){
|
|
933
|
+
if(eve){ act.i.ok = 1; eve.off(); }
|
|
934
|
+
if(!act.h.ok || !act.i.ok){ return }
|
|
935
|
+
cat.ing = false;
|
|
936
|
+
cb({ok: 0, pub: act.pair.pub}); // callback that the user has been created. (Note: ok = 0 because we didn't wait for disk to ack)
|
|
937
|
+
if(noop === cb){ pair ? gun.auth(pair) : gun.auth(alias, pass); } // if no callback is passed, auto-login after signing up.
|
|
938
|
+
};
|
|
939
|
+
root.get('~@'+alias).once(act.a);
|
|
940
|
+
return gun;
|
|
941
|
+
};
|
|
942
|
+
User.prototype.leave = function(opt, cb){
|
|
943
|
+
var gun = this, user = (gun.back(-1)._).user;
|
|
944
|
+
if(user){
|
|
945
|
+
delete user.is;
|
|
946
|
+
delete user._.is;
|
|
947
|
+
delete user._.sea;
|
|
948
|
+
}
|
|
949
|
+
if(SEA.window){
|
|
950
|
+
try{var sS = {};
|
|
951
|
+
sS = SEA.window.sessionStorage;
|
|
952
|
+
delete sS.recall;
|
|
953
|
+
delete sS.pair;
|
|
954
|
+
}catch(e){} }
|
|
955
|
+
return gun;
|
|
956
|
+
};
|
|
957
|
+
})(USE, './create');
|
|
958
|
+
USE(function(module){
|
|
959
|
+
var User = USE('./user'), SEA = User.SEA, Gun = User.GUN, noop = function(){};
|
|
960
|
+
// now that we have created a user, we want to authenticate them!
|
|
961
|
+
User.prototype.auth = function(...args){ // TODO: this PR with arguments need to be cleaned up / refactored.
|
|
962
|
+
var pair = typeof args[0] === 'object' && (args[0].pub || args[0].epub) ? args[0] : typeof args[1] === 'object' && (args[1].pub || args[1].epub) ? args[1] : null;
|
|
963
|
+
var alias = !pair && typeof args[0] === 'string' ? args[0] : null;
|
|
964
|
+
var pass = (alias || (pair && !(pair.priv && pair.epriv))) && typeof args[1] === 'string' ? args[1] : null;
|
|
965
|
+
var cb = args.filter(arg => typeof arg === 'function')[0] || null; // cb now can stand anywhere, after alias/pass or pair
|
|
966
|
+
var opt = args && args.length > 1 && typeof args[args.length-1] === 'object' ? args[args.length-1] : {}; // opt is always the last parameter which typeof === 'object' and stands after cb
|
|
967
|
+
|
|
968
|
+
var gun = this, cat = (gun._), root = gun.back(-1);
|
|
969
|
+
|
|
970
|
+
if(cat.ing){
|
|
971
|
+
(cb || noop)({err: Gun.log("User is already being created or authenticated!"), wait: true});
|
|
972
|
+
return gun;
|
|
973
|
+
}
|
|
974
|
+
cat.ing = true;
|
|
975
|
+
|
|
976
|
+
var act = {}, u, tries = 9;
|
|
977
|
+
act.a = function(data){
|
|
978
|
+
if(!data){ return act.b() }
|
|
979
|
+
if(!data.pub){
|
|
980
|
+
var tmp = []; Object.keys(data).forEach(function(k){ if('_'==k){ return } tmp.push(data[k]); });
|
|
981
|
+
return act.b(tmp);
|
|
982
|
+
}
|
|
983
|
+
if(act.name){ return act.f(data) }
|
|
984
|
+
act.c((act.data = data).auth);
|
|
985
|
+
};
|
|
986
|
+
act.b = function(list){
|
|
987
|
+
var get = (act.list = (act.list||[]).concat(list||[])).shift();
|
|
988
|
+
if(u === get){
|
|
989
|
+
if(act.name){ return act.err('Your user account is not published for dApps to access, please consider syncing it online, or allowing local access by adding your device as a peer.') }
|
|
990
|
+
if(alias && tries--){
|
|
991
|
+
root.get('~@'+alias).once(act.a);
|
|
992
|
+
return;
|
|
993
|
+
}
|
|
994
|
+
return act.err('Wrong user or password.')
|
|
995
|
+
}
|
|
996
|
+
root.get(get).once(act.a);
|
|
997
|
+
};
|
|
998
|
+
act.c = function(auth){
|
|
999
|
+
if(u === auth){ return act.b() }
|
|
1000
|
+
if('string' == typeof auth){ return act.c(obj_ify(auth)) } // in case of legacy
|
|
1001
|
+
SEA.work(pass, (act.auth = auth).s, act.d, act.enc); // the proof of work is evidence that we've spent some time/effort trying to log in, this slows brute force.
|
|
1002
|
+
};
|
|
1003
|
+
act.d = function(proof){
|
|
1004
|
+
SEA.decrypt(act.auth.ek, proof, act.e, act.enc);
|
|
1005
|
+
};
|
|
1006
|
+
act.e = function(half){
|
|
1007
|
+
if(u === half){
|
|
1008
|
+
if(!act.enc){ // try old format
|
|
1009
|
+
act.enc = {encode: 'utf8'};
|
|
1010
|
+
return act.c(act.auth);
|
|
1011
|
+
} act.enc = null; // end backwards
|
|
1012
|
+
return act.b();
|
|
1013
|
+
}
|
|
1014
|
+
act.half = half;
|
|
1015
|
+
act.f(act.data);
|
|
1016
|
+
};
|
|
1017
|
+
act.f = function(pair){
|
|
1018
|
+
var half = act.half || {}, data = act.data || {};
|
|
1019
|
+
act.g(act.lol = {pub: pair.pub || data.pub, epub: pair.epub || data.epub, priv: pair.priv || half.priv, epriv: pair.epriv || half.epriv});
|
|
1020
|
+
};
|
|
1021
|
+
act.g = function(pair){
|
|
1022
|
+
if(!pair || !pair.pub || !pair.epub){ return act.b() }
|
|
1023
|
+
act.pair = pair;
|
|
1024
|
+
var user = (root._).user, at = (user._);
|
|
1025
|
+
at.tag;
|
|
1026
|
+
var upt = at.opt;
|
|
1027
|
+
at = user._ = root.get('~'+pair.pub)._;
|
|
1028
|
+
at.opt = upt;
|
|
1029
|
+
// add our credentials in-memory only to our root user instance
|
|
1030
|
+
user.is = {pub: pair.pub, epub: pair.epub, alias: alias || pair.pub};
|
|
1031
|
+
at.sea = act.pair;
|
|
1032
|
+
cat.ing = false;
|
|
1033
|
+
try{if(pass && u == (obj_ify(cat.root.graph['~'+pair.pub].auth)||'')[':']){ opt.shuffle = opt.change = pass; } }catch(e){} // migrate UTF8 & Shuffle!
|
|
1034
|
+
opt.change? act.z() : (cb || noop)(at);
|
|
1035
|
+
if(SEA.window && ((gun.back('user')._).opt||opt).remember){
|
|
1036
|
+
// TODO: this needs to be modular.
|
|
1037
|
+
try{var sS = {};
|
|
1038
|
+
sS = SEA.window.sessionStorage; // TODO: FIX BUG putting on `.is`!
|
|
1039
|
+
sS.recall = true;
|
|
1040
|
+
sS.pair = JSON.stringify(pair); // auth using pair is more reliable than alias/pass
|
|
1041
|
+
}catch(e){}
|
|
1042
|
+
}
|
|
1043
|
+
try{
|
|
1044
|
+
if(root._.tag.auth){ // auth handle might not be registered yet
|
|
1045
|
+
(root._).on('auth', at); // TODO: Deprecate this, emit on user instead! Update docs when you do.
|
|
1046
|
+
} else { setTimeout(function(){ (root._).on('auth', at); },1); } // if not, hackily add a timeout.
|
|
1047
|
+
//at.on('auth', at) // Arrgh, this doesn't work without event "merge" code, but "merge" code causes stack overflow and crashes after logging in & trying to write data.
|
|
1048
|
+
}catch(e){
|
|
1049
|
+
Gun.log("Your 'auth' callback crashed with:", e);
|
|
1050
|
+
}
|
|
1051
|
+
};
|
|
1052
|
+
act.h = function(data){
|
|
1053
|
+
if(!data){ return act.b() }
|
|
1054
|
+
alias = data.alias;
|
|
1055
|
+
if(!alias)
|
|
1056
|
+
alias = data.alias = "~" + pair.pub;
|
|
1057
|
+
if(!data.auth){
|
|
1058
|
+
return act.g(pair);
|
|
1059
|
+
}
|
|
1060
|
+
pair = null;
|
|
1061
|
+
act.c((act.data = data).auth);
|
|
1062
|
+
};
|
|
1063
|
+
act.z = function(){
|
|
1064
|
+
// password update so encrypt private key using new pwd + salt
|
|
1065
|
+
act.salt = String.random(64); // pseudo-random
|
|
1066
|
+
SEA.work(opt.change, act.salt, act.y);
|
|
1067
|
+
};
|
|
1068
|
+
act.y = function(proof){
|
|
1069
|
+
SEA.encrypt({priv: act.pair.priv, epriv: act.pair.epriv}, proof, act.x, {raw:1});
|
|
1070
|
+
};
|
|
1071
|
+
act.x = function(auth){
|
|
1072
|
+
act.w(JSON.stringify({ek: auth, s: act.salt}));
|
|
1073
|
+
};
|
|
1074
|
+
act.w = function(auth){
|
|
1075
|
+
if(opt.shuffle){ // delete in future!
|
|
1076
|
+
console.log('migrate core account from UTF8 & shuffle');
|
|
1077
|
+
var tmp = {}; Object.keys(act.data).forEach(function(k){ tmp[k] = act.data[k]; });
|
|
1078
|
+
delete tmp._;
|
|
1079
|
+
tmp.auth = auth;
|
|
1080
|
+
root.get('~'+act.pair.pub).put(tmp);
|
|
1081
|
+
} // end delete
|
|
1082
|
+
root.get('~'+act.pair.pub).get('auth').put(auth, cb || noop);
|
|
1083
|
+
};
|
|
1084
|
+
act.err = function(e){
|
|
1085
|
+
var ack = {err: Gun.log(e || 'User cannot be found!')};
|
|
1086
|
+
cat.ing = false;
|
|
1087
|
+
(cb || noop)(ack);
|
|
1088
|
+
};
|
|
1089
|
+
act.plugin = function(name){
|
|
1090
|
+
if(!(act.name = name)){ return act.err() }
|
|
1091
|
+
var tmp = [name];
|
|
1092
|
+
if('~' !== name[0]){
|
|
1093
|
+
tmp[1] = '~'+name;
|
|
1094
|
+
tmp[2] = '~@'+name;
|
|
1095
|
+
}
|
|
1096
|
+
act.b(tmp);
|
|
1097
|
+
};
|
|
1098
|
+
if(pair){
|
|
1099
|
+
if(pair.priv && pair.epriv)
|
|
1100
|
+
act.g(pair);
|
|
1101
|
+
else
|
|
1102
|
+
root.get('~'+pair.pub).once(act.h);
|
|
1103
|
+
} else
|
|
1104
|
+
if(alias){
|
|
1105
|
+
root.get('~@'+alias).once(act.a);
|
|
1106
|
+
} else
|
|
1107
|
+
if(!alias && !pass){
|
|
1108
|
+
SEA.name(act.plugin);
|
|
1109
|
+
}
|
|
1110
|
+
return gun;
|
|
1111
|
+
};
|
|
1112
|
+
function obj_ify(o){
|
|
1113
|
+
if('string' != typeof o){ return o }
|
|
1114
|
+
try{o = JSON.parse(o);
|
|
1115
|
+
}catch(e){o={};} return o;
|
|
1116
|
+
}
|
|
1117
|
+
})(USE, './auth');
|
|
1118
|
+
USE(function(module){
|
|
1119
|
+
var User = USE('./user'), SEA = User.SEA; User.GUN;
|
|
1120
|
+
User.prototype.recall = function(opt, cb){
|
|
1121
|
+
var gun = this, root = gun.back(-1);
|
|
1122
|
+
opt = opt || {};
|
|
1123
|
+
if(opt && opt.sessionStorage){
|
|
1124
|
+
if(SEA.window){
|
|
1125
|
+
try{
|
|
1126
|
+
var sS = {};
|
|
1127
|
+
sS = SEA.window.sessionStorage; // TODO: FIX BUG putting on `.is`!
|
|
1128
|
+
if(sS){
|
|
1129
|
+
(root._).opt.remember = true;
|
|
1130
|
+
((gun.back('user')._).opt||opt).remember = true;
|
|
1131
|
+
if(sS.recall || sS.pair) root.user().auth(JSON.parse(sS.pair), cb); // pair is more reliable than alias/pass
|
|
1132
|
+
}
|
|
1133
|
+
}catch(e){}
|
|
1134
|
+
}
|
|
1135
|
+
return gun;
|
|
1136
|
+
}
|
|
1137
|
+
/*
|
|
1138
|
+
TODO: copy mhelander's expiry code back in.
|
|
1139
|
+
Although, we should check with community,
|
|
1140
|
+
should expiry be core or a plugin?
|
|
1141
|
+
*/
|
|
1142
|
+
return gun;
|
|
1143
|
+
};
|
|
1144
|
+
})(USE, './recall');
|
|
1145
|
+
USE(function(module){
|
|
1146
|
+
var User = USE('./user'), SEA = User.SEA, Gun = User.GUN, noop = function(){};
|
|
1147
|
+
User.prototype.pair = function(){
|
|
1148
|
+
var user = this, proxy; // undeprecated, hiding with proxies.
|
|
1149
|
+
try{ proxy = new Proxy({DANGER:'\u2620'}, {get: function(t,p,r){
|
|
1150
|
+
if(!user.is || !(user._||'').sea){ return }
|
|
1151
|
+
return user._.sea[p];
|
|
1152
|
+
}});}catch(e){}
|
|
1153
|
+
return proxy;
|
|
1154
|
+
};
|
|
1155
|
+
// If authenticated user wants to delete his/her account, let's support it!
|
|
1156
|
+
User.prototype.delete = async function(alias, pass, cb){
|
|
1157
|
+
console.log("user.delete() IS DEPRECATED AND WILL BE MOVED TO A MODULE!!!");
|
|
1158
|
+
var gun = this; gun.back(-1); var user = gun.back('user');
|
|
1159
|
+
try {
|
|
1160
|
+
user.auth(alias, pass, function(ack){
|
|
1161
|
+
var pub = (user.is||{}).pub;
|
|
1162
|
+
// Delete user data
|
|
1163
|
+
user.map().once(function(){ this.put(null); });
|
|
1164
|
+
// Wipe user data from memory
|
|
1165
|
+
user.leave();
|
|
1166
|
+
(cb || noop)({ok: 0});
|
|
1167
|
+
});
|
|
1168
|
+
} catch (e) {
|
|
1169
|
+
Gun.log('User.delete failed! Error:', e);
|
|
1170
|
+
}
|
|
1171
|
+
return gun;
|
|
1172
|
+
};
|
|
1173
|
+
User.prototype.alive = async function(){
|
|
1174
|
+
console.log("user.alive() IS DEPRECATED!!!");
|
|
1175
|
+
const gunRoot = this.back(-1);
|
|
1176
|
+
try {
|
|
1177
|
+
// All is good. Should we do something more with actual recalled data?
|
|
1178
|
+
await authRecall(gunRoot);
|
|
1179
|
+
return gunRoot._.user._
|
|
1180
|
+
} catch (e) {
|
|
1181
|
+
const err = 'No session!';
|
|
1182
|
+
Gun.log(err);
|
|
1183
|
+
throw { err }
|
|
1184
|
+
}
|
|
1185
|
+
};
|
|
1186
|
+
User.prototype.trust = async function(user){
|
|
1187
|
+
console.log("`.trust` API MAY BE DELETED OR CHANGED OR RENAMED, DO NOT USE!");
|
|
1188
|
+
// TODO: BUG!!! SEA `node` read listener needs to be async, which means core needs to be async too.
|
|
1189
|
+
//gun.get('alice').get('age').trust(bob);
|
|
1190
|
+
if (Gun.is(user)) {
|
|
1191
|
+
user.get('pub').get((ctx, ev) => {
|
|
1192
|
+
console.log(ctx, ev);
|
|
1193
|
+
});
|
|
1194
|
+
}
|
|
1195
|
+
user.get('trust').get(path).put(theirPubkey);
|
|
1196
|
+
|
|
1197
|
+
// do a lookup on this gun chain directly (that gets bob's copy of the data)
|
|
1198
|
+
// do a lookup on the metadata trust table for this path (that gets all the pubkeys allowed to write on this path)
|
|
1199
|
+
// do a lookup on each of those pubKeys ON the path (to get the collab data "layers")
|
|
1200
|
+
// THEN you perform Jachen's mix operation
|
|
1201
|
+
// and return the result of that to...
|
|
1202
|
+
};
|
|
1203
|
+
User.prototype.grant = function(to, cb){
|
|
1204
|
+
console.log("`.grant` API MAY BE DELETED OR CHANGED OR RENAMED, DO NOT USE!");
|
|
1205
|
+
var gun = this, user = gun.back(-1).user(), pair = user._.sea, path = '';
|
|
1206
|
+
gun.back(function(at){ if(at.is){ return } path += (at.get||''); });
|
|
1207
|
+
(async function(){
|
|
1208
|
+
var enc, sec = await user.get('grant').get(pair.pub).get(path).then();
|
|
1209
|
+
sec = await SEA.decrypt(sec, pair);
|
|
1210
|
+
if(!sec){
|
|
1211
|
+
sec = SEA.random(16).toString();
|
|
1212
|
+
enc = await SEA.encrypt(sec, pair);
|
|
1213
|
+
user.get('grant').get(pair.pub).get(path).put(enc);
|
|
1214
|
+
}
|
|
1215
|
+
var pub = to.get('pub').then();
|
|
1216
|
+
var epub = to.get('epub').then();
|
|
1217
|
+
pub = await pub; epub = await epub;
|
|
1218
|
+
var dh = await SEA.secret(epub, pair);
|
|
1219
|
+
enc = await SEA.encrypt(sec, dh);
|
|
1220
|
+
user.get('grant').get(pub).get(path).put(enc, cb);
|
|
1221
|
+
}());
|
|
1222
|
+
return gun;
|
|
1223
|
+
};
|
|
1224
|
+
User.prototype.secret = function(data, cb){
|
|
1225
|
+
console.log("`.secret` API MAY BE DELETED OR CHANGED OR RENAMED, DO NOT USE!");
|
|
1226
|
+
var gun = this, user = gun.back(-1).user(), pair = user.pair(), path = '';
|
|
1227
|
+
gun.back(function(at){ if(at.is){ return } path += (at.get||''); });
|
|
1228
|
+
(async function(){
|
|
1229
|
+
var enc, sec = await user.get('trust').get(pair.pub).get(path).then();
|
|
1230
|
+
sec = await SEA.decrypt(sec, pair);
|
|
1231
|
+
if(!sec){
|
|
1232
|
+
sec = SEA.random(16).toString();
|
|
1233
|
+
enc = await SEA.encrypt(sec, pair);
|
|
1234
|
+
user.get('trust').get(pair.pub).get(path).put(enc);
|
|
1235
|
+
}
|
|
1236
|
+
enc = await SEA.encrypt(data, sec);
|
|
1237
|
+
gun.put(enc, cb);
|
|
1238
|
+
}());
|
|
1239
|
+
return gun;
|
|
1240
|
+
};
|
|
1241
|
+
|
|
1242
|
+
/**
|
|
1243
|
+
* returns the decrypted value, encrypted by secret
|
|
1244
|
+
* @returns {Promise<any>}
|
|
1245
|
+
// Mark needs to review 1st before officially supported
|
|
1246
|
+
User.prototype.decrypt = function(cb) {
|
|
1247
|
+
let gun = this,
|
|
1248
|
+
path = ''
|
|
1249
|
+
gun.back(function(at) {
|
|
1250
|
+
if (at.is) {
|
|
1251
|
+
return
|
|
1252
|
+
}
|
|
1253
|
+
path += at.get || ''
|
|
1254
|
+
})
|
|
1255
|
+
return gun
|
|
1256
|
+
.then(async data => {
|
|
1257
|
+
if (data == null) {
|
|
1258
|
+
return
|
|
1259
|
+
}
|
|
1260
|
+
const user = gun.back(-1).user()
|
|
1261
|
+
const pair = user.pair()
|
|
1262
|
+
let sec = await user
|
|
1263
|
+
.get('trust')
|
|
1264
|
+
.get(pair.pub)
|
|
1265
|
+
.get(path)
|
|
1266
|
+
sec = await SEA.decrypt(sec, pair)
|
|
1267
|
+
if (!sec) {
|
|
1268
|
+
return data
|
|
1269
|
+
}
|
|
1270
|
+
let decrypted = await SEA.decrypt(data, sec)
|
|
1271
|
+
return decrypted
|
|
1272
|
+
})
|
|
1273
|
+
.then(res => {
|
|
1274
|
+
cb && cb(res)
|
|
1275
|
+
return res
|
|
1276
|
+
})
|
|
1277
|
+
}
|
|
1278
|
+
*/
|
|
1279
|
+
module.exports = User;
|
|
1280
|
+
})(USE, './share');
|
|
1281
|
+
USE(function(module){
|
|
1282
|
+
var SEA = USE('./sea'), S = USE('./settings'), u;
|
|
1283
|
+
var Gun = (SEA.window||'').GUN || USE((''+u === typeof MODULE?'.':'')+'./gun', 1);
|
|
1284
|
+
// After we have a GUN extension to make user registration/login easy, we then need to handle everything else.
|
|
1285
|
+
|
|
1286
|
+
// We do this with a GUN adapter, we first listen to when a gun instance is created (and when its options change)
|
|
1287
|
+
Gun.on('opt', function(at){
|
|
1288
|
+
if(!at.sea){ // only add SEA once per instance, on the "at" context.
|
|
1289
|
+
at.sea = {own: {}};
|
|
1290
|
+
at.on('put', check, at); // SEA now runs its firewall on HAM diffs, not all i/o.
|
|
1291
|
+
}
|
|
1292
|
+
this.to.next(at); // make sure to call the "next" middleware adapter.
|
|
1293
|
+
});
|
|
1294
|
+
|
|
1295
|
+
// Alright, this next adapter gets run at the per node level in the graph database.
|
|
1296
|
+
// correction: 2020 it gets run on each key/value pair in a node upon a HAM diff.
|
|
1297
|
+
// This will let us verify that every property on a node has a value signed by a public key we trust.
|
|
1298
|
+
// If the signature does not match, the data is just `undefined` so it doesn't get passed on.
|
|
1299
|
+
// If it does match, then we transform the in-memory "view" of the data into its plain value (without the signature).
|
|
1300
|
+
// Now NOTE! Some data is "system" data, not user data. Example: List of public keys, aliases, etc.
|
|
1301
|
+
// This data is self-enforced (the value can only match its ID), but that is handled in the `security` function.
|
|
1302
|
+
// From the self-enforced data, we can see all the edges in the graph that belong to a public key.
|
|
1303
|
+
// Example: ~ASDF is the ID of a node with ASDF as its public key, signed alias and salt, and
|
|
1304
|
+
// its encrypted private key, but it might also have other signed values on it like `profile = <ID>` edge.
|
|
1305
|
+
// Using that directed edge's ID, we can then track (in memory) which IDs belong to which keys.
|
|
1306
|
+
// Here is a problem: Multiple public keys can "claim" any node's ID, so this is dangerous!
|
|
1307
|
+
// This means we should ONLY trust our "friends" (our key ring) public keys, not any ones.
|
|
1308
|
+
// I have not yet added that to SEA yet in this alpha release. That is coming soon, but beware in the meanwhile!
|
|
1309
|
+
|
|
1310
|
+
function check(msg){ // REVISE / IMPROVE, NO NEED TO PASS MSG/EVE EACH SUB?
|
|
1311
|
+
var eve = this, at = eve.as, put = msg.put, soul = put['#'], key = put['.'], val = put[':'], state = put['>'], id = msg['#'], tmp;
|
|
1312
|
+
if(!soul || !key){ return }
|
|
1313
|
+
if((msg._||'').faith && (at.opt||'').faith && 'function' == typeof msg._){
|
|
1314
|
+
SEA.opt.pack(put, function(raw){
|
|
1315
|
+
SEA.verify(raw, false, function(data){ // this is synchronous if false
|
|
1316
|
+
put['='] = SEA.opt.unpack(data);
|
|
1317
|
+
eve.to.next(msg);
|
|
1318
|
+
});});
|
|
1319
|
+
return
|
|
1320
|
+
}
|
|
1321
|
+
var no = function(why){ at.on('in', {'@': id, err: msg.err = why}); }; // exploit internal relay stun for now, maybe violates spec, but testing for now. // Note: this may be only the sharded message, not original batch.
|
|
1322
|
+
//var no = function(why){ msg.ack(why) };
|
|
1323
|
+
(msg._||'').DBG && ((msg._||'').DBG.c = +new Date);
|
|
1324
|
+
if(0 <= soul.indexOf('<?')){ // special case for "do not sync data X old" forget
|
|
1325
|
+
// 'a~pub.key/b<?9'
|
|
1326
|
+
tmp = parseFloat(soul.split('<?')[1]||'');
|
|
1327
|
+
if(tmp && (state < (Gun.state() - (tmp * 1000)))){ // sec to ms
|
|
1328
|
+
(tmp = msg._) && (tmp.stun) && (tmp.stun--); // THIS IS BAD CODE! It assumes GUN internals do something that will probably change in future, but hacking in now.
|
|
1329
|
+
return; // omit!
|
|
1330
|
+
}
|
|
1331
|
+
}
|
|
1332
|
+
|
|
1333
|
+
if('~@' === soul){ // special case for shared system data, the list of aliases.
|
|
1334
|
+
check.alias(eve, msg, val, key, soul, at, no); return;
|
|
1335
|
+
}
|
|
1336
|
+
if('~@' === soul.slice(0,2)){ // special case for shared system data, the list of public keys for an alias.
|
|
1337
|
+
check.pubs(eve, msg, val, key, soul, at, no); return;
|
|
1338
|
+
}
|
|
1339
|
+
//if('~' === soul.slice(0,1) && 2 === (tmp = soul.slice(1)).split('.').length){ // special case, account data for a public key.
|
|
1340
|
+
if(tmp = SEA.opt.pub(soul)){ // special case, account data for a public key.
|
|
1341
|
+
check.pub(eve, msg, val, key, soul, at, no, at.user||'', tmp); return;
|
|
1342
|
+
}
|
|
1343
|
+
if(0 <= soul.indexOf('#')){ // special case for content addressing immutable hashed data.
|
|
1344
|
+
check.hash(eve, msg, val, key, soul, at, no); return;
|
|
1345
|
+
}
|
|
1346
|
+
check.any(eve, msg, val, key, soul, at, no, at.user||''); return;
|
|
1347
|
+
}
|
|
1348
|
+
check.hash = function(eve, msg, val, key, soul, at, no){ // mark unbuilt @i001962 's epic hex contrib!
|
|
1349
|
+
SEA.work(val, null, function(data){
|
|
1350
|
+
function hexToBase64(hexStr) {
|
|
1351
|
+
let base64 = "";
|
|
1352
|
+
for(let i = 0; i < hexStr.length; i++) {
|
|
1353
|
+
base64 += !(i - 1 & 1) ? String.fromCharCode(parseInt(hexStr.substring(i - 1, i + 1), 16)) : "";}
|
|
1354
|
+
return btoa(base64);}
|
|
1355
|
+
if(data && data === key.split('#').slice(-1)[0]){ return eve.to.next(msg) }
|
|
1356
|
+
else if (data && data === hexToBase64(key.split('#').slice(-1)[0])){
|
|
1357
|
+
return eve.to.next(msg) }
|
|
1358
|
+
no("Data hash not same as hash!");
|
|
1359
|
+
}, {name: 'SHA-256'});
|
|
1360
|
+
};
|
|
1361
|
+
check.alias = function(eve, msg, val, key, soul, at, no){ // Example: {_:#~@, ~@alice: {#~@alice}}
|
|
1362
|
+
if(!val){ return no("Data must exist!") } // data MUST exist
|
|
1363
|
+
if('~@'+key === link_is(val)){ return eve.to.next(msg) } // in fact, it must be EXACTLY equal to itself
|
|
1364
|
+
no("Alias not same!"); // if it isn't, reject.
|
|
1365
|
+
};
|
|
1366
|
+
check.pubs = function(eve, msg, val, key, soul, at, no){ // Example: {_:#~@alice, ~asdf: {#~asdf}}
|
|
1367
|
+
if(!val){ return no("Alias must exist!") } // data MUST exist
|
|
1368
|
+
if(key === link_is(val)){ return eve.to.next(msg) } // and the ID must be EXACTLY equal to its property
|
|
1369
|
+
no("Alias not same!"); // that way nobody can tamper with the list of public keys.
|
|
1370
|
+
};
|
|
1371
|
+
check.pub = async function(eve, msg, val, key, soul, at, no, user, pub){ var tmp; // Example: {_:#~asdf, hello:'world'~fdsa}}
|
|
1372
|
+
const raw = await S.parse(val) || {};
|
|
1373
|
+
const verify = (certificate, certificant, cb) => {
|
|
1374
|
+
if (certificate.m && certificate.s && certificant && pub)
|
|
1375
|
+
// now verify certificate
|
|
1376
|
+
return SEA.verify(certificate, pub, data => { // check if "pub" (of the graph owner) really issued this cert
|
|
1377
|
+
if (u !== data && u !== data.e && msg.put['>'] && msg.put['>'] > parseFloat(data.e)) return no("Certificate expired.") // certificate expired
|
|
1378
|
+
// "data.c" = a list of certificants/certified users
|
|
1379
|
+
// "data.w" = lex WRITE permission, in the future, there will be "data.r" which means lex READ permission
|
|
1380
|
+
if (u !== data && data.c && data.w && (data.c === certificant || data.c.indexOf('*' ) > -1)) {
|
|
1381
|
+
// ok, now "certificant" is in the "certificants" list, but is "path" allowed? Check path
|
|
1382
|
+
let path = soul.indexOf('/') > -1 ? soul.replace(soul.substring(0, soul.indexOf('/') + 1), '') : '';
|
|
1383
|
+
String.match = String.match || Gun.text.match;
|
|
1384
|
+
const w = Array.isArray(data.w) ? data.w : typeof data.w === 'object' || typeof data.w === 'string' ? [data.w] : [];
|
|
1385
|
+
for (const lex of w) {
|
|
1386
|
+
if ((String.match(path, lex['#']) && String.match(key, lex['.'])) || (!lex['.'] && String.match(path, lex['#'])) || (!lex['#'] && String.match(key, lex['.'])) || String.match((path ? path + '/' + key : key), lex['#'] || lex)) {
|
|
1387
|
+
// is Certificant forced to present in Path
|
|
1388
|
+
if (lex['+'] && lex['+'].indexOf('*') > -1 && path && path.indexOf(certificant) == -1 && key.indexOf(certificant) == -1) return no(`Path "${path}" or key "${key}" must contain string "${certificant}".`)
|
|
1389
|
+
// path is allowed, but is there any WRITE block? Check it out
|
|
1390
|
+
if (data.wb && (typeof data.wb === 'string' || ((data.wb || {})['#']))) { // "data.wb" = path to the WRITE block
|
|
1391
|
+
var root = eve.as.root.$.back(-1);
|
|
1392
|
+
if (typeof data.wb === 'string' && '~' !== data.wb.slice(0, 1)) root = root.get('~' + pub);
|
|
1393
|
+
return root.get(data.wb).get(certificant).once(value => { // TODO: INTENT TO DEPRECATE.
|
|
1394
|
+
if (value && (value === 1 || value === true)) return no(`Certificant ${certificant} blocked.`)
|
|
1395
|
+
return cb(data)
|
|
1396
|
+
})
|
|
1397
|
+
}
|
|
1398
|
+
return cb(data)
|
|
1399
|
+
}
|
|
1400
|
+
}
|
|
1401
|
+
return no("Certificate verification fail.")
|
|
1402
|
+
}
|
|
1403
|
+
})
|
|
1404
|
+
return
|
|
1405
|
+
};
|
|
1406
|
+
|
|
1407
|
+
if ('pub' === key && '~' + pub === soul) {
|
|
1408
|
+
if (val === pub) return eve.to.next(msg) // the account MUST match `pub` property that equals the ID of the public key.
|
|
1409
|
+
return no("Account not same!")
|
|
1410
|
+
}
|
|
1411
|
+
|
|
1412
|
+
if ((tmp = user.is) && tmp.pub && !raw['*'] && !raw['+'] && (pub === tmp.pub || (pub !== tmp.pub && ((msg._.msg || {}).opt || {}).cert))){
|
|
1413
|
+
SEA.opt.pack(msg.put, packed => {
|
|
1414
|
+
SEA.sign(packed, (user._).sea, async function(data) {
|
|
1415
|
+
if (u === data) return no(SEA.err || 'Signature fail.')
|
|
1416
|
+
msg.put[':'] = {':': tmp = SEA.opt.unpack(data.m), '~': data.s};
|
|
1417
|
+
msg.put['='] = tmp;
|
|
1418
|
+
|
|
1419
|
+
// if writing to own graph, just allow it
|
|
1420
|
+
if (pub === user.is.pub) {
|
|
1421
|
+
if (tmp = link_is(val)) (at.sea.own[tmp] = at.sea.own[tmp] || {})[pub] = 1;
|
|
1422
|
+
JSON.stringifyAsync(msg.put[':'], function(err,s){
|
|
1423
|
+
if(err){ return no(err || "Stringify error.") }
|
|
1424
|
+
msg.put[':'] = s;
|
|
1425
|
+
return eve.to.next(msg);
|
|
1426
|
+
});
|
|
1427
|
+
return
|
|
1428
|
+
}
|
|
1429
|
+
|
|
1430
|
+
// if writing to other's graph, check if cert exists then try to inject cert into put, also inject self pub so that everyone can verify the put
|
|
1431
|
+
if (pub !== user.is.pub && ((msg._.msg || {}).opt || {}).cert) {
|
|
1432
|
+
const cert = await S.parse(msg._.msg.opt.cert);
|
|
1433
|
+
// even if cert exists, we must verify it
|
|
1434
|
+
if (cert && cert.m && cert.s)
|
|
1435
|
+
verify(cert, user.is.pub, _ => {
|
|
1436
|
+
msg.put[':']['+'] = cert; // '+' is a certificate
|
|
1437
|
+
msg.put[':']['*'] = user.is.pub; // '*' is pub of the user who puts
|
|
1438
|
+
JSON.stringifyAsync(msg.put[':'], function(err,s){
|
|
1439
|
+
if(err){ return no(err || "Stringify error.") }
|
|
1440
|
+
msg.put[':'] = s;
|
|
1441
|
+
return eve.to.next(msg);
|
|
1442
|
+
});
|
|
1443
|
+
return
|
|
1444
|
+
});
|
|
1445
|
+
}
|
|
1446
|
+
}, {raw: 1});
|
|
1447
|
+
});
|
|
1448
|
+
return;
|
|
1449
|
+
}
|
|
1450
|
+
|
|
1451
|
+
SEA.opt.pack(msg.put, packed => {
|
|
1452
|
+
SEA.verify(packed, raw['*'] || pub, function(data){ var tmp;
|
|
1453
|
+
data = SEA.opt.unpack(data);
|
|
1454
|
+
if (u === data) return no("Unverified data.") // make sure the signature matches the account it claims to be on. // reject any updates that are signed with a mismatched account.
|
|
1455
|
+
if ((tmp = link_is(data)) && pub === SEA.opt.pub(tmp)) (at.sea.own[tmp] = at.sea.own[tmp] || {})[pub] = 1;
|
|
1456
|
+
|
|
1457
|
+
// check if cert ('+') and putter's pub ('*') exist
|
|
1458
|
+
if (raw['+'] && raw['+']['m'] && raw['+']['s'] && raw['*'])
|
|
1459
|
+
// now verify certificate
|
|
1460
|
+
verify(raw['+'], raw['*'], _ => {
|
|
1461
|
+
msg.put['='] = data;
|
|
1462
|
+
return eve.to.next(msg);
|
|
1463
|
+
});
|
|
1464
|
+
else {
|
|
1465
|
+
msg.put['='] = data;
|
|
1466
|
+
return eve.to.next(msg);
|
|
1467
|
+
}
|
|
1468
|
+
});
|
|
1469
|
+
});
|
|
1470
|
+
return
|
|
1471
|
+
};
|
|
1472
|
+
check.any = function(eve, msg, val, key, soul, at, no, user){ if(at.opt.secure){ return no("Soul missing public key at '" + key + "'.") }
|
|
1473
|
+
// TODO: Ask community if should auto-sign non user-graph data.
|
|
1474
|
+
at.on('secure', function(msg){ this.off();
|
|
1475
|
+
if(!at.opt.secure){ return eve.to.next(msg) }
|
|
1476
|
+
no("Data cannot be changed.");
|
|
1477
|
+
}).on.on('secure', msg);
|
|
1478
|
+
return;
|
|
1479
|
+
};
|
|
1480
|
+
|
|
1481
|
+
var valid = Gun.valid, link_is = function(d,l){ return 'string' == typeof (l = valid(d)) && l }; (Gun.state||'').ify;
|
|
1482
|
+
|
|
1483
|
+
var pubcut = /[^\w_-]/; // anything not alphanumeric or _ -
|
|
1484
|
+
SEA.opt.pub = function(s){
|
|
1485
|
+
if(!s){ return }
|
|
1486
|
+
s = s.split('~');
|
|
1487
|
+
if(!s || !(s = s[1])){ return }
|
|
1488
|
+
s = s.split(pubcut).slice(0,2);
|
|
1489
|
+
if(!s || 2 != s.length){ return }
|
|
1490
|
+
if('@' === (s[0]||'')[0]){ return }
|
|
1491
|
+
s = s.slice(0,2).join('.');
|
|
1492
|
+
return s;
|
|
1493
|
+
};
|
|
1494
|
+
SEA.opt.stringy = function(t){
|
|
1495
|
+
// TODO: encrypt etc. need to check string primitive. Make as breaking change.
|
|
1496
|
+
};
|
|
1497
|
+
SEA.opt.pack = function(d,cb,k, n,s){ var tmp, f; // pack for verifying
|
|
1498
|
+
if(SEA.opt.check(d)){ return cb(d) }
|
|
1499
|
+
if(d && d['#'] && d['.'] && d['>']){ tmp = d[':']; f = 1; }
|
|
1500
|
+
JSON.parseAsync(f? tmp : d, function(err, meta){
|
|
1501
|
+
var sig = ((u !== (meta||'')[':']) && (meta||'')['~']); // or just ~ check?
|
|
1502
|
+
if(!sig){ cb(d); return }
|
|
1503
|
+
cb({m: {'#':s||d['#'],'.':k||d['.'],':':(meta||'')[':'],'>':d['>']||Gun.state.is(n, k)}, s: sig});
|
|
1504
|
+
});
|
|
1505
|
+
};
|
|
1506
|
+
var O = SEA.opt;
|
|
1507
|
+
SEA.opt.unpack = function(d, k, n){ var tmp;
|
|
1508
|
+
if(u === d){ return }
|
|
1509
|
+
if(d && (u !== (tmp = d[':']))){ return tmp }
|
|
1510
|
+
k = k || O.fall_key; if(!n && O.fall_val){ n = {}; n[k] = O.fall_val; }
|
|
1511
|
+
if(!k || !n){ return }
|
|
1512
|
+
if(d === n[k]){ return d }
|
|
1513
|
+
if(!SEA.opt.check(n[k])){ return d }
|
|
1514
|
+
var soul = (n && n._ && n._['#']) || O.fall_soul, s = Gun.state.is(n, k) || O.fall_state;
|
|
1515
|
+
if(d && 4 === d.length && soul === d[0] && k === d[1] && fl(s) === fl(d[3])){
|
|
1516
|
+
return d[2];
|
|
1517
|
+
}
|
|
1518
|
+
if(s < SEA.opt.shuffle_attack){
|
|
1519
|
+
return d;
|
|
1520
|
+
}
|
|
1521
|
+
};
|
|
1522
|
+
SEA.opt.shuffle_attack = 1546329600000; // Jan 1, 2019
|
|
1523
|
+
var fl = Math.floor; // TODO: Still need to fix inconsistent state issue.
|
|
1524
|
+
// TODO: Potential bug? If pub/priv key starts with `-`? IDK how possible.
|
|
1525
|
+
|
|
1526
|
+
})(USE, './index');
|
|
1527
|
+
}());
|
|
1528
|
+
} (sea));
|
|
1529
|
+
|
|
1530
|
+
var seaExports = sea.exports;
|
|
1531
|
+
var SEA = /*@__PURE__*/getDefaultExportFromCjs(seaExports);
|
|
16
1532
|
|
|
17
1533
|
let contractAddresses$1 = {
|
|
18
1534
|
PROOF_OF_INTEGRITY_ADDRESS: "0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512",
|
|
@@ -20,15 +1536,15 @@ let contractAddresses$1 = {
|
|
|
20
1536
|
};
|
|
21
1537
|
|
|
22
1538
|
if (typeof window === 'undefined') {
|
|
23
|
-
const { fileURLToPath } = require('url');
|
|
24
|
-
const { dirname } = require('path');
|
|
25
|
-
const { readFileSync } = require('fs');
|
|
26
|
-
const { join } = require('path');
|
|
27
|
-
|
|
28
1539
|
try {
|
|
1540
|
+
const { fileURLToPath } = require('url');
|
|
1541
|
+
const { dirname, join } = require('path');
|
|
1542
|
+
const { readFileSync } = require('fs');
|
|
1543
|
+
|
|
29
1544
|
const __filename = fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('gun-eth.cjs.js', document.baseURI).href)));
|
|
30
1545
|
const __dirname = dirname(__filename);
|
|
31
|
-
|
|
1546
|
+
|
|
1547
|
+
const rawdata = readFileSync(join(__dirname, 'contract-address.json'));
|
|
32
1548
|
contractAddresses$1 = JSON.parse(rawdata);
|
|
33
1549
|
console.log("Loaded contract addresses:", contractAddresses$1);
|
|
34
1550
|
} catch (error) {
|
|
@@ -44,56 +1560,6 @@ const LOCAL_CONFIG = {
|
|
|
44
1560
|
GUN_PEER: "http://localhost:8765/gun"
|
|
45
1561
|
};
|
|
46
1562
|
|
|
47
|
-
// Indirizzi di produzione per diverse chain
|
|
48
|
-
const CHAIN_CONFIG = {
|
|
49
|
-
optimismSepolia: {
|
|
50
|
-
STEALTH_ANNOUNCER_ADDRESS: "",
|
|
51
|
-
PROOF_OF_INTEGRITY_ADDRESS: "",
|
|
52
|
-
RPC_URL: "https://sepolia.optimism.io",
|
|
53
|
-
CHAIN_ID: 11155420
|
|
54
|
-
},
|
|
55
|
-
arbitrumSepolia: {
|
|
56
|
-
STEALTH_ANNOUNCER_ADDRESS: "",
|
|
57
|
-
PROOF_OF_INTEGRITY_ADDRESS: "",
|
|
58
|
-
RPC_URL: "https://sepolia-rollup.arbitrum.io/rpc",
|
|
59
|
-
CHAIN_ID: 421614
|
|
60
|
-
},
|
|
61
|
-
localhost: {
|
|
62
|
-
RPC_URL: "http://127.0.0.1:8545",
|
|
63
|
-
CHAIN_ID: 1337
|
|
64
|
-
}
|
|
65
|
-
};
|
|
66
|
-
|
|
67
|
-
// Funzione per ottenere gli indirizzi corretti
|
|
68
|
-
function getAddressesForChain(chainName) {
|
|
69
|
-
let config;
|
|
70
|
-
|
|
71
|
-
// Se è localhost, prova a caricare gli indirizzi locali
|
|
72
|
-
if (chainName === 'localhost') {
|
|
73
|
-
try {
|
|
74
|
-
// Carica gli indirizzi dal file generato dal deploy locale
|
|
75
|
-
const localAddresses = require$$0;
|
|
76
|
-
config = {
|
|
77
|
-
...CHAIN_CONFIG.localhost,
|
|
78
|
-
...localAddresses
|
|
79
|
-
};
|
|
80
|
-
console.log("Using local addresses:", config);
|
|
81
|
-
return config;
|
|
82
|
-
} catch (err) {
|
|
83
|
-
console.warn('No local addresses found');
|
|
84
|
-
throw new Error('No local addresses found. Did you run local deployment?');
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
// Altrimenti usa gli indirizzi di produzione
|
|
89
|
-
config = CHAIN_CONFIG[chainName];
|
|
90
|
-
if (!config) {
|
|
91
|
-
throw new Error(`Chain ${chainName} not supported. Supported chains: ${Object.keys(CHAIN_CONFIG).join(', ')}`);
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
return config;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
1563
|
const STEALTH_ANNOUNCER_ABI = [
|
|
98
1564
|
{
|
|
99
1565
|
"inputs": [
|
|
@@ -425,12 +1891,12 @@ const PROOF_OF_INTEGRITY_ABI = [
|
|
|
425
1891
|
"stateMutability": "view",
|
|
426
1892
|
"type": "function"
|
|
427
1893
|
}
|
|
428
|
-
];
|
|
1894
|
+
];
|
|
1895
|
+
const STEALTH_ANNOUNCER_ADDRESS = "...";
|
|
429
1896
|
|
|
430
|
-
//
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
chainConfig.PROOF_OF_INTEGRITY_ADDRESS;
|
|
1897
|
+
// =============================================
|
|
1898
|
+
// IMPORTS AND GLOBAL VARIABLES
|
|
1899
|
+
// =============================================
|
|
434
1900
|
|
|
435
1901
|
let PROOF_CONTRACT_ADDRESS;
|
|
436
1902
|
let rpcUrl = "";
|