cryptpad-server 0.0.1
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/build/core.js +9183 -0
- package/build/core.worker.js +993 -0
- package/build/front.js +5815 -0
- package/build/front.worker.js +4619 -0
- package/build/http.js +5327 -0
- package/build/http.worker.js +4621 -0
- package/build/storage.cluster.js +8425 -0
- package/build/storage.js +12103 -0
- package/build/storage.worker.js +6544 -0
- package/index.js +169 -0
- package/package.json +68 -0
- package/readme.md +104 -0
|
@@ -0,0 +1,4619 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var require$$0 = require("tweetnacl-util");
|
|
4
|
+
|
|
5
|
+
var require$$1$2 = require("express");
|
|
6
|
+
|
|
7
|
+
var require$$0$2 = require("node:fs");
|
|
8
|
+
|
|
9
|
+
var require$$1 = require("node:path");
|
|
10
|
+
|
|
11
|
+
var require$$3 = require("node:crypto");
|
|
12
|
+
|
|
13
|
+
var require$$0$1 = require("stream-to-pull-stream");
|
|
14
|
+
|
|
15
|
+
var require$$1$1 = require("pull-stream");
|
|
16
|
+
|
|
17
|
+
var require$$5 = require("fs-extra");
|
|
18
|
+
|
|
19
|
+
var require$$6 = require("nthen");
|
|
20
|
+
|
|
21
|
+
var require$$4 = require("saferphore");
|
|
22
|
+
|
|
23
|
+
var require$$4$1 = require("ws");
|
|
24
|
+
|
|
25
|
+
var require$$6$1 = require("cookie-parser");
|
|
26
|
+
|
|
27
|
+
var require$$7 = require("body-parser");
|
|
28
|
+
|
|
29
|
+
function getDefaultExportFromCjs(x) {
|
|
30
|
+
return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, "default") ? x["default"] : x;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
var worker$1 = {};
|
|
34
|
+
|
|
35
|
+
var commonUtil$2 = {
|
|
36
|
+
exports: {}
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
var commonUtil$1 = commonUtil$2.exports;
|
|
40
|
+
|
|
41
|
+
var hasRequiredCommonUtil$1;
|
|
42
|
+
|
|
43
|
+
function requireCommonUtil$1() {
|
|
44
|
+
if (hasRequiredCommonUtil$1) return commonUtil$2.exports;
|
|
45
|
+
hasRequiredCommonUtil$1 = 1;
|
|
46
|
+
(function(module) {
|
|
47
|
+
(function(window) {
|
|
48
|
+
const factory = NaclUtil => {
|
|
49
|
+
var Util = window.CryptPad_Util = {};
|
|
50
|
+
window.atob = window.atob || function(str) {
|
|
51
|
+
return Buffer.from(str, "base64").toString("binary");
|
|
52
|
+
};
|
|
53
|
+
window.btoa = window.btoa || function(str) {
|
|
54
|
+
return Buffer.from(str, "binary").toString("base64");
|
|
55
|
+
};
|
|
56
|
+
Util.encodeBase64 = NaclUtil.encodeBase64;
|
|
57
|
+
Util.decodeBase64 = str => {
|
|
58
|
+
let i = str.length % 4;
|
|
59
|
+
if (i) {
|
|
60
|
+
str += "=".repeat(4 - i);
|
|
61
|
+
}
|
|
62
|
+
return NaclUtil.decodeBase64(str);
|
|
63
|
+
};
|
|
64
|
+
Util.encodeUTF8 = NaclUtil.encodeUTF8;
|
|
65
|
+
Util.decodeUTF8 = NaclUtil.decodeUTF8;
|
|
66
|
+
Util.slice = function(A, start, end) {
|
|
67
|
+
return Array.prototype.slice.call(A, start, end);
|
|
68
|
+
};
|
|
69
|
+
Util.u8ToBase64 = (u8, cb) => {
|
|
70
|
+
const reader = new FileReader;
|
|
71
|
+
reader.onload = () => {
|
|
72
|
+
let res = reader.result;
|
|
73
|
+
let trim = res.slice(res.indexOf(",") + 1);
|
|
74
|
+
cb(trim);
|
|
75
|
+
};
|
|
76
|
+
reader.readAsDataURL(new Blob([ u8 ]));
|
|
77
|
+
};
|
|
78
|
+
Util.shuffleArray = function(a) {
|
|
79
|
+
for (var i = a.length - 1; i > 0; i--) {
|
|
80
|
+
var j = Math.floor(Math.random() * (i + 1));
|
|
81
|
+
var tmp = a[i];
|
|
82
|
+
a[i] = a[j];
|
|
83
|
+
a[j] = tmp;
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
Util.bake = function(f, args) {
|
|
87
|
+
if (typeof args === "undefined") {
|
|
88
|
+
args = [];
|
|
89
|
+
}
|
|
90
|
+
if (!Array.isArray(args)) {
|
|
91
|
+
args = [ args ];
|
|
92
|
+
}
|
|
93
|
+
return function() {
|
|
94
|
+
return f.apply(null, args);
|
|
95
|
+
};
|
|
96
|
+
};
|
|
97
|
+
Util.both = function(pre, post) {
|
|
98
|
+
if (typeof pre !== "function") {
|
|
99
|
+
throw new Error("INVALID_USAGE");
|
|
100
|
+
}
|
|
101
|
+
if (typeof post !== "function") {
|
|
102
|
+
post = function(x) {
|
|
103
|
+
return x;
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
return function() {
|
|
107
|
+
pre.apply(null, arguments);
|
|
108
|
+
return post.apply(null, arguments);
|
|
109
|
+
};
|
|
110
|
+
};
|
|
111
|
+
Util.clone = function(o) {
|
|
112
|
+
if (o === undefined || o === null) {
|
|
113
|
+
return o;
|
|
114
|
+
}
|
|
115
|
+
return JSON.parse(JSON.stringify(o));
|
|
116
|
+
};
|
|
117
|
+
Util.serializeError = function(err) {
|
|
118
|
+
if (!(err instanceof Error)) {
|
|
119
|
+
return err;
|
|
120
|
+
}
|
|
121
|
+
var ser = {};
|
|
122
|
+
Object.getOwnPropertyNames(err).forEach(function(key) {
|
|
123
|
+
ser[key] = err[key];
|
|
124
|
+
});
|
|
125
|
+
return ser;
|
|
126
|
+
};
|
|
127
|
+
Util.tryParse = function(s) {
|
|
128
|
+
try {
|
|
129
|
+
return JSON.parse(s);
|
|
130
|
+
} catch (e) {
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
};
|
|
134
|
+
Util.mkAsync = function(f, ms) {
|
|
135
|
+
if (typeof f !== "function") {
|
|
136
|
+
throw new Error("EXPECTED_FUNCTION");
|
|
137
|
+
}
|
|
138
|
+
return function() {
|
|
139
|
+
var args = Array.prototype.slice.call(arguments);
|
|
140
|
+
setTimeout(function() {
|
|
141
|
+
f.apply(null, args);
|
|
142
|
+
}, ms);
|
|
143
|
+
};
|
|
144
|
+
};
|
|
145
|
+
Util.mkEvent = function(once) {
|
|
146
|
+
var handlers = [];
|
|
147
|
+
var fired = false;
|
|
148
|
+
let promiseResolve;
|
|
149
|
+
const promise = new Promise(resolve => {
|
|
150
|
+
promiseResolve = resolve;
|
|
151
|
+
});
|
|
152
|
+
return {
|
|
153
|
+
reg: function(cb) {
|
|
154
|
+
if (once && fired) {
|
|
155
|
+
return void setTimeout(cb);
|
|
156
|
+
}
|
|
157
|
+
handlers.push(cb);
|
|
158
|
+
},
|
|
159
|
+
unreg: function(cb) {
|
|
160
|
+
if (handlers.indexOf(cb) === -1) {
|
|
161
|
+
return void console.log("event handler was already unregistered");
|
|
162
|
+
}
|
|
163
|
+
handlers.splice(handlers.indexOf(cb), 1);
|
|
164
|
+
},
|
|
165
|
+
fire: function() {
|
|
166
|
+
if (once && fired) {
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
var args = Array.prototype.slice.call(arguments);
|
|
170
|
+
if (!fired) {
|
|
171
|
+
promiseResolve.apply(null, args);
|
|
172
|
+
}
|
|
173
|
+
fired = true;
|
|
174
|
+
handlers.forEach(function(h) {
|
|
175
|
+
h.apply(null, args);
|
|
176
|
+
});
|
|
177
|
+
},
|
|
178
|
+
promise
|
|
179
|
+
};
|
|
180
|
+
};
|
|
181
|
+
Util.mkTimeout = function(_f, ms) {
|
|
182
|
+
ms = ms || 0;
|
|
183
|
+
var f = Util.once(_f);
|
|
184
|
+
var timeout = setTimeout(function() {
|
|
185
|
+
f("TIMEOUT");
|
|
186
|
+
}, ms);
|
|
187
|
+
return Util.both(f, function() {
|
|
188
|
+
clearTimeout(timeout);
|
|
189
|
+
});
|
|
190
|
+
};
|
|
191
|
+
Util.onClickEnter = function($element, handler, cfg) {
|
|
192
|
+
$element.on("click keydown", function(e) {
|
|
193
|
+
var isClick = e.type === "click";
|
|
194
|
+
var isEnter = e.type === "keydown" && e.which === 13;
|
|
195
|
+
var isSpace = e.type === "keydown" && e.which === 32 && cfg && cfg.space;
|
|
196
|
+
if (!isClick && !isEnter && !isSpace) {
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
199
|
+
if (e.type === "keydown") {
|
|
200
|
+
e.preventDefault();
|
|
201
|
+
}
|
|
202
|
+
handler(e);
|
|
203
|
+
});
|
|
204
|
+
};
|
|
205
|
+
Util.response = function(errorHandler) {
|
|
206
|
+
var pending = {};
|
|
207
|
+
var timeouts = {};
|
|
208
|
+
if (typeof errorHandler !== "function") {
|
|
209
|
+
errorHandler = function(label) {
|
|
210
|
+
throw new Error(label);
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
var clear = function(id) {
|
|
214
|
+
clearTimeout(timeouts[id]);
|
|
215
|
+
delete timeouts[id];
|
|
216
|
+
delete pending[id];
|
|
217
|
+
};
|
|
218
|
+
var expect = function(id, fn, ms) {
|
|
219
|
+
if (typeof id !== "string") {
|
|
220
|
+
errorHandler("EXPECTED_STRING");
|
|
221
|
+
}
|
|
222
|
+
if (typeof fn !== "function") {
|
|
223
|
+
errorHandler("EXPECTED_CALLBACK");
|
|
224
|
+
}
|
|
225
|
+
pending[id] = fn;
|
|
226
|
+
if (typeof ms === "number" && ms) {
|
|
227
|
+
timeouts[id] = setTimeout(function() {
|
|
228
|
+
if (typeof pending[id] === "function") {
|
|
229
|
+
pending[id]("TIMEOUT");
|
|
230
|
+
}
|
|
231
|
+
clear(id);
|
|
232
|
+
}, ms);
|
|
233
|
+
}
|
|
234
|
+
};
|
|
235
|
+
var handle = function(id, args) {
|
|
236
|
+
var fn = pending[id];
|
|
237
|
+
if (typeof fn !== "function") {
|
|
238
|
+
return void errorHandler("MISSING_CALLBACK", {
|
|
239
|
+
id,
|
|
240
|
+
args
|
|
241
|
+
});
|
|
242
|
+
}
|
|
243
|
+
try {
|
|
244
|
+
fn.apply(null, Array.isArray(args) ? args : [ args ]);
|
|
245
|
+
} catch (err) {
|
|
246
|
+
console.trace(err);
|
|
247
|
+
errorHandler("HANDLER_ERROR", {
|
|
248
|
+
error: err,
|
|
249
|
+
id,
|
|
250
|
+
args
|
|
251
|
+
});
|
|
252
|
+
}
|
|
253
|
+
clear(id);
|
|
254
|
+
};
|
|
255
|
+
return {
|
|
256
|
+
clear,
|
|
257
|
+
expected: function(id) {
|
|
258
|
+
return Boolean(pending[id]);
|
|
259
|
+
},
|
|
260
|
+
expectation: function(id) {
|
|
261
|
+
return pending[id];
|
|
262
|
+
},
|
|
263
|
+
expect,
|
|
264
|
+
handle,
|
|
265
|
+
_pending: pending
|
|
266
|
+
};
|
|
267
|
+
};
|
|
268
|
+
Util.inc = function(map, key, val) {
|
|
269
|
+
map[key] = (map[key] || 0) + (typeof val === "number" ? val : 1);
|
|
270
|
+
};
|
|
271
|
+
Util.values = function(obj) {
|
|
272
|
+
return Object.keys(obj).map(function(k) {
|
|
273
|
+
return obj[k];
|
|
274
|
+
});
|
|
275
|
+
};
|
|
276
|
+
Util.find = function(map, path) {
|
|
277
|
+
var l = path.length;
|
|
278
|
+
for (var i = 0; i < l; i++) {
|
|
279
|
+
if (typeof map[path[i]] === "undefined") {
|
|
280
|
+
return;
|
|
281
|
+
}
|
|
282
|
+
map = map[path[i]];
|
|
283
|
+
}
|
|
284
|
+
return map;
|
|
285
|
+
};
|
|
286
|
+
Util.uid = function() {
|
|
287
|
+
return Number(Math.floor(Math.random() * Number.MAX_SAFE_INTEGER)).toString(32).replace(/\./g, "");
|
|
288
|
+
};
|
|
289
|
+
Util.guid = function(map) {
|
|
290
|
+
var id = Util.uid();
|
|
291
|
+
if (typeof map[id] === "undefined") {
|
|
292
|
+
return id;
|
|
293
|
+
}
|
|
294
|
+
return Util.guid(map);
|
|
295
|
+
};
|
|
296
|
+
Util.fixHTML = function(str) {
|
|
297
|
+
if (!str) {
|
|
298
|
+
return "";
|
|
299
|
+
}
|
|
300
|
+
return str.replace(/[<>&"']/g, function(x) {
|
|
301
|
+
return {
|
|
302
|
+
"<": "<",
|
|
303
|
+
">": ">",
|
|
304
|
+
"&": "&",
|
|
305
|
+
'"': """,
|
|
306
|
+
"'": "'"
|
|
307
|
+
}[x];
|
|
308
|
+
});
|
|
309
|
+
};
|
|
310
|
+
Util.hexToBase64 = function(hex) {
|
|
311
|
+
var hexArray = hex.replace(/\r|\n/g, "").replace(/([\da-fA-F]{2}) ?/g, "0x$1 ").replace(/ +$/, "").split(" ");
|
|
312
|
+
var byteString = String.fromCharCode.apply(null, hexArray);
|
|
313
|
+
return window.btoa(byteString).replace(/\//g, "-").replace(/=+$/, "");
|
|
314
|
+
};
|
|
315
|
+
Util.base64ToHex = function(b64String) {
|
|
316
|
+
var hexArray = [];
|
|
317
|
+
window.atob(b64String.replace(/-/g, "/")).split("").forEach(function(e) {
|
|
318
|
+
var h = e.charCodeAt(0).toString(16);
|
|
319
|
+
if (h.length === 1) {
|
|
320
|
+
h = "0" + h;
|
|
321
|
+
}
|
|
322
|
+
hexArray.push(h);
|
|
323
|
+
});
|
|
324
|
+
return hexArray.join("");
|
|
325
|
+
};
|
|
326
|
+
Util.uint8ArrayToHex = function(bytes) {
|
|
327
|
+
var hexString = "";
|
|
328
|
+
for (var i = 0; i < bytes.length; i++) {
|
|
329
|
+
if (bytes[i] < 16) {
|
|
330
|
+
hexString += "0";
|
|
331
|
+
}
|
|
332
|
+
hexString += bytes[i].toString(16);
|
|
333
|
+
}
|
|
334
|
+
return hexString;
|
|
335
|
+
};
|
|
336
|
+
Util.hexToUint8Array = function(hexString) {
|
|
337
|
+
var bytes = new Uint8Array(Math.ceil(hexString.length / 2));
|
|
338
|
+
for (var i = 0; i < bytes.length; i++) {
|
|
339
|
+
bytes[i] = parseInt(hexString.substr(i * 2, 2), 16);
|
|
340
|
+
}
|
|
341
|
+
return bytes;
|
|
342
|
+
};
|
|
343
|
+
Util.uint8ArrayJoin = function(AA) {
|
|
344
|
+
var l = 0;
|
|
345
|
+
var i = 0;
|
|
346
|
+
for (;i < AA.length; i++) {
|
|
347
|
+
l += AA[i].length;
|
|
348
|
+
}
|
|
349
|
+
var C = new Uint8Array(l);
|
|
350
|
+
i = 0;
|
|
351
|
+
for (var offset = 0; i < AA.length; i++) {
|
|
352
|
+
C.set(AA[i], offset);
|
|
353
|
+
offset += AA[i].length;
|
|
354
|
+
}
|
|
355
|
+
return C;
|
|
356
|
+
};
|
|
357
|
+
Util.escapeKeyCharacters = function(key) {
|
|
358
|
+
return key && key.replace && key.replace(/\//g, "-");
|
|
359
|
+
};
|
|
360
|
+
Util.unescapeKeyCharacters = function(key) {
|
|
361
|
+
return key.replace(/\-/g, "/");
|
|
362
|
+
};
|
|
363
|
+
Util.deduplicateString = function(array) {
|
|
364
|
+
return Array.from(new Set(array));
|
|
365
|
+
};
|
|
366
|
+
Util.fixFileName = function(filename) {
|
|
367
|
+
return filename.replace(/ /g, "-").replace(/[\/\?]/g, "_").replace(/_+/g, "_");
|
|
368
|
+
};
|
|
369
|
+
var oneKilobyte = 1024;
|
|
370
|
+
var oneMegabyte = 1024 * oneKilobyte;
|
|
371
|
+
var oneGigabyte = 1024 * oneMegabyte;
|
|
372
|
+
Util.bytesToGigabytes = function(bytes) {
|
|
373
|
+
return Math.ceil(bytes / oneGigabyte * 100) / 100;
|
|
374
|
+
};
|
|
375
|
+
Util.bytesToMegabytes = function(bytes) {
|
|
376
|
+
return Math.ceil(bytes / oneMegabyte * 100) / 100;
|
|
377
|
+
};
|
|
378
|
+
Util.bytesToKilobytes = function(bytes) {
|
|
379
|
+
return Math.ceil(bytes / oneKilobyte * 100) / 100;
|
|
380
|
+
};
|
|
381
|
+
Util.magnitudeOfBytes = function(bytes) {
|
|
382
|
+
if (bytes >= oneGigabyte) {
|
|
383
|
+
return "GB";
|
|
384
|
+
} else if (bytes >= oneMegabyte) {
|
|
385
|
+
return "MB";
|
|
386
|
+
} else {
|
|
387
|
+
return "KB";
|
|
388
|
+
}
|
|
389
|
+
};
|
|
390
|
+
var getCacheKey = function(src) {
|
|
391
|
+
var _src = src.replace(/(\/)*$/, "");
|
|
392
|
+
var idx = _src.lastIndexOf("/");
|
|
393
|
+
var cacheKey = _src.slice(idx + 1);
|
|
394
|
+
if (!/^[a-f0-9]{48}$/.test(cacheKey)) {
|
|
395
|
+
cacheKey = undefined;
|
|
396
|
+
}
|
|
397
|
+
return cacheKey;
|
|
398
|
+
};
|
|
399
|
+
Util.getBlock = function(src, opt, cb) {
|
|
400
|
+
var CB = Util.once(Util.mkAsync(cb));
|
|
401
|
+
var headers = {};
|
|
402
|
+
if (typeof opt.bearer === "string" && opt.bearer) {
|
|
403
|
+
headers.authorization = `Bearer ${opt.bearer}`;
|
|
404
|
+
}
|
|
405
|
+
fetch(src, {
|
|
406
|
+
method: "GET",
|
|
407
|
+
credentials: "include",
|
|
408
|
+
headers
|
|
409
|
+
}).then(response => {
|
|
410
|
+
if (response.ok) {
|
|
411
|
+
return void CB(void 0, response);
|
|
412
|
+
}
|
|
413
|
+
if (response.status === 401 || response.status === 404) {
|
|
414
|
+
response.json().then(data => {
|
|
415
|
+
CB(response.status, data);
|
|
416
|
+
}).catch(() => {
|
|
417
|
+
CB(response.status);
|
|
418
|
+
});
|
|
419
|
+
return;
|
|
420
|
+
}
|
|
421
|
+
CB(response.status, response);
|
|
422
|
+
}).catch(error => {
|
|
423
|
+
CB(error);
|
|
424
|
+
});
|
|
425
|
+
};
|
|
426
|
+
Util.fetchApi = function(origin, type, ignoreCache, cb) {
|
|
427
|
+
const url = new URL(origin);
|
|
428
|
+
url.pathname = `api/${type}`;
|
|
429
|
+
let href = url.href + (ignoreCache ? "?" + +new Date : "");
|
|
430
|
+
if (typeof self !== "undefined" && self.crypto) {
|
|
431
|
+
fetch(href).then(res => {
|
|
432
|
+
if (!res.ok) {
|
|
433
|
+
throw new Error(`Fetch error: ${res.status}`);
|
|
434
|
+
}
|
|
435
|
+
return res.text();
|
|
436
|
+
}).then(body => {
|
|
437
|
+
cb(JSON.parse(body.slice(27, -5)));
|
|
438
|
+
}).catch(err => {
|
|
439
|
+
console.error(err.message);
|
|
440
|
+
cb({});
|
|
441
|
+
});
|
|
442
|
+
} else if (typeof require !== "undefined") {
|
|
443
|
+
const H = url.protocol === "http:" ? require("node:http") : require("node:https");
|
|
444
|
+
H.get(url.href, res => {
|
|
445
|
+
let body = "";
|
|
446
|
+
res.on("data", data => {
|
|
447
|
+
body += data;
|
|
448
|
+
});
|
|
449
|
+
res.on("end", () => {
|
|
450
|
+
try {
|
|
451
|
+
cb(JSON.parse(body.slice(27, -5)));
|
|
452
|
+
} catch (e) {
|
|
453
|
+
console.error(e);
|
|
454
|
+
cb({});
|
|
455
|
+
}
|
|
456
|
+
});
|
|
457
|
+
});
|
|
458
|
+
}
|
|
459
|
+
};
|
|
460
|
+
Util.fetch = function(src, cb, progress, cache) {
|
|
461
|
+
var CB = Util.once(Util.mkAsync(cb));
|
|
462
|
+
var cacheKey = getCacheKey(src);
|
|
463
|
+
var getBlobCache = function(id, cb) {
|
|
464
|
+
if (!cache || typeof cache.getBlobCache !== "function") {
|
|
465
|
+
return void cb("EINVAL");
|
|
466
|
+
}
|
|
467
|
+
cache.getBlobCache(id, cb);
|
|
468
|
+
};
|
|
469
|
+
var setBlobCache = function(id, u8, cb) {
|
|
470
|
+
if (!cache || typeof cache.setBlobCache !== "function") {
|
|
471
|
+
return void cb("EINVAL");
|
|
472
|
+
}
|
|
473
|
+
cache.setBlobCache(id, u8, cb);
|
|
474
|
+
};
|
|
475
|
+
var xhr;
|
|
476
|
+
var fetch = function() {
|
|
477
|
+
xhr = new XMLHttpRequest;
|
|
478
|
+
xhr.open("GET", src, true);
|
|
479
|
+
if (progress) {
|
|
480
|
+
xhr.addEventListener("progress", function(evt) {
|
|
481
|
+
if (evt.lengthComputable) {
|
|
482
|
+
var percentComplete = evt.loaded / evt.total;
|
|
483
|
+
progress(percentComplete);
|
|
484
|
+
}
|
|
485
|
+
}, false);
|
|
486
|
+
}
|
|
487
|
+
xhr.responseType = "arraybuffer";
|
|
488
|
+
xhr.onerror = function(err) {
|
|
489
|
+
CB(err);
|
|
490
|
+
};
|
|
491
|
+
xhr.onload = function() {
|
|
492
|
+
if (/^4/.test("" + this.status)) {
|
|
493
|
+
return CB("XHR_ERROR");
|
|
494
|
+
}
|
|
495
|
+
var arrayBuffer = xhr.response;
|
|
496
|
+
if (arrayBuffer) {
|
|
497
|
+
var u8 = new Uint8Array(arrayBuffer);
|
|
498
|
+
if (cacheKey) {
|
|
499
|
+
return void setBlobCache(cacheKey, u8, function() {
|
|
500
|
+
CB(null, u8);
|
|
501
|
+
});
|
|
502
|
+
}
|
|
503
|
+
return void CB(void 0, u8);
|
|
504
|
+
}
|
|
505
|
+
CB("ENOENT");
|
|
506
|
+
};
|
|
507
|
+
xhr.send(null);
|
|
508
|
+
};
|
|
509
|
+
if (!cacheKey) {
|
|
510
|
+
return void fetch();
|
|
511
|
+
}
|
|
512
|
+
getBlobCache(cacheKey, function(err, u8) {
|
|
513
|
+
if (err || !u8) {
|
|
514
|
+
return void fetch();
|
|
515
|
+
}
|
|
516
|
+
CB(void 0, u8);
|
|
517
|
+
});
|
|
518
|
+
return {
|
|
519
|
+
cancel: function() {
|
|
520
|
+
if (xhr && xhr.abort) {
|
|
521
|
+
xhr.abort();
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
};
|
|
525
|
+
};
|
|
526
|
+
Util.dataURIToBlob = function(dataURI) {
|
|
527
|
+
var byteString = atob(dataURI.split(",")[1]);
|
|
528
|
+
var mimeString = dataURI.split(",")[0].split(":")[1].split(";")[0];
|
|
529
|
+
var ab = new ArrayBuffer(byteString.length);
|
|
530
|
+
var ia = new Uint8Array(ab);
|
|
531
|
+
for (var i = 0; i < byteString.length; i++) {
|
|
532
|
+
ia[i] = byteString.charCodeAt(i);
|
|
533
|
+
}
|
|
534
|
+
var bb = new Blob([ ab ], {
|
|
535
|
+
type: mimeString
|
|
536
|
+
});
|
|
537
|
+
return bb;
|
|
538
|
+
};
|
|
539
|
+
Util.throttle = function(f, ms) {
|
|
540
|
+
var last = 0;
|
|
541
|
+
var to;
|
|
542
|
+
var args;
|
|
543
|
+
var defer = function(delay) {
|
|
544
|
+
to = setTimeout(function() {
|
|
545
|
+
to = undefined;
|
|
546
|
+
var now = +new Date;
|
|
547
|
+
var diff = now - last;
|
|
548
|
+
if (diff < ms) {
|
|
549
|
+
return void defer(ms - diff);
|
|
550
|
+
}
|
|
551
|
+
f.apply(null, args);
|
|
552
|
+
}, delay);
|
|
553
|
+
};
|
|
554
|
+
var g = function() {
|
|
555
|
+
last = +new Date;
|
|
556
|
+
args = Util.slice(arguments);
|
|
557
|
+
if (to) {
|
|
558
|
+
return;
|
|
559
|
+
}
|
|
560
|
+
defer(ms);
|
|
561
|
+
};
|
|
562
|
+
g.clear = function() {
|
|
563
|
+
clearTimeout(to);
|
|
564
|
+
to = undefined;
|
|
565
|
+
};
|
|
566
|
+
return g;
|
|
567
|
+
};
|
|
568
|
+
Util.notAgainForAnother = function(f, t) {
|
|
569
|
+
if (typeof f !== "function" || typeof t !== "number") {
|
|
570
|
+
throw new Error("invalid inputs");
|
|
571
|
+
}
|
|
572
|
+
var last = null;
|
|
573
|
+
return function() {
|
|
574
|
+
var now = +new Date;
|
|
575
|
+
if (last && now <= last + t) {
|
|
576
|
+
return t - (now - last);
|
|
577
|
+
}
|
|
578
|
+
last = now;
|
|
579
|
+
f.apply(null, Util.slice(arguments));
|
|
580
|
+
return null;
|
|
581
|
+
};
|
|
582
|
+
};
|
|
583
|
+
Util.createRandomInteger = function() {
|
|
584
|
+
return Math.floor(Math.random() * Number.MAX_SAFE_INTEGER);
|
|
585
|
+
};
|
|
586
|
+
Util.noop = function() {};
|
|
587
|
+
Util.once = function(f, g) {
|
|
588
|
+
return function() {
|
|
589
|
+
if (!f) {
|
|
590
|
+
return;
|
|
591
|
+
}
|
|
592
|
+
f.apply(this, Array.prototype.slice.call(arguments));
|
|
593
|
+
f = g;
|
|
594
|
+
};
|
|
595
|
+
};
|
|
596
|
+
Util.blobToImage = function(blob, cb) {
|
|
597
|
+
var reader = new FileReader;
|
|
598
|
+
reader.onloadend = function() {
|
|
599
|
+
cb(reader.result);
|
|
600
|
+
};
|
|
601
|
+
reader.readAsDataURL(blob);
|
|
602
|
+
};
|
|
603
|
+
Util.blobURLToImage = function(url, cb) {
|
|
604
|
+
var xhr = new XMLHttpRequest;
|
|
605
|
+
xhr.onload = function() {
|
|
606
|
+
var reader = new FileReader;
|
|
607
|
+
reader.onloadend = function() {
|
|
608
|
+
cb(reader.result);
|
|
609
|
+
};
|
|
610
|
+
reader.readAsDataURL(xhr.response);
|
|
611
|
+
};
|
|
612
|
+
xhr.open("GET", url);
|
|
613
|
+
xhr.responseType = "blob";
|
|
614
|
+
xhr.send();
|
|
615
|
+
};
|
|
616
|
+
Util.isObject = function(o) {
|
|
617
|
+
return typeof o === "object" && Object.prototype.toString.call(o) === "[object Object]";
|
|
618
|
+
};
|
|
619
|
+
Util.isCircular = function(o) {
|
|
620
|
+
try {
|
|
621
|
+
JSON.stringify(o);
|
|
622
|
+
return false;
|
|
623
|
+
} catch (e) {
|
|
624
|
+
return true;
|
|
625
|
+
}
|
|
626
|
+
};
|
|
627
|
+
Util.extend = function(a, b) {
|
|
628
|
+
if (!Util.isObject(a) || !Util.isObject(b)) {
|
|
629
|
+
return void console.log("Extend only works with 2 objects");
|
|
630
|
+
}
|
|
631
|
+
if (Util.isCircular(b)) {
|
|
632
|
+
return void console.log("Extend doesn't accept circular objects");
|
|
633
|
+
}
|
|
634
|
+
for (var k in b) {
|
|
635
|
+
if (Util.isObject(b[k])) {
|
|
636
|
+
a[k] = Util.isObject(a[k]) ? a[k] : {};
|
|
637
|
+
Util.extend(a[k], b[k]);
|
|
638
|
+
continue;
|
|
639
|
+
}
|
|
640
|
+
if (Array.isArray(b[k])) {
|
|
641
|
+
a[k] = b[k].slice();
|
|
642
|
+
continue;
|
|
643
|
+
}
|
|
644
|
+
a[k] = b[k];
|
|
645
|
+
}
|
|
646
|
+
};
|
|
647
|
+
Util.isChecked = function(el) {
|
|
648
|
+
if (!el) {
|
|
649
|
+
return false;
|
|
650
|
+
}
|
|
651
|
+
if (typeof el.tagName !== "undefined") {
|
|
652
|
+
return Boolean(el.checked);
|
|
653
|
+
}
|
|
654
|
+
if (typeof el.prop === "function") {
|
|
655
|
+
return Boolean(el.prop("checked"));
|
|
656
|
+
}
|
|
657
|
+
return false;
|
|
658
|
+
};
|
|
659
|
+
Util.hexToRGB = function(hex) {
|
|
660
|
+
var h = hex.replace(/^#/, "");
|
|
661
|
+
return [ parseInt(h.slice(0, 2), 16), parseInt(h.slice(2, 4), 16), parseInt(h.slice(4, 6), 16) ];
|
|
662
|
+
};
|
|
663
|
+
Util.rgbToHex = function(rgb) {
|
|
664
|
+
return `#${rgb.match(/^rgb\((\d+),\s*(\d+),\s*(\d+)\)$/).slice(1).map(n => parseInt(n, 10).toString(16).padStart(2, "0")).join("")}`;
|
|
665
|
+
};
|
|
666
|
+
Util.isSmallScreen = function() {
|
|
667
|
+
return window.innerHeight < 800 || window.innerWidth < 800;
|
|
668
|
+
};
|
|
669
|
+
Util.stripTags = function(text) {
|
|
670
|
+
var div = document.createElement("div");
|
|
671
|
+
div.innerHTML = text;
|
|
672
|
+
return div.innerText;
|
|
673
|
+
};
|
|
674
|
+
Util.parseFilename = function(filename) {
|
|
675
|
+
if (!filename || !filename.trim()) {
|
|
676
|
+
return {};
|
|
677
|
+
}
|
|
678
|
+
var parsedName = /^(\.?.+?)(\.[^.]+)?$/.exec(filename) || [];
|
|
679
|
+
return {
|
|
680
|
+
name: parsedName[1],
|
|
681
|
+
ext: parsedName[2]
|
|
682
|
+
};
|
|
683
|
+
};
|
|
684
|
+
Util.isPlainTextFile = function(type, name) {
|
|
685
|
+
if (type && type.indexOf("text/") === 0) {
|
|
686
|
+
return true;
|
|
687
|
+
}
|
|
688
|
+
var parsedName = Util.parseFilename(name);
|
|
689
|
+
if (!type && name && !parsedName.ext) {
|
|
690
|
+
return true;
|
|
691
|
+
}
|
|
692
|
+
if (type === "application/x-javascript") {
|
|
693
|
+
return true;
|
|
694
|
+
}
|
|
695
|
+
if (type === "application/xml") {
|
|
696
|
+
return true;
|
|
697
|
+
}
|
|
698
|
+
return false;
|
|
699
|
+
};
|
|
700
|
+
Util.isSpreadsheet = function(type, name) {
|
|
701
|
+
return type && (type === "application/vnd.oasis.opendocument.spreadsheet" || type === "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet") || name && (name.endsWith(".xlsx") || name.endsWith(".ods"));
|
|
702
|
+
};
|
|
703
|
+
Util.isOfficeDoc = function(type, name) {
|
|
704
|
+
return type && (type === "application/vnd.oasis.opendocument.text" || type === "application/vnd.openxmlformats-officedocument.wordprocessingml.document") || name && (name.endsWith(".docx") || name.endsWith(".odt"));
|
|
705
|
+
};
|
|
706
|
+
Util.isPresentation = function(type, name) {
|
|
707
|
+
return type && (type === "application/vnd.oasis.opendocument.presentation" || type === "application/vnd.openxmlformats-officedocument.presentationml.presentation") || name && (name.endsWith(".pptx") || name.endsWith(".odp"));
|
|
708
|
+
};
|
|
709
|
+
Util.isValidURL = function(str) {
|
|
710
|
+
var pattern = new RegExp("^(https?:\\/\\/)" + "((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|" + "((\\d{1,3}\\.){3}\\d{1,3}))" + "(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*" + "(\\?[;&a-z\\d%_.~+=-]*)?");
|
|
711
|
+
return !!pattern.test(str);
|
|
712
|
+
};
|
|
713
|
+
var emoji_patt = /([\uD800-\uDBFF][\uDC00-\uDFFF])/;
|
|
714
|
+
var isEmoji = function(str) {
|
|
715
|
+
return emoji_patt.test(str);
|
|
716
|
+
};
|
|
717
|
+
var emojiStringToArray = function(str) {
|
|
718
|
+
var split = str.split(emoji_patt);
|
|
719
|
+
var arr = [];
|
|
720
|
+
for (var i = 0; i < split.length; i++) {
|
|
721
|
+
var char = split[i];
|
|
722
|
+
if (char !== "") {
|
|
723
|
+
arr.push(char);
|
|
724
|
+
}
|
|
725
|
+
}
|
|
726
|
+
return arr;
|
|
727
|
+
};
|
|
728
|
+
Util.getFirstCharacter = function(str) {
|
|
729
|
+
if (!str || !str.trim()) {
|
|
730
|
+
return "?";
|
|
731
|
+
}
|
|
732
|
+
var emojis = emojiStringToArray(str);
|
|
733
|
+
return isEmoji(emojis[0]) ? emojis[0] : str[0];
|
|
734
|
+
};
|
|
735
|
+
Util.getRandomColor = function(light) {
|
|
736
|
+
var getColor = function() {
|
|
737
|
+
if (light) {
|
|
738
|
+
return Math.floor(Math.random() * 156) + 70;
|
|
739
|
+
}
|
|
740
|
+
return Math.floor(Math.random() * 200) + 25;
|
|
741
|
+
};
|
|
742
|
+
return "#" + getColor().toString(16) + getColor().toString(16) + getColor().toString(16);
|
|
743
|
+
};
|
|
744
|
+
Util.checkRestrictedApp = function(app, AppConfig, earlyTypes, plan, loggedIn) {
|
|
745
|
+
if (Array.isArray(earlyTypes) && earlyTypes.includes(app) && !AppConfig.enableEarlyAccess) {
|
|
746
|
+
return -2;
|
|
747
|
+
}
|
|
748
|
+
var premiumTypes = AppConfig.premiumTypes;
|
|
749
|
+
if (!Array.isArray(premiumTypes) || !premiumTypes.includes(app)) {
|
|
750
|
+
return 2;
|
|
751
|
+
}
|
|
752
|
+
if (!loggedIn) {
|
|
753
|
+
return -1;
|
|
754
|
+
}
|
|
755
|
+
return plan ? 1 : 0;
|
|
756
|
+
};
|
|
757
|
+
var supportsSharedArrayBuffers = function() {
|
|
758
|
+
try {
|
|
759
|
+
return Object.prototype.toString.call(new window.WebAssembly.Memory({
|
|
760
|
+
shared: true,
|
|
761
|
+
initial: 0,
|
|
762
|
+
maximum: 0
|
|
763
|
+
}).buffer) === "[object SharedArrayBuffer]";
|
|
764
|
+
} catch (err) {
|
|
765
|
+
console.error(err);
|
|
766
|
+
}
|
|
767
|
+
return false;
|
|
768
|
+
};
|
|
769
|
+
Util.supportsWasm = function() {
|
|
770
|
+
return !(typeof Atomics === "undefined" || !supportsSharedArrayBuffers() || typeof WebAssembly === "undefined");
|
|
771
|
+
};
|
|
772
|
+
Util.getKeysArray = function(length) {
|
|
773
|
+
return [ ...Array(length).keys() ];
|
|
774
|
+
};
|
|
775
|
+
Util.getVersionFromUrlArgs = urlArgs => {
|
|
776
|
+
let arr = /ver=([0-9.]+)(-[0-9]*)?/.exec(urlArgs);
|
|
777
|
+
let ver = Array.isArray(arr) && arr[1];
|
|
778
|
+
return ver || undefined;
|
|
779
|
+
};
|
|
780
|
+
Util.Saferphore = {
|
|
781
|
+
create: resourceCount => {
|
|
782
|
+
var queue = [];
|
|
783
|
+
var check;
|
|
784
|
+
var mkRa = function() {
|
|
785
|
+
var outerCalled = 0;
|
|
786
|
+
return function(func) {
|
|
787
|
+
if (outerCalled++) {
|
|
788
|
+
throw new Error("returnAfter() called multiple times");
|
|
789
|
+
}
|
|
790
|
+
var called = 0;
|
|
791
|
+
return function() {
|
|
792
|
+
if (called++) {
|
|
793
|
+
throw new Error("returnAfter wrapped callback called multiple times");
|
|
794
|
+
}
|
|
795
|
+
if (func) {
|
|
796
|
+
func.apply(null, arguments);
|
|
797
|
+
}
|
|
798
|
+
resourceCount++;
|
|
799
|
+
check();
|
|
800
|
+
};
|
|
801
|
+
};
|
|
802
|
+
};
|
|
803
|
+
check = function() {
|
|
804
|
+
if (resourceCount < 0) {
|
|
805
|
+
throw new Error("(resourceCount < 0) should never happen");
|
|
806
|
+
}
|
|
807
|
+
if (resourceCount === 0 || queue.length === 0) {
|
|
808
|
+
return;
|
|
809
|
+
}
|
|
810
|
+
resourceCount--;
|
|
811
|
+
queue.shift()(mkRa());
|
|
812
|
+
};
|
|
813
|
+
return {
|
|
814
|
+
take: function(func) {
|
|
815
|
+
queue.push(func);
|
|
816
|
+
check();
|
|
817
|
+
}
|
|
818
|
+
};
|
|
819
|
+
}
|
|
820
|
+
};
|
|
821
|
+
return Util;
|
|
822
|
+
};
|
|
823
|
+
if (module.exports) {
|
|
824
|
+
module.exports = factory(require$$0);
|
|
825
|
+
}
|
|
826
|
+
})(typeof self !== "undefined" ? self : commonUtil$1);
|
|
827
|
+
})(commonUtil$2);
|
|
828
|
+
return commonUtil$2.exports;
|
|
829
|
+
}
|
|
830
|
+
|
|
831
|
+
var version = "0.0.1";
|
|
832
|
+
|
|
833
|
+
var require$$2 = {
|
|
834
|
+
version
|
|
835
|
+
};
|
|
836
|
+
|
|
837
|
+
var keys = {
|
|
838
|
+
exports: {}
|
|
839
|
+
};
|
|
840
|
+
|
|
841
|
+
var hasRequiredKeys;
|
|
842
|
+
|
|
843
|
+
function requireKeys() {
|
|
844
|
+
if (hasRequiredKeys) return keys.exports;
|
|
845
|
+
hasRequiredKeys = 1;
|
|
846
|
+
(function(module) {
|
|
847
|
+
(function() {
|
|
848
|
+
var factory = function() {
|
|
849
|
+
var Keys = {};
|
|
850
|
+
var unescape = function(s) {
|
|
851
|
+
return s.replace(/-/g, "/");
|
|
852
|
+
};
|
|
853
|
+
var parseNewUser = function(userString) {
|
|
854
|
+
if (!/^\[.*?@.*\]$/.test(userString)) {
|
|
855
|
+
return;
|
|
856
|
+
}
|
|
857
|
+
var temp = userString.slice(1, -1);
|
|
858
|
+
var domain, username, pubkey;
|
|
859
|
+
temp = temp.replace(/\/([a-zA-Z0-9+-]{43}=)$/, function(all, k) {
|
|
860
|
+
pubkey = unescape(k);
|
|
861
|
+
return "";
|
|
862
|
+
});
|
|
863
|
+
if (!pubkey) {
|
|
864
|
+
return;
|
|
865
|
+
}
|
|
866
|
+
var index = temp.lastIndexOf("@");
|
|
867
|
+
if (index < 1) {
|
|
868
|
+
return;
|
|
869
|
+
}
|
|
870
|
+
domain = temp.slice(index + 1);
|
|
871
|
+
username = temp.slice(0, index);
|
|
872
|
+
return {
|
|
873
|
+
domain,
|
|
874
|
+
user: username,
|
|
875
|
+
pubkey
|
|
876
|
+
};
|
|
877
|
+
};
|
|
878
|
+
var isValidUser = function(parsed) {
|
|
879
|
+
if (!parsed) {
|
|
880
|
+
return;
|
|
881
|
+
}
|
|
882
|
+
if (!(parsed.domain && parsed.user && parsed.pubkey)) {
|
|
883
|
+
return;
|
|
884
|
+
}
|
|
885
|
+
return true;
|
|
886
|
+
};
|
|
887
|
+
Keys.parseUser = function(user) {
|
|
888
|
+
var parsed = parseNewUser(user);
|
|
889
|
+
if (isValidUser(parsed)) {
|
|
890
|
+
return parsed;
|
|
891
|
+
}
|
|
892
|
+
var domain, username, pubkey;
|
|
893
|
+
user.replace(/^https*:\/\/([^\/]+)\/user\/#\/1\/([^\/]+)\/([a-zA-Z0-9+-]{43}=)$/, function(a, d, u, k) {
|
|
894
|
+
domain = d;
|
|
895
|
+
username = u;
|
|
896
|
+
pubkey = unescape(k);
|
|
897
|
+
return "";
|
|
898
|
+
});
|
|
899
|
+
if (!domain) {
|
|
900
|
+
throw new Error("Could not parse user id [" + user + "]");
|
|
901
|
+
}
|
|
902
|
+
return {
|
|
903
|
+
domain,
|
|
904
|
+
user: username,
|
|
905
|
+
pubkey
|
|
906
|
+
};
|
|
907
|
+
};
|
|
908
|
+
Keys.serialize = function(origin, username, pubkey) {
|
|
909
|
+
return "[" + username + "@" + origin.replace(/https*:\/\//, "") + "/" + pubkey.replace(/\//g, "-") + "]";
|
|
910
|
+
};
|
|
911
|
+
Keys.canonicalize = function(input) {
|
|
912
|
+
if (typeof input !== "string") {
|
|
913
|
+
return;
|
|
914
|
+
}
|
|
915
|
+
if (input.length === 44) {
|
|
916
|
+
return unescape(input);
|
|
917
|
+
}
|
|
918
|
+
try {
|
|
919
|
+
return Keys.parseUser(input).pubkey;
|
|
920
|
+
} catch (err) {
|
|
921
|
+
return;
|
|
922
|
+
}
|
|
923
|
+
};
|
|
924
|
+
return Keys;
|
|
925
|
+
};
|
|
926
|
+
if (module.exports) {
|
|
927
|
+
module.exports = factory();
|
|
928
|
+
}
|
|
929
|
+
})();
|
|
930
|
+
})(keys);
|
|
931
|
+
return keys.exports;
|
|
932
|
+
}
|
|
933
|
+
|
|
934
|
+
var core = {
|
|
935
|
+
exports: {}
|
|
936
|
+
};
|
|
937
|
+
|
|
938
|
+
var constants;
|
|
939
|
+
|
|
940
|
+
var hasRequiredConstants;
|
|
941
|
+
|
|
942
|
+
function requireConstants() {
|
|
943
|
+
if (hasRequiredConstants) return constants;
|
|
944
|
+
hasRequiredConstants = 1;
|
|
945
|
+
const Constants = {};
|
|
946
|
+
Constants.CHECKPOINT_PATTERN = /^cp\|(([A-Za-z0-9+/=]+)\|)?/;
|
|
947
|
+
Constants.STANDARD_CHANNEL_LENGTH = 32;
|
|
948
|
+
Constants.ADMIN_CHANNEL_LENGTH = 33;
|
|
949
|
+
Constants.EPHEMERAL_CHANNEL_LENGTH = 34;
|
|
950
|
+
Constants.BLOB_ID_LENGTH = 48;
|
|
951
|
+
Constants.publicKeyLength = 32;
|
|
952
|
+
Constants.hkId = "0123456789abcdef";
|
|
953
|
+
Constants.TEMPORARY_CHANNEL_LIFETIME = 30 * 1e3;
|
|
954
|
+
Constants.paths = {
|
|
955
|
+
base: "./data/",
|
|
956
|
+
channel: "channel/",
|
|
957
|
+
blob: "blob/",
|
|
958
|
+
blobstage: "blobstage/",
|
|
959
|
+
block: "block/",
|
|
960
|
+
pin: "pins/",
|
|
961
|
+
archive: "archive/",
|
|
962
|
+
tasks: "tasks/",
|
|
963
|
+
decrees: "decrees/",
|
|
964
|
+
challenges: "challenges/",
|
|
965
|
+
logo: "logo/"
|
|
966
|
+
};
|
|
967
|
+
Constants.adminDecree = "decree.ndjson";
|
|
968
|
+
constants = Constants;
|
|
969
|
+
return constants;
|
|
970
|
+
}
|
|
971
|
+
|
|
972
|
+
var hasRequiredCore;
|
|
973
|
+
|
|
974
|
+
function requireCore() {
|
|
975
|
+
if (hasRequiredCore) return core.exports;
|
|
976
|
+
hasRequiredCore = 1;
|
|
977
|
+
(function(module) {
|
|
978
|
+
const Core = module.exports;
|
|
979
|
+
const Util = requireCommonUtil$1();
|
|
980
|
+
const Constants = requireConstants();
|
|
981
|
+
const escapeKeyCharacters = Util.escapeKeyCharacters;
|
|
982
|
+
const Path = require$$1;
|
|
983
|
+
const Crypto = require$$3;
|
|
984
|
+
const Keys = requireKeys();
|
|
985
|
+
Core.DEFAULT_LIMIT = 50 * 1024 * 1024;
|
|
986
|
+
Core.SESSION_EXPIRATION_TIME = 60 * 1e3;
|
|
987
|
+
Core.isValidId = chan => chan && chan.length && /^[a-zA-Z0-9=+-]*$/.test(chan) && [ Constants.STANDARD_CHANNEL_LENGTH, Constants.ADMIN_CHANNEL_LENGTH, Constants.BLOB_ID_LENGTH ].indexOf(chan.length) > -1;
|
|
988
|
+
Core.isValidPublicKey = owner => typeof owner === "string" && owner.length === 44;
|
|
989
|
+
Core.isValidBlockId = id => typeof id === "string" && id.length === 44;
|
|
990
|
+
const makeToken = Core.makeToken = () => Number(Math.floor(Math.random() * Number.MAX_SAFE_INTEGER)).toString(16);
|
|
991
|
+
Core.makeCookie = function(token) {
|
|
992
|
+
let time = +new Date;
|
|
993
|
+
time -= time % 5e3;
|
|
994
|
+
return [ time, process.pid, token ];
|
|
995
|
+
};
|
|
996
|
+
const parseCookie = cookie => {
|
|
997
|
+
if (!(cookie && cookie.split)) {
|
|
998
|
+
return null;
|
|
999
|
+
}
|
|
1000
|
+
let parts = cookie.split("|");
|
|
1001
|
+
if (parts.length !== 3) {
|
|
1002
|
+
return null;
|
|
1003
|
+
}
|
|
1004
|
+
let c = {};
|
|
1005
|
+
c.time = new Date(parts[0]);
|
|
1006
|
+
c.pid = Number(parts[1]);
|
|
1007
|
+
c.seq = parts[2];
|
|
1008
|
+
return c;
|
|
1009
|
+
};
|
|
1010
|
+
Core.getSession = (Sessions, key) => {
|
|
1011
|
+
let safeKey = escapeKeyCharacters(key);
|
|
1012
|
+
if (Sessions[safeKey]) {
|
|
1013
|
+
Sessions[safeKey].atime = +new Date;
|
|
1014
|
+
return Sessions[safeKey];
|
|
1015
|
+
}
|
|
1016
|
+
let user = Sessions[safeKey] = {};
|
|
1017
|
+
user.atime = +new Date;
|
|
1018
|
+
user.tokens = [ makeToken() ];
|
|
1019
|
+
return user;
|
|
1020
|
+
};
|
|
1021
|
+
Core.expireSession = (Sessions, safeKey) => {
|
|
1022
|
+
let session = Sessions[safeKey];
|
|
1023
|
+
if (!session) {
|
|
1024
|
+
return;
|
|
1025
|
+
}
|
|
1026
|
+
if (session.blobstage) {
|
|
1027
|
+
session.blobstage.close();
|
|
1028
|
+
}
|
|
1029
|
+
delete Sessions[safeKey];
|
|
1030
|
+
};
|
|
1031
|
+
Core.expireSessionAsync = (Env, safeKey, cb) => {
|
|
1032
|
+
setTimeout(() => {
|
|
1033
|
+
Core.expireSession(Env.Sessions, safeKey);
|
|
1034
|
+
cb(void 0, "OK");
|
|
1035
|
+
});
|
|
1036
|
+
};
|
|
1037
|
+
const isTooOld = (time, now) => now - time > 3e5;
|
|
1038
|
+
Core.expireSessions = Sessions => {
|
|
1039
|
+
let now = +new Date;
|
|
1040
|
+
Object.keys(Sessions).forEach(safeKey => {
|
|
1041
|
+
let session = Sessions[safeKey];
|
|
1042
|
+
if (session && isTooOld(session.atime, now)) {
|
|
1043
|
+
Core.expireSession(Sessions, safeKey);
|
|
1044
|
+
}
|
|
1045
|
+
});
|
|
1046
|
+
};
|
|
1047
|
+
const addTokenForKey = (Sessions, publicKey, token) => {
|
|
1048
|
+
if (!Sessions[publicKey]) {
|
|
1049
|
+
throw new Error("undefined user");
|
|
1050
|
+
}
|
|
1051
|
+
let user = Core.getSession(Sessions, publicKey);
|
|
1052
|
+
user.tokens.push(token);
|
|
1053
|
+
user.atime = +new Date;
|
|
1054
|
+
if (user.tokens.length > 2) {
|
|
1055
|
+
user.tokens.shift();
|
|
1056
|
+
}
|
|
1057
|
+
};
|
|
1058
|
+
Core.isValidCookie = (Sessions, publicKey, cookie) => {
|
|
1059
|
+
let parsed = parseCookie(cookie);
|
|
1060
|
+
if (!parsed) {
|
|
1061
|
+
return false;
|
|
1062
|
+
}
|
|
1063
|
+
let now = +new Date;
|
|
1064
|
+
if (!parsed.time) {
|
|
1065
|
+
return false;
|
|
1066
|
+
}
|
|
1067
|
+
if (isTooOld(parsed.time, now)) {
|
|
1068
|
+
return false;
|
|
1069
|
+
}
|
|
1070
|
+
if (process.pid !== parsed.pid) {
|
|
1071
|
+
return false;
|
|
1072
|
+
}
|
|
1073
|
+
let user = Core.getSession(Sessions, publicKey);
|
|
1074
|
+
if (!user) {
|
|
1075
|
+
return false;
|
|
1076
|
+
}
|
|
1077
|
+
let idx = user.tokens.indexOf(parsed.seq);
|
|
1078
|
+
if (idx === -1) {
|
|
1079
|
+
return false;
|
|
1080
|
+
}
|
|
1081
|
+
if (idx > 0) {
|
|
1082
|
+
addTokenForKey(Sessions, publicKey, Core.makeToken());
|
|
1083
|
+
}
|
|
1084
|
+
return true;
|
|
1085
|
+
};
|
|
1086
|
+
Core.hasOwners = function(metadata) {
|
|
1087
|
+
return Boolean(metadata && Array.isArray(metadata.owners));
|
|
1088
|
+
};
|
|
1089
|
+
Core.hasPendingOwners = function(metadata) {
|
|
1090
|
+
return Boolean(metadata && Array.isArray(metadata.pending_owners));
|
|
1091
|
+
};
|
|
1092
|
+
Core.isOwner = function(metadata, unsafeKey) {
|
|
1093
|
+
return metadata.owners.indexOf(unsafeKey) !== -1;
|
|
1094
|
+
};
|
|
1095
|
+
Core.isPendingOwner = function(metadata, unsafeKey) {
|
|
1096
|
+
return metadata.pending_owners.indexOf(unsafeKey) !== -1;
|
|
1097
|
+
};
|
|
1098
|
+
Core.haveACookie = function(Env, safeKey, cb) {
|
|
1099
|
+
cb();
|
|
1100
|
+
};
|
|
1101
|
+
Core.getPaths = (mainConfig, isEnv) => {
|
|
1102
|
+
const {index, config} = mainConfig;
|
|
1103
|
+
const paths = Constants.paths;
|
|
1104
|
+
const idx = String(index);
|
|
1105
|
+
const all = {
|
|
1106
|
+
basePath: config.basePath || Path.join(paths.base, idx),
|
|
1107
|
+
filePath: config.filePath || Path.join(paths.base, idx, paths.channel),
|
|
1108
|
+
blobPath: config.blobPath || Path.join(paths.base, idx, paths.blob),
|
|
1109
|
+
blobStagingPath: config.blobStagingPath || Path.join(paths.base, idx, paths.blobstage),
|
|
1110
|
+
blockPath: config.blockPath || Path.join(paths.base, idx, paths.block),
|
|
1111
|
+
pinPath: config.pinPath || Path.join(paths.base, idx, paths.pin),
|
|
1112
|
+
archivePath: config.archivePath || Path.join(paths.base, idx, paths.archive),
|
|
1113
|
+
taskPath: config.taskPath || Path.join(paths.base, idx, paths.tasks),
|
|
1114
|
+
decreePath: config.decreePath || Path.join(paths.base, "0", paths.decrees),
|
|
1115
|
+
logoPath: config.logoPath || Path.join(paths.base, "0", paths.logo),
|
|
1116
|
+
challengePath: config.challengePath || Path.join(paths.base, idx, paths.challenges)
|
|
1117
|
+
};
|
|
1118
|
+
if (!isEnv) {
|
|
1119
|
+
return all;
|
|
1120
|
+
}
|
|
1121
|
+
return {
|
|
1122
|
+
channel: all.filePath,
|
|
1123
|
+
data: all.filePath,
|
|
1124
|
+
blob: all.blobPath,
|
|
1125
|
+
block: all.blockPath,
|
|
1126
|
+
staging: all.blobStagingPath,
|
|
1127
|
+
pin: all.pinPath,
|
|
1128
|
+
decree: all.decreePath,
|
|
1129
|
+
logo: all.logoPath,
|
|
1130
|
+
base: all.basePath,
|
|
1131
|
+
archive: all.archivePath,
|
|
1132
|
+
task: all.taskPath
|
|
1133
|
+
};
|
|
1134
|
+
};
|
|
1135
|
+
Core.getChannelsStorage = (Env, channels) => {
|
|
1136
|
+
const channelsByStorage = {};
|
|
1137
|
+
channels.forEach(channel => {
|
|
1138
|
+
const storageId = Env.getStorageId(channel);
|
|
1139
|
+
const list = channelsByStorage[storageId] ||= new Set;
|
|
1140
|
+
list.add(channel);
|
|
1141
|
+
});
|
|
1142
|
+
Object.keys(channelsByStorage).forEach(storageId => {
|
|
1143
|
+
channelsByStorage[storageId] = Array.from(channelsByStorage[storageId]);
|
|
1144
|
+
});
|
|
1145
|
+
return channelsByStorage;
|
|
1146
|
+
};
|
|
1147
|
+
Core.getChannelsCore = (Env, channels) => {
|
|
1148
|
+
const channelsByCore = {};
|
|
1149
|
+
channels.forEach(channel => {
|
|
1150
|
+
const coreId = Env.getCoreId(channel);
|
|
1151
|
+
const list = channelsByCore[coreId] ||= new Set;
|
|
1152
|
+
list.add(channel);
|
|
1153
|
+
});
|
|
1154
|
+
Object.keys(channelsByCore).forEach(coreId => {
|
|
1155
|
+
channelsByCore[coreId] = Array.from(channelsByCore[coreId]);
|
|
1156
|
+
});
|
|
1157
|
+
return channelsByCore;
|
|
1158
|
+
};
|
|
1159
|
+
Core.getUsersFront = (Env, users) => {
|
|
1160
|
+
const usersByFront = {};
|
|
1161
|
+
users.forEach(userId => {
|
|
1162
|
+
const frontId = Env.userCache?.[userId]?.from;
|
|
1163
|
+
if (!frontId) {
|
|
1164
|
+
return;
|
|
1165
|
+
}
|
|
1166
|
+
const list = usersByFront[frontId] ||= new Set;
|
|
1167
|
+
list.add(userId);
|
|
1168
|
+
});
|
|
1169
|
+
Object.keys(usersByFront).forEach(frontId => {
|
|
1170
|
+
usersByFront[frontId] = Array.from(usersByFront[frontId]);
|
|
1171
|
+
});
|
|
1172
|
+
return usersByFront;
|
|
1173
|
+
};
|
|
1174
|
+
const validLimitFields = [ "limit", "plan", "note", "users", "origin" ];
|
|
1175
|
+
Core.isValidLimit = o => {
|
|
1176
|
+
var valid = o && typeof o === "object" && typeof o.limit === "number" && typeof o.plan === "string" && typeof o.note === "string" && (Array.isArray(o.users) || typeof o.users === "undefined") && !Object.keys(o).some(function(k) {
|
|
1177
|
+
return validLimitFields.indexOf(k) === -1;
|
|
1178
|
+
});
|
|
1179
|
+
return valid;
|
|
1180
|
+
};
|
|
1181
|
+
Core.applyLimits = Env => {
|
|
1182
|
+
const customLimits = function(custom) {
|
|
1183
|
+
const limits = {};
|
|
1184
|
+
Object.keys(custom).forEach(k => {
|
|
1185
|
+
const unsafeKey = Keys.canonicalize(k);
|
|
1186
|
+
if (!unsafeKey) {
|
|
1187
|
+
return;
|
|
1188
|
+
}
|
|
1189
|
+
limits[unsafeKey] = custom[k];
|
|
1190
|
+
});
|
|
1191
|
+
return limits;
|
|
1192
|
+
}(Env.customLimits || {});
|
|
1193
|
+
Env.limits = Env.limits || {};
|
|
1194
|
+
Object.keys(customLimits).forEach(k => {
|
|
1195
|
+
if (!Core.isValidLimit(customLimits[k])) {
|
|
1196
|
+
return;
|
|
1197
|
+
}
|
|
1198
|
+
Env.limits[k] = customLimits[k];
|
|
1199
|
+
});
|
|
1200
|
+
};
|
|
1201
|
+
Core.coreToStorage = (Env, id, cmd, data, cb) => {
|
|
1202
|
+
const storageId = Env.getStorageId(id);
|
|
1203
|
+
Env.interface.sendQuery(storageId, cmd, data, res => {
|
|
1204
|
+
if (res.error) {
|
|
1205
|
+
return void cb(res.error);
|
|
1206
|
+
}
|
|
1207
|
+
cb(void 0, res.data);
|
|
1208
|
+
});
|
|
1209
|
+
};
|
|
1210
|
+
Core.storageToStorage = (Env, id, cmd, data, cb) => {
|
|
1211
|
+
if (id === "all") {
|
|
1212
|
+
Env.interface.broadcast("storage", cmd, data, (errors, data) => {
|
|
1213
|
+
if (errors && errors.length) {
|
|
1214
|
+
return void cb(errors, data);
|
|
1215
|
+
}
|
|
1216
|
+
cb(void 0, data);
|
|
1217
|
+
});
|
|
1218
|
+
return;
|
|
1219
|
+
}
|
|
1220
|
+
const storageId = Env.getStorageId(id);
|
|
1221
|
+
Env.interface.sendQuery(storageId, cmd, data, res => {
|
|
1222
|
+
if (res.error) {
|
|
1223
|
+
return void cb(res.error);
|
|
1224
|
+
}
|
|
1225
|
+
cb(void 0, res.data);
|
|
1226
|
+
});
|
|
1227
|
+
};
|
|
1228
|
+
Core.storageToFront = (Env, cmd, data, cb) => {
|
|
1229
|
+
const id = String(+new Date);
|
|
1230
|
+
const coreId = Env.getCoreId(id);
|
|
1231
|
+
Env.interface.sendQuery(coreId, "STORAGE_FRONT", {
|
|
1232
|
+
cmd,
|
|
1233
|
+
data
|
|
1234
|
+
}, res => {
|
|
1235
|
+
if (res.error) {
|
|
1236
|
+
return void cb(res.error);
|
|
1237
|
+
}
|
|
1238
|
+
cb(void 0, res.data);
|
|
1239
|
+
});
|
|
1240
|
+
};
|
|
1241
|
+
Core.checkStorage = (Env, id, cmd, data, cb) => {
|
|
1242
|
+
const storageId = Env.getStorageId(id);
|
|
1243
|
+
if (storageId !== Env.myId) {
|
|
1244
|
+
Core.storageToStorage(Env, id, cmd, data, cb);
|
|
1245
|
+
return false;
|
|
1246
|
+
}
|
|
1247
|
+
return true;
|
|
1248
|
+
};
|
|
1249
|
+
Core.createChannelId = () => Crypto.randomBytes(16).toString("hex");
|
|
1250
|
+
})(core);
|
|
1251
|
+
return core.exports;
|
|
1252
|
+
}
|
|
1253
|
+
|
|
1254
|
+
var defaults = {
|
|
1255
|
+
exports: {}
|
|
1256
|
+
};
|
|
1257
|
+
|
|
1258
|
+
var hasRequiredDefaults;
|
|
1259
|
+
|
|
1260
|
+
function requireDefaults() {
|
|
1261
|
+
if (hasRequiredDefaults) return defaults.exports;
|
|
1262
|
+
hasRequiredDefaults = 1;
|
|
1263
|
+
(function(module) {
|
|
1264
|
+
var Default = module.exports;
|
|
1265
|
+
Default.commonCSP = function(Env) {
|
|
1266
|
+
var domain = Env.httpUnsafeOrigin;
|
|
1267
|
+
var sandbox = Env.httpSafeOrigin;
|
|
1268
|
+
sandbox = sandbox && sandbox !== domain ? sandbox : "";
|
|
1269
|
+
var accounts_api = Env.accounts_api || "";
|
|
1270
|
+
var wsURL = domain.replace("https://", "wss://").replace("http://", "ws://");
|
|
1271
|
+
return [ `default-src 'none'`, `style-src 'unsafe-inline' 'self' ${domain}`, `font-src 'self' data: ${domain}`, `child-src ${domain}`, `frame-src 'self' blob: ${sandbox}`, `connect-src 'self' blob: ${domain} ${sandbox} ${accounts_api} ${wsURL}`, `img-src 'self' data: blob: ${domain}`, `media-src blob:`, Env.enableEmbedding ? `frame-ancestors 'self' ${Env.protocol} vector:` : `frame-ancestors 'self' ${domain}`, `worker-src 'self'`, "" ];
|
|
1272
|
+
};
|
|
1273
|
+
Default.contentSecurity = function(Env) {
|
|
1274
|
+
return (Default.commonCSP(Env).join("; ") + "script-src 'self' resource: " + Env.httpUnsafeOrigin).replace(/\s+/g, " ");
|
|
1275
|
+
};
|
|
1276
|
+
Default.padContentSecurity = function(Env) {
|
|
1277
|
+
return (Default.commonCSP(Env).join("; ") + "script-src 'self' 'unsafe-eval' 'unsafe-inline' resource: " + Env.httpUnsafeOrigin).replace(/\s+/g, " ");
|
|
1278
|
+
};
|
|
1279
|
+
Default.httpHeaders = function(Env) {
|
|
1280
|
+
return {
|
|
1281
|
+
"X-XSS-Protection": "1; mode=block",
|
|
1282
|
+
"X-Content-Type-Options": "nosniff",
|
|
1283
|
+
"Access-Control-Allow-Origin": Env.enableEmbedding ? "*" : Env.permittedEmbedders,
|
|
1284
|
+
"Referrer-Policy": "same-origin",
|
|
1285
|
+
"Permissions-policy": "interest-cohort=()"
|
|
1286
|
+
};
|
|
1287
|
+
};
|
|
1288
|
+
Default.mainPages = function() {
|
|
1289
|
+
return [ "index", "contact", "features", "maintenance" ];
|
|
1290
|
+
};
|
|
1291
|
+
Default.recommendedVersion = [ 16, 14, 2 ];
|
|
1292
|
+
})(defaults);
|
|
1293
|
+
return defaults.exports;
|
|
1294
|
+
}
|
|
1295
|
+
|
|
1296
|
+
var streamFile = {
|
|
1297
|
+
exports: {}
|
|
1298
|
+
};
|
|
1299
|
+
|
|
1300
|
+
var hasRequiredStreamFile;
|
|
1301
|
+
|
|
1302
|
+
function requireStreamFile() {
|
|
1303
|
+
if (hasRequiredStreamFile) return streamFile.exports;
|
|
1304
|
+
hasRequiredStreamFile = 1;
|
|
1305
|
+
(function(module) {
|
|
1306
|
+
const ToPull = require$$0$1;
|
|
1307
|
+
const Pull = require$$1$1;
|
|
1308
|
+
const Stream = module.exports;
|
|
1309
|
+
const NEWLINE_CHR = "\n".charCodeAt(0);
|
|
1310
|
+
const mkBufferSplit = () => {
|
|
1311
|
+
let remainder = null;
|
|
1312
|
+
return Pull(read => (abort, cb) => {
|
|
1313
|
+
read(abort, function(end, data) {
|
|
1314
|
+
if (end) {
|
|
1315
|
+
if (data) {
|
|
1316
|
+
console.log("mkBufferSplit() Data at the end");
|
|
1317
|
+
}
|
|
1318
|
+
cb(end, remainder ? [ remainder, data ] : [ data ]);
|
|
1319
|
+
remainder = null;
|
|
1320
|
+
return;
|
|
1321
|
+
}
|
|
1322
|
+
const queue = [];
|
|
1323
|
+
for (;;) {
|
|
1324
|
+
const offset = data.indexOf(NEWLINE_CHR);
|
|
1325
|
+
if (offset < 0) {
|
|
1326
|
+
remainder = remainder ? Buffer.concat([ remainder, data ]) : data;
|
|
1327
|
+
break;
|
|
1328
|
+
}
|
|
1329
|
+
let subArray = data.slice(0, offset);
|
|
1330
|
+
if (remainder) {
|
|
1331
|
+
subArray = Buffer.concat([ remainder, subArray ]);
|
|
1332
|
+
remainder = null;
|
|
1333
|
+
}
|
|
1334
|
+
queue.push(subArray);
|
|
1335
|
+
data = data.slice(offset + 1);
|
|
1336
|
+
}
|
|
1337
|
+
cb(end, queue);
|
|
1338
|
+
});
|
|
1339
|
+
}, Pull.flatten());
|
|
1340
|
+
};
|
|
1341
|
+
const mkOffsetCounter = offset => {
|
|
1342
|
+
offset = offset || 0;
|
|
1343
|
+
return Pull.map(buff => {
|
|
1344
|
+
const out = {
|
|
1345
|
+
offset,
|
|
1346
|
+
buff
|
|
1347
|
+
};
|
|
1348
|
+
offset += buff.length + 1;
|
|
1349
|
+
return out;
|
|
1350
|
+
});
|
|
1351
|
+
};
|
|
1352
|
+
Stream.readFileBin = (stream, msgHandler, cb, opt) => {
|
|
1353
|
+
opt = opt || {};
|
|
1354
|
+
let keepReading = true;
|
|
1355
|
+
Pull(ToPull.read(stream), mkBufferSplit(), mkOffsetCounter(opt.offset), Pull.asyncMap((data, moreCb) => {
|
|
1356
|
+
msgHandler(data, moreCb, () => {
|
|
1357
|
+
try {
|
|
1358
|
+
stream.close();
|
|
1359
|
+
} catch (err) {
|
|
1360
|
+
console.error("READ_FILE_BIN_ERR", err);
|
|
1361
|
+
}
|
|
1362
|
+
keepReading = false;
|
|
1363
|
+
moreCb();
|
|
1364
|
+
});
|
|
1365
|
+
}), Pull.drain(() => keepReading, err => {
|
|
1366
|
+
cb(keepReading ? err : undefined);
|
|
1367
|
+
}));
|
|
1368
|
+
};
|
|
1369
|
+
})(streamFile);
|
|
1370
|
+
return streamFile.exports;
|
|
1371
|
+
}
|
|
1372
|
+
|
|
1373
|
+
var writeQueue;
|
|
1374
|
+
|
|
1375
|
+
var hasRequiredWriteQueue;
|
|
1376
|
+
|
|
1377
|
+
function requireWriteQueue() {
|
|
1378
|
+
if (hasRequiredWriteQueue) return writeQueue;
|
|
1379
|
+
hasRequiredWriteQueue = 1;
|
|
1380
|
+
var fix1 = function(f, x) {
|
|
1381
|
+
return function() {
|
|
1382
|
+
f(x);
|
|
1383
|
+
};
|
|
1384
|
+
};
|
|
1385
|
+
writeQueue = function() {
|
|
1386
|
+
var map = {};
|
|
1387
|
+
var next = function(id) {
|
|
1388
|
+
setTimeout(function() {
|
|
1389
|
+
if (!map[id] || map[id].length === 0) {
|
|
1390
|
+
return void delete map[id];
|
|
1391
|
+
}
|
|
1392
|
+
var task = map[id].shift();
|
|
1393
|
+
task(fix1(next, id));
|
|
1394
|
+
});
|
|
1395
|
+
};
|
|
1396
|
+
return function(id, task) {
|
|
1397
|
+
if (typeof id === "function" && typeof task === "undefined") {
|
|
1398
|
+
task = id;
|
|
1399
|
+
id = "";
|
|
1400
|
+
}
|
|
1401
|
+
if (typeof task !== "function") {
|
|
1402
|
+
throw new Error("Expected function");
|
|
1403
|
+
}
|
|
1404
|
+
if (map[id]) {
|
|
1405
|
+
return void map[id].push(task);
|
|
1406
|
+
}
|
|
1407
|
+
map[id] = [ task ];
|
|
1408
|
+
next(id);
|
|
1409
|
+
};
|
|
1410
|
+
};
|
|
1411
|
+
return writeQueue;
|
|
1412
|
+
}
|
|
1413
|
+
|
|
1414
|
+
var commonUtil;
|
|
1415
|
+
|
|
1416
|
+
var hasRequiredCommonUtil;
|
|
1417
|
+
|
|
1418
|
+
function requireCommonUtil() {
|
|
1419
|
+
if (hasRequiredCommonUtil) return commonUtil;
|
|
1420
|
+
hasRequiredCommonUtil = 1;
|
|
1421
|
+
commonUtil = requireCommonUtil$1();
|
|
1422
|
+
return commonUtil;
|
|
1423
|
+
}
|
|
1424
|
+
|
|
1425
|
+
var schedule;
|
|
1426
|
+
|
|
1427
|
+
var hasRequiredSchedule;
|
|
1428
|
+
|
|
1429
|
+
function requireSchedule() {
|
|
1430
|
+
if (hasRequiredSchedule) return schedule;
|
|
1431
|
+
hasRequiredSchedule = 1;
|
|
1432
|
+
var WriteQueue = requireWriteQueue();
|
|
1433
|
+
var Util = requireCommonUtil();
|
|
1434
|
+
var unusedUid = function(set) {
|
|
1435
|
+
var uid = Util.uid();
|
|
1436
|
+
if (set[uid]) {
|
|
1437
|
+
return unusedUid();
|
|
1438
|
+
}
|
|
1439
|
+
return uid;
|
|
1440
|
+
};
|
|
1441
|
+
var lookup = function(map, id) {
|
|
1442
|
+
return map[id] = map[id] || {
|
|
1443
|
+
active: {},
|
|
1444
|
+
blocked: {}
|
|
1445
|
+
};
|
|
1446
|
+
};
|
|
1447
|
+
var isEmpty = function(map) {
|
|
1448
|
+
for (var key in map) {
|
|
1449
|
+
if (Object.prototype.hasOwnProperty.call(map, key)) {
|
|
1450
|
+
return false;
|
|
1451
|
+
}
|
|
1452
|
+
}
|
|
1453
|
+
return true;
|
|
1454
|
+
};
|
|
1455
|
+
schedule = function() {
|
|
1456
|
+
var queue = WriteQueue();
|
|
1457
|
+
var Ordered = function(id, task) {
|
|
1458
|
+
queue(id, task);
|
|
1459
|
+
};
|
|
1460
|
+
var map = {};
|
|
1461
|
+
var collectGarbage = function(id) {
|
|
1462
|
+
var local = map[id];
|
|
1463
|
+
if (!local) {
|
|
1464
|
+
return;
|
|
1465
|
+
}
|
|
1466
|
+
if (local.lock) {
|
|
1467
|
+
return;
|
|
1468
|
+
}
|
|
1469
|
+
if (!isEmpty(local.active)) {
|
|
1470
|
+
return;
|
|
1471
|
+
}
|
|
1472
|
+
delete map[id];
|
|
1473
|
+
};
|
|
1474
|
+
var runImmediately = function(local, task) {
|
|
1475
|
+
var uid = unusedUid(local.active);
|
|
1476
|
+
local.active[uid] = true;
|
|
1477
|
+
task(function() {
|
|
1478
|
+
delete local.active[uid];
|
|
1479
|
+
if (!isEmpty(local.active)) {
|
|
1480
|
+
return;
|
|
1481
|
+
}
|
|
1482
|
+
if (typeof local.waiting !== "function") {
|
|
1483
|
+
return void collectGarbage();
|
|
1484
|
+
}
|
|
1485
|
+
setTimeout(local.waiting);
|
|
1486
|
+
});
|
|
1487
|
+
};
|
|
1488
|
+
var runOnceUnblocked = function(local, task) {
|
|
1489
|
+
var uid = unusedUid(local.blocked);
|
|
1490
|
+
local.blocked[uid] = function() {
|
|
1491
|
+
runImmediately(local, task);
|
|
1492
|
+
};
|
|
1493
|
+
};
|
|
1494
|
+
var Unordered = function(id, task) {
|
|
1495
|
+
var local = lookup(map, id);
|
|
1496
|
+
if (local.lock) {
|
|
1497
|
+
return runOnceUnblocked(local, task);
|
|
1498
|
+
}
|
|
1499
|
+
runImmediately(local, task);
|
|
1500
|
+
};
|
|
1501
|
+
var runBlocked = function(local) {
|
|
1502
|
+
for (var task in local.blocked) {
|
|
1503
|
+
runImmediately(local, local.blocked[task]);
|
|
1504
|
+
}
|
|
1505
|
+
};
|
|
1506
|
+
var Blocking = function(id, task) {
|
|
1507
|
+
var local = lookup(map, id);
|
|
1508
|
+
queue(id, function(next) {
|
|
1509
|
+
if (isEmpty(local.active)) {
|
|
1510
|
+
local.lock = true;
|
|
1511
|
+
return void task(function() {
|
|
1512
|
+
delete local.lock;
|
|
1513
|
+
runBlocked(local);
|
|
1514
|
+
next();
|
|
1515
|
+
});
|
|
1516
|
+
}
|
|
1517
|
+
local.waiting = function() {
|
|
1518
|
+
local.lock = true;
|
|
1519
|
+
task(function() {
|
|
1520
|
+
delete local.lock;
|
|
1521
|
+
delete local.waiting;
|
|
1522
|
+
runBlocked(local);
|
|
1523
|
+
next();
|
|
1524
|
+
});
|
|
1525
|
+
};
|
|
1526
|
+
});
|
|
1527
|
+
};
|
|
1528
|
+
return {
|
|
1529
|
+
ordered: Ordered,
|
|
1530
|
+
unordered: Unordered,
|
|
1531
|
+
blocking: Blocking
|
|
1532
|
+
};
|
|
1533
|
+
};
|
|
1534
|
+
return schedule;
|
|
1535
|
+
}
|
|
1536
|
+
|
|
1537
|
+
var decreesCore;
|
|
1538
|
+
|
|
1539
|
+
var hasRequiredDecreesCore;
|
|
1540
|
+
|
|
1541
|
+
function requireDecreesCore() {
|
|
1542
|
+
if (hasRequiredDecreesCore) return decreesCore;
|
|
1543
|
+
hasRequiredDecreesCore = 1;
|
|
1544
|
+
const Util = requireCommonUtil$1();
|
|
1545
|
+
const Path = require$$1;
|
|
1546
|
+
const Fs = require$$0$2;
|
|
1547
|
+
const readFileBin = requireStreamFile().readFileBin;
|
|
1548
|
+
const Schedule = requireSchedule();
|
|
1549
|
+
const Fse = require$$5;
|
|
1550
|
+
const nThen = require$$6;
|
|
1551
|
+
const Decrees = {};
|
|
1552
|
+
const Utils = Decrees.Utils = {};
|
|
1553
|
+
const isString = str => typeof str === "string";
|
|
1554
|
+
const isInteger = n => !(typeof n !== "number" || isNaN(n) || n % 1 !== 0);
|
|
1555
|
+
Utils.args_isBoolean = args => !(!Array.isArray(args) || typeof args[0] !== "boolean");
|
|
1556
|
+
Utils.args_isString = args => !(!Array.isArray(args) || !isString(args[0]));
|
|
1557
|
+
Utils.args_isInteger = args => !(!Array.isArray(args) || !isInteger(args[0]));
|
|
1558
|
+
Utils.args_isPositiveInteger = args => Array.isArray(args) && isInteger(args[0]) && args[0] > 0;
|
|
1559
|
+
Decrees.create = (name, commands) => {
|
|
1560
|
+
const handleCommand = (Env, line) => {
|
|
1561
|
+
let command = line[0];
|
|
1562
|
+
let args = line[1];
|
|
1563
|
+
if (typeof commands[command] !== "function") {
|
|
1564
|
+
throw new Error("DECREE_UNSUPPORTED_COMMAND");
|
|
1565
|
+
}
|
|
1566
|
+
let outcome = commands[command](Env, args);
|
|
1567
|
+
return outcome;
|
|
1568
|
+
};
|
|
1569
|
+
const createLineHandler = Env => {
|
|
1570
|
+
const Log = Env.Log;
|
|
1571
|
+
let index = -1;
|
|
1572
|
+
return (err, line) => {
|
|
1573
|
+
index++;
|
|
1574
|
+
if (err) {
|
|
1575
|
+
return void Log.error("DECREE_LINE_ERR", {
|
|
1576
|
+
error: err.message,
|
|
1577
|
+
index,
|
|
1578
|
+
line
|
|
1579
|
+
});
|
|
1580
|
+
}
|
|
1581
|
+
if (Array.isArray(line)) {
|
|
1582
|
+
try {
|
|
1583
|
+
return handleCommand(Env, line);
|
|
1584
|
+
} catch (err2) {
|
|
1585
|
+
return void Log.error("DECREE_COMMAND_ERR", {
|
|
1586
|
+
error: err2.message,
|
|
1587
|
+
index,
|
|
1588
|
+
line
|
|
1589
|
+
});
|
|
1590
|
+
}
|
|
1591
|
+
}
|
|
1592
|
+
Log.error("DECREE_HANDLER_WEIRD_LINE", {
|
|
1593
|
+
line,
|
|
1594
|
+
index
|
|
1595
|
+
});
|
|
1596
|
+
};
|
|
1597
|
+
};
|
|
1598
|
+
const loadRemote = (Env, decrees, cb) => {
|
|
1599
|
+
cb ||= () => {};
|
|
1600
|
+
if (!Array.isArray(decrees)) {
|
|
1601
|
+
return void cb("INVALID_DECREES");
|
|
1602
|
+
}
|
|
1603
|
+
decrees.forEach(line => {
|
|
1604
|
+
if (!Array.isArray(line)) {
|
|
1605
|
+
return;
|
|
1606
|
+
}
|
|
1607
|
+
try {
|
|
1608
|
+
handleCommand(Env, line);
|
|
1609
|
+
} catch {}
|
|
1610
|
+
});
|
|
1611
|
+
cb();
|
|
1612
|
+
};
|
|
1613
|
+
const load = (Env, _cb) => {
|
|
1614
|
+
Env.scheduleDecree ||= Schedule();
|
|
1615
|
+
const toSend = [];
|
|
1616
|
+
const cb = Util.once(Util.mkAsync(err => {
|
|
1617
|
+
if (err && err.code !== "ENOENT") {
|
|
1618
|
+
return void _cb(err);
|
|
1619
|
+
}
|
|
1620
|
+
_cb(void 0, toSend);
|
|
1621
|
+
}));
|
|
1622
|
+
Env.scheduleDecree.blocking("", unblock => {
|
|
1623
|
+
const done = Util.once(Util.both(cb, unblock));
|
|
1624
|
+
nThen(w => {
|
|
1625
|
+
Fse.mkdirp(Env.paths.decree, w(function(err) {
|
|
1626
|
+
if (!err) {
|
|
1627
|
+
return;
|
|
1628
|
+
}
|
|
1629
|
+
w.abort();
|
|
1630
|
+
done(err);
|
|
1631
|
+
}));
|
|
1632
|
+
}).nThen(function() {
|
|
1633
|
+
const decreeName = Path.join(Env.paths.decree, name);
|
|
1634
|
+
const stream = Fs.createReadStream(decreeName, {
|
|
1635
|
+
start: 0
|
|
1636
|
+
});
|
|
1637
|
+
const handler = createLineHandler(Env);
|
|
1638
|
+
readFileBin(stream, (msgObj, next) => {
|
|
1639
|
+
let text = msgObj.buff.toString("utf8");
|
|
1640
|
+
let line;
|
|
1641
|
+
let changed = false;
|
|
1642
|
+
try {
|
|
1643
|
+
line = JSON.parse(text);
|
|
1644
|
+
changed = handler(void 0, line);
|
|
1645
|
+
} catch (err) {
|
|
1646
|
+
handler(err, text);
|
|
1647
|
+
}
|
|
1648
|
+
if (changed) {
|
|
1649
|
+
toSend.push(line);
|
|
1650
|
+
}
|
|
1651
|
+
next();
|
|
1652
|
+
}, err => {
|
|
1653
|
+
done(err);
|
|
1654
|
+
});
|
|
1655
|
+
});
|
|
1656
|
+
});
|
|
1657
|
+
};
|
|
1658
|
+
const write = function(Env, decree, _cb) {
|
|
1659
|
+
var path = Path.join(Env.paths.decree, name);
|
|
1660
|
+
Env.scheduleDecree.ordered("", function(next) {
|
|
1661
|
+
var cb = Util.both(Util.mkAsync(_cb), next);
|
|
1662
|
+
Fs.appendFile(path, JSON.stringify(decree) + "\n", cb);
|
|
1663
|
+
});
|
|
1664
|
+
};
|
|
1665
|
+
return {
|
|
1666
|
+
handleCommand,
|
|
1667
|
+
loadRemote,
|
|
1668
|
+
load,
|
|
1669
|
+
write
|
|
1670
|
+
};
|
|
1671
|
+
};
|
|
1672
|
+
decreesCore = Decrees;
|
|
1673
|
+
return decreesCore;
|
|
1674
|
+
}
|
|
1675
|
+
|
|
1676
|
+
var adminDecrees;
|
|
1677
|
+
|
|
1678
|
+
var hasRequiredAdminDecrees;
|
|
1679
|
+
|
|
1680
|
+
function requireAdminDecrees() {
|
|
1681
|
+
if (hasRequiredAdminDecrees) return adminDecrees;
|
|
1682
|
+
hasRequiredAdminDecrees = 1;
|
|
1683
|
+
const Core = requireCore();
|
|
1684
|
+
const Keys = requireKeys();
|
|
1685
|
+
const DecreesCore = requireDecreesCore();
|
|
1686
|
+
const {args_isBoolean, args_isString, args_isInteger, args_isPositiveInteger} = DecreesCore.Utils;
|
|
1687
|
+
const makeBooleanSetter = function(attr) {
|
|
1688
|
+
return function(Env, args) {
|
|
1689
|
+
if (!args_isBoolean(args)) {
|
|
1690
|
+
throw new Error("INVALID_ARGS");
|
|
1691
|
+
}
|
|
1692
|
+
var bool = args[0];
|
|
1693
|
+
if (bool === Env[attr]) {
|
|
1694
|
+
return false;
|
|
1695
|
+
}
|
|
1696
|
+
Env[attr] = bool;
|
|
1697
|
+
return true;
|
|
1698
|
+
};
|
|
1699
|
+
};
|
|
1700
|
+
const default_validator = function() {
|
|
1701
|
+
return true;
|
|
1702
|
+
};
|
|
1703
|
+
const makeGenericSetter = function(attr, validator) {
|
|
1704
|
+
validator = validator || default_validator;
|
|
1705
|
+
return function(Env, args) {
|
|
1706
|
+
if (!validator(args)) {
|
|
1707
|
+
throw new Error("INVALID_ARGS");
|
|
1708
|
+
}
|
|
1709
|
+
var value = args[0];
|
|
1710
|
+
if (value === Env[attr]) {
|
|
1711
|
+
return false;
|
|
1712
|
+
}
|
|
1713
|
+
Env[attr] = value;
|
|
1714
|
+
return true;
|
|
1715
|
+
};
|
|
1716
|
+
};
|
|
1717
|
+
const makeIntegerSetter = function(attr) {
|
|
1718
|
+
return makeGenericSetter(attr, args_isInteger);
|
|
1719
|
+
};
|
|
1720
|
+
const makeTranslation = function(attr) {
|
|
1721
|
+
return function(Env, args) {
|
|
1722
|
+
if (!Array.isArray(args)) {
|
|
1723
|
+
throw new Error("INVALID_ARGS");
|
|
1724
|
+
}
|
|
1725
|
+
var value = args[0];
|
|
1726
|
+
var state = Env[attr];
|
|
1727
|
+
if (typeof value === "string") {
|
|
1728
|
+
if (state.default === value) {
|
|
1729
|
+
return false;
|
|
1730
|
+
}
|
|
1731
|
+
state.default = value;
|
|
1732
|
+
return true;
|
|
1733
|
+
}
|
|
1734
|
+
if (value && typeof value === "object") {
|
|
1735
|
+
var changed = false;
|
|
1736
|
+
Object.keys(value).forEach(function(lang) {
|
|
1737
|
+
if (state[lang] === value[lang]) {
|
|
1738
|
+
return;
|
|
1739
|
+
}
|
|
1740
|
+
state[lang] = value[lang];
|
|
1741
|
+
changed = true;
|
|
1742
|
+
});
|
|
1743
|
+
return changed;
|
|
1744
|
+
}
|
|
1745
|
+
return false;
|
|
1746
|
+
};
|
|
1747
|
+
};
|
|
1748
|
+
const commands = {};
|
|
1749
|
+
const isNumber = function(value) {
|
|
1750
|
+
return typeof value === "number" && !isNaN(value);
|
|
1751
|
+
};
|
|
1752
|
+
const args_isMaintenance = function(args) {
|
|
1753
|
+
return Array.isArray(args) && args[0] && (args[0] === "" || isNumber(args[0].end) && isNumber(args[0].start));
|
|
1754
|
+
};
|
|
1755
|
+
const makeBroadcastSetter = function(attr, validation) {
|
|
1756
|
+
return function(Env, args) {
|
|
1757
|
+
if (validation && !validation(args) && !args_isString(args)) {
|
|
1758
|
+
throw new Error("INVALID_ARGS");
|
|
1759
|
+
}
|
|
1760
|
+
var str = args[0];
|
|
1761
|
+
if (str === Env[attr]) {
|
|
1762
|
+
return false;
|
|
1763
|
+
}
|
|
1764
|
+
Env[attr] = str;
|
|
1765
|
+
Env.broadcastCache = {};
|
|
1766
|
+
return true;
|
|
1767
|
+
};
|
|
1768
|
+
};
|
|
1769
|
+
commands.ENABLE_EMBEDDING = makeBooleanSetter("enableEmbedding");
|
|
1770
|
+
commands.ENFORCE_MFA = makeBooleanSetter("enforceMFA");
|
|
1771
|
+
commands.RESTRICT_REGISTRATION = makeBooleanSetter("restrictRegistration");
|
|
1772
|
+
commands.RESTRICT_SSO_REGISTRATION = makeBooleanSetter("restrictSsoRegistration");
|
|
1773
|
+
commands.DISABLE_STORE_INVITED_USERS = makeBooleanSetter("dontStoreInvitedUsers");
|
|
1774
|
+
commands.DISABLE_STORE_SSO_USERS = makeBooleanSetter("dontStoreSSOUsers");
|
|
1775
|
+
commands.DISABLE_INTEGRATED_EVICTION = makeBooleanSetter("disableIntegratedEviction");
|
|
1776
|
+
commands.DISABLE_INTEGRATED_TASKS = makeBooleanSetter("disableIntegratedTasks");
|
|
1777
|
+
commands.CONSENT_TO_CONTACT = makeBooleanSetter("consentToContact");
|
|
1778
|
+
commands.LIST_MY_INSTANCE = makeBooleanSetter("listMyInstance");
|
|
1779
|
+
commands.PROVIDE_AGGREGATE_STATISTICS = makeBooleanSetter("provideAggregateStatistics");
|
|
1780
|
+
commands.REMOVE_DONATE_BUTTON = makeBooleanSetter("removeDonateButton");
|
|
1781
|
+
commands.BLOCK_DAILY_CHECK = makeBooleanSetter("blockDailyCheck");
|
|
1782
|
+
commands.SET_ACCENT_COLOR = makeGenericSetter("accentColor", args_isString);
|
|
1783
|
+
commands.ENABLE_PROFILING = makeBooleanSetter("enableProfiling");
|
|
1784
|
+
commands.SET_PROFILING_WINDOW = makeGenericSetter("profilingWindow", args_isPositiveInteger);
|
|
1785
|
+
commands.SET_MAX_UPLOAD_SIZE = makeIntegerSetter("maxUploadSize");
|
|
1786
|
+
commands.SET_PREMIUM_UPLOAD_SIZE = makeIntegerSetter("premiumUploadSize");
|
|
1787
|
+
commands.UPDATE_DEFAULT_STORAGE = makeIntegerSetter("defaultStorageLimit");
|
|
1788
|
+
commands.SET_INACTIVE_TIME = makeIntegerSetter("inactiveTime");
|
|
1789
|
+
commands.SET_ARCHIVE_RETENTION_TIME = makeIntegerSetter("archiveRetentionTime");
|
|
1790
|
+
commands.SET_ACCOUNT_RETENTION_TIME = makeIntegerSetter("accountRetentionTime");
|
|
1791
|
+
commands.SET_ADMIN_EMAIL = makeGenericSetter("adminEmail", args_isString);
|
|
1792
|
+
commands.HAS_CUSTOM_LOGO = makeBooleanSetter("customLogo");
|
|
1793
|
+
commands.SET_SUPPORT_MAILBOX = makeGenericSetter("supportMailbox", function(args) {
|
|
1794
|
+
return args_isString(args) && Core.isValidPublicKey(args[0]);
|
|
1795
|
+
});
|
|
1796
|
+
commands.SET_LOGO_MIME = makeGenericSetter("logoMimeType", args_isString);
|
|
1797
|
+
commands.DISABLE_APPS = function(Env, args) {
|
|
1798
|
+
if (!Array.isArray(args)) {
|
|
1799
|
+
throw new Error("INVALID_ARGS");
|
|
1800
|
+
}
|
|
1801
|
+
if (JSON.stringify(args) === JSON.stringify(Env.appsToDisable)) {
|
|
1802
|
+
return false;
|
|
1803
|
+
}
|
|
1804
|
+
Env.appsToDisable = args;
|
|
1805
|
+
return true;
|
|
1806
|
+
};
|
|
1807
|
+
commands.SET_SUPPORT_KEYS = function(Env, args) {
|
|
1808
|
+
const curvePublic = args[0];
|
|
1809
|
+
const edPublic = args[1];
|
|
1810
|
+
let validated = typeof curvePublic === "string" && (Core.isValidPublicKey(curvePublic) || !curvePublic) && typeof edPublic === "string" && (Core.isValidPublicKey(edPublic) || !edPublic);
|
|
1811
|
+
if (!validated) {
|
|
1812
|
+
throw new Error("INVALID_ARGS");
|
|
1813
|
+
}
|
|
1814
|
+
if (Env.supportMailboxKey === curvePublic && Env.supportPinKey === edPublic) {
|
|
1815
|
+
return false;
|
|
1816
|
+
}
|
|
1817
|
+
Env.supportMailboxKey = curvePublic;
|
|
1818
|
+
Env.supportPinKey = edPublic;
|
|
1819
|
+
return true;
|
|
1820
|
+
};
|
|
1821
|
+
commands.SET_INSTANCE_PURPOSE = makeGenericSetter("instancePurpose", args_isString);
|
|
1822
|
+
commands.SET_INSTANCE_JURISDICTION = makeTranslation("instanceJurisdiction");
|
|
1823
|
+
commands.SET_INSTANCE_NAME = makeTranslation("instanceName");
|
|
1824
|
+
commands.SET_INSTANCE_DESCRIPTION = makeTranslation("instanceDescription");
|
|
1825
|
+
commands.SET_INSTANCE_NOTICE = makeTranslation("instanceNotice");
|
|
1826
|
+
commands.SET_LAST_BROADCAST_HASH = makeBroadcastSetter("lastBroadcastHash");
|
|
1827
|
+
commands.SET_SURVEY_URL = makeBroadcastSetter("surveyURL");
|
|
1828
|
+
commands.SET_MAINTENANCE = makeBroadcastSetter("maintenance", args_isMaintenance);
|
|
1829
|
+
commands.SET_QUOTA = function(Env, args) {
|
|
1830
|
+
if (!Array.isArray(args) || args.length !== 2) {
|
|
1831
|
+
throw new Error("INVALID_ARGS");
|
|
1832
|
+
}
|
|
1833
|
+
var unsafeKey = Keys.canonicalize(args[0]);
|
|
1834
|
+
if (!unsafeKey) {
|
|
1835
|
+
throw new Error("INVALID_ARGS");
|
|
1836
|
+
}
|
|
1837
|
+
var limit = args[1];
|
|
1838
|
+
if (!Core.isValidLimit(limit)) {
|
|
1839
|
+
throw new Error("INVALID_ARGS");
|
|
1840
|
+
}
|
|
1841
|
+
limit.origin = "decree";
|
|
1842
|
+
Env.customLimits[unsafeKey] = limit;
|
|
1843
|
+
Env.limits[unsafeKey] = limit;
|
|
1844
|
+
return true;
|
|
1845
|
+
};
|
|
1846
|
+
commands.RM_QUOTA = function(Env, args) {
|
|
1847
|
+
if (!Array.isArray(args) || args.length !== 1) {
|
|
1848
|
+
throw new Error("INVALID_ARGS");
|
|
1849
|
+
}
|
|
1850
|
+
var unsafeKey = Keys.canonicalize(args[0]);
|
|
1851
|
+
if (!unsafeKey) {
|
|
1852
|
+
throw new Error("INVALID_ARGS");
|
|
1853
|
+
}
|
|
1854
|
+
if (!Env.customLimits[unsafeKey]) {
|
|
1855
|
+
throw new Error("ENOENT");
|
|
1856
|
+
}
|
|
1857
|
+
delete Env.customLimits[unsafeKey];
|
|
1858
|
+
delete Env.limits[unsafeKey];
|
|
1859
|
+
return true;
|
|
1860
|
+
};
|
|
1861
|
+
commands.ADD_INSTALL_TOKEN = function(Env, args) {
|
|
1862
|
+
if (!Array.isArray(args) || args.length !== 1 || !args[0]) {
|
|
1863
|
+
throw new Error("INVALID_ARGS");
|
|
1864
|
+
}
|
|
1865
|
+
var token = args[0];
|
|
1866
|
+
Env.installToken = token;
|
|
1867
|
+
return true;
|
|
1868
|
+
};
|
|
1869
|
+
commands.ADD_ADMIN_KEY = function(Env, args) {
|
|
1870
|
+
if (!Array.isArray(args) || args.length !== 1 || !args[0]) {
|
|
1871
|
+
throw new Error("INVALID_ARGS");
|
|
1872
|
+
}
|
|
1873
|
+
Env.admins = Env.admins || [];
|
|
1874
|
+
var key = Keys.canonicalize(args[0]);
|
|
1875
|
+
if (!key) {
|
|
1876
|
+
throw new Error("INVALID_KEY");
|
|
1877
|
+
}
|
|
1878
|
+
if (Env.admins.includes(key)) {
|
|
1879
|
+
return false;
|
|
1880
|
+
}
|
|
1881
|
+
Env.admins.push(key);
|
|
1882
|
+
Env.adminsData.push(args[0]);
|
|
1883
|
+
return true;
|
|
1884
|
+
};
|
|
1885
|
+
commands.RM_ADMIN_KEY = function(Env, args) {
|
|
1886
|
+
if (!Array.isArray(args) || args.length !== 1 || !args[0]) {
|
|
1887
|
+
throw new Error("INVALID_ARGS");
|
|
1888
|
+
}
|
|
1889
|
+
const key = Keys.canonicalize(args[0]);
|
|
1890
|
+
if (!key) {
|
|
1891
|
+
throw new Error("INVALID_KEY");
|
|
1892
|
+
}
|
|
1893
|
+
Env.admins = Env.admins || [];
|
|
1894
|
+
if (!Env.admins.includes(key)) {
|
|
1895
|
+
return false;
|
|
1896
|
+
}
|
|
1897
|
+
if (Array.isArray(Env?.config?.adminKeys) && Env.config.adminKeys.includes(key)) {
|
|
1898
|
+
throw new Error("CANT_REMOVE_CONFIG");
|
|
1899
|
+
}
|
|
1900
|
+
let idx = Env.admins.indexOf(key);
|
|
1901
|
+
if (idx < 0) {
|
|
1902
|
+
return false;
|
|
1903
|
+
}
|
|
1904
|
+
if (Env.admins.length === 1) {
|
|
1905
|
+
throw new Error("CANT_REMOVE_LAST_ADMIN");
|
|
1906
|
+
}
|
|
1907
|
+
Env.admins.splice(idx, 1);
|
|
1908
|
+
Env.adminsData = Env.adminsData.filter(str => {
|
|
1909
|
+
const ed = Keys.canonicalize(str);
|
|
1910
|
+
if (!ed) {
|
|
1911
|
+
return true;
|
|
1912
|
+
}
|
|
1913
|
+
return ed !== key;
|
|
1914
|
+
});
|
|
1915
|
+
return true;
|
|
1916
|
+
};
|
|
1917
|
+
commands.PROOFS_MIGRATED = function(Env, args) {
|
|
1918
|
+
if (args !== 1) {
|
|
1919
|
+
throw new Error("INVALID_ARGS");
|
|
1920
|
+
}
|
|
1921
|
+
Env.proofsMigrated = true;
|
|
1922
|
+
return true;
|
|
1923
|
+
};
|
|
1924
|
+
commands.SET_BEARER_SECRET = function(Env, args) {
|
|
1925
|
+
if (!args_isString(args) || args.length !== 1 || !args[0]) {
|
|
1926
|
+
throw new Error("INVALID_ARGS");
|
|
1927
|
+
}
|
|
1928
|
+
var secret = args[0];
|
|
1929
|
+
if (secret === Env.bearerSecret) {
|
|
1930
|
+
return false;
|
|
1931
|
+
}
|
|
1932
|
+
Env.bearerSecret = secret;
|
|
1933
|
+
return true;
|
|
1934
|
+
};
|
|
1935
|
+
commands.TEST_DECREE = (Env, args) => {
|
|
1936
|
+
if (typeof args !== "string") {
|
|
1937
|
+
throw new Error("INVALID_ARGS");
|
|
1938
|
+
}
|
|
1939
|
+
Env.testDecreeValue = args;
|
|
1940
|
+
return true;
|
|
1941
|
+
};
|
|
1942
|
+
adminDecrees = commands;
|
|
1943
|
+
return adminDecrees;
|
|
1944
|
+
}
|
|
1945
|
+
|
|
1946
|
+
var consistentHash;
|
|
1947
|
+
|
|
1948
|
+
var hasRequiredConsistentHash;
|
|
1949
|
+
|
|
1950
|
+
function requireConsistentHash() {
|
|
1951
|
+
if (hasRequiredConsistentHash) return consistentHash;
|
|
1952
|
+
hasRequiredConsistentHash = 1;
|
|
1953
|
+
consistentHash = {
|
|
1954
|
+
jumpConsistentHash: function(key, num_buckets) {
|
|
1955
|
+
let keyBigInt = key.readBigUInt64LE();
|
|
1956
|
+
let b = -1n;
|
|
1957
|
+
let j = 0n;
|
|
1958
|
+
while (j < num_buckets) {
|
|
1959
|
+
b = j;
|
|
1960
|
+
keyBigInt = (keyBigInt * 2862933555777941757n + 1n) % (1n << 64n);
|
|
1961
|
+
j = BigInt(Math.floor((Number(b) + 1) * Number(1n << 31n) / Number((keyBigInt >> 33n) + 1n)));
|
|
1962
|
+
}
|
|
1963
|
+
return b;
|
|
1964
|
+
}
|
|
1965
|
+
};
|
|
1966
|
+
return consistentHash;
|
|
1967
|
+
}
|
|
1968
|
+
|
|
1969
|
+
var pluginManager;
|
|
1970
|
+
|
|
1971
|
+
var hasRequiredPluginManager;
|
|
1972
|
+
|
|
1973
|
+
function requirePluginManager() {
|
|
1974
|
+
if (hasRequiredPluginManager) return pluginManager;
|
|
1975
|
+
hasRequiredPluginManager = 1;
|
|
1976
|
+
const fs = require$$0$2;
|
|
1977
|
+
const Path = require$$1;
|
|
1978
|
+
const plugins = {};
|
|
1979
|
+
const extensions = plugins._extensions = [];
|
|
1980
|
+
const styles = plugins._styles = [];
|
|
1981
|
+
try {
|
|
1982
|
+
const path = Path.join(__dirname, "..", "plugins");
|
|
1983
|
+
let pluginsDir = fs.readdirSync(path);
|
|
1984
|
+
pluginsDir.forEach(name => {
|
|
1985
|
+
if (name === "README.md") {
|
|
1986
|
+
return;
|
|
1987
|
+
}
|
|
1988
|
+
try {
|
|
1989
|
+
let plugin = require(`../plugins/${name}/index.js`);
|
|
1990
|
+
plugins[plugin.name] = plugin.modules;
|
|
1991
|
+
try {
|
|
1992
|
+
let hasExt = fs.existsSync(`./plugins/${name}/client/extensions.js`);
|
|
1993
|
+
if (hasExt) {
|
|
1994
|
+
extensions.push(plugin.name.toLowerCase());
|
|
1995
|
+
}
|
|
1996
|
+
} catch (e) {}
|
|
1997
|
+
try {
|
|
1998
|
+
let hasStyle = fs.existsSync(`./plugins/${name}/client/style.less`);
|
|
1999
|
+
if (hasStyle) {
|
|
2000
|
+
styles.push(plugin.name.toLowerCase());
|
|
2001
|
+
}
|
|
2002
|
+
} catch (e) {}
|
|
2003
|
+
} catch (err) {
|
|
2004
|
+
console.error(err);
|
|
2005
|
+
}
|
|
2006
|
+
});
|
|
2007
|
+
} catch (err) {
|
|
2008
|
+
if (err.code !== "ENOENT") {
|
|
2009
|
+
console.error(err);
|
|
2010
|
+
}
|
|
2011
|
+
}
|
|
2012
|
+
plugins.call = command => function() {
|
|
2013
|
+
Object.values(plugins).forEach(plugin => {
|
|
2014
|
+
const f = plugin?.[command];
|
|
2015
|
+
if (typeof f !== "function") {
|
|
2016
|
+
return;
|
|
2017
|
+
}
|
|
2018
|
+
f.apply(null, arguments);
|
|
2019
|
+
});
|
|
2020
|
+
};
|
|
2021
|
+
plugins.get = attr => {
|
|
2022
|
+
const result = [];
|
|
2023
|
+
Object.values(plugins).forEach(plugin => {
|
|
2024
|
+
const v = plugin?.[attr];
|
|
2025
|
+
if (typeof v !== "undefined") {
|
|
2026
|
+
result.push(v);
|
|
2027
|
+
}
|
|
2028
|
+
});
|
|
2029
|
+
return result;
|
|
2030
|
+
};
|
|
2031
|
+
plugins.addHttpEndpoints = (Env, app, type) => {
|
|
2032
|
+
Object.values(plugins).forEach(plugin => {
|
|
2033
|
+
const ep = plugin.httpEndpoints;
|
|
2034
|
+
if (!Array.isArray(ep)) {
|
|
2035
|
+
return;
|
|
2036
|
+
}
|
|
2037
|
+
ep.forEach(obj => {
|
|
2038
|
+
if (obj.type !== type && obj.target !== type) {
|
|
2039
|
+
return;
|
|
2040
|
+
}
|
|
2041
|
+
obj.f(Env, app);
|
|
2042
|
+
});
|
|
2043
|
+
});
|
|
2044
|
+
};
|
|
2045
|
+
plugins.getHttpProxy = () => {
|
|
2046
|
+
const list = [];
|
|
2047
|
+
Object.values(plugins).forEach(plugin => {
|
|
2048
|
+
const ep = plugin.httpEndpoints;
|
|
2049
|
+
if (!Array.isArray(ep)) {
|
|
2050
|
+
return;
|
|
2051
|
+
}
|
|
2052
|
+
ep.forEach(obj => {
|
|
2053
|
+
if (obj.type !== "proxy") {
|
|
2054
|
+
return;
|
|
2055
|
+
}
|
|
2056
|
+
list.push(obj);
|
|
2057
|
+
});
|
|
2058
|
+
});
|
|
2059
|
+
return list;
|
|
2060
|
+
};
|
|
2061
|
+
pluginManager = plugins;
|
|
2062
|
+
return pluginManager;
|
|
2063
|
+
}
|
|
2064
|
+
|
|
2065
|
+
var env;
|
|
2066
|
+
|
|
2067
|
+
var hasRequiredEnv;
|
|
2068
|
+
|
|
2069
|
+
function requireEnv() {
|
|
2070
|
+
if (hasRequiredEnv) return env;
|
|
2071
|
+
hasRequiredEnv = 1;
|
|
2072
|
+
const {existsSync, readdirSync} = require$$0$2;
|
|
2073
|
+
const Path = require$$1;
|
|
2074
|
+
const Package = require$$2;
|
|
2075
|
+
const Util = requireCommonUtil$1();
|
|
2076
|
+
const Keys = requireKeys();
|
|
2077
|
+
const Core = requireCore();
|
|
2078
|
+
const Constants = requireConstants();
|
|
2079
|
+
const Default = requireDefaults();
|
|
2080
|
+
const DecreesCore = requireDecreesCore();
|
|
2081
|
+
const AdminDecrees = requireAdminDecrees();
|
|
2082
|
+
const {jumpConsistentHash} = requireConsistentHash();
|
|
2083
|
+
const plugins = requirePluginManager();
|
|
2084
|
+
const isRecentVersion = function() {
|
|
2085
|
+
let R = Default.recommendedVersion;
|
|
2086
|
+
let V = process.version;
|
|
2087
|
+
if (typeof V !== "string") {
|
|
2088
|
+
return false;
|
|
2089
|
+
}
|
|
2090
|
+
let parts = V.replace(/^v/, "").split(".").map(Number);
|
|
2091
|
+
if (parts.length < 3) {
|
|
2092
|
+
return false;
|
|
2093
|
+
}
|
|
2094
|
+
if (!parts.every(n => typeof n === "number" && !isNaN(n))) {
|
|
2095
|
+
return false;
|
|
2096
|
+
}
|
|
2097
|
+
if (parts[0] < R[0]) {
|
|
2098
|
+
return false;
|
|
2099
|
+
}
|
|
2100
|
+
if (parts[0] > R[0]) {
|
|
2101
|
+
return true;
|
|
2102
|
+
}
|
|
2103
|
+
if (parts[1] < R[1]) {
|
|
2104
|
+
return false;
|
|
2105
|
+
}
|
|
2106
|
+
if (parts[1] > R[1]) {
|
|
2107
|
+
return true;
|
|
2108
|
+
}
|
|
2109
|
+
if (parts[2] >= R[2]) {
|
|
2110
|
+
return true;
|
|
2111
|
+
}
|
|
2112
|
+
return false;
|
|
2113
|
+
};
|
|
2114
|
+
const getInstalledOOVersions = Env => {
|
|
2115
|
+
const path = Path.join(Env.clientRoot, "www/common/onlyoffice/dist");
|
|
2116
|
+
if (!existsSync(path)) {
|
|
2117
|
+
return [];
|
|
2118
|
+
}
|
|
2119
|
+
return readdirSync(path);
|
|
2120
|
+
};
|
|
2121
|
+
const init = (Env, mainConfig, pluginModules) => {
|
|
2122
|
+
const {config, infra} = mainConfig;
|
|
2123
|
+
const publicConfig = infra?.public || {};
|
|
2124
|
+
Env.config = config;
|
|
2125
|
+
Env.adminDecrees = DecreesCore.create(Constants.adminDecree, AdminDecrees);
|
|
2126
|
+
Env.modules = {
|
|
2127
|
+
Core,
|
|
2128
|
+
Util,
|
|
2129
|
+
Constants,
|
|
2130
|
+
DecreesCore
|
|
2131
|
+
};
|
|
2132
|
+
Object.assign(Env.modules, pluginModules || {});
|
|
2133
|
+
Env.myId = mainConfig.myId;
|
|
2134
|
+
Env.clientRoot = config?.clientRoot || "../cryptpad";
|
|
2135
|
+
Env.version = Package.version;
|
|
2136
|
+
Env.launchTime = +new Date;
|
|
2137
|
+
Env.numberStorages = infra.storage.length;
|
|
2138
|
+
Env.numberCores = infra.core.length;
|
|
2139
|
+
Env.Util = Util;
|
|
2140
|
+
Env.Core = Core;
|
|
2141
|
+
Env.getStorageId = data => {
|
|
2142
|
+
data = Util.escapeKeyCharacters(data || "") + "00000000";
|
|
2143
|
+
const key = Buffer.from(data.slice(0, 8));
|
|
2144
|
+
const id = jumpConsistentHash(key, Env.numberStorages);
|
|
2145
|
+
return "storage:" + id;
|
|
2146
|
+
};
|
|
2147
|
+
Env.getCoreId = data => {
|
|
2148
|
+
data = Util.escapeKeyCharacters(data) + "00000000";
|
|
2149
|
+
const key = Buffer.from(data.slice(0, 8));
|
|
2150
|
+
const id = jumpConsistentHash(key, Env.numberCores);
|
|
2151
|
+
return "core:" + id;
|
|
2152
|
+
};
|
|
2153
|
+
(() => {
|
|
2154
|
+
Env.maxWorkers = typeof config.maxWorkers === "object" ? config.maxWorkers : {};
|
|
2155
|
+
Env.maxJobs = typeof config.maxJobs === "object" ? config.maxJobs : {};
|
|
2156
|
+
})();
|
|
2157
|
+
Env.getDecree = type => Env.plugins[type]?.getDecree(Env) || Env.adminDecrees;
|
|
2158
|
+
Env.allDecrees = {};
|
|
2159
|
+
Env.cacheDecrees = (type, decrees) => {
|
|
2160
|
+
type ||= "admin";
|
|
2161
|
+
const cache = Env.allDecrees[type] ||= [];
|
|
2162
|
+
Array.prototype.push.apply(cache, decrees);
|
|
2163
|
+
};
|
|
2164
|
+
Env.getCachedDecrees = () => Env.allDecrees;
|
|
2165
|
+
Env.httpUnsafeOrigin = publicConfig?.origin;
|
|
2166
|
+
Env.httpSafeOrigin = publicConfig?.sandboxOrigin;
|
|
2167
|
+
const unsafe = new URL(Env.httpUnsafeOrigin);
|
|
2168
|
+
const safe = new URL(Env.httpSafeOrigin);
|
|
2169
|
+
Env.httpAddress = publicConfig?.httpHost || unsafe.hostname;
|
|
2170
|
+
Env.httpPort = publicConfig?.httpPort || unsafe.port;
|
|
2171
|
+
if (unsafe.port && unsafe.hostname === safe.hostname && safe.port) {
|
|
2172
|
+
Env.httpSafePort = safe.port;
|
|
2173
|
+
}
|
|
2174
|
+
if (publicConfig?.httpSafePort) {
|
|
2175
|
+
Env.httpSafePort = publicConfig.httpSafePort;
|
|
2176
|
+
}
|
|
2177
|
+
Env.protocol = unsafe.protocol;
|
|
2178
|
+
Env.websocketPath = publicConfig.externalWebsocketURL;
|
|
2179
|
+
Env.fileHost = publicConfig.fileHost || undefined;
|
|
2180
|
+
Env.DEV_MODE = Boolean(process.env.DEV);
|
|
2181
|
+
Env.FRESH_KEY = process.env.DEV || process.env.PACKAGE ? "" : +new Date;
|
|
2182
|
+
Env.OFFLINE_MODE = Boolean(process.env.OFFLINE);
|
|
2183
|
+
Env.admins = (config.adminKeys || []).map(k => {
|
|
2184
|
+
try {
|
|
2185
|
+
return Keys.canonicalize(k);
|
|
2186
|
+
} catch (err) {
|
|
2187
|
+
return;
|
|
2188
|
+
}
|
|
2189
|
+
}).filter(Boolean);
|
|
2190
|
+
Env.adminEmail = config.adminEmail;
|
|
2191
|
+
Env.adminsData = (config.adminKeys || []).slice();
|
|
2192
|
+
Env.moderators = [];
|
|
2193
|
+
Env.supportMailbox = undefined;
|
|
2194
|
+
Env.supportMailboxKey = undefined;
|
|
2195
|
+
Env.lastBroadcastHash = "";
|
|
2196
|
+
Env.maintenance = undefined;
|
|
2197
|
+
Env.surveyURL = undefined;
|
|
2198
|
+
Env.logFeedback = Boolean(config.logFeedback);
|
|
2199
|
+
Env.enableEmbedding = false;
|
|
2200
|
+
Env.permittedEmbedders = publicConfig?.sandboxOrigin;
|
|
2201
|
+
Env.restrictRegistration = false;
|
|
2202
|
+
Env.disableIntegratedTasks = config.disableIntegratedTasks || false;
|
|
2203
|
+
Env.disableIntegratedEviction = typeof config.disableIntegratedEviction === "undefined" ? true : config.disableIntegratedEviction;
|
|
2204
|
+
Env.lastEviction = +new Date;
|
|
2205
|
+
Env.evictionReport = {};
|
|
2206
|
+
Env.installMethod = config.installMethod || undefined;
|
|
2207
|
+
Env.inactiveTime = config.inactiveTime;
|
|
2208
|
+
Env.accountRetentionTime = config.accountRetentionTime;
|
|
2209
|
+
Env.archiveRetentionTime = config.archiveRetentionTime;
|
|
2210
|
+
Env.defaultStorageLimit = typeof config.defaultStorageLimit === "number" && config.defaultStorageLimit >= 0 ? config.defaultStorageLimit : Core.DEFAULT_LIMIT;
|
|
2211
|
+
Env.maxUploadSize = config.maxUploadSize || 20 * 1024 * 1024;
|
|
2212
|
+
Env.premiumUploadSize = Math.max(Env.maxUploadSize, Number(config.premiumUploadSize) || 0);
|
|
2213
|
+
Env.removeDonateButton = config.removeDonateButton;
|
|
2214
|
+
Env.listMyInstance = false;
|
|
2215
|
+
Env.enforceMFA = config.enforceMFA;
|
|
2216
|
+
Env.logIP = config.logIP;
|
|
2217
|
+
Env.consentToContact = false;
|
|
2218
|
+
Env.instanceName = {};
|
|
2219
|
+
Env.instanceDescription = {};
|
|
2220
|
+
Env.instanceJurisdiction = {};
|
|
2221
|
+
Env.instanceNotice = {};
|
|
2222
|
+
Env.blockDailyCheck = config.blockDailyCheck === true;
|
|
2223
|
+
Env.provideAggregateStatistics = false;
|
|
2224
|
+
Env.updateAvailable = undefined;
|
|
2225
|
+
Env.accountsLimits = {};
|
|
2226
|
+
Env.customLimits = {};
|
|
2227
|
+
Env.limits = {};
|
|
2228
|
+
Env.otpSessionExpiration = config.otpSessionExpiration;
|
|
2229
|
+
let ooVersions = getInstalledOOVersions(Env);
|
|
2230
|
+
Env.onlyOffice = config.onlyOffice || (ooVersions.length ? {
|
|
2231
|
+
availableVersions: ooVersions
|
|
2232
|
+
} : false);
|
|
2233
|
+
Env.shouldUpdateNode = !isRecentVersion();
|
|
2234
|
+
Env.paths = Core.getPaths(mainConfig, true);
|
|
2235
|
+
Env.plugins = plugins;
|
|
2236
|
+
plugins.call("customizeEnv")(Env);
|
|
2237
|
+
return Env;
|
|
2238
|
+
};
|
|
2239
|
+
env = {
|
|
2240
|
+
init
|
|
2241
|
+
};
|
|
2242
|
+
return env;
|
|
2243
|
+
}
|
|
2244
|
+
|
|
2245
|
+
var file = {};
|
|
2246
|
+
|
|
2247
|
+
var metadata = {
|
|
2248
|
+
exports: {}
|
|
2249
|
+
};
|
|
2250
|
+
|
|
2251
|
+
var hasRequiredMetadata;
|
|
2252
|
+
|
|
2253
|
+
function requireMetadata() {
|
|
2254
|
+
if (hasRequiredMetadata) return metadata.exports;
|
|
2255
|
+
hasRequiredMetadata = 1;
|
|
2256
|
+
(function(module) {
|
|
2257
|
+
var Meta = module.exports;
|
|
2258
|
+
var Core = requireCore();
|
|
2259
|
+
var deduplicate = requireCommonUtil().deduplicateString;
|
|
2260
|
+
var commands = {};
|
|
2261
|
+
var isValidPublicKey = Core.isValidPublicKey;
|
|
2262
|
+
var isValidOwner = isValidPublicKey;
|
|
2263
|
+
commands.RESTRICT_ACCESS = function(meta, args) {
|
|
2264
|
+
if (!Array.isArray(args) || typeof args[0] !== "boolean") {
|
|
2265
|
+
throw new Error("INVALID_STATE");
|
|
2266
|
+
}
|
|
2267
|
+
var bool = args[0];
|
|
2268
|
+
if (meta.restricted === bool) {
|
|
2269
|
+
return false;
|
|
2270
|
+
}
|
|
2271
|
+
meta.restricted = args[0];
|
|
2272
|
+
if (!bool) {
|
|
2273
|
+
return true;
|
|
2274
|
+
}
|
|
2275
|
+
if (Array.isArray(meta.allowed)) {
|
|
2276
|
+
return true;
|
|
2277
|
+
}
|
|
2278
|
+
meta.allowed = [];
|
|
2279
|
+
return true;
|
|
2280
|
+
};
|
|
2281
|
+
commands.ALLOW_LINE_DELETION = function(meta, args) {
|
|
2282
|
+
if (!Array.isArray(args) || typeof args[0] !== "boolean") {
|
|
2283
|
+
throw new Error("INVALID_STATE");
|
|
2284
|
+
}
|
|
2285
|
+
var bool = args[0];
|
|
2286
|
+
if (meta.deleteLines === bool) {
|
|
2287
|
+
return false;
|
|
2288
|
+
}
|
|
2289
|
+
meta.deleteLines = args[0];
|
|
2290
|
+
return true;
|
|
2291
|
+
};
|
|
2292
|
+
commands.ADD_ALLOWED = function(meta, args) {
|
|
2293
|
+
if (!Array.isArray(args)) {
|
|
2294
|
+
throw new Error("INVALID_ARGS");
|
|
2295
|
+
}
|
|
2296
|
+
var allowed = meta.allowed || [];
|
|
2297
|
+
var changed = false;
|
|
2298
|
+
args.forEach(function(arg) {
|
|
2299
|
+
if (!isValidPublicKey(arg)) {
|
|
2300
|
+
return;
|
|
2301
|
+
}
|
|
2302
|
+
if (meta.owners.indexOf(arg) >= 0) {
|
|
2303
|
+
return;
|
|
2304
|
+
}
|
|
2305
|
+
if (allowed.indexOf(arg) >= 0) {
|
|
2306
|
+
return;
|
|
2307
|
+
}
|
|
2308
|
+
allowed.push(arg);
|
|
2309
|
+
changed = true;
|
|
2310
|
+
});
|
|
2311
|
+
if (changed) {
|
|
2312
|
+
meta.allowed = meta.allowed || allowed;
|
|
2313
|
+
}
|
|
2314
|
+
return changed;
|
|
2315
|
+
};
|
|
2316
|
+
commands.RM_ALLOWED = function(meta, args) {
|
|
2317
|
+
if (!Array.isArray(args)) {
|
|
2318
|
+
throw new Error("INVALID_ARGS");
|
|
2319
|
+
}
|
|
2320
|
+
if (!meta.allowed) {
|
|
2321
|
+
return false;
|
|
2322
|
+
}
|
|
2323
|
+
var changed = false;
|
|
2324
|
+
args.forEach(function(arg) {
|
|
2325
|
+
var index = meta.allowed.indexOf(arg);
|
|
2326
|
+
if (index < 0) {
|
|
2327
|
+
return;
|
|
2328
|
+
}
|
|
2329
|
+
meta.allowed.splice(index, 1);
|
|
2330
|
+
changed = true;
|
|
2331
|
+
});
|
|
2332
|
+
return changed;
|
|
2333
|
+
};
|
|
2334
|
+
var arrayHasChanged = function(A, B) {
|
|
2335
|
+
var changed;
|
|
2336
|
+
A.some(function(a) {
|
|
2337
|
+
if (B.indexOf(a) < 0) {
|
|
2338
|
+
return changed = true;
|
|
2339
|
+
}
|
|
2340
|
+
});
|
|
2341
|
+
if (changed) {
|
|
2342
|
+
return true;
|
|
2343
|
+
}
|
|
2344
|
+
B.some(function(b) {
|
|
2345
|
+
if (A.indexOf(b) < 0) {
|
|
2346
|
+
return changed = true;
|
|
2347
|
+
}
|
|
2348
|
+
});
|
|
2349
|
+
return changed;
|
|
2350
|
+
};
|
|
2351
|
+
var filterInPlace = function(A, f) {
|
|
2352
|
+
for (var i = A.length - 1; i >= 0; i--) {
|
|
2353
|
+
if (f(A[i], i, A)) {
|
|
2354
|
+
A.splice(i, 1);
|
|
2355
|
+
}
|
|
2356
|
+
}
|
|
2357
|
+
};
|
|
2358
|
+
commands.RESET_ALLOWED = function(meta, args) {
|
|
2359
|
+
if (!Array.isArray(args)) {
|
|
2360
|
+
throw new Error("INVALID_ARGS");
|
|
2361
|
+
}
|
|
2362
|
+
var updated = args.filter(function(arg) {
|
|
2363
|
+
if (!isValidPublicKey(arg)) {
|
|
2364
|
+
return false;
|
|
2365
|
+
}
|
|
2366
|
+
if (meta.owners.indexOf(arg)) {
|
|
2367
|
+
return false;
|
|
2368
|
+
}
|
|
2369
|
+
return true;
|
|
2370
|
+
});
|
|
2371
|
+
if (meta.allowed && meta.allowed.length !== updated.length) {
|
|
2372
|
+
meta.allowed = updated;
|
|
2373
|
+
return true;
|
|
2374
|
+
}
|
|
2375
|
+
if (!arrayHasChanged(meta.allowed, updated)) {
|
|
2376
|
+
return false;
|
|
2377
|
+
}
|
|
2378
|
+
meta.allowed = updated;
|
|
2379
|
+
return true;
|
|
2380
|
+
};
|
|
2381
|
+
commands.ADD_OWNERS = function(meta, args) {
|
|
2382
|
+
if (!Array.isArray(args)) {
|
|
2383
|
+
throw new Error("METADATA_INVALID_OWNERS");
|
|
2384
|
+
}
|
|
2385
|
+
if (!Array.isArray(meta.owners)) {
|
|
2386
|
+
throw new Error("METADATA_NONSENSE_OWNERS");
|
|
2387
|
+
}
|
|
2388
|
+
var changed = false;
|
|
2389
|
+
args.forEach(function(owner) {
|
|
2390
|
+
if (!isValidOwner(owner)) {
|
|
2391
|
+
return;
|
|
2392
|
+
}
|
|
2393
|
+
if (meta.owners.indexOf(owner) >= 0) {
|
|
2394
|
+
return;
|
|
2395
|
+
}
|
|
2396
|
+
meta.owners.push(owner);
|
|
2397
|
+
changed = true;
|
|
2398
|
+
});
|
|
2399
|
+
if (changed && Array.isArray(meta.allowed)) {
|
|
2400
|
+
filterInPlace(meta.allowed, function(member) {
|
|
2401
|
+
return meta.owners.indexOf(member) !== -1;
|
|
2402
|
+
});
|
|
2403
|
+
}
|
|
2404
|
+
return changed;
|
|
2405
|
+
};
|
|
2406
|
+
commands.RM_OWNERS = function(meta, args) {
|
|
2407
|
+
if (!Array.isArray(args)) {
|
|
2408
|
+
throw new Error("METADATA_INVALID_OWNERS");
|
|
2409
|
+
}
|
|
2410
|
+
if (!Array.isArray(meta.owners)) {
|
|
2411
|
+
throw new Error("METADATA_NONSENSE_OWNERS");
|
|
2412
|
+
}
|
|
2413
|
+
var changed = false;
|
|
2414
|
+
args.forEach(function(owner) {
|
|
2415
|
+
var index = meta.owners.indexOf(owner);
|
|
2416
|
+
if (index < 0) {
|
|
2417
|
+
return;
|
|
2418
|
+
}
|
|
2419
|
+
if (meta.mailbox) {
|
|
2420
|
+
if (typeof meta.mailbox === "string") {
|
|
2421
|
+
delete meta.mailbox;
|
|
2422
|
+
} else {
|
|
2423
|
+
delete meta.mailbox[owner];
|
|
2424
|
+
}
|
|
2425
|
+
}
|
|
2426
|
+
meta.owners.splice(index, 1);
|
|
2427
|
+
changed = true;
|
|
2428
|
+
});
|
|
2429
|
+
if (meta.owners.length === 0 && meta.restricted) {
|
|
2430
|
+
meta.restricted = false;
|
|
2431
|
+
}
|
|
2432
|
+
return changed;
|
|
2433
|
+
};
|
|
2434
|
+
commands.ADD_PENDING_OWNERS = function(meta, args) {
|
|
2435
|
+
if (!Array.isArray(args)) {
|
|
2436
|
+
throw new Error("METADATA_INVALID_PENDING_OWNERS");
|
|
2437
|
+
}
|
|
2438
|
+
if (meta.pending_owners && !Array.isArray(meta.pending_owners)) {
|
|
2439
|
+
throw new Error("METADATA_NONSENSE_PENDING_OWNERS");
|
|
2440
|
+
}
|
|
2441
|
+
var changed = false;
|
|
2442
|
+
if (!meta.pending_owners) {
|
|
2443
|
+
meta.pending_owners = deduplicate(args);
|
|
2444
|
+
return true;
|
|
2445
|
+
}
|
|
2446
|
+
args.forEach(function(owner) {
|
|
2447
|
+
if (!isValidOwner(owner)) {
|
|
2448
|
+
return;
|
|
2449
|
+
}
|
|
2450
|
+
if (meta.pending_owners.indexOf(owner) >= 0) {
|
|
2451
|
+
return;
|
|
2452
|
+
}
|
|
2453
|
+
meta.pending_owners.push(owner);
|
|
2454
|
+
changed = true;
|
|
2455
|
+
});
|
|
2456
|
+
return changed;
|
|
2457
|
+
};
|
|
2458
|
+
commands.RM_PENDING_OWNERS = function(meta, args) {
|
|
2459
|
+
if (!Array.isArray(args)) {
|
|
2460
|
+
throw new Error("METADATA_INVALID_PENDING_OWNERS");
|
|
2461
|
+
}
|
|
2462
|
+
if (!Array.isArray(meta.pending_owners)) {
|
|
2463
|
+
throw new Error("METADATA_NONSENSE_PENDING_OWNERS");
|
|
2464
|
+
}
|
|
2465
|
+
var changed = false;
|
|
2466
|
+
args.forEach(function(owner) {
|
|
2467
|
+
var index = meta.pending_owners.indexOf(owner);
|
|
2468
|
+
if (index < 0) {
|
|
2469
|
+
return;
|
|
2470
|
+
}
|
|
2471
|
+
meta.pending_owners.splice(index, 1);
|
|
2472
|
+
changed = true;
|
|
2473
|
+
});
|
|
2474
|
+
return changed;
|
|
2475
|
+
};
|
|
2476
|
+
commands.RESET_OWNERS = function(meta, args) {
|
|
2477
|
+
if (!Array.isArray(args)) {
|
|
2478
|
+
throw new Error("METADATA_INVALID_OWNERS");
|
|
2479
|
+
}
|
|
2480
|
+
if (!Array.isArray(meta.owners)) {
|
|
2481
|
+
throw new Error("METADATA_NONSENSE_OWNERS");
|
|
2482
|
+
}
|
|
2483
|
+
meta.owners = deduplicate(args.filter(isValidOwner));
|
|
2484
|
+
if (Array.isArray(meta.allowed)) {
|
|
2485
|
+
filterInPlace(meta.allowed, function(member) {
|
|
2486
|
+
return meta.owners.indexOf(member) !== -1;
|
|
2487
|
+
});
|
|
2488
|
+
}
|
|
2489
|
+
if (meta.owners.length === 0 && meta.restricted) {
|
|
2490
|
+
meta.restricted = false;
|
|
2491
|
+
}
|
|
2492
|
+
return true;
|
|
2493
|
+
};
|
|
2494
|
+
commands.ADD_MAILBOX = function(meta, args) {
|
|
2495
|
+
if (!args || typeof args !== "object") {
|
|
2496
|
+
throw new Error("METADATA_INVALID_MAILBOX");
|
|
2497
|
+
}
|
|
2498
|
+
if (!Array.isArray(meta.owners)) {
|
|
2499
|
+
throw new Error("METADATA_NONSENSE_OWNERS");
|
|
2500
|
+
}
|
|
2501
|
+
var changed = false;
|
|
2502
|
+
Object.keys(args).forEach(function(edPublic) {
|
|
2503
|
+
if (meta.owners.indexOf(edPublic) === -1) {
|
|
2504
|
+
return;
|
|
2505
|
+
}
|
|
2506
|
+
if (typeof meta.mailbox === "string") {
|
|
2507
|
+
var str = meta.mailbox;
|
|
2508
|
+
meta.mailbox = {};
|
|
2509
|
+
meta.mailbox[meta.owners[0]] = str;
|
|
2510
|
+
}
|
|
2511
|
+
if (!meta.mailbox) {
|
|
2512
|
+
meta.mailbox = {};
|
|
2513
|
+
}
|
|
2514
|
+
meta.mailbox[edPublic] = args[edPublic];
|
|
2515
|
+
changed = true;
|
|
2516
|
+
});
|
|
2517
|
+
return changed;
|
|
2518
|
+
};
|
|
2519
|
+
commands.RM_MAILBOX = function(meta, args) {
|
|
2520
|
+
if (!Array.isArray(args)) {
|
|
2521
|
+
throw new Error("INVALID_ARGS");
|
|
2522
|
+
}
|
|
2523
|
+
if (!meta.mailbox || typeof meta.mailbox === "undefined") {
|
|
2524
|
+
return false;
|
|
2525
|
+
}
|
|
2526
|
+
if (typeof meta.mailbox === "string" && args.length === 0) {
|
|
2527
|
+
delete meta.mailbox;
|
|
2528
|
+
return true;
|
|
2529
|
+
}
|
|
2530
|
+
var changed = false;
|
|
2531
|
+
args.forEach(function(arg) {
|
|
2532
|
+
if (meta.mailbox[arg] === "undefined") {
|
|
2533
|
+
return;
|
|
2534
|
+
}
|
|
2535
|
+
delete meta.mailbox[arg];
|
|
2536
|
+
changed = true;
|
|
2537
|
+
});
|
|
2538
|
+
return changed;
|
|
2539
|
+
};
|
|
2540
|
+
commands.UPDATE_EXPIRATION = function() {
|
|
2541
|
+
throw new Error("E_NOT_IMPLEMENTED");
|
|
2542
|
+
};
|
|
2543
|
+
var handleCommand = Meta.handleCommand = function(meta, line) {
|
|
2544
|
+
var command = line[0];
|
|
2545
|
+
var args = line[1];
|
|
2546
|
+
if (typeof commands[command] !== "function") {
|
|
2547
|
+
throw new Error("METADATA_UNSUPPORTED_COMMAND");
|
|
2548
|
+
}
|
|
2549
|
+
return commands[command](meta, args);
|
|
2550
|
+
};
|
|
2551
|
+
Meta.commands = Object.keys(commands);
|
|
2552
|
+
Meta.createLineHandler = function(ref, errorHandler) {
|
|
2553
|
+
ref.meta = {};
|
|
2554
|
+
ref.index = 0;
|
|
2555
|
+
ref.logged = {};
|
|
2556
|
+
var overwritten = false;
|
|
2557
|
+
return function(err, line) {
|
|
2558
|
+
if (err) {
|
|
2559
|
+
if (ref.index === 0 && err.code === "ENOENT") {
|
|
2560
|
+
return;
|
|
2561
|
+
}
|
|
2562
|
+
return void errorHandler("METADATA_HANDLER_LINE_ERR", {
|
|
2563
|
+
error: err,
|
|
2564
|
+
index: ref.index,
|
|
2565
|
+
line: JSON.stringify(line)
|
|
2566
|
+
});
|
|
2567
|
+
}
|
|
2568
|
+
var index = ref.index++;
|
|
2569
|
+
if (typeof line === "undefined") {
|
|
2570
|
+
return;
|
|
2571
|
+
}
|
|
2572
|
+
if (Array.isArray(line)) {
|
|
2573
|
+
try {
|
|
2574
|
+
handleCommand(ref.meta, line);
|
|
2575
|
+
} catch (err2) {
|
|
2576
|
+
var code = err2.message;
|
|
2577
|
+
if (ref.logged[code]) {
|
|
2578
|
+
return;
|
|
2579
|
+
}
|
|
2580
|
+
ref.logged[code] = true;
|
|
2581
|
+
errorHandler("METADATA_COMMAND_ERR", {
|
|
2582
|
+
error: err2.stack,
|
|
2583
|
+
line
|
|
2584
|
+
});
|
|
2585
|
+
}
|
|
2586
|
+
return;
|
|
2587
|
+
}
|
|
2588
|
+
if (index < 2 && line && typeof line === "object") {
|
|
2589
|
+
if (overwritten) {
|
|
2590
|
+
return;
|
|
2591
|
+
}
|
|
2592
|
+
overwritten = true;
|
|
2593
|
+
ref.meta = line;
|
|
2594
|
+
return;
|
|
2595
|
+
}
|
|
2596
|
+
errorHandler("METADATA_HANDLER_WEIRDLINE", {
|
|
2597
|
+
line,
|
|
2598
|
+
index
|
|
2599
|
+
});
|
|
2600
|
+
};
|
|
2601
|
+
};
|
|
2602
|
+
})(metadata);
|
|
2603
|
+
return metadata.exports;
|
|
2604
|
+
}
|
|
2605
|
+
|
|
2606
|
+
var hkUtil = {
|
|
2607
|
+
exports: {}
|
|
2608
|
+
};
|
|
2609
|
+
|
|
2610
|
+
var hasRequiredHkUtil;
|
|
2611
|
+
|
|
2612
|
+
function requireHkUtil() {
|
|
2613
|
+
if (hasRequiredHkUtil) return hkUtil.exports;
|
|
2614
|
+
hasRequiredHkUtil = 1;
|
|
2615
|
+
(function(module) {
|
|
2616
|
+
const Constants = requireConstants();
|
|
2617
|
+
var HK = module.exports;
|
|
2618
|
+
const {STANDARD_CHANNEL_LENGTH, ADMIN_CHANNEL_LENGTH, publicKeyLength} = Constants;
|
|
2619
|
+
HK.STANDARD_CHANNEL_LENGTH = STANDARD_CHANNEL_LENGTH;
|
|
2620
|
+
HK.ADMIN_CHANNEL_LENGTH = ADMIN_CHANNEL_LENGTH;
|
|
2621
|
+
HK.getHash = function(msg, Log) {
|
|
2622
|
+
if (typeof msg !== "string") {
|
|
2623
|
+
if (Log) {
|
|
2624
|
+
Log.warn("HK_GET_HASH", "getHash() called on " + typeof msg + ": " + msg);
|
|
2625
|
+
}
|
|
2626
|
+
return "";
|
|
2627
|
+
}
|
|
2628
|
+
return msg.slice(0, 64);
|
|
2629
|
+
};
|
|
2630
|
+
HK.sliceCpIndex = function(cpIndex, line) {
|
|
2631
|
+
const minLine = Math.max(0, line - 100);
|
|
2632
|
+
let start = cpIndex.slice(0, -2);
|
|
2633
|
+
const end = cpIndex.slice(-2);
|
|
2634
|
+
start = start.filter(function(obj) {
|
|
2635
|
+
return obj.line > minLine;
|
|
2636
|
+
});
|
|
2637
|
+
return start.concat(end);
|
|
2638
|
+
};
|
|
2639
|
+
HK.isMetadataMessage = function(parsed) {
|
|
2640
|
+
return Boolean(parsed && parsed.channel);
|
|
2641
|
+
};
|
|
2642
|
+
const decodeBase64 = function(string) {
|
|
2643
|
+
return Buffer.from(string, "base64");
|
|
2644
|
+
};
|
|
2645
|
+
HK.isValidValidateKeyString = key => {
|
|
2646
|
+
try {
|
|
2647
|
+
return typeof key === "string" && decodeBase64(key).length === publicKeyLength;
|
|
2648
|
+
} catch {
|
|
2649
|
+
return false;
|
|
2650
|
+
}
|
|
2651
|
+
};
|
|
2652
|
+
HK.trimMapByOffset = function(map, offset) {
|
|
2653
|
+
if (!offset) {
|
|
2654
|
+
return;
|
|
2655
|
+
}
|
|
2656
|
+
for (let k in map) {
|
|
2657
|
+
if (map[k] < offset) {
|
|
2658
|
+
delete map[k];
|
|
2659
|
+
}
|
|
2660
|
+
}
|
|
2661
|
+
};
|
|
2662
|
+
HK.checkOffsetMap = function(map) {
|
|
2663
|
+
var prev = 0;
|
|
2664
|
+
var cur;
|
|
2665
|
+
var ooo = 0;
|
|
2666
|
+
var count = 0;
|
|
2667
|
+
for (let k in map) {
|
|
2668
|
+
count++;
|
|
2669
|
+
cur = map[k];
|
|
2670
|
+
if (!ooo && prev > cur) {
|
|
2671
|
+
ooo = true;
|
|
2672
|
+
}
|
|
2673
|
+
prev = cur;
|
|
2674
|
+
}
|
|
2675
|
+
return ooo ? count * -1 : count;
|
|
2676
|
+
};
|
|
2677
|
+
HK.trimOffsetByOrder = function(map, n) {
|
|
2678
|
+
var toRemove = Math.max(n - 50, 0);
|
|
2679
|
+
var i = 0;
|
|
2680
|
+
for (let k in map) {
|
|
2681
|
+
if (i >= toRemove) {
|
|
2682
|
+
return;
|
|
2683
|
+
}
|
|
2684
|
+
i++;
|
|
2685
|
+
delete map[k];
|
|
2686
|
+
}
|
|
2687
|
+
};
|
|
2688
|
+
HK.listAllowedUsers = metadata => (metadata.owners || []).concat(metadata.allowed || []);
|
|
2689
|
+
HK.isUserSessionAllowed = (allowed, authKeys) => {
|
|
2690
|
+
if (!authKeys) {
|
|
2691
|
+
return false;
|
|
2692
|
+
}
|
|
2693
|
+
for (var unsafeKey in authKeys) {
|
|
2694
|
+
if (allowed.includes(unsafeKey)) {
|
|
2695
|
+
return true;
|
|
2696
|
+
}
|
|
2697
|
+
}
|
|
2698
|
+
return false;
|
|
2699
|
+
};
|
|
2700
|
+
})(hkUtil);
|
|
2701
|
+
return hkUtil.exports;
|
|
2702
|
+
}
|
|
2703
|
+
|
|
2704
|
+
var batchRead;
|
|
2705
|
+
|
|
2706
|
+
var hasRequiredBatchRead;
|
|
2707
|
+
|
|
2708
|
+
function requireBatchRead() {
|
|
2709
|
+
if (hasRequiredBatchRead) return batchRead;
|
|
2710
|
+
hasRequiredBatchRead = 1;
|
|
2711
|
+
batchRead = function() {
|
|
2712
|
+
var map = {};
|
|
2713
|
+
return function(id, cb, impl) {
|
|
2714
|
+
if (typeof cb !== "function" || typeof impl !== "function") {
|
|
2715
|
+
throw new Error("expected callback and implementation");
|
|
2716
|
+
}
|
|
2717
|
+
if (map[id]) {
|
|
2718
|
+
return void map[id].push(cb);
|
|
2719
|
+
}
|
|
2720
|
+
map[id] = [ cb ];
|
|
2721
|
+
impl(function() {
|
|
2722
|
+
var args = Array.prototype.slice.call(arguments);
|
|
2723
|
+
setTimeout(function() {
|
|
2724
|
+
map[id].forEach(function(h) {
|
|
2725
|
+
h.apply(null, args);
|
|
2726
|
+
});
|
|
2727
|
+
delete map[id];
|
|
2728
|
+
});
|
|
2729
|
+
});
|
|
2730
|
+
};
|
|
2731
|
+
};
|
|
2732
|
+
return batchRead;
|
|
2733
|
+
}
|
|
2734
|
+
|
|
2735
|
+
var hasRequiredFile;
|
|
2736
|
+
|
|
2737
|
+
function requireFile() {
|
|
2738
|
+
if (hasRequiredFile) return file;
|
|
2739
|
+
hasRequiredFile = 1;
|
|
2740
|
+
var Fs = require$$0$2;
|
|
2741
|
+
var Fse = require$$5;
|
|
2742
|
+
var Path = require$$1;
|
|
2743
|
+
var nThen = require$$6;
|
|
2744
|
+
var Semaphore = require$$4;
|
|
2745
|
+
var Util = requireCommonUtil();
|
|
2746
|
+
var Meta = requireMetadata();
|
|
2747
|
+
var Extras = requireHkUtil();
|
|
2748
|
+
const readFileBin = requireStreamFile().readFileBin;
|
|
2749
|
+
const BatchRead = requireBatchRead();
|
|
2750
|
+
const Schedule = requireSchedule();
|
|
2751
|
+
const CHANNEL_WRITE_WINDOW = 3e5;
|
|
2752
|
+
const STREAM_CLOSE_TIMEOUT = 12e4;
|
|
2753
|
+
const STREAM_DESTROY_TIMEOUT = 3e4;
|
|
2754
|
+
const isValidChannelId = function(id) {
|
|
2755
|
+
return typeof id === "string" && id.length >= 32 && id.length < 50 && /^[a-zA-Z0-9=+-]*$/.test(id);
|
|
2756
|
+
};
|
|
2757
|
+
const PERMISSIVE = 511;
|
|
2758
|
+
var mkPath = function(env, channelId) {
|
|
2759
|
+
return Path.join(env.root, channelId.slice(0, 2), channelId) + ".ndjson";
|
|
2760
|
+
};
|
|
2761
|
+
var mkArchivePath = function(env, channelId) {
|
|
2762
|
+
return Path.join(env.archiveRoot, env.volumeId, channelId.slice(0, 2), channelId) + ".ndjson";
|
|
2763
|
+
};
|
|
2764
|
+
var mkMetadataPath = function(env, channelId) {
|
|
2765
|
+
return Path.join(env.root, channelId.slice(0, 2), channelId) + ".metadata.ndjson";
|
|
2766
|
+
};
|
|
2767
|
+
var mkArchiveMetadataPath = function(env, channelId) {
|
|
2768
|
+
return Path.join(env.archiveRoot, env.volumeId, channelId.slice(0, 2), channelId) + ".metadata.ndjson";
|
|
2769
|
+
};
|
|
2770
|
+
var mkTempPath = function(env, channelId) {
|
|
2771
|
+
return mkPath(env, channelId) + ".temp";
|
|
2772
|
+
};
|
|
2773
|
+
var mkOffsetPath = function(env, channelId) {
|
|
2774
|
+
return mkPath(env, channelId) + ".offset";
|
|
2775
|
+
};
|
|
2776
|
+
var mkPlaceholderPath = function(env, channelId) {
|
|
2777
|
+
return mkPath(env, channelId) + ".placeholder";
|
|
2778
|
+
};
|
|
2779
|
+
var channelExists = function(filepath, cb) {
|
|
2780
|
+
Fs.stat(filepath, function(err, stat) {
|
|
2781
|
+
if (err) {
|
|
2782
|
+
if (err.code === "ENOENT") {
|
|
2783
|
+
return void cb(void 0, false);
|
|
2784
|
+
}
|
|
2785
|
+
return void cb(err);
|
|
2786
|
+
}
|
|
2787
|
+
if (!stat.isFile()) {
|
|
2788
|
+
return void cb("E_NOT_FILE");
|
|
2789
|
+
}
|
|
2790
|
+
return void cb(void 0, true);
|
|
2791
|
+
});
|
|
2792
|
+
};
|
|
2793
|
+
var isChannelAvailable = function(env, channelName, cb) {
|
|
2794
|
+
var filepath = mkPath(env, channelName);
|
|
2795
|
+
var metapath = mkMetadataPath(env, channelName);
|
|
2796
|
+
env.schedule.unordered(channelName, function(next) {
|
|
2797
|
+
var done = Util.once(Util.mkAsync(Util.both(cb, next)));
|
|
2798
|
+
var exists = false;
|
|
2799
|
+
var handler = function(err, _exists) {
|
|
2800
|
+
if (err) {
|
|
2801
|
+
return void done(err);
|
|
2802
|
+
}
|
|
2803
|
+
exists = exists || _exists;
|
|
2804
|
+
};
|
|
2805
|
+
nThen(function(w) {
|
|
2806
|
+
channelExists(filepath, w(handler));
|
|
2807
|
+
channelExists(metapath, w(handler));
|
|
2808
|
+
}).nThen(function() {
|
|
2809
|
+
done(void 0, exists);
|
|
2810
|
+
});
|
|
2811
|
+
});
|
|
2812
|
+
};
|
|
2813
|
+
var isChannelArchived = function(env, channelName, cb) {
|
|
2814
|
+
var filepath = mkArchivePath(env, channelName);
|
|
2815
|
+
var metapath = mkArchiveMetadataPath(env, channelName);
|
|
2816
|
+
env.schedule.unordered(channelName, function(next) {
|
|
2817
|
+
var done = Util.once(Util.mkAsync(Util.both(cb, next)));
|
|
2818
|
+
var exists = false;
|
|
2819
|
+
var handler = function(err, _exists) {
|
|
2820
|
+
if (err) {
|
|
2821
|
+
return void done(err);
|
|
2822
|
+
}
|
|
2823
|
+
exists = exists || _exists;
|
|
2824
|
+
};
|
|
2825
|
+
nThen(function(w) {
|
|
2826
|
+
channelExists(filepath, w(handler));
|
|
2827
|
+
channelExists(metapath, w(handler));
|
|
2828
|
+
}).nThen(function() {
|
|
2829
|
+
done(void 0, exists);
|
|
2830
|
+
});
|
|
2831
|
+
});
|
|
2832
|
+
};
|
|
2833
|
+
var addPlaceholder = function(env, channelId, reason, cb) {
|
|
2834
|
+
if (!reason) {
|
|
2835
|
+
return cb();
|
|
2836
|
+
}
|
|
2837
|
+
var path = mkPlaceholderPath(env, channelId);
|
|
2838
|
+
var s_data = typeof reason === "string" ? reason : `${reason.code}:${reason.txt}`;
|
|
2839
|
+
Fs.writeFile(path, s_data, cb);
|
|
2840
|
+
};
|
|
2841
|
+
var clearPlaceholder = function(env, channelId, cb) {
|
|
2842
|
+
var path = mkPlaceholderPath(env, channelId);
|
|
2843
|
+
Fs.unlink(path, cb);
|
|
2844
|
+
};
|
|
2845
|
+
var readPlaceholder = function(env, channelId, cb) {
|
|
2846
|
+
var path = mkPlaceholderPath(env, channelId);
|
|
2847
|
+
Fs.readFile(path, function(err, content) {
|
|
2848
|
+
if (err) {
|
|
2849
|
+
return void cb();
|
|
2850
|
+
}
|
|
2851
|
+
cb(content.toString("utf8"));
|
|
2852
|
+
});
|
|
2853
|
+
};
|
|
2854
|
+
const destroyStream = function(stream) {
|
|
2855
|
+
if (!stream) {
|
|
2856
|
+
return;
|
|
2857
|
+
}
|
|
2858
|
+
try {
|
|
2859
|
+
stream.close();
|
|
2860
|
+
if (stream.closed && stream.fd === null) {
|
|
2861
|
+
return;
|
|
2862
|
+
}
|
|
2863
|
+
} catch (err) {
|
|
2864
|
+
console.error(err);
|
|
2865
|
+
}
|
|
2866
|
+
setTimeout(function() {
|
|
2867
|
+
try {
|
|
2868
|
+
stream.destroy();
|
|
2869
|
+
} catch (err) {
|
|
2870
|
+
console.error(err);
|
|
2871
|
+
}
|
|
2872
|
+
}, STREAM_DESTROY_TIMEOUT);
|
|
2873
|
+
};
|
|
2874
|
+
const createIdleStreamCollector = function(stream) {
|
|
2875
|
+
var collector = Util.once(Util.mkAsync(Util.bake(destroyStream, [ stream ])));
|
|
2876
|
+
collector.keepAlive = Util.throttle(collector, STREAM_CLOSE_TIMEOUT);
|
|
2877
|
+
collector.keepAlive();
|
|
2878
|
+
return collector;
|
|
2879
|
+
};
|
|
2880
|
+
const readMessagesBin = (env, id, start, msgHandler, cb) => {
|
|
2881
|
+
const stream = Fs.createReadStream(mkPath(env, id), {
|
|
2882
|
+
start
|
|
2883
|
+
});
|
|
2884
|
+
const collector = createIdleStreamCollector(stream);
|
|
2885
|
+
const handleMessageAndKeepStreamAlive = Util.both(msgHandler, collector.keepAlive);
|
|
2886
|
+
const done = Util.both(err => {
|
|
2887
|
+
if (err && err.code === "ENOENT") {
|
|
2888
|
+
return readPlaceholder(env, id, content => {
|
|
2889
|
+
cb(err, content);
|
|
2890
|
+
});
|
|
2891
|
+
}
|
|
2892
|
+
cb(err);
|
|
2893
|
+
}, collector);
|
|
2894
|
+
return void readFileBin(stream, handleMessageAndKeepStreamAlive, done, {
|
|
2895
|
+
offset: start
|
|
2896
|
+
});
|
|
2897
|
+
};
|
|
2898
|
+
var getMetadataAtPath = function(Env, path, _cb) {
|
|
2899
|
+
const stream = Fs.createReadStream(path, {
|
|
2900
|
+
start: 0
|
|
2901
|
+
});
|
|
2902
|
+
const collector = createIdleStreamCollector(stream);
|
|
2903
|
+
var cb = Util.once(Util.mkAsync(Util.both(_cb, collector)));
|
|
2904
|
+
var i = 0;
|
|
2905
|
+
return readFileBin(stream, function(msgObj, readMore, abort) {
|
|
2906
|
+
collector.keepAlive();
|
|
2907
|
+
const line = msgObj.buff.toString("utf8");
|
|
2908
|
+
if (!line) {
|
|
2909
|
+
return readMore();
|
|
2910
|
+
}
|
|
2911
|
+
if (i++ > 0) {
|
|
2912
|
+
abort();
|
|
2913
|
+
return void cb();
|
|
2914
|
+
}
|
|
2915
|
+
var metadata;
|
|
2916
|
+
try {
|
|
2917
|
+
metadata = JSON.parse(line);
|
|
2918
|
+
if (metadata && typeof metadata === "object" && !Array.isArray(metadata)) {
|
|
2919
|
+
return void cb(void 0, metadata);
|
|
2920
|
+
} else {
|
|
2921
|
+
return void cb();
|
|
2922
|
+
}
|
|
2923
|
+
} catch {
|
|
2924
|
+
return void cb("INVALID_METADATA");
|
|
2925
|
+
}
|
|
2926
|
+
}, function(err) {
|
|
2927
|
+
cb(err);
|
|
2928
|
+
});
|
|
2929
|
+
};
|
|
2930
|
+
var closeChannel = function(env, channelName, cb) {
|
|
2931
|
+
if (!env.channels[channelName]) {
|
|
2932
|
+
return void cb();
|
|
2933
|
+
}
|
|
2934
|
+
try {
|
|
2935
|
+
if (typeof Util.find(env, [ "channels", channelName, "writeStream", "close" ]) === "function") {
|
|
2936
|
+
var stream = env.channels[channelName].writeStream;
|
|
2937
|
+
destroyStream(stream, channelName);
|
|
2938
|
+
}
|
|
2939
|
+
delete env.channels[channelName];
|
|
2940
|
+
cb();
|
|
2941
|
+
} catch (err) {
|
|
2942
|
+
cb(err);
|
|
2943
|
+
}
|
|
2944
|
+
};
|
|
2945
|
+
var closeInactiveChannels = function(env, schedule, activeSet) {
|
|
2946
|
+
Object.keys(env.channels).forEach(channelName => {
|
|
2947
|
+
if (!activeSet.has(channelName)) {
|
|
2948
|
+
schedule.ordered(channelName, function(next) {
|
|
2949
|
+
closeChannel(env, channelName, next);
|
|
2950
|
+
});
|
|
2951
|
+
}
|
|
2952
|
+
});
|
|
2953
|
+
};
|
|
2954
|
+
var clearOffset = function(env, channelId, cb) {
|
|
2955
|
+
var path = mkOffsetPath(env, channelId);
|
|
2956
|
+
Fs.unlink(path, cb);
|
|
2957
|
+
};
|
|
2958
|
+
var writeOffset = function(env, channelId, data, cb) {
|
|
2959
|
+
var path = mkOffsetPath(env, channelId);
|
|
2960
|
+
var s_data;
|
|
2961
|
+
try {
|
|
2962
|
+
s_data = JSON.stringify(data);
|
|
2963
|
+
} catch (err) {
|
|
2964
|
+
return void cb(err);
|
|
2965
|
+
}
|
|
2966
|
+
Fs.writeFile(path, s_data, cb);
|
|
2967
|
+
};
|
|
2968
|
+
var getOffset = function(env, channelId, cb) {
|
|
2969
|
+
var path = mkOffsetPath(env, channelId);
|
|
2970
|
+
Fs.readFile(path, function(err, content) {
|
|
2971
|
+
if (err) {
|
|
2972
|
+
return void cb(err);
|
|
2973
|
+
}
|
|
2974
|
+
try {
|
|
2975
|
+
var json = JSON.parse(content);
|
|
2976
|
+
cb(void 0, json);
|
|
2977
|
+
} catch (err2) {
|
|
2978
|
+
cb(err2);
|
|
2979
|
+
}
|
|
2980
|
+
});
|
|
2981
|
+
};
|
|
2982
|
+
var clearChannel = function(env, channelId, _cb) {
|
|
2983
|
+
var cb = Util.once(Util.mkAsync(_cb));
|
|
2984
|
+
var path = mkPath(env, channelId);
|
|
2985
|
+
getMetadataAtPath(env, path, function(e, metadata) {
|
|
2986
|
+
if (e) {
|
|
2987
|
+
return cb(new Error(e));
|
|
2988
|
+
}
|
|
2989
|
+
if (!metadata) {
|
|
2990
|
+
return void Fs.truncate(path, 0, cb);
|
|
2991
|
+
}
|
|
2992
|
+
var len = JSON.stringify(metadata).length + 1;
|
|
2993
|
+
closeChannel(env, channelId, function(err) {
|
|
2994
|
+
if (err) {
|
|
2995
|
+
cb(err);
|
|
2996
|
+
}
|
|
2997
|
+
Fs.truncate(path, len, function(err) {
|
|
2998
|
+
if (err) {
|
|
2999
|
+
return cb(err);
|
|
3000
|
+
}
|
|
3001
|
+
cb();
|
|
3002
|
+
});
|
|
3003
|
+
});
|
|
3004
|
+
clearOffset(env, channelId, function() {});
|
|
3005
|
+
});
|
|
3006
|
+
};
|
|
3007
|
+
var readMessages = function(path, msgHandler, _cb) {
|
|
3008
|
+
var stream = Fs.createReadStream(path, {
|
|
3009
|
+
start: 0
|
|
3010
|
+
});
|
|
3011
|
+
var collector = createIdleStreamCollector(stream);
|
|
3012
|
+
var cb = Util.once(Util.mkAsync(Util.both(_cb, collector)));
|
|
3013
|
+
return readFileBin(stream, function(msgObj, readMore) {
|
|
3014
|
+
collector.keepAlive();
|
|
3015
|
+
msgHandler(msgObj.buff.toString("utf8"));
|
|
3016
|
+
setTimeout(readMore);
|
|
3017
|
+
}, function(err) {
|
|
3018
|
+
cb(err);
|
|
3019
|
+
});
|
|
3020
|
+
};
|
|
3021
|
+
var getChannelMetadata = function(Env, channelId, cb) {
|
|
3022
|
+
var path = mkPath(Env, channelId);
|
|
3023
|
+
getMetadataAtPath(Env, path, cb);
|
|
3024
|
+
};
|
|
3025
|
+
var getDedicatedMetadata = function(env, channelId, handler, _cb) {
|
|
3026
|
+
var metadataPath = mkMetadataPath(env, channelId);
|
|
3027
|
+
var stream = Fs.createReadStream(metadataPath, {
|
|
3028
|
+
start: 0
|
|
3029
|
+
});
|
|
3030
|
+
const collector = createIdleStreamCollector(stream);
|
|
3031
|
+
var cb = Util.both(_cb, collector);
|
|
3032
|
+
readFileBin(stream, function(msgObj, readMore) {
|
|
3033
|
+
collector.keepAlive();
|
|
3034
|
+
var line = msgObj.buff.toString("utf8");
|
|
3035
|
+
try {
|
|
3036
|
+
var parsed = JSON.parse(line);
|
|
3037
|
+
handler(null, parsed);
|
|
3038
|
+
} catch (err) {
|
|
3039
|
+
handler(err, line);
|
|
3040
|
+
}
|
|
3041
|
+
readMore();
|
|
3042
|
+
}, function(err) {
|
|
3043
|
+
if (!err || err.code === "ENOENT") {
|
|
3044
|
+
if (err && err.code === "ENOENT") {
|
|
3045
|
+
return readPlaceholder(env, channelId, content => {
|
|
3046
|
+
cb(content);
|
|
3047
|
+
});
|
|
3048
|
+
}
|
|
3049
|
+
return void cb();
|
|
3050
|
+
}
|
|
3051
|
+
cb(err);
|
|
3052
|
+
});
|
|
3053
|
+
};
|
|
3054
|
+
var readMetadata = function(env, channelId, handler, cb) {
|
|
3055
|
+
let requiresChannel = true;
|
|
3056
|
+
let all = [];
|
|
3057
|
+
nThen(function(w) {
|
|
3058
|
+
let first = true;
|
|
3059
|
+
getDedicatedMetadata(env, channelId, (err, line) => {
|
|
3060
|
+
if (first && !err) {
|
|
3061
|
+
if (!Array.isArray(line)) {
|
|
3062
|
+
requiresChannel = false;
|
|
3063
|
+
}
|
|
3064
|
+
first = false;
|
|
3065
|
+
}
|
|
3066
|
+
all.push({
|
|
3067
|
+
err,
|
|
3068
|
+
line
|
|
3069
|
+
});
|
|
3070
|
+
}, w(function(err) {
|
|
3071
|
+
if (err) {
|
|
3072
|
+
w.abort();
|
|
3073
|
+
return void cb(err);
|
|
3074
|
+
}
|
|
3075
|
+
}));
|
|
3076
|
+
}).nThen(function(w) {
|
|
3077
|
+
if (!requiresChannel) {
|
|
3078
|
+
return;
|
|
3079
|
+
}
|
|
3080
|
+
getChannelMetadata(env, channelId, w(function(err, data) {
|
|
3081
|
+
if (err) {
|
|
3082
|
+
return void handler(err, data);
|
|
3083
|
+
}
|
|
3084
|
+
if (!data || typeof data !== "object" || Array.isArray(data)) {
|
|
3085
|
+
return;
|
|
3086
|
+
}
|
|
3087
|
+
handler(null, data);
|
|
3088
|
+
}));
|
|
3089
|
+
}).nThen(function() {
|
|
3090
|
+
all.forEach(({err, line}) => {
|
|
3091
|
+
handler(err, line);
|
|
3092
|
+
});
|
|
3093
|
+
cb();
|
|
3094
|
+
});
|
|
3095
|
+
};
|
|
3096
|
+
var writeMetadata = function(env, channelId, data, cb) {
|
|
3097
|
+
var path = mkMetadataPath(env, channelId);
|
|
3098
|
+
Fse.mkdirp(Path.dirname(path), PERMISSIVE, function(err) {
|
|
3099
|
+
if (err && err.code !== "EEXIST") {
|
|
3100
|
+
return void cb(err);
|
|
3101
|
+
}
|
|
3102
|
+
Fs.appendFile(path, data + "\n", cb);
|
|
3103
|
+
});
|
|
3104
|
+
};
|
|
3105
|
+
var checkPath = function(path, callback) {
|
|
3106
|
+
Fs.stat(path, function(err) {
|
|
3107
|
+
if (!err) {
|
|
3108
|
+
callback(undefined, true);
|
|
3109
|
+
return;
|
|
3110
|
+
}
|
|
3111
|
+
if (err.code !== "ENOENT") {
|
|
3112
|
+
callback(err);
|
|
3113
|
+
return;
|
|
3114
|
+
}
|
|
3115
|
+
Fse.mkdirp(Path.dirname(path), PERMISSIVE, function(err) {
|
|
3116
|
+
if (err && err.code !== "EEXIST") {
|
|
3117
|
+
callback(err);
|
|
3118
|
+
return;
|
|
3119
|
+
}
|
|
3120
|
+
callback(undefined, false);
|
|
3121
|
+
});
|
|
3122
|
+
});
|
|
3123
|
+
};
|
|
3124
|
+
var labelError = function(label, err) {
|
|
3125
|
+
return label + (err.code ? "_" + err.code : "");
|
|
3126
|
+
};
|
|
3127
|
+
var removeChannel = function(env, channelName, cb) {
|
|
3128
|
+
var channelPath = mkPath(env, channelName);
|
|
3129
|
+
var metadataPath = mkMetadataPath(env, channelName);
|
|
3130
|
+
var CB = Util.once(cb);
|
|
3131
|
+
var errors = 0;
|
|
3132
|
+
nThen(function(w) {
|
|
3133
|
+
Fs.unlink(channelPath, w(function(err) {
|
|
3134
|
+
if (err) {
|
|
3135
|
+
if (err.code === "ENOENT") {
|
|
3136
|
+
errors++;
|
|
3137
|
+
return;
|
|
3138
|
+
}
|
|
3139
|
+
w.abort();
|
|
3140
|
+
CB(labelError("E_CHANNEL_REMOVAL", err));
|
|
3141
|
+
}
|
|
3142
|
+
}));
|
|
3143
|
+
Fs.unlink(metadataPath, w(function(err) {
|
|
3144
|
+
if (err) {
|
|
3145
|
+
if (err.code === "ENOENT") {
|
|
3146
|
+
errors++;
|
|
3147
|
+
return;
|
|
3148
|
+
}
|
|
3149
|
+
w.abort();
|
|
3150
|
+
CB(labelError("E_METADATA_REMOVAL", err));
|
|
3151
|
+
}
|
|
3152
|
+
}));
|
|
3153
|
+
clearOffset(env, channelName, w());
|
|
3154
|
+
}).nThen(function() {
|
|
3155
|
+
if (errors === 2) {
|
|
3156
|
+
return void CB(labelError("E_REMOVE_CHANNEL", new Error("ENOENT")));
|
|
3157
|
+
}
|
|
3158
|
+
CB();
|
|
3159
|
+
});
|
|
3160
|
+
};
|
|
3161
|
+
var removeArchivedChannel = function(env, channelName, cb) {
|
|
3162
|
+
var channelPath = mkArchivePath(env, channelName);
|
|
3163
|
+
var metadataPath = mkArchiveMetadataPath(env, channelName);
|
|
3164
|
+
var CB = Util.once(cb);
|
|
3165
|
+
nThen(function(w) {
|
|
3166
|
+
Fs.unlink(channelPath, w(function(err) {
|
|
3167
|
+
if (err) {
|
|
3168
|
+
if (err.code === "ENOENT") {
|
|
3169
|
+
return;
|
|
3170
|
+
}
|
|
3171
|
+
w.abort();
|
|
3172
|
+
CB(labelError("E_ARCHIVED_CHANNEL_REMOVAL", err));
|
|
3173
|
+
}
|
|
3174
|
+
}));
|
|
3175
|
+
Fs.unlink(metadataPath, w(function(err) {
|
|
3176
|
+
if (err) {
|
|
3177
|
+
if (err.code === "ENOENT") {
|
|
3178
|
+
return;
|
|
3179
|
+
}
|
|
3180
|
+
w.abort();
|
|
3181
|
+
CB(labelError("E_ARCHIVED_METADATA_REMOVAL", err));
|
|
3182
|
+
}
|
|
3183
|
+
}));
|
|
3184
|
+
}).nThen(function() {
|
|
3185
|
+
CB();
|
|
3186
|
+
});
|
|
3187
|
+
};
|
|
3188
|
+
var _getStats = function(metadataPath, filePath, channel, cb, isLonelyMetadata) {
|
|
3189
|
+
var metaStat, channelStat;
|
|
3190
|
+
var metaErr, channelErr;
|
|
3191
|
+
nThen(function(ww) {
|
|
3192
|
+
Fs.stat(metadataPath, ww(function(err, stats) {
|
|
3193
|
+
if (err) {
|
|
3194
|
+
metaErr = err;
|
|
3195
|
+
return;
|
|
3196
|
+
}
|
|
3197
|
+
metaStat = stats;
|
|
3198
|
+
}));
|
|
3199
|
+
if (isLonelyMetadata) {
|
|
3200
|
+
return;
|
|
3201
|
+
}
|
|
3202
|
+
Fs.stat(filePath, ww(function(err, stats) {
|
|
3203
|
+
if (err) {
|
|
3204
|
+
channelErr = err;
|
|
3205
|
+
return;
|
|
3206
|
+
}
|
|
3207
|
+
channelStat = stats;
|
|
3208
|
+
}));
|
|
3209
|
+
}).nThen(function() {
|
|
3210
|
+
if (channelErr && metaErr) {
|
|
3211
|
+
return void cb(channelErr);
|
|
3212
|
+
}
|
|
3213
|
+
var data = {
|
|
3214
|
+
channel
|
|
3215
|
+
};
|
|
3216
|
+
if (metaStat && channelStat) {
|
|
3217
|
+
data.atime = Math.max(channelStat.atime, metaStat.atime);
|
|
3218
|
+
data.mtime = Math.max(channelStat.mtime, metaStat.mtime);
|
|
3219
|
+
data.ctime = Math.max(channelStat.ctime, metaStat.ctime);
|
|
3220
|
+
data.size = channelStat.size + metaStat.size;
|
|
3221
|
+
} else if (metaStat) {
|
|
3222
|
+
data.atime = metaStat.atime;
|
|
3223
|
+
data.mtime = metaStat.mtime;
|
|
3224
|
+
data.ctime = metaStat.ctime;
|
|
3225
|
+
data.size = metaStat.size;
|
|
3226
|
+
} else if (channelStat) {
|
|
3227
|
+
data.atime = channelStat.atime;
|
|
3228
|
+
data.mtime = channelStat.mtime;
|
|
3229
|
+
data.ctime = channelStat.ctime;
|
|
3230
|
+
data.size = channelStat.size;
|
|
3231
|
+
} else {
|
|
3232
|
+
return void cb("NO_DATA");
|
|
3233
|
+
}
|
|
3234
|
+
cb(void 0, data);
|
|
3235
|
+
});
|
|
3236
|
+
};
|
|
3237
|
+
var getStats = function(env, channelName, cb) {
|
|
3238
|
+
var metadataPath = mkMetadataPath(env, channelName);
|
|
3239
|
+
var filePath = mkPath(env, channelName);
|
|
3240
|
+
_getStats(metadataPath, filePath, channelName, cb);
|
|
3241
|
+
};
|
|
3242
|
+
var listChannels = function(root, handler, cb, fast) {
|
|
3243
|
+
var dirList = [];
|
|
3244
|
+
nThen(function(w) {
|
|
3245
|
+
Fs.readdir(root, w(function(err, list) {
|
|
3246
|
+
if (err) {
|
|
3247
|
+
w.abort();
|
|
3248
|
+
return void cb(err);
|
|
3249
|
+
}
|
|
3250
|
+
dirList = list;
|
|
3251
|
+
}));
|
|
3252
|
+
}).nThen(function(waitFor) {
|
|
3253
|
+
var n = nThen;
|
|
3254
|
+
dirList.forEach(function(dir) {
|
|
3255
|
+
n = n(function(w) {
|
|
3256
|
+
var sema = Semaphore.create(20);
|
|
3257
|
+
var nestedDirPath = Path.join(root, dir);
|
|
3258
|
+
Fs.readdir(nestedDirPath, w(function(err, list) {
|
|
3259
|
+
if (err) {
|
|
3260
|
+
return void handler(err);
|
|
3261
|
+
}
|
|
3262
|
+
list.forEach(function(item) {
|
|
3263
|
+
if (/^\./.test(item)) {
|
|
3264
|
+
return;
|
|
3265
|
+
}
|
|
3266
|
+
if (!/^[0-9a-fA-F]{32}(\.metadata?)*\.ndjson$/.test(item)) {
|
|
3267
|
+
return;
|
|
3268
|
+
}
|
|
3269
|
+
var isLonelyMetadata = false;
|
|
3270
|
+
var channelName;
|
|
3271
|
+
var metadataName;
|
|
3272
|
+
if (!/^[0-9a-fA-F]{32,33}\.ndjson$/.test(item)) {
|
|
3273
|
+
metadataName = item;
|
|
3274
|
+
channelName = item.replace(/\.metadata/, "");
|
|
3275
|
+
if (list.indexOf(channelName) !== -1) {
|
|
3276
|
+
return;
|
|
3277
|
+
}
|
|
3278
|
+
isLonelyMetadata = true;
|
|
3279
|
+
} else {
|
|
3280
|
+
channelName = item;
|
|
3281
|
+
metadataName = channelName.replace(/\.ndjson$/, ".metadata.ndjson");
|
|
3282
|
+
}
|
|
3283
|
+
var channel = metadataName.replace(/\.metadata.ndjson$/, "");
|
|
3284
|
+
if ([ 32, 33, 34, 44 ].indexOf(channel.length) === -1) {
|
|
3285
|
+
return;
|
|
3286
|
+
}
|
|
3287
|
+
sema.take(function(give) {
|
|
3288
|
+
var next = w(give());
|
|
3289
|
+
if (fast) {
|
|
3290
|
+
return void handler(void 0, {
|
|
3291
|
+
channel
|
|
3292
|
+
}, next);
|
|
3293
|
+
}
|
|
3294
|
+
var filePath = Path.join(nestedDirPath, channelName);
|
|
3295
|
+
var metadataPath = Path.join(nestedDirPath, metadataName);
|
|
3296
|
+
return void _getStats(metadataPath, filePath, channel, function(err, data) {
|
|
3297
|
+
if (err) {
|
|
3298
|
+
return void handler(err, void 0, next);
|
|
3299
|
+
}
|
|
3300
|
+
handler(void 0, data, next);
|
|
3301
|
+
}, isLonelyMetadata);
|
|
3302
|
+
});
|
|
3303
|
+
});
|
|
3304
|
+
}));
|
|
3305
|
+
}).nThen;
|
|
3306
|
+
});
|
|
3307
|
+
n(waitFor());
|
|
3308
|
+
}).nThen(function() {
|
|
3309
|
+
cb();
|
|
3310
|
+
});
|
|
3311
|
+
};
|
|
3312
|
+
var archiveChannel = function(env, channelName, reason, cb) {
|
|
3313
|
+
var currentPath = mkPath(env, channelName);
|
|
3314
|
+
var archivePath = mkArchivePath(env, channelName);
|
|
3315
|
+
nThen(function(w) {
|
|
3316
|
+
Fse.move(currentPath, archivePath, {
|
|
3317
|
+
overwrite: true
|
|
3318
|
+
}, w(function(err) {
|
|
3319
|
+
if (err) {
|
|
3320
|
+
if (err.code === "ENOENT") {
|
|
3321
|
+
return;
|
|
3322
|
+
}
|
|
3323
|
+
w.abort();
|
|
3324
|
+
return void cb(err);
|
|
3325
|
+
}
|
|
3326
|
+
}));
|
|
3327
|
+
}).nThen(function(w) {
|
|
3328
|
+
clearOffset(env, channelName, w());
|
|
3329
|
+
}).nThen(function(w) {
|
|
3330
|
+
if (!reason) {
|
|
3331
|
+
return;
|
|
3332
|
+
}
|
|
3333
|
+
addPlaceholder(env, channelName, reason, w());
|
|
3334
|
+
}).nThen(function(w) {
|
|
3335
|
+
var metadataPath = mkMetadataPath(env, channelName);
|
|
3336
|
+
var archiveMetadataPath = mkArchiveMetadataPath(env, channelName);
|
|
3337
|
+
Fse.move(metadataPath, archiveMetadataPath, {
|
|
3338
|
+
overwrite: true
|
|
3339
|
+
}, w(function(err) {
|
|
3340
|
+
if (err && err.code === "ENOENT") {
|
|
3341
|
+
return void cb();
|
|
3342
|
+
}
|
|
3343
|
+
if (err) {
|
|
3344
|
+
return void cb(labelError("E_METADATA_ARCHIVAL", err));
|
|
3345
|
+
}
|
|
3346
|
+
cb();
|
|
3347
|
+
}));
|
|
3348
|
+
});
|
|
3349
|
+
};
|
|
3350
|
+
var unarchiveChannel = function(env, channelName, cb) {
|
|
3351
|
+
var channelPath = mkPath(env, channelName);
|
|
3352
|
+
var metadataPath = mkMetadataPath(env, channelName);
|
|
3353
|
+
var CB = Util.once(cb);
|
|
3354
|
+
var ENOENT = false;
|
|
3355
|
+
nThen(function(w) {
|
|
3356
|
+
channelExists(channelPath, w(function(err, exists) {
|
|
3357
|
+
if (err) {
|
|
3358
|
+
w.abort();
|
|
3359
|
+
return void CB(err);
|
|
3360
|
+
}
|
|
3361
|
+
if (exists) {
|
|
3362
|
+
w.abort();
|
|
3363
|
+
return CB("UNARCHIVE_CHANNEL_CONFLICT");
|
|
3364
|
+
}
|
|
3365
|
+
}));
|
|
3366
|
+
channelExists(metadataPath, w(function(err, exists) {
|
|
3367
|
+
if (err) {
|
|
3368
|
+
w.abort();
|
|
3369
|
+
return void CB(err);
|
|
3370
|
+
}
|
|
3371
|
+
if (exists) {
|
|
3372
|
+
w.abort();
|
|
3373
|
+
return CB("UNARCHIVE_METADATA_CONFLICT");
|
|
3374
|
+
}
|
|
3375
|
+
}));
|
|
3376
|
+
}).nThen(function(w) {
|
|
3377
|
+
var archiveChannelPath = mkArchivePath(env, channelName);
|
|
3378
|
+
Fse.move(archiveChannelPath, channelPath, w(function(err) {
|
|
3379
|
+
if (err && err.code === "ENOENT") {
|
|
3380
|
+
ENOENT = true;
|
|
3381
|
+
return;
|
|
3382
|
+
}
|
|
3383
|
+
if (err) {
|
|
3384
|
+
w.abort();
|
|
3385
|
+
return void CB(err);
|
|
3386
|
+
}
|
|
3387
|
+
}));
|
|
3388
|
+
}).nThen(function(w) {
|
|
3389
|
+
clearPlaceholder(env, channelName, w());
|
|
3390
|
+
}).nThen(function(w) {
|
|
3391
|
+
var archiveMetadataPath = mkArchiveMetadataPath(env, channelName);
|
|
3392
|
+
Fse.move(archiveMetadataPath, metadataPath, w(function(err) {
|
|
3393
|
+
if (err && err.code === "ENOENT") {
|
|
3394
|
+
if (ENOENT) {
|
|
3395
|
+
return void cb("ENOENT");
|
|
3396
|
+
}
|
|
3397
|
+
return CB();
|
|
3398
|
+
}
|
|
3399
|
+
if (err) {
|
|
3400
|
+
w.abort();
|
|
3401
|
+
return void CB(labelError("E_METADATA_RESTORATION", err));
|
|
3402
|
+
}
|
|
3403
|
+
CB();
|
|
3404
|
+
}));
|
|
3405
|
+
});
|
|
3406
|
+
};
|
|
3407
|
+
var channelBytes = function(env, chanName, cb) {
|
|
3408
|
+
var channelPath = mkPath(env, chanName);
|
|
3409
|
+
var dataPath = mkMetadataPath(env, chanName);
|
|
3410
|
+
var CB = Util.once(cb);
|
|
3411
|
+
var channelSize = 0;
|
|
3412
|
+
var dataSize = 0;
|
|
3413
|
+
nThen(function(w) {
|
|
3414
|
+
Fs.stat(channelPath, w(function(err, stats) {
|
|
3415
|
+
if (err) {
|
|
3416
|
+
if (err.code === "ENOENT") {
|
|
3417
|
+
return;
|
|
3418
|
+
}
|
|
3419
|
+
return void CB(err);
|
|
3420
|
+
}
|
|
3421
|
+
channelSize = stats.size;
|
|
3422
|
+
}));
|
|
3423
|
+
Fs.stat(dataPath, w(function(err, stats) {
|
|
3424
|
+
if (err) {
|
|
3425
|
+
if (err.code === "ENOENT") {
|
|
3426
|
+
return;
|
|
3427
|
+
}
|
|
3428
|
+
return void CB(err);
|
|
3429
|
+
}
|
|
3430
|
+
dataSize = stats.size;
|
|
3431
|
+
}));
|
|
3432
|
+
}).nThen(function() {
|
|
3433
|
+
CB(void 0, channelSize + dataSize);
|
|
3434
|
+
});
|
|
3435
|
+
};
|
|
3436
|
+
var getChannel = function(env, id, _callback) {
|
|
3437
|
+
var cb = Util.once(Util.mkAsync(_callback));
|
|
3438
|
+
if (env.channels[id]) {
|
|
3439
|
+
var chan = env.channels[id];
|
|
3440
|
+
chan.delayClose();
|
|
3441
|
+
return void cb(void 0, chan);
|
|
3442
|
+
}
|
|
3443
|
+
return void env.batchGetChannel(id, cb, function(done) {
|
|
3444
|
+
var path = mkPath(env, id);
|
|
3445
|
+
var channel = {
|
|
3446
|
+
onError: []
|
|
3447
|
+
};
|
|
3448
|
+
nThen(function(w) {
|
|
3449
|
+
checkPath(path, w(function(err) {
|
|
3450
|
+
if (err) {
|
|
3451
|
+
w.abort();
|
|
3452
|
+
return void done(err);
|
|
3453
|
+
}
|
|
3454
|
+
}));
|
|
3455
|
+
}).nThen(function(w) {
|
|
3456
|
+
var stream = channel.writeStream = Fs.createWriteStream(path, {
|
|
3457
|
+
flags: "a"
|
|
3458
|
+
});
|
|
3459
|
+
stream.on("open", w());
|
|
3460
|
+
stream.on("error", function(err) {
|
|
3461
|
+
w.abort();
|
|
3462
|
+
channel.onError.forEach(function(handler) {
|
|
3463
|
+
handler(err);
|
|
3464
|
+
});
|
|
3465
|
+
});
|
|
3466
|
+
}).nThen(function() {
|
|
3467
|
+
channel.delayClose = Util.throttle(Util.once(function() {
|
|
3468
|
+
delete env.channels[id];
|
|
3469
|
+
destroyStream(channel.writeStream);
|
|
3470
|
+
}), CHANNEL_WRITE_WINDOW);
|
|
3471
|
+
channel.delayClose();
|
|
3472
|
+
env.channels[id] = channel;
|
|
3473
|
+
done(void 0, channel);
|
|
3474
|
+
});
|
|
3475
|
+
});
|
|
3476
|
+
};
|
|
3477
|
+
const messageBin = (env, chanName, msgBin, cb) => {
|
|
3478
|
+
var complete = Util.once(cb);
|
|
3479
|
+
getChannel(env, chanName, function(err, chan) {
|
|
3480
|
+
if (!chan) {
|
|
3481
|
+
return void complete(err);
|
|
3482
|
+
}
|
|
3483
|
+
chan.onError.push(complete);
|
|
3484
|
+
chan.writeStream.write(msgBin, function() {
|
|
3485
|
+
chan.onError.splice(chan.onError.indexOf(complete), 1);
|
|
3486
|
+
complete();
|
|
3487
|
+
if (chan.onError.length) {
|
|
3488
|
+
return;
|
|
3489
|
+
}
|
|
3490
|
+
if (chan.delayClose && chan.delayClose.clear) {
|
|
3491
|
+
chan.delayClose.clear();
|
|
3492
|
+
destroyStream(chan.writeStream);
|
|
3493
|
+
delete env.channels[chanName];
|
|
3494
|
+
}
|
|
3495
|
+
});
|
|
3496
|
+
});
|
|
3497
|
+
};
|
|
3498
|
+
var message = function(env, chanName, msg, cb) {
|
|
3499
|
+
messageBin(env, chanName, Buffer.from(msg + "\n", "utf8"), cb);
|
|
3500
|
+
};
|
|
3501
|
+
var getMessages = function(env, chanName, handler, cb) {
|
|
3502
|
+
var errorState = false;
|
|
3503
|
+
var path = mkPath(env, chanName);
|
|
3504
|
+
readMessages(path, function(msg) {
|
|
3505
|
+
if (!msg || errorState) {
|
|
3506
|
+
return;
|
|
3507
|
+
}
|
|
3508
|
+
try {
|
|
3509
|
+
handler(msg);
|
|
3510
|
+
} catch (e) {
|
|
3511
|
+
errorState = true;
|
|
3512
|
+
return void cb(e);
|
|
3513
|
+
}
|
|
3514
|
+
}, function(err) {
|
|
3515
|
+
if (err) {
|
|
3516
|
+
errorState = true;
|
|
3517
|
+
return void cb(err);
|
|
3518
|
+
}
|
|
3519
|
+
cb();
|
|
3520
|
+
});
|
|
3521
|
+
};
|
|
3522
|
+
var filterMessages = function(env, channelName, check, filterHandler, _cb) {
|
|
3523
|
+
var cb = Util.once(Util.mkAsync(_cb));
|
|
3524
|
+
var tempChannelPath = mkTempPath(env, channelName);
|
|
3525
|
+
var channelPath = mkPath(env, channelName);
|
|
3526
|
+
var metadataPath = mkMetadataPath(env, channelName);
|
|
3527
|
+
var archiveChannelPath = mkArchivePath(env, channelName);
|
|
3528
|
+
var archiveMetadataPath = mkArchiveMetadataPath(env, channelName);
|
|
3529
|
+
var metadataReference = {};
|
|
3530
|
+
var tempStream;
|
|
3531
|
+
var ABORT;
|
|
3532
|
+
var cleanUp = function(cb) {
|
|
3533
|
+
destroyStream(tempStream);
|
|
3534
|
+
Fse.unlink(tempChannelPath, function(err) {
|
|
3535
|
+
if (!err || err.code === "ENOENT") {
|
|
3536
|
+
return cb();
|
|
3537
|
+
}
|
|
3538
|
+
cb(err);
|
|
3539
|
+
});
|
|
3540
|
+
};
|
|
3541
|
+
nThen(function(w) {
|
|
3542
|
+
closeChannel(env, channelName, w(function(err) {
|
|
3543
|
+
if (err) {
|
|
3544
|
+
w.abort();
|
|
3545
|
+
return void cb(err);
|
|
3546
|
+
}
|
|
3547
|
+
}));
|
|
3548
|
+
}).nThen(function(w) {
|
|
3549
|
+
clearOffset(env, channelName, w());
|
|
3550
|
+
cleanUp(w(function(err) {
|
|
3551
|
+
if (err) {
|
|
3552
|
+
w.abort();
|
|
3553
|
+
cb(err);
|
|
3554
|
+
}
|
|
3555
|
+
}));
|
|
3556
|
+
}).nThen(function(w) {
|
|
3557
|
+
var lineHandler = Meta.createLineHandler(metadataReference, Util.noop);
|
|
3558
|
+
readMetadata(env, channelName, lineHandler, w(function(err) {
|
|
3559
|
+
if (err) {
|
|
3560
|
+
w.abort();
|
|
3561
|
+
return void cb(err);
|
|
3562
|
+
}
|
|
3563
|
+
}));
|
|
3564
|
+
}).nThen(function(w) {
|
|
3565
|
+
if (typeof check !== "function") {
|
|
3566
|
+
return;
|
|
3567
|
+
}
|
|
3568
|
+
if (!metadataReference.meta || !check(metadataReference.meta)) {
|
|
3569
|
+
w.abort();
|
|
3570
|
+
return void cb("EFORBIDDEN");
|
|
3571
|
+
}
|
|
3572
|
+
}).nThen(function(w) {
|
|
3573
|
+
tempStream = Fs.createWriteStream(tempChannelPath, {
|
|
3574
|
+
flags: "a"
|
|
3575
|
+
});
|
|
3576
|
+
tempStream.on("open", w());
|
|
3577
|
+
tempStream.on("error", function(err) {
|
|
3578
|
+
w.abort();
|
|
3579
|
+
ABORT = true;
|
|
3580
|
+
cleanUp(function() {
|
|
3581
|
+
cb(err);
|
|
3582
|
+
});
|
|
3583
|
+
});
|
|
3584
|
+
}).nThen(function(w) {
|
|
3585
|
+
var i = 0;
|
|
3586
|
+
var retain = false;
|
|
3587
|
+
var handler = function(msgObj, readMore, abort) {
|
|
3588
|
+
if (ABORT) {
|
|
3589
|
+
return void abort();
|
|
3590
|
+
}
|
|
3591
|
+
if (i++ === 0 && msgObj.buff.indexOf("{") === 0) {
|
|
3592
|
+
return readMore();
|
|
3593
|
+
}
|
|
3594
|
+
var s_msg = msgObj.buff.toString("utf8");
|
|
3595
|
+
if (retain) {
|
|
3596
|
+
return void tempStream.write(s_msg + "\n", function() {
|
|
3597
|
+
readMore();
|
|
3598
|
+
});
|
|
3599
|
+
}
|
|
3600
|
+
var msg = Util.tryParse(s_msg);
|
|
3601
|
+
if (!msg) {
|
|
3602
|
+
return void readMore();
|
|
3603
|
+
}
|
|
3604
|
+
var msgHash = Extras.getHash(msg[4]);
|
|
3605
|
+
var remove = function() {
|
|
3606
|
+
readMore();
|
|
3607
|
+
};
|
|
3608
|
+
var preserve = function() {
|
|
3609
|
+
tempStream.write(s_msg + "\n", function() {
|
|
3610
|
+
readMore();
|
|
3611
|
+
});
|
|
3612
|
+
};
|
|
3613
|
+
var preserveRemaining = function() {
|
|
3614
|
+
retain = true;
|
|
3615
|
+
};
|
|
3616
|
+
filterHandler(msg, msgHash, abort, remove, preserve, preserveRemaining);
|
|
3617
|
+
};
|
|
3618
|
+
readMessagesBin(env, channelName, 0, handler, w(function(err) {
|
|
3619
|
+
if (err) {
|
|
3620
|
+
w.abort();
|
|
3621
|
+
return void cleanUp(function() {
|
|
3622
|
+
cb(err);
|
|
3623
|
+
});
|
|
3624
|
+
}
|
|
3625
|
+
if (!retain) {
|
|
3626
|
+
w.abort();
|
|
3627
|
+
cleanUp(function() {
|
|
3628
|
+
cb("HASH_NOT_FOUND");
|
|
3629
|
+
});
|
|
3630
|
+
}
|
|
3631
|
+
}));
|
|
3632
|
+
}).nThen(function(w) {
|
|
3633
|
+
Fse.copy(channelPath, archiveChannelPath, w(function(err) {
|
|
3634
|
+
if (!err || err.code === "ENOENT") {
|
|
3635
|
+
return;
|
|
3636
|
+
}
|
|
3637
|
+
w.abort();
|
|
3638
|
+
cleanUp(function() {
|
|
3639
|
+
cb(err);
|
|
3640
|
+
});
|
|
3641
|
+
}));
|
|
3642
|
+
Fse.copy(metadataPath, archiveMetadataPath, w(function(err) {
|
|
3643
|
+
if (!err || err.code === "ENOENT") {
|
|
3644
|
+
return;
|
|
3645
|
+
}
|
|
3646
|
+
w.abort();
|
|
3647
|
+
cleanUp(function() {
|
|
3648
|
+
cb(err);
|
|
3649
|
+
});
|
|
3650
|
+
}));
|
|
3651
|
+
}).nThen(function(w) {
|
|
3652
|
+
Fs.writeFile(metadataPath, JSON.stringify(metadataReference.meta) + "\n", w(function(err) {
|
|
3653
|
+
if (err) {
|
|
3654
|
+
w.abort();
|
|
3655
|
+
cb(err);
|
|
3656
|
+
}
|
|
3657
|
+
}));
|
|
3658
|
+
Fse.move(tempChannelPath, channelPath, {
|
|
3659
|
+
overwrite: true
|
|
3660
|
+
}, w(function(err) {
|
|
3661
|
+
if (err) {
|
|
3662
|
+
w.abort();
|
|
3663
|
+
cb(err);
|
|
3664
|
+
}
|
|
3665
|
+
}));
|
|
3666
|
+
}).nThen(function() {
|
|
3667
|
+
cleanUp(function() {
|
|
3668
|
+
cb();
|
|
3669
|
+
});
|
|
3670
|
+
});
|
|
3671
|
+
};
|
|
3672
|
+
var deleteChannelLine = function(env, channelName, hash, checkRights, _cb) {
|
|
3673
|
+
var check = function(meta) {
|
|
3674
|
+
return Boolean(meta.deleteLines);
|
|
3675
|
+
};
|
|
3676
|
+
var handler = function(msg, msgHash, abort, remove, preserve, preserveRemaining) {
|
|
3677
|
+
if (msgHash === hash) {
|
|
3678
|
+
if (typeof checkRights === "function" && !checkRights(msg[4])) {
|
|
3679
|
+
return void abort();
|
|
3680
|
+
}
|
|
3681
|
+
preserveRemaining();
|
|
3682
|
+
return void remove();
|
|
3683
|
+
}
|
|
3684
|
+
preserve();
|
|
3685
|
+
};
|
|
3686
|
+
filterMessages(env, channelName, check, handler, _cb);
|
|
3687
|
+
};
|
|
3688
|
+
var trimChannel = function(env, channelName, hash, _cb) {
|
|
3689
|
+
var handler = function(msg, msgHash, abort, remove, preserve, preserveRemaining) {
|
|
3690
|
+
if (msgHash === hash) {
|
|
3691
|
+
preserveRemaining();
|
|
3692
|
+
return void preserve();
|
|
3693
|
+
}
|
|
3694
|
+
remove();
|
|
3695
|
+
};
|
|
3696
|
+
filterMessages(env, channelName, null, handler, _cb);
|
|
3697
|
+
};
|
|
3698
|
+
file.create = function(conf, _cb) {
|
|
3699
|
+
var cb = Util.once(Util.mkAsync(_cb));
|
|
3700
|
+
var env = {
|
|
3701
|
+
root: Path.resolve(conf.filePath || "./datastore"),
|
|
3702
|
+
archiveRoot: Path.resolve(conf.archivePath || "./data/archive"),
|
|
3703
|
+
volumeId: conf.volumeId || "datastore",
|
|
3704
|
+
channels: {},
|
|
3705
|
+
batchGetChannel: BatchRead("store_batch_channel")
|
|
3706
|
+
};
|
|
3707
|
+
var it;
|
|
3708
|
+
var schedule = env.schedule = Schedule();
|
|
3709
|
+
nThen(function(w) {
|
|
3710
|
+
Fse.mkdirp(env.root, PERMISSIVE, w(function(err) {
|
|
3711
|
+
if (err && err.code !== "EEXIST") {
|
|
3712
|
+
w.abort();
|
|
3713
|
+
return void cb(err);
|
|
3714
|
+
}
|
|
3715
|
+
}));
|
|
3716
|
+
Fse.mkdirp(Path.join(env.archiveRoot, env.volumeId), PERMISSIVE, w(function(err) {
|
|
3717
|
+
if (err && err.code !== "EEXIST") {
|
|
3718
|
+
w.abort();
|
|
3719
|
+
return void cb(err);
|
|
3720
|
+
}
|
|
3721
|
+
}));
|
|
3722
|
+
}).nThen(function() {
|
|
3723
|
+
cb(void 0, {
|
|
3724
|
+
message: function(channelName, content, cb) {
|
|
3725
|
+
if (!isValidChannelId(channelName)) {
|
|
3726
|
+
return void cb(new Error("EINVAL"));
|
|
3727
|
+
}
|
|
3728
|
+
schedule.ordered(channelName, function(next) {
|
|
3729
|
+
message(env, channelName, content, Util.both(cb, next));
|
|
3730
|
+
});
|
|
3731
|
+
},
|
|
3732
|
+
getMessages: function(channelName, msgHandler, cb) {
|
|
3733
|
+
if (!isValidChannelId(channelName)) {
|
|
3734
|
+
return void cb(new Error("EINVAL"));
|
|
3735
|
+
}
|
|
3736
|
+
schedule.unordered(channelName, function(next) {
|
|
3737
|
+
getMessages(env, channelName, msgHandler, Util.both(cb, next));
|
|
3738
|
+
});
|
|
3739
|
+
},
|
|
3740
|
+
messageBin: (channelName, content, cb) => {
|
|
3741
|
+
if (!isValidChannelId(channelName)) {
|
|
3742
|
+
return void cb(new Error("EINVAL"));
|
|
3743
|
+
}
|
|
3744
|
+
schedule.ordered(channelName, function(next) {
|
|
3745
|
+
messageBin(env, channelName, content, Util.both(cb, next));
|
|
3746
|
+
});
|
|
3747
|
+
},
|
|
3748
|
+
readMessagesBin: (channelName, start, asyncMsgHandler, cb) => {
|
|
3749
|
+
if (!isValidChannelId(channelName)) {
|
|
3750
|
+
return void cb(new Error("EINVAL"));
|
|
3751
|
+
}
|
|
3752
|
+
schedule.unordered(channelName, function(next) {
|
|
3753
|
+
readMessagesBin(env, channelName, start, asyncMsgHandler, Util.both(cb, next));
|
|
3754
|
+
});
|
|
3755
|
+
},
|
|
3756
|
+
getWeakLock: function(channelName, _cb) {
|
|
3757
|
+
var cb = Util.once(Util.mkAsync(_cb));
|
|
3758
|
+
schedule.unordered(channelName, cb);
|
|
3759
|
+
},
|
|
3760
|
+
removeChannel: function(channelName, cb) {
|
|
3761
|
+
if (!isValidChannelId(channelName)) {
|
|
3762
|
+
return void cb(new Error("EINVAL"));
|
|
3763
|
+
}
|
|
3764
|
+
schedule.ordered(channelName, function(next) {
|
|
3765
|
+
removeChannel(env, channelName, Util.both(cb, next));
|
|
3766
|
+
});
|
|
3767
|
+
},
|
|
3768
|
+
removeArchivedChannel: function(channelName, cb) {
|
|
3769
|
+
if (!isValidChannelId(channelName)) {
|
|
3770
|
+
return void cb(new Error("EINVAL"));
|
|
3771
|
+
}
|
|
3772
|
+
schedule.ordered(channelName, function(next) {
|
|
3773
|
+
removeArchivedChannel(env, channelName, Util.both(cb, next));
|
|
3774
|
+
});
|
|
3775
|
+
},
|
|
3776
|
+
clearChannel: function(channelName, cb) {
|
|
3777
|
+
if (!isValidChannelId(channelName)) {
|
|
3778
|
+
return void cb(new Error("EINVAL"));
|
|
3779
|
+
}
|
|
3780
|
+
schedule.ordered(channelName, function(next) {
|
|
3781
|
+
clearChannel(env, channelName, Util.both(cb, next));
|
|
3782
|
+
});
|
|
3783
|
+
},
|
|
3784
|
+
trimChannel: function(channelName, hash, cb) {
|
|
3785
|
+
if (!isValidChannelId(channelName)) {
|
|
3786
|
+
return void cb(new Error("EINVAL"));
|
|
3787
|
+
}
|
|
3788
|
+
schedule.blocking(channelName, function(next) {
|
|
3789
|
+
trimChannel(env, channelName, hash, Util.both(cb, next));
|
|
3790
|
+
});
|
|
3791
|
+
},
|
|
3792
|
+
deleteChannelLine: function(channelName, hash, checkRights, cb) {
|
|
3793
|
+
if (!isValidChannelId(channelName)) {
|
|
3794
|
+
return void cb(new Error("EINVAL"));
|
|
3795
|
+
}
|
|
3796
|
+
schedule.blocking(channelName, function(next) {
|
|
3797
|
+
deleteChannelLine(env, channelName, hash, checkRights, Util.both(cb, next));
|
|
3798
|
+
});
|
|
3799
|
+
},
|
|
3800
|
+
isChannelAvailable: function(channelName, cb) {
|
|
3801
|
+
if (!isValidChannelId(channelName)) {
|
|
3802
|
+
return void cb(new Error("EINVAL"));
|
|
3803
|
+
}
|
|
3804
|
+
isChannelAvailable(env, channelName, cb);
|
|
3805
|
+
},
|
|
3806
|
+
isChannelArchived: function(channelName, cb) {
|
|
3807
|
+
if (!isValidChannelId(channelName)) {
|
|
3808
|
+
return void cb(new Error("EINVAL"));
|
|
3809
|
+
}
|
|
3810
|
+
isChannelArchived(env, channelName, cb);
|
|
3811
|
+
},
|
|
3812
|
+
archiveChannel: function(channelName, reason, cb) {
|
|
3813
|
+
if (!isValidChannelId(channelName)) {
|
|
3814
|
+
return void cb(new Error("EINVAL"));
|
|
3815
|
+
}
|
|
3816
|
+
schedule.unordered(channelName, function(next) {
|
|
3817
|
+
archiveChannel(env, channelName, reason, Util.both(cb, next));
|
|
3818
|
+
});
|
|
3819
|
+
},
|
|
3820
|
+
restoreArchivedChannel: function(channelName, cb) {
|
|
3821
|
+
if (!isValidChannelId(channelName)) {
|
|
3822
|
+
return void cb(new Error("EINVAL"));
|
|
3823
|
+
}
|
|
3824
|
+
schedule.ordered(channelName, function(next) {
|
|
3825
|
+
unarchiveChannel(env, channelName, Util.both(cb, next));
|
|
3826
|
+
});
|
|
3827
|
+
},
|
|
3828
|
+
clearOffset: function(channelName, _cb) {
|
|
3829
|
+
var cb = Util.once(Util.mkAsync(_cb));
|
|
3830
|
+
if (!isValidChannelId(channelName)) {
|
|
3831
|
+
return void cb(new Error("EINVAL"));
|
|
3832
|
+
}
|
|
3833
|
+
clearOffset(env, channelName, cb);
|
|
3834
|
+
},
|
|
3835
|
+
writeOffset: function(channelName, data, _cb) {
|
|
3836
|
+
var cb = Util.once(Util.mkAsync(_cb));
|
|
3837
|
+
if (!isValidChannelId(channelName)) {
|
|
3838
|
+
return void cb(new Error("EINVAL"));
|
|
3839
|
+
}
|
|
3840
|
+
writeOffset(env, channelName, data, cb);
|
|
3841
|
+
},
|
|
3842
|
+
getOffset: function(channelName, _cb) {
|
|
3843
|
+
var cb = Util.once(Util.mkAsync(_cb));
|
|
3844
|
+
if (!isValidChannelId(channelName)) {
|
|
3845
|
+
return void cb(new Error("EINVAL"));
|
|
3846
|
+
}
|
|
3847
|
+
getOffset(env, channelName, cb);
|
|
3848
|
+
},
|
|
3849
|
+
getChannelMetadata: function(channelName, cb) {
|
|
3850
|
+
if (!isValidChannelId(channelName)) {
|
|
3851
|
+
return void cb(new Error("EINVAL"));
|
|
3852
|
+
}
|
|
3853
|
+
schedule.unordered(channelName, function(next) {
|
|
3854
|
+
getChannelMetadata(env, channelName, Util.both(cb, next));
|
|
3855
|
+
});
|
|
3856
|
+
},
|
|
3857
|
+
readDedicatedMetadata: function(channelName, handler, cb) {
|
|
3858
|
+
if (!isValidChannelId(channelName)) {
|
|
3859
|
+
return void cb(new Error("EINVAL"));
|
|
3860
|
+
}
|
|
3861
|
+
schedule.unordered(channelName, function(next) {
|
|
3862
|
+
getDedicatedMetadata(env, channelName, handler, Util.both(cb, next));
|
|
3863
|
+
});
|
|
3864
|
+
},
|
|
3865
|
+
readChannelMetadata: function(channelName, handler, cb) {
|
|
3866
|
+
if (!isValidChannelId(channelName)) {
|
|
3867
|
+
return void cb(new Error("EINVAL"));
|
|
3868
|
+
}
|
|
3869
|
+
schedule.unordered(channelName, function(next) {
|
|
3870
|
+
readMetadata(env, channelName, handler, Util.both(cb, next));
|
|
3871
|
+
});
|
|
3872
|
+
},
|
|
3873
|
+
writeMetadata: function(channelName, data, cb) {
|
|
3874
|
+
if (!isValidChannelId(channelName)) {
|
|
3875
|
+
return void cb(new Error("EINVAL"));
|
|
3876
|
+
}
|
|
3877
|
+
schedule.ordered(channelName, function(next) {
|
|
3878
|
+
writeMetadata(env, channelName, data, Util.both(cb, next));
|
|
3879
|
+
});
|
|
3880
|
+
},
|
|
3881
|
+
listChannels: function(handler, cb, fastMode) {
|
|
3882
|
+
listChannels(env.root, handler, cb, fastMode);
|
|
3883
|
+
},
|
|
3884
|
+
listArchivedChannels: function(handler, cb, fastMode) {
|
|
3885
|
+
listChannels(Path.join(env.archiveRoot, "datastore"), handler, cb, fastMode);
|
|
3886
|
+
},
|
|
3887
|
+
getChannelStats: function(channelName, cb) {
|
|
3888
|
+
if (!isValidChannelId(channelName)) {
|
|
3889
|
+
return void cb(new Error("EINVAL"));
|
|
3890
|
+
}
|
|
3891
|
+
getStats(env, channelName, cb);
|
|
3892
|
+
},
|
|
3893
|
+
getChannelSize: function(channelName, cb) {
|
|
3894
|
+
if (!isValidChannelId(channelName)) {
|
|
3895
|
+
return void cb(new Error("EINVAL"));
|
|
3896
|
+
}
|
|
3897
|
+
schedule.ordered(channelName, function(next) {
|
|
3898
|
+
channelBytes(env, channelName, Util.both(cb, next));
|
|
3899
|
+
});
|
|
3900
|
+
},
|
|
3901
|
+
getPlaceholder: function(channelName, cb) {
|
|
3902
|
+
readPlaceholder(env, channelName, cb);
|
|
3903
|
+
},
|
|
3904
|
+
closeChannel: function(channelName, cb) {
|
|
3905
|
+
if (!isValidChannelId(channelName)) {
|
|
3906
|
+
return void cb(new Error("EINVAL"));
|
|
3907
|
+
}
|
|
3908
|
+
schedule.ordered(channelName, function(next) {
|
|
3909
|
+
closeChannel(env, channelName, Util.both(cb, next));
|
|
3910
|
+
});
|
|
3911
|
+
},
|
|
3912
|
+
closeInactiveChannels: function(activeSet) {
|
|
3913
|
+
closeInactiveChannels(env, schedule, activeSet);
|
|
3914
|
+
},
|
|
3915
|
+
log: function(channelName, content, cb) {
|
|
3916
|
+
schedule.ordered(channelName, function(next) {
|
|
3917
|
+
message(env, channelName, content, Util.both(cb, next));
|
|
3918
|
+
});
|
|
3919
|
+
},
|
|
3920
|
+
shutdown: function() {
|
|
3921
|
+
clearInterval(it);
|
|
3922
|
+
}
|
|
3923
|
+
});
|
|
3924
|
+
});
|
|
3925
|
+
};
|
|
3926
|
+
return file;
|
|
3927
|
+
}
|
|
3928
|
+
|
|
3929
|
+
var logger;
|
|
3930
|
+
|
|
3931
|
+
var hasRequiredLogger;
|
|
3932
|
+
|
|
3933
|
+
function requireLogger() {
|
|
3934
|
+
if (hasRequiredLogger) return logger;
|
|
3935
|
+
hasRequiredLogger = 1;
|
|
3936
|
+
const Store = requireFile();
|
|
3937
|
+
const Util = requireCommonUtil$1();
|
|
3938
|
+
const Path = require$$1;
|
|
3939
|
+
const logLevels = [ "silly", "verbose", "debug", "feedback", "info", "warn", "error" ];
|
|
3940
|
+
const handlers = {};
|
|
3941
|
+
const messageTemplate = (type, time, tag, info, nodeId) => JSON.stringify([ type.toUpperCase(), time, nodeId, tag, info ]);
|
|
3942
|
+
const getDateString = () => {
|
|
3943
|
+
const now = new Date;
|
|
3944
|
+
return now.toLocaleDateString(void 0, {
|
|
3945
|
+
month: "2-digit"
|
|
3946
|
+
}) + now.toLocaleDateString("en-CA");
|
|
3947
|
+
};
|
|
3948
|
+
const noop = function() {
|
|
3949
|
+
const args = Array.prototype.slice.call(arguments);
|
|
3950
|
+
if (!args.length) {
|
|
3951
|
+
return;
|
|
3952
|
+
}
|
|
3953
|
+
let cb = args.pop();
|
|
3954
|
+
if (typeof cb !== "function") {
|
|
3955
|
+
return;
|
|
3956
|
+
}
|
|
3957
|
+
if (cb) {
|
|
3958
|
+
setTimeout(cb);
|
|
3959
|
+
}
|
|
3960
|
+
};
|
|
3961
|
+
const write = function(ctx, content, cb) {
|
|
3962
|
+
if (!ctx.store) {
|
|
3963
|
+
return setTimeout(cb);
|
|
3964
|
+
}
|
|
3965
|
+
ctx.store.log(`${getDateString()}-${ctx.logId}`, content, cb);
|
|
3966
|
+
};
|
|
3967
|
+
[ "silly", "debug", "verbose", "feedback", "info" ].forEach(level => {
|
|
3968
|
+
handlers[level] = console.log;
|
|
3969
|
+
});
|
|
3970
|
+
handlers["warn"] = console.warn;
|
|
3971
|
+
handlers["error"] = console.error;
|
|
3972
|
+
const createLogType = function(ctx, type) {
|
|
3973
|
+
if (logLevels.indexOf(type) < logLevels.indexOf(ctx.logLevel)) {
|
|
3974
|
+
return noop;
|
|
3975
|
+
}
|
|
3976
|
+
return function() {
|
|
3977
|
+
const args = Array.prototype.slice.call(arguments);
|
|
3978
|
+
const tag = args.shift();
|
|
3979
|
+
let cb = args.pop();
|
|
3980
|
+
if (typeof cb !== "function") {
|
|
3981
|
+
args.push(cb);
|
|
3982
|
+
cb = () => {};
|
|
3983
|
+
}
|
|
3984
|
+
if (ctx.shutdown) {
|
|
3985
|
+
return;
|
|
3986
|
+
}
|
|
3987
|
+
const time = (new Date).toISOString();
|
|
3988
|
+
const info = args.length === 1 ? args[0] : args;
|
|
3989
|
+
let content;
|
|
3990
|
+
try {
|
|
3991
|
+
content = messageTemplate(type, time, tag, info, ctx.myId);
|
|
3992
|
+
} catch (e) {
|
|
3993
|
+
return;
|
|
3994
|
+
}
|
|
3995
|
+
if (ctx.logToStdout && typeof handlers[type] === "function") {
|
|
3996
|
+
handlers[type](content);
|
|
3997
|
+
}
|
|
3998
|
+
ctx.onReady?.reg(() => {
|
|
3999
|
+
write(ctx, content, cb);
|
|
4000
|
+
});
|
|
4001
|
+
};
|
|
4002
|
+
};
|
|
4003
|
+
const createMethods = function(ctx) {
|
|
4004
|
+
const log = {};
|
|
4005
|
+
logLevels.forEach(function(type) {
|
|
4006
|
+
log[type] = createLogType(ctx, type);
|
|
4007
|
+
});
|
|
4008
|
+
return log;
|
|
4009
|
+
};
|
|
4010
|
+
const Logger = (loggerConfig, myId) => {
|
|
4011
|
+
loggerConfig ||= {};
|
|
4012
|
+
const logId = myId ? myId.split(":")?.[0] : "unknown";
|
|
4013
|
+
if (typeof loggerConfig?.logLevel !== "string") {
|
|
4014
|
+
loggerConfig.logLevel = "info";
|
|
4015
|
+
}
|
|
4016
|
+
const ctx = {
|
|
4017
|
+
logFeedback: Boolean(loggerConfig.logFeedback),
|
|
4018
|
+
logLevel: loggerConfig.logLevel,
|
|
4019
|
+
logToStdout: loggerConfig.logToStdout,
|
|
4020
|
+
logPath: loggerConfig.logPath,
|
|
4021
|
+
logId,
|
|
4022
|
+
myId
|
|
4023
|
+
};
|
|
4024
|
+
if (!loggerConfig.logPath) {
|
|
4025
|
+
console.log(`${myId}: No logPath configured. Logging to file disabled`);
|
|
4026
|
+
const logger = createMethods(ctx);
|
|
4027
|
+
logger.shutdown = () => {};
|
|
4028
|
+
return logger;
|
|
4029
|
+
}
|
|
4030
|
+
ctx.onReady = Util.mkEvent(true);
|
|
4031
|
+
const year = (new Date).getFullYear().toString();
|
|
4032
|
+
Store.create({
|
|
4033
|
+
filePath: Path.join(loggerConfig.logPath, year),
|
|
4034
|
+
archivePath: loggerConfig.archivePath
|
|
4035
|
+
}, function(err, store) {
|
|
4036
|
+
if (err) {
|
|
4037
|
+
throw err;
|
|
4038
|
+
}
|
|
4039
|
+
ctx.store = store;
|
|
4040
|
+
ctx.onReady.fire();
|
|
4041
|
+
});
|
|
4042
|
+
const logger = createMethods(ctx);
|
|
4043
|
+
logger.shutdown = () => {
|
|
4044
|
+
delete ctx.store;
|
|
4045
|
+
ctx.shutdown = true;
|
|
4046
|
+
ctx.store.shutdown();
|
|
4047
|
+
};
|
|
4048
|
+
return Object.freeze(logger);
|
|
4049
|
+
};
|
|
4050
|
+
logger = Logger;
|
|
4051
|
+
return logger;
|
|
4052
|
+
}
|
|
4053
|
+
|
|
4054
|
+
var headers;
|
|
4055
|
+
|
|
4056
|
+
var hasRequiredHeaders;
|
|
4057
|
+
|
|
4058
|
+
function requireHeaders() {
|
|
4059
|
+
if (hasRequiredHeaders) return headers;
|
|
4060
|
+
hasRequiredHeaders = 1;
|
|
4061
|
+
const Default = requireDefaults();
|
|
4062
|
+
const Util = requireCommonUtil$1();
|
|
4063
|
+
const EXEMPT = [ /^\/common\/onlyoffice\/.*\.html.*/, /^\/common\/onlyoffice\/dist\/.*\/sdkjs\/common\/spell\/spell\/spell.js.*/, /^\/(sheet|presentation|doc)\/inner\.html.*/, /^\/unsafeiframe\/inner\.html.*$/ ];
|
|
4064
|
+
const applyHeaderMap = (res, map) => {
|
|
4065
|
+
for (let header in map) {
|
|
4066
|
+
if (typeof map[header] === "string") {
|
|
4067
|
+
res.setHeader(header, map[header]);
|
|
4068
|
+
}
|
|
4069
|
+
}
|
|
4070
|
+
};
|
|
4071
|
+
const cacheHeaders = (Env, key, headers) => {
|
|
4072
|
+
if (Env.DEV_MODE) {
|
|
4073
|
+
return;
|
|
4074
|
+
}
|
|
4075
|
+
Env[key] = headers;
|
|
4076
|
+
};
|
|
4077
|
+
const getHeaders = (Env, type) => {
|
|
4078
|
+
const key = type + "HeadersCache";
|
|
4079
|
+
if (Env[key]) {
|
|
4080
|
+
return Util.clone(Env[key]);
|
|
4081
|
+
}
|
|
4082
|
+
const headers = Default.httpHeaders(Env);
|
|
4083
|
+
let csp;
|
|
4084
|
+
if (type === "office") {
|
|
4085
|
+
csp = Default.padContentSecurity(Env);
|
|
4086
|
+
} else {
|
|
4087
|
+
csp = Default.contentSecurity(Env);
|
|
4088
|
+
}
|
|
4089
|
+
headers["Content-Security-Policy"] = csp;
|
|
4090
|
+
headers["Cross-Origin-Resource-Policy"] = "cross-origin";
|
|
4091
|
+
headers["Cross-Origin-Embedder-Policy"] = "require-corp";
|
|
4092
|
+
cacheHeaders(Env, key, headers);
|
|
4093
|
+
if (type === "api") {
|
|
4094
|
+
delete headers["Content-Security-Policy"];
|
|
4095
|
+
}
|
|
4096
|
+
return Util.clone(headers);
|
|
4097
|
+
};
|
|
4098
|
+
const setHeaders = (Env, req, res) => {
|
|
4099
|
+
let type;
|
|
4100
|
+
if (EXEMPT.some(regex => regex.test(req.url))) {
|
|
4101
|
+
type = "office";
|
|
4102
|
+
} else if (/^\/api\/(broadcast|config)/.test(req.url)) {
|
|
4103
|
+
type = "api";
|
|
4104
|
+
} else {
|
|
4105
|
+
type = "standard";
|
|
4106
|
+
}
|
|
4107
|
+
let h = getHeaders(Env, type);
|
|
4108
|
+
if (!Env.enableEmbedding && req.get("origin") === Env.httpUnsafeOrigin && /^\/common\/onlyoffice\/dist\/.*\/fonts\/.*/.test(req.url)) {
|
|
4109
|
+
h["Access-Control-Allow-Origin"] = Env.httpUnsafeOrigin;
|
|
4110
|
+
}
|
|
4111
|
+
applyHeaderMap(res, h);
|
|
4112
|
+
};
|
|
4113
|
+
headers = {
|
|
4114
|
+
setHeaders
|
|
4115
|
+
};
|
|
4116
|
+
return headers;
|
|
4117
|
+
}
|
|
4118
|
+
|
|
4119
|
+
var hasRequiredWorker;
|
|
4120
|
+
|
|
4121
|
+
function requireWorker() {
|
|
4122
|
+
if (hasRequiredWorker) return worker$1;
|
|
4123
|
+
hasRequiredWorker = 1;
|
|
4124
|
+
const Util = requireCommonUtil$1();
|
|
4125
|
+
const Http = require("node:http");
|
|
4126
|
+
const Express = require$$1$2;
|
|
4127
|
+
const Environment = requireEnv();
|
|
4128
|
+
const Logger = requireLogger();
|
|
4129
|
+
const WebSocketServer = require$$4$1.Server;
|
|
4130
|
+
const {setHeaders} = requireHeaders();
|
|
4131
|
+
const Crypto = require("crypto");
|
|
4132
|
+
const cookieParser = require$$6$1;
|
|
4133
|
+
const bodyParser = require$$7;
|
|
4134
|
+
const COMMANDS = {};
|
|
4135
|
+
const Env = {
|
|
4136
|
+
active: true,
|
|
4137
|
+
isWorker: true,
|
|
4138
|
+
users: {}
|
|
4139
|
+
};
|
|
4140
|
+
const onEnvReady = Util.mkEvent(true);
|
|
4141
|
+
const app = Express();
|
|
4142
|
+
app.use(function(req, res, next) {
|
|
4143
|
+
setHeaders(Env, req, res);
|
|
4144
|
+
if (/[\?\&]ver=[^\/]+$/.test(req.url)) {
|
|
4145
|
+
res.setHeader("Cache-Control", "max-age=31536000");
|
|
4146
|
+
} else {
|
|
4147
|
+
res.setHeader("Cache-Control", "no-cache");
|
|
4148
|
+
}
|
|
4149
|
+
next();
|
|
4150
|
+
});
|
|
4151
|
+
const response = Util.response((errLabel, info) => {
|
|
4152
|
+
Env.Log.error("WORKER__" + errLabel, info);
|
|
4153
|
+
});
|
|
4154
|
+
const guid = () => {
|
|
4155
|
+
let id = Util.uid();
|
|
4156
|
+
return response.expected(id) ? guid() : id;
|
|
4157
|
+
};
|
|
4158
|
+
const sendCommand = (cmd, data, cb) => {
|
|
4159
|
+
const txid = guid();
|
|
4160
|
+
response.expect(txid, (err, response) => {
|
|
4161
|
+
cb(err, response);
|
|
4162
|
+
}, 2 * 6e4);
|
|
4163
|
+
process.send({
|
|
4164
|
+
txid,
|
|
4165
|
+
cmd,
|
|
4166
|
+
data,
|
|
4167
|
+
pid: Env.pid
|
|
4168
|
+
});
|
|
4169
|
+
};
|
|
4170
|
+
app.use(bodyParser.urlencoded({
|
|
4171
|
+
extended: true
|
|
4172
|
+
}));
|
|
4173
|
+
app.use(cookieParser());
|
|
4174
|
+
const cacheString = () => (Env.FRESH_KEY ? "-" + Env.FRESH_KEY : "") + (Env.DEV_MODE ? "-" + +new Date : "");
|
|
4175
|
+
const makeRouteCache = (template, cacheName) => {
|
|
4176
|
+
const cleanUp = {};
|
|
4177
|
+
return function(req, res) {
|
|
4178
|
+
const cache = Env[cacheName] ||= {};
|
|
4179
|
+
const host = req.headers.host.replace(/\:[0-9]+/, "");
|
|
4180
|
+
res.setHeader("Content-Type", "text/javascript");
|
|
4181
|
+
if (Env.DEV_MODE) {
|
|
4182
|
+
return void res.send(template(host));
|
|
4183
|
+
}
|
|
4184
|
+
let cacheKey = host + ":" + cacheString();
|
|
4185
|
+
if (!cache[cacheKey]) {
|
|
4186
|
+
cache[cacheKey] = template(host);
|
|
4187
|
+
cleanUp[cacheKey] = Util.throttle(function() {
|
|
4188
|
+
delete cleanUp[cacheKey];
|
|
4189
|
+
delete cache[cacheKey];
|
|
4190
|
+
}, 2e4);
|
|
4191
|
+
}
|
|
4192
|
+
if (typeof cleanUp[cacheKey] === "function") {
|
|
4193
|
+
cleanUp[cacheKey]();
|
|
4194
|
+
}
|
|
4195
|
+
return void res.send(cache[cacheKey]);
|
|
4196
|
+
};
|
|
4197
|
+
};
|
|
4198
|
+
const serveConfig = makeRouteCache(function() {
|
|
4199
|
+
const ssoList = Env.sso && Env.sso.enabled && Array.isArray(Env.sso.list) && Env.sso.list.map(function(obj) {
|
|
4200
|
+
return obj.name;
|
|
4201
|
+
}) || [];
|
|
4202
|
+
const SSOUtils = Env?.plugins?.SSO?.utils;
|
|
4203
|
+
const ssoCfg = SSOUtils && ssoList.length ? {
|
|
4204
|
+
force: Env.sso && Env.sso.enforced && 1 || 0,
|
|
4205
|
+
password: Env.sso && Env.sso.cpPassword && (Env.sso.forceCpPassword ? 2 : 1) || 0,
|
|
4206
|
+
list: ssoList
|
|
4207
|
+
} : false;
|
|
4208
|
+
return [ "define(function(){", "return " + JSON.stringify({
|
|
4209
|
+
requireConf: {
|
|
4210
|
+
waitSeconds: 600,
|
|
4211
|
+
urlArgs: "ver=" + Env.version + cacheString()
|
|
4212
|
+
},
|
|
4213
|
+
removeDonateButton: Env.removeDonateButton === true,
|
|
4214
|
+
accounts_api: Env.accounts_api,
|
|
4215
|
+
websocketPath: Env.websocketPath,
|
|
4216
|
+
httpUnsafeOrigin: Env.httpUnsafeOrigin,
|
|
4217
|
+
adminEmail: Env.adminEmail,
|
|
4218
|
+
adminKeys: Env.admins,
|
|
4219
|
+
moderatorKeys: Env.moderators,
|
|
4220
|
+
inactiveTime: Env.inactiveTime,
|
|
4221
|
+
supportMailbox: Env.supportMailbox,
|
|
4222
|
+
supportMailboxKey: Env.supportMailboxKey,
|
|
4223
|
+
defaultStorageLimit: Env.defaultStorageLimit,
|
|
4224
|
+
maxUploadSize: Env.maxUploadSize,
|
|
4225
|
+
premiumUploadSize: Env.premiumUploadSize,
|
|
4226
|
+
restrictRegistration: Env.restrictRegistration,
|
|
4227
|
+
restrictSsoRegistration: Env.restrictSsoRegistration,
|
|
4228
|
+
appsToDisable: Env.appsToDisable,
|
|
4229
|
+
httpSafeOrigin: Env.httpSafeOrigin,
|
|
4230
|
+
enableEmbedding: Env.enableEmbedding,
|
|
4231
|
+
fileHost: Env.fileHost,
|
|
4232
|
+
shouldUpdateNode: Env.shouldUpdateNode || undefined,
|
|
4233
|
+
listMyInstance: Env.listMyInstance,
|
|
4234
|
+
sso: ssoCfg,
|
|
4235
|
+
enforceMFA: Env.enforceMFA,
|
|
4236
|
+
onlyOffice: Env.onlyOffice
|
|
4237
|
+
}, null, "\t"), "});" ].join(";\n");
|
|
4238
|
+
}, "configCache");
|
|
4239
|
+
const serveBroadcast = makeRouteCache(function() {
|
|
4240
|
+
let maintenance = Env.maintenance;
|
|
4241
|
+
if (maintenance && maintenance.end && maintenance.end < +new Date) {
|
|
4242
|
+
maintenance = undefined;
|
|
4243
|
+
}
|
|
4244
|
+
return [ "define(function(){", "return " + JSON.stringify({
|
|
4245
|
+
curvePublic: Env?.curveKeys?.curvePublic,
|
|
4246
|
+
lastBroadcastHash: Env.lastBroadcastHash,
|
|
4247
|
+
surveyURL: Env.surveyURL,
|
|
4248
|
+
maintenance
|
|
4249
|
+
}, null, "\t"), "});" ].join(";\n");
|
|
4250
|
+
}, "broadcastCache");
|
|
4251
|
+
const Define = obj => `define(function (){\n return ${JSON.stringify(obj, null, "\t")};\n});`;
|
|
4252
|
+
const serveInstance = (req, res) => {
|
|
4253
|
+
res.setHeader("Content-Type", "text/javascript");
|
|
4254
|
+
res.send(Define({
|
|
4255
|
+
color: Env.accentColor,
|
|
4256
|
+
name: Env.instanceName,
|
|
4257
|
+
description: Env.instanceDescription,
|
|
4258
|
+
location: Env.instanceJurisdiction,
|
|
4259
|
+
notice: Env.instanceNotice
|
|
4260
|
+
}));
|
|
4261
|
+
};
|
|
4262
|
+
app.get("/api/config", serveConfig);
|
|
4263
|
+
app.get("/api/broadcast", serveBroadcast);
|
|
4264
|
+
app.get("/api/instance", serveInstance);
|
|
4265
|
+
const servePlugins = Env => {
|
|
4266
|
+
const plugins = Env.plugins;
|
|
4267
|
+
let extensions = plugins._extensions;
|
|
4268
|
+
let styles = plugins._styles;
|
|
4269
|
+
let str = JSON.stringify(extensions);
|
|
4270
|
+
let str2 = JSON.stringify(styles);
|
|
4271
|
+
let js = `let extensions = ${str};\nlet styles = ${str2};\nlet lang = window.cryptpadLanguage;\nlet paths = [];\nextensions.forEach(name => {\n paths.push(\`optional!/\${name}/extensions.js\`);\n paths.push(\`optional!json!/\${name}/translations/messages.json\`);\n const l = lang === "en" ? '' : \`\${lang}.\`;\n paths.push(\`optional!json!/\${name}/translations/messages.\${l}json\`);\n});\nstyles.forEach(name => {\n paths.push(\`optional!less!/\${name}/style.less\`);\n});\ndefine(paths, function () {\n let args = Array.prototype.slice.apply(arguments);\n return args;\n}, function () {\n // ignore missing files\n});`;
|
|
4272
|
+
app.get("/extensions.js", (req, res) => {
|
|
4273
|
+
res.setHeader("Content-Type", "text/javascript");
|
|
4274
|
+
res.send(js);
|
|
4275
|
+
});
|
|
4276
|
+
};
|
|
4277
|
+
app.get("/api/profiling", () => {
|
|
4278
|
+
throw new Error("NOT_IMPLEMENTED");
|
|
4279
|
+
});
|
|
4280
|
+
app.use(Express.json());
|
|
4281
|
+
app.post("/api/auth", (req, res) => {
|
|
4282
|
+
const body = Util.clone(req.body);
|
|
4283
|
+
const cookies = req.cookies;
|
|
4284
|
+
body._cookies = cookies;
|
|
4285
|
+
sendCommand("HTTP_COMMAND", body, (err, response) => {
|
|
4286
|
+
if (err) {
|
|
4287
|
+
return res.status(500).json({
|
|
4288
|
+
error: err
|
|
4289
|
+
});
|
|
4290
|
+
}
|
|
4291
|
+
if (response._cookie) {
|
|
4292
|
+
res.setHeader("Set-Cookie", response._cookie);
|
|
4293
|
+
}
|
|
4294
|
+
res.status(200).json(response);
|
|
4295
|
+
});
|
|
4296
|
+
});
|
|
4297
|
+
COMMANDS.NEW_DECREES = (data, cb) => {
|
|
4298
|
+
const {decrees, type, curveKeys, freshKey} = data;
|
|
4299
|
+
Env.FRESH_KEY = freshKey;
|
|
4300
|
+
Env.curveKeys ||= curveKeys;
|
|
4301
|
+
Env.getDecree(type).loadRemote(Env, decrees);
|
|
4302
|
+
[ "configCache", "broadcastCache" ].forEach(key => {
|
|
4303
|
+
Env[key] = {};
|
|
4304
|
+
});
|
|
4305
|
+
onEnvReady.fire();
|
|
4306
|
+
cb();
|
|
4307
|
+
};
|
|
4308
|
+
COMMANDS.FLUSH_CACHE = (args, cb) => {
|
|
4309
|
+
Env.FRESH_KEY = args.freshKey;
|
|
4310
|
+
cb();
|
|
4311
|
+
};
|
|
4312
|
+
const now = () => +new Date;
|
|
4313
|
+
const randName = () => Crypto.randomBytes(16).toString("hex");
|
|
4314
|
+
const createUniqueName = Env => {
|
|
4315
|
+
const name = randName();
|
|
4316
|
+
if (typeof Env.users[name] === "undefined") {
|
|
4317
|
+
return name;
|
|
4318
|
+
}
|
|
4319
|
+
return createUniqueName(Env);
|
|
4320
|
+
};
|
|
4321
|
+
const socketSendable = socket => socket && socket.readyState === 1;
|
|
4322
|
+
const QUEUE_CHR = 1024 * 1024 * 4;
|
|
4323
|
+
const WEBSOCKET_CLOSING = 2;
|
|
4324
|
+
const WEBSOCKET_CLOSED = 3;
|
|
4325
|
+
const dropUser = (user, reason) => {
|
|
4326
|
+
if (!user || !user.socket) {
|
|
4327
|
+
return;
|
|
4328
|
+
}
|
|
4329
|
+
if (user.socket.readyState !== WEBSOCKET_CLOSING && user.socket.readyState !== WEBSOCKET_CLOSED) {
|
|
4330
|
+
try {
|
|
4331
|
+
user.socket.close();
|
|
4332
|
+
} catch (e) {
|
|
4333
|
+
Env.Log.error(e, "FAIL_TO_DISCONNECT", {
|
|
4334
|
+
id: user.id
|
|
4335
|
+
});
|
|
4336
|
+
try {
|
|
4337
|
+
user.socket.terminate();
|
|
4338
|
+
} catch (ee) {
|
|
4339
|
+
Env.Log.error(ee, "FAIL_TO_TERMINATE", {
|
|
4340
|
+
id: user.id
|
|
4341
|
+
});
|
|
4342
|
+
}
|
|
4343
|
+
}
|
|
4344
|
+
}
|
|
4345
|
+
sendCommand("WS_DROP_USER", {
|
|
4346
|
+
id: user.id,
|
|
4347
|
+
reason
|
|
4348
|
+
}, () => {});
|
|
4349
|
+
delete Env.users[user.id];
|
|
4350
|
+
if (Env.logIP && ![ "SOCKET_CLOSED", "INACTIVITY" ].includes(reason)) {
|
|
4351
|
+
return void Env.Log.info("USER_DISCONNECTED_ERROR", {
|
|
4352
|
+
userId: user.id,
|
|
4353
|
+
reason
|
|
4354
|
+
});
|
|
4355
|
+
}
|
|
4356
|
+
if ([ "BAD_MESSAGE", "SEND_MESSAGE_FAIL_2" ].includes(reason)) {
|
|
4357
|
+
return void Env.Log.error("SESSION_CLOSE_WITH_ERROR", {
|
|
4358
|
+
userId: user.id,
|
|
4359
|
+
reason
|
|
4360
|
+
});
|
|
4361
|
+
}
|
|
4362
|
+
if ([ "SOCKET_CLOSED", "SOCKET_ERROR" ].includes(reason)) {
|
|
4363
|
+
return;
|
|
4364
|
+
}
|
|
4365
|
+
Env.Log.silly("SESSION_CLOSE_ROUTINE", {
|
|
4366
|
+
userId: user.id,
|
|
4367
|
+
reason
|
|
4368
|
+
});
|
|
4369
|
+
};
|
|
4370
|
+
const sendMsgPromise = (user, msg) => new Promise((resolve, reject) => {
|
|
4371
|
+
if (!user) {
|
|
4372
|
+
return void reject("NO_USER");
|
|
4373
|
+
}
|
|
4374
|
+
if (!socketSendable(user.socket)) {
|
|
4375
|
+
return void reject("UNSENDABLE");
|
|
4376
|
+
}
|
|
4377
|
+
Env.Log.silly("Sending", msg, "to", user.id);
|
|
4378
|
+
try {
|
|
4379
|
+
const strMsg = JSON.stringify(msg);
|
|
4380
|
+
user.inQueue += strMsg.length;
|
|
4381
|
+
user.sendMsgCallbacks.push(() => {
|
|
4382
|
+
resolve({
|
|
4383
|
+
length: strMsg.length
|
|
4384
|
+
});
|
|
4385
|
+
});
|
|
4386
|
+
user.socket.send(strMsg, () => {
|
|
4387
|
+
user.inQueue -= strMsg.length;
|
|
4388
|
+
if (user.inQueue > QUEUE_CHR) {
|
|
4389
|
+
return;
|
|
4390
|
+
}
|
|
4391
|
+
const smcb = user.sendMsgCallbacks;
|
|
4392
|
+
user.sendMsgCallbacks = [];
|
|
4393
|
+
try {
|
|
4394
|
+
smcb.forEach(cb => {
|
|
4395
|
+
cb();
|
|
4396
|
+
});
|
|
4397
|
+
} catch (e) {
|
|
4398
|
+
Env.Log.error(e, "SEND_MESSAGE_FAIL");
|
|
4399
|
+
}
|
|
4400
|
+
});
|
|
4401
|
+
} catch (e) {
|
|
4402
|
+
reject(e);
|
|
4403
|
+
Env.Log.error(e, "SEND_MESSAGE_FAIL_2");
|
|
4404
|
+
dropUser(user, "SEND_MESSAGE_FAIL_2");
|
|
4405
|
+
}
|
|
4406
|
+
});
|
|
4407
|
+
const sendMsg = (user, msg) => {
|
|
4408
|
+
sendMsgPromise(user, msg).catch(e => {
|
|
4409
|
+
if ([ "NO_USER", "UNSENDABLE" ].includes(e)) {
|
|
4410
|
+
return;
|
|
4411
|
+
}
|
|
4412
|
+
Env.Log.error(e, "SEND_MESSAGE", {
|
|
4413
|
+
user: user.id,
|
|
4414
|
+
message: msg
|
|
4415
|
+
});
|
|
4416
|
+
});
|
|
4417
|
+
};
|
|
4418
|
+
const handleMessage = (user, msg, cb) => {
|
|
4419
|
+
try {
|
|
4420
|
+
let json = JSON.parse(msg);
|
|
4421
|
+
let seq = json.shift();
|
|
4422
|
+
let cmd = json[0];
|
|
4423
|
+
user.timeOfLastMessage = now();
|
|
4424
|
+
user.pingOutstanding = false;
|
|
4425
|
+
sendCommand("WS_MESSAGE", {
|
|
4426
|
+
userId: user.id,
|
|
4427
|
+
cmd,
|
|
4428
|
+
seq,
|
|
4429
|
+
json,
|
|
4430
|
+
length: msg.length
|
|
4431
|
+
}, cb);
|
|
4432
|
+
} catch (e) {
|
|
4433
|
+
cb(e);
|
|
4434
|
+
}
|
|
4435
|
+
};
|
|
4436
|
+
const LAG_MAX_BEFORE_DISCONNECT = 6e4;
|
|
4437
|
+
const LAG_MAX_BEFORE_PING = 15e3;
|
|
4438
|
+
const checkUserActivity = () => {
|
|
4439
|
+
const time = now();
|
|
4440
|
+
Object.keys(Env.users).forEach(userId => {
|
|
4441
|
+
const u = Env.users[userId];
|
|
4442
|
+
try {
|
|
4443
|
+
if (time - u.timeOfLastMessage > LAG_MAX_BEFORE_DISCONNECT) {
|
|
4444
|
+
dropUser(u, "INACTIVITY");
|
|
4445
|
+
}
|
|
4446
|
+
if (!u.pingOutstanding && time - u.timeOfLastMessage > LAG_MAX_BEFORE_PING) {
|
|
4447
|
+
sendMsg(u, [ 0, "", "PING", now() ]);
|
|
4448
|
+
u.pingOutstanding = true;
|
|
4449
|
+
sendCommand("WS_SEND_PING", {}, () => {});
|
|
4450
|
+
}
|
|
4451
|
+
} catch (err) {
|
|
4452
|
+
Env.Log.error(err, "USER_ACTIVITY_CHECK");
|
|
4453
|
+
}
|
|
4454
|
+
});
|
|
4455
|
+
};
|
|
4456
|
+
const initServerHandlers = () => {
|
|
4457
|
+
if (!Env.wss) {
|
|
4458
|
+
throw new Error("No WebSocket Server");
|
|
4459
|
+
}
|
|
4460
|
+
setInterval(() => {
|
|
4461
|
+
checkUserActivity();
|
|
4462
|
+
}, 5e3);
|
|
4463
|
+
Env.wss.on("connection", (socket, req) => {
|
|
4464
|
+
if (!Env.active) {
|
|
4465
|
+
return;
|
|
4466
|
+
}
|
|
4467
|
+
if (!socket.upgradeReq) {
|
|
4468
|
+
socket.upgradeReq = req;
|
|
4469
|
+
}
|
|
4470
|
+
const ip = req.headers && req.headers["x-real-ip"] || req.socket.remoteAddress || "";
|
|
4471
|
+
const user = {
|
|
4472
|
+
socket,
|
|
4473
|
+
id: createUniqueName(Env),
|
|
4474
|
+
timeOfLastMessage: now(),
|
|
4475
|
+
pingOutstanding: false,
|
|
4476
|
+
inQueue: 0,
|
|
4477
|
+
ip: ip.replace(/^::ffff:/, ""),
|
|
4478
|
+
sendMsgCallbacks: []
|
|
4479
|
+
};
|
|
4480
|
+
Env.users[user.id] = user;
|
|
4481
|
+
sendMsg(user, [ 0, "", "IDENT", user.id ]);
|
|
4482
|
+
sendCommand("WS_NEW_USER", {
|
|
4483
|
+
id: user.id,
|
|
4484
|
+
ip: user.ip
|
|
4485
|
+
}, () => {});
|
|
4486
|
+
socket.on("message", message => {
|
|
4487
|
+
if (!Env.users[user.id]) {
|
|
4488
|
+
return;
|
|
4489
|
+
}
|
|
4490
|
+
Env.Log.silly("Receiving", JSON.parse(message), "from", user.id);
|
|
4491
|
+
handleMessage(user, message, e => {
|
|
4492
|
+
if (!e) {
|
|
4493
|
+
return;
|
|
4494
|
+
}
|
|
4495
|
+
Env.Log.error(e, "NETFLUX_BAD_MESSAGE", {
|
|
4496
|
+
user: user.id,
|
|
4497
|
+
message
|
|
4498
|
+
});
|
|
4499
|
+
dropUser(user, "BAD_MESSAGE");
|
|
4500
|
+
});
|
|
4501
|
+
});
|
|
4502
|
+
socket.on("close", function() {
|
|
4503
|
+
dropUser(user, "SOCKET_CLOSED");
|
|
4504
|
+
});
|
|
4505
|
+
socket.on("error", function(err) {
|
|
4506
|
+
Env.Log.error(err, "NETFLUX_WEBSOCKET_ERROR");
|
|
4507
|
+
dropUser(user, "SOCKET_ERROR");
|
|
4508
|
+
});
|
|
4509
|
+
});
|
|
4510
|
+
};
|
|
4511
|
+
COMMANDS.WS_SEND_MESSAGE = (args, cb) => {
|
|
4512
|
+
const {id, msg} = args;
|
|
4513
|
+
const user = Env.users[id];
|
|
4514
|
+
sendMsgPromise(user, msg).then(obj => {
|
|
4515
|
+
cb(void 0, obj);
|
|
4516
|
+
}).catch(e => {
|
|
4517
|
+
cb(e);
|
|
4518
|
+
});
|
|
4519
|
+
};
|
|
4520
|
+
COMMANDS.WS_SHUTDOWN = (args, cb) => {
|
|
4521
|
+
if (!Env.wss) {
|
|
4522
|
+
return;
|
|
4523
|
+
}
|
|
4524
|
+
Env.active = false;
|
|
4525
|
+
Env.wss.close();
|
|
4526
|
+
delete Env.wss;
|
|
4527
|
+
cb();
|
|
4528
|
+
};
|
|
4529
|
+
COMMANDS.SET_MODERATORS = (args, cb) => {
|
|
4530
|
+
Env.Log.silly("SET_MODERATORS_FRONT_WORKER");
|
|
4531
|
+
Env.moderators = args;
|
|
4532
|
+
cb();
|
|
4533
|
+
};
|
|
4534
|
+
COMMANDS.BROADCAST_MESSAGE = (args, cb) => {
|
|
4535
|
+
const message = args?.message;
|
|
4536
|
+
if (!message) {
|
|
4537
|
+
return void cb();
|
|
4538
|
+
}
|
|
4539
|
+
Object.keys(Env.users).forEach(userId => {
|
|
4540
|
+
const u = Env.users[userId];
|
|
4541
|
+
sendMsg(u, message);
|
|
4542
|
+
});
|
|
4543
|
+
cb();
|
|
4544
|
+
};
|
|
4545
|
+
COMMANDS.GET_WS_DATA = (args, cb) => {
|
|
4546
|
+
cb(void 0, {
|
|
4547
|
+
pid: process?.pid,
|
|
4548
|
+
nb: Object.keys(Env.users)?.length,
|
|
4549
|
+
nb_wss: Env?.wss?.clients?.size
|
|
4550
|
+
});
|
|
4551
|
+
};
|
|
4552
|
+
const init = (config, cb) => {
|
|
4553
|
+
Env.Log = Logger(config.config, config.myId);
|
|
4554
|
+
Environment.init(Env, config);
|
|
4555
|
+
servePlugins(Env);
|
|
4556
|
+
onEnvReady.reg(() => {
|
|
4557
|
+
const cfg = config?.infra?.front[config.index];
|
|
4558
|
+
const server = Http.createServer(app);
|
|
4559
|
+
server.listen(cfg.port, cfg.host, () => {
|
|
4560
|
+
Env.Log.debug("HTTP worker listening on port", cfg.port);
|
|
4561
|
+
});
|
|
4562
|
+
Env.wss = new WebSocketServer({
|
|
4563
|
+
server
|
|
4564
|
+
});
|
|
4565
|
+
initServerHandlers();
|
|
4566
|
+
});
|
|
4567
|
+
cb();
|
|
4568
|
+
};
|
|
4569
|
+
let ready = false;
|
|
4570
|
+
process.on("message", function(obj) {
|
|
4571
|
+
if (!obj || !obj.txid || !obj.pid) {
|
|
4572
|
+
return void process.send({
|
|
4573
|
+
error: "E_INVAL",
|
|
4574
|
+
data: obj
|
|
4575
|
+
});
|
|
4576
|
+
}
|
|
4577
|
+
if (response.expected(obj.txid) && (obj.response || obj.error)) {
|
|
4578
|
+
response.handle(obj.txid, [ obj.error, obj.response ]);
|
|
4579
|
+
return;
|
|
4580
|
+
}
|
|
4581
|
+
const command = COMMANDS[obj.command];
|
|
4582
|
+
const data = obj.data;
|
|
4583
|
+
Env.pid = obj.pid;
|
|
4584
|
+
const cb = function(err, value) {
|
|
4585
|
+
process.send({
|
|
4586
|
+
error: Util.serializeError(err),
|
|
4587
|
+
txid: obj.txid,
|
|
4588
|
+
pid: obj.pid,
|
|
4589
|
+
value
|
|
4590
|
+
});
|
|
4591
|
+
};
|
|
4592
|
+
if (!ready) {
|
|
4593
|
+
return void init(obj.config, err => {
|
|
4594
|
+
if (err) {
|
|
4595
|
+
return void cb(Util.serializeError(err));
|
|
4596
|
+
}
|
|
4597
|
+
ready = true;
|
|
4598
|
+
cb();
|
|
4599
|
+
});
|
|
4600
|
+
}
|
|
4601
|
+
if (typeof command !== "function") {
|
|
4602
|
+
return void cb("E_BAD_COMMAND");
|
|
4603
|
+
}
|
|
4604
|
+
command(data, cb);
|
|
4605
|
+
});
|
|
4606
|
+
process.on("uncaughtException", function(err) {
|
|
4607
|
+
console.error("[%s] UNCAUGHT EXCEPTION IN DB WORKER", new Date);
|
|
4608
|
+
console.error(err);
|
|
4609
|
+
console.error("TERMINATING");
|
|
4610
|
+
process.exit(1);
|
|
4611
|
+
});
|
|
4612
|
+
return worker$1;
|
|
4613
|
+
}
|
|
4614
|
+
|
|
4615
|
+
var workerExports = requireWorker();
|
|
4616
|
+
|
|
4617
|
+
var worker = getDefaultExportFromCjs(workerExports);
|
|
4618
|
+
|
|
4619
|
+
module.exports = worker;
|