cryptpad-server 0.0.3 → 0.0.4

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/front.js CHANGED
@@ -1358,6 +1358,9 @@ function requireWsConnector() {
1358
1358
  cb(void 0, ctx.self);
1359
1359
  };
1360
1360
  const port = config.wsPort || config.port;
1361
+ httpServer.on("error", e => {
1362
+ cb(e);
1363
+ });
1361
1364
  httpServer.listen(port, config.host, onServerReady);
1362
1365
  },
1363
1366
  initClient: (ctx, config, id, onConnected, cb) => {
@@ -2772,6 +2775,14 @@ function requireFile() {
2772
2775
  writeLinkedFile(env, path, content, cb);
2773
2776
  });
2774
2777
  };
2778
+ const hasLinkedDocuments = (env, channelId) => {
2779
+ const path = mkLinkedPath(env, channelId);
2780
+ try {
2781
+ return Fs.existsSync(path);
2782
+ } catch (e) {
2783
+ return false;
2784
+ }
2785
+ };
2775
2786
  const getLinkedDocuments = (env, channelId, cb) => {
2776
2787
  const path = mkLinkedPath(env, channelId);
2777
2788
  readLinkedFile(env, path, cb);
@@ -3844,6 +3855,7 @@ function requireFile() {
3844
3855
  writeMetadata(env, channelName, data, Util.both(cb, next));
3845
3856
  });
3846
3857
  },
3858
+ hasLinkedDocuments: channelId => hasLinkedDocuments(env, channelId),
3847
3859
  getLinkedDocuments: (channelId, cb) => {
3848
3860
  if (!isValidChannelId(channelId)) {
3849
3861
  return cb(new Error("EINVAL"));
@@ -4049,7 +4061,7 @@ function requireLogger() {
4049
4061
  return logger;
4050
4062
  }
4051
4063
 
4052
- var version = "0.0.3";
4064
+ var version = "0.0.4";
4053
4065
 
4054
4066
  var require$$2 = {
4055
4067
  version
@@ -5795,7 +5807,8 @@ function requireFront() {
5795
5807
  process.send({
5796
5808
  type: "front",
5797
5809
  index,
5798
- msg: "READY"
5810
+ msg: "READY",
5811
+ pid: process.pid
5799
5812
  });
5800
5813
  } else {
5801
5814
  Env.Log.info("SINGLE_FRONT_STARTED", Env.myId);
package/build/http.js CHANGED
@@ -2200,6 +2200,14 @@ function requireFile() {
2200
2200
  writeLinkedFile(env, path, content, cb);
2201
2201
  });
2202
2202
  };
2203
+ const hasLinkedDocuments = (env, channelId) => {
2204
+ const path = mkLinkedPath(env, channelId);
2205
+ try {
2206
+ return Fs.existsSync(path);
2207
+ } catch (e) {
2208
+ return false;
2209
+ }
2210
+ };
2203
2211
  const getLinkedDocuments = (env, channelId, cb) => {
2204
2212
  const path = mkLinkedPath(env, channelId);
2205
2213
  readLinkedFile(env, path, cb);
@@ -3272,6 +3280,7 @@ function requireFile() {
3272
3280
  writeMetadata(env, channelName, data, Util.both(cb, next));
3273
3281
  });
3274
3282
  },
3283
+ hasLinkedDocuments: channelId => hasLinkedDocuments(env, channelId),
3275
3284
  getLinkedDocuments: (channelId, cb) => {
3276
3285
  if (!isValidChannelId(channelId)) {
3277
3286
  return cb(new Error("EINVAL"));
@@ -3477,7 +3486,7 @@ function requireLogger() {
3477
3486
  return logger;
3478
3487
  }
3479
3488
 
3480
- var version = "0.0.3";
3489
+ var version = "0.0.4";
3481
3490
 
3482
3491
  var require$$2 = {
3483
3492
  version
@@ -5172,6 +5181,9 @@ function requireWsConnector() {
5172
5181
  cb(void 0, ctx.self);
5173
5182
  };
5174
5183
  const port = config.wsPort || config.port;
5184
+ httpServer.on("error", e => {
5185
+ cb(e);
5186
+ });
5175
5187
  httpServer.listen(port, config.host, onServerReady);
5176
5188
  },
5177
5189
  initClient: (ctx, config, id, onConnected, cb) => {
@@ -5313,7 +5325,8 @@ function requireHttpServer() {
5313
5325
  type: "http",
5314
5326
  index: 0,
5315
5327
  dev: Env.DEV_MODE,
5316
- msg: "READY"
5328
+ msg: "READY",
5329
+ pid: process.pid
5317
5330
  });
5318
5331
  });
5319
5332
  };
@@ -2210,6 +2210,14 @@ function requireFile() {
2210
2210
  writeLinkedFile(env, path, content, cb);
2211
2211
  });
2212
2212
  };
2213
+ const hasLinkedDocuments = (env, channelId) => {
2214
+ const path = mkLinkedPath(env, channelId);
2215
+ try {
2216
+ return Fs.existsSync(path);
2217
+ } catch (e) {
2218
+ return false;
2219
+ }
2220
+ };
2213
2221
  const getLinkedDocuments = (env, channelId, cb) => {
2214
2222
  const path = mkLinkedPath(env, channelId);
2215
2223
  readLinkedFile(env, path, cb);
@@ -3282,6 +3290,7 @@ function requireFile() {
3282
3290
  writeMetadata(env, channelName, data, Util.both(cb, next));
3283
3291
  });
3284
3292
  },
3293
+ hasLinkedDocuments: channelId => hasLinkedDocuments(env, channelId),
3285
3294
  getLinkedDocuments: (channelId, cb) => {
3286
3295
  if (!isValidChannelId(channelId)) {
3287
3296
  return cb(new Error("EINVAL"));
@@ -3529,7 +3538,7 @@ function requireDefaults() {
3529
3538
  return defaults.exports;
3530
3539
  }
3531
3540
 
3532
- var version = "0.0.3";
3541
+ var version = "0.0.4";
3533
3542
 
3534
3543
  var require$$2 = {
3535
3544
  version
@@ -4611,6 +4620,10 @@ function requireWorker() {
4611
4620
  txid: obj.txid,
4612
4621
  pid: obj.pid,
4613
4622
  value
4623
+ }, e => {
4624
+ if (e) {
4625
+ console.error("E_RESPONSE", Util.serializeError(e));
4626
+ }
4614
4627
  });
4615
4628
  };
4616
4629
  if (!ready) {
@@ -2879,7 +2879,7 @@ function requireMfa() {
2879
2879
  return mfa.exports;
2880
2880
  }
2881
2881
 
2882
- var version = "0.0.3";
2882
+ var version = "0.0.4";
2883
2883
 
2884
2884
  var require$$2 = {
2885
2885
  version
@@ -4473,6 +4473,14 @@ function requireFile() {
4473
4473
  writeLinkedFile(env, path, content, cb);
4474
4474
  });
4475
4475
  };
4476
+ const hasLinkedDocuments = (env, channelId) => {
4477
+ const path = mkLinkedPath(env, channelId);
4478
+ try {
4479
+ return Fs.existsSync(path);
4480
+ } catch (e) {
4481
+ return false;
4482
+ }
4483
+ };
4476
4484
  const getLinkedDocuments = (env, channelId, cb) => {
4477
4485
  const path = mkLinkedPath(env, channelId);
4478
4486
  readLinkedFile(env, path, cb);
@@ -5545,6 +5553,7 @@ function requireFile() {
5545
5553
  writeMetadata(env, channelName, data, Util.both(cb, next));
5546
5554
  });
5547
5555
  },
5556
+ hasLinkedDocuments: channelId => hasLinkedDocuments(env, channelId),
5548
5557
  getLinkedDocuments: (channelId, cb) => {
5549
5558
  if (!isValidChannelId(channelId)) {
5550
5559
  return cb(new Error("EINVAL"));
package/build/storage.js CHANGED
@@ -2202,6 +2202,14 @@ function requireFile() {
2202
2202
  writeLinkedFile(env, path, content, cb);
2203
2203
  });
2204
2204
  };
2205
+ const hasLinkedDocuments = (env, channelId) => {
2206
+ const path = mkLinkedPath(env, channelId);
2207
+ try {
2208
+ return Fs.existsSync(path);
2209
+ } catch (e) {
2210
+ return false;
2211
+ }
2212
+ };
2205
2213
  const getLinkedDocuments = (env, channelId, cb) => {
2206
2214
  const path = mkLinkedPath(env, channelId);
2207
2215
  readLinkedFile(env, path, cb);
@@ -3274,6 +3282,7 @@ function requireFile() {
3274
3282
  writeMetadata(env, channelName, data, Util.both(cb, next));
3275
3283
  });
3276
3284
  },
3285
+ hasLinkedDocuments: channelId => hasLinkedDocuments(env, channelId),
3277
3286
  getLinkedDocuments: (channelId, cb) => {
3278
3287
  if (!isValidChannelId(channelId)) {
3279
3288
  return cb(new Error("EINVAL"));
@@ -5025,10 +5034,17 @@ function requireChannelManager() {
5025
5034
  }
5026
5035
  }));
5027
5036
  }).nThen(function(w) {
5037
+ if (!store.hasLinkedDocuments(channel)) {
5038
+ return;
5039
+ }
5028
5040
  Linked.trimHistory(Env, {
5029
5041
  channel
5030
5042
  }, w());
5031
5043
  }).nThen(function() {
5044
+ Env.Log.info("HK_TRIM_HISTORY_START", {
5045
+ unsafeKey,
5046
+ channel
5047
+ });
5032
5048
  store.trimChannel(channel, hash, err => {
5033
5049
  Env.Log.info("HK_TRIM_HISTORY", {
5034
5050
  unsafeKey,
@@ -6695,7 +6711,7 @@ function requireMfaManager() {
6695
6711
  return mfaManager;
6696
6712
  }
6697
6713
 
6698
- var version = "0.0.3";
6714
+ var version = "0.0.4";
6699
6715
 
6700
6716
  var require$$2 = {
6701
6717
  version
@@ -7924,6 +7940,9 @@ function requireWsConnector() {
7924
7940
  cb(void 0, ctx.self);
7925
7941
  };
7926
7942
  const port = config.wsPort || config.port;
7943
+ httpServer.on("error", e => {
7944
+ cb(e);
7945
+ });
7927
7946
  httpServer.listen(port, config.host, onServerReady);
7928
7947
  },
7929
7948
  initClient: (ctx, config, id, onConnected, cb) => {
@@ -12113,7 +12132,8 @@ function requireStorage() {
12113
12132
  process.send({
12114
12133
  type: "storage",
12115
12134
  index,
12116
- msg: "READY"
12135
+ msg: "READY",
12136
+ pid: process.pid
12117
12137
  });
12118
12138
  } else {
12119
12139
  console.log(myId, "started");
@@ -2204,6 +2204,14 @@ function requireFile() {
2204
2204
  writeLinkedFile(env, path, content, cb);
2205
2205
  });
2206
2206
  };
2207
+ const hasLinkedDocuments = (env, channelId) => {
2208
+ const path = mkLinkedPath(env, channelId);
2209
+ try {
2210
+ return Fs.existsSync(path);
2211
+ } catch (e) {
2212
+ return false;
2213
+ }
2214
+ };
2207
2215
  const getLinkedDocuments = (env, channelId, cb) => {
2208
2216
  const path = mkLinkedPath(env, channelId);
2209
2217
  readLinkedFile(env, path, cb);
@@ -3276,6 +3284,7 @@ function requireFile() {
3276
3284
  writeMetadata(env, channelName, data, Util.both(cb, next));
3277
3285
  });
3278
3286
  },
3287
+ hasLinkedDocuments: channelId => hasLinkedDocuments(env, channelId),
3279
3288
  getLinkedDocuments: (channelId, cb) => {
3280
3289
  if (!isValidChannelId(channelId)) {
3281
3290
  return cb(new Error("EINVAL"));
@@ -4731,7 +4740,7 @@ function requireTasks() {
4731
4740
  return tasks.exports;
4732
4741
  }
4733
4742
 
4734
- var version = "0.0.3";
4743
+ var version = "0.0.4";
4735
4744
 
4736
4745
  var require$$2 = {
4737
4746
  version
@@ -5589,10 +5598,11 @@ function requirePinManager() {
5589
5598
  hasRequiredPinManager = 1;
5590
5599
  (function(module) {
5591
5600
  const Pins = module.exports;
5592
- __require$2();
5593
- __require$1();
5594
- requireCommonUtil$1();
5595
- requireFile();
5601
+ const Fs = __require$2();
5602
+ const Path = __require$1();
5603
+ const Util = requireCommonUtil$1();
5604
+ const Semaphore = require$$4;
5605
+ const nThen = require$$3;
5596
5606
  const createLineHandler = Pins.createLineHandler = (ref, errorHandler) => {
5597
5607
  let fileName;
5598
5608
  if (typeof errorHandler === "string") {
@@ -5712,8 +5722,72 @@ function requirePinManager() {
5712
5722
  const ref = processPinFile(pinFile, fileName);
5713
5723
  return Object.keys(ref.pins);
5714
5724
  };
5715
- Pins.load = (cb, config) => {
5716
- throw new Error("EVICTION NOT IMPLEMENTED");
5725
+ Pins.load = (Env, cb, config) => {
5726
+ const sema = Semaphore.create(config.workers || 5);
5727
+ let dirList;
5728
+ const fileList = [];
5729
+ const pinned = {};
5730
+ var done = Util.once(cb);
5731
+ var handler = config.handler;
5732
+ let store = Env.pinStore;
5733
+ let pinPath = Env.paths.pin;
5734
+ nThen(waitFor => {
5735
+ Fs.readdir(pinPath, waitFor((err, list) => {
5736
+ if (err) {
5737
+ if (err.code === "ENOENT") {
5738
+ dirList = [];
5739
+ return;
5740
+ }
5741
+ waitFor.abort();
5742
+ return void done(err);
5743
+ }
5744
+ dirList = list;
5745
+ }));
5746
+ }).nThen(waitFor => {
5747
+ dirList.forEach(f => {
5748
+ sema.take(returnAfter => {
5749
+ Fs.readdir(Path.join(pinPath, f), waitFor(returnAfter((err, list2) => {
5750
+ if (err) {
5751
+ waitFor.abort();
5752
+ return void done(err);
5753
+ }
5754
+ list2.forEach(ff => {
5755
+ if (config && config.exclude && config.exclude.indexOf(ff) > -1) {
5756
+ return;
5757
+ }
5758
+ fileList.push(ff.replace(/(\.ndjson)$/, ""));
5759
+ });
5760
+ })));
5761
+ });
5762
+ });
5763
+ }).nThen(waitFor => {
5764
+ fileList.forEach(id => {
5765
+ sema.take(returnAfter => {
5766
+ var next = waitFor(returnAfter());
5767
+ var ref = {};
5768
+ var h = createLineHandler(ref, id);
5769
+ store.readMessagesBin(id, 0, (msgObj, next) => {
5770
+ h(msgObj.buff.toString("utf8"));
5771
+ next();
5772
+ }, err => {
5773
+ if (err) {
5774
+ waitFor.abort();
5775
+ return void done(err);
5776
+ }
5777
+ if (handler) {
5778
+ return void handler(ref, id, next);
5779
+ }
5780
+ const hashes = Object.keys(ref.pins);
5781
+ hashes.forEach(x => {
5782
+ (pinned[x] = pinned[x] || {})[id] = 1;
5783
+ });
5784
+ next();
5785
+ });
5786
+ });
5787
+ });
5788
+ }).nThen(() => {
5789
+ done(void 0, pinned);
5790
+ });
5717
5791
  };
5718
5792
  })(pinManager);
5719
5793
  return pinManager.exports;
@@ -6519,6 +6593,10 @@ function requireWorker() {
6519
6593
  txid: obj.txid,
6520
6594
  pid: obj.pid,
6521
6595
  value
6596
+ }, e => {
6597
+ if (e) {
6598
+ console.error("E_RESPONSE", Util.serializeError(e));
6599
+ }
6522
6600
  });
6523
6601
  };
6524
6602
  if (!ready) {
@@ -6535,6 +6613,9 @@ function requireWorker() {
6535
6613
  }
6536
6614
  command(data, cb);
6537
6615
  });
6616
+ process.on("disconnect", () => {
6617
+ process.exit(0);
6618
+ });
6538
6619
  process.on("uncaughtException", function(err) {
6539
6620
  console.error("[%s] UNCAUGHT EXCEPTION IN DB WORKER", new Date);
6540
6621
  console.error(err);
package/index.js CHANGED
@@ -47,6 +47,14 @@ args.some(arg => {
47
47
  prev = '';
48
48
  });
49
49
 
50
+ // Clean quit: kill child processes
51
+ const childPids = [];
52
+
53
+ const cleanSubprocesses = () => childPids.forEach((pid) => process.kill(pid));
54
+
55
+ process.on('SIGTERM', cleanSubprocesses);
56
+ process.on('exit', cleanSubprocesses);
57
+
50
58
  const start = (serverConfig, infraConfig) => {
51
59
  const Log = {
52
60
  debug: console.debug,
@@ -57,9 +65,7 @@ const start = (serverConfig, infraConfig) => {
57
65
  };
58
66
 
59
67
  let serverId;
60
- const startNode = (type, index, forking, cb) => {
61
- if (typeof (cb) !== 'function') { cb = () => { }; };
62
-
68
+ const startNode = (type, index, forking) => new Promise((resolve, reject) => {
63
69
  const nodeFile = './build/' + type + '.js';
64
70
  const path = Path.join(__dirname, nodeFile);
65
71
  const initConfig = {
@@ -72,51 +78,49 @@ const start = (serverConfig, infraConfig) => {
72
78
  //Log.info(`Starting: ${initConfig.myId}`);
73
79
  if (forking) {
74
80
  let nodeProcess = fork(path);
81
+ childPids.push(nodeProcess.pid);
75
82
  nodeProcess.send(initConfig);
76
83
  nodeProcess.on('message', (message) => {
77
84
  if (message.msg === 'READY') {
78
- Log.info(`Started: ${type}:${message.index}`);
85
+ // Log.info(`Started: ${type}:${message.index}`);
79
86
  if (message.dev) {
80
87
  Log.info('DEV mode enabled');
81
88
  }
82
- cb();
89
+ resolve();
83
90
  }
84
91
  });
85
- // FIXME
86
92
  nodeProcess.on('error', (err) => {
87
93
  Log.error('Child process stopped due to error.');
88
94
  Log.error(err);
95
+ reject(`${type}:${index}: error ${err}`);
89
96
  process.exit(1);
90
97
  });
91
98
  nodeProcess.on('exit', (err) => {
92
99
  Log.error('Child process stopped due to error.');
93
100
  Log.error(err);
94
- process.exit(1);
101
+ reject(`${type}:${index}: exit(${err})`);
102
+ process.exit(err);
95
103
  });
96
104
  } else {
105
+ // Single process start
106
+ // Can only be called from CLI and not from external module
97
107
  require(path).start(initConfig);
98
108
  }
99
- };
109
+ });
100
110
 
101
111
  const coresReady = () => {
102
112
  const promises = [];
103
113
  infraConfig?.front?.forEach((data, index) => {
104
- promises.push(new Promise(resolve => {
105
- if (serverId && data.serverId !== serverId) { return resolve(); }
106
- startNode('front', index, true, resolve);
107
- }));
114
+ if (serverId && data.serverId !== serverId) { return; }
115
+ promises.push(startNode('front', index, true));
108
116
  });
109
117
  infraConfig?.storage?.forEach((data, index) => {
110
- promises.push(new Promise(resolve => {
111
- if (serverId && data.serverId !== serverId) { return resolve(); }
112
- startNode('storage', index, true, resolve);
113
- }));
118
+ if (serverId && data.serverId !== serverId) { return; }
119
+ promises.push(startNode('storage', index, true));
114
120
  });
115
- promises.push(new Promise(resolve => {
116
- if (serverId && infraConfig?.public?.httpServerId !== serverId) { return resolve(); }
117
- startNode('http', 0, true, resolve);
118
- }));
119
- Promise.all(promises).then(() => {
121
+ if (serverId && infraConfig?.public?.httpServerId !== serverId) { return; }
122
+ promises.push(startNode('http', 0, true));
123
+ return Promise.all(promises.filter(Boolean)).then(() => {
120
124
  Log.info('CryptPad server ready');
121
125
  });
122
126
  };
@@ -128,21 +132,14 @@ const start = (serverConfig, infraConfig) => {
128
132
  }
129
133
  serverConfig.private.nodes_key = Crypto.randomBytes(32).toString('base64');
130
134
  }
131
- const corePromises = infraConfig?.core.map((data, index) => new Promise((resolve, reject) => {
135
+ const corePromises = infraConfig?.core.map((data, index) => {
132
136
  // hosted on another machine?
133
- if (serverId && data.serverId !== serverId) { return resolve(); }
134
- startNode('core', index, true, (err) => {
135
- if (err) {
136
- Log.error('START_CORE_ERROR', err);
137
- return reject(err);
138
- }
139
- return resolve();
140
- });
141
- }));
137
+ if (serverId && data.serverId !== serverId) { return; }
138
+ return startNode('core', index, true);
139
+ });
142
140
 
143
- Promise.all(corePromises)
144
- .then(() => { coresReady(); })
145
- .catch((e) => { return Log.error('START_CORE_ERROR', e); });
141
+ return Promise.all(corePromises.filter(Boolean))
142
+ .then(() => coresReady());
146
143
  };
147
144
 
148
145
 
@@ -153,18 +150,18 @@ const start = (serverConfig, infraConfig) => {
153
150
  if (!serverConfig?.private?.nodes_key) {
154
151
  throw Error('E_MISSINGKEY');
155
152
  }
156
- startNode(type, index, false, (err) => {
153
+ return startNode(type, index, false).catch((err) => {
157
154
  if (err) { return Log.error('START_NODE_ERROR', err); }
158
155
  });
159
156
  } else {
160
157
  serverId = cliArgs.server;
161
- startCores();
158
+ return startCores();
162
159
  }
163
160
  };
164
161
 
165
162
  if (require.main === module) {
166
- const { config, infra } = require('./common/load-config');
167
- start(config, infra);
163
+ const { config, infra } = require('./common/load-config')();
164
+ start(config, infra).catch((e) => { console.error('CryptPad server start failed:', e); });
168
165
  } else {
169
166
  module.exports = { start };
170
167
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "cryptpad-server",
3
3
  "description": "CryptPad Server",
4
- "version": "0.0.3",
4
+ "version": "0.0.4",
5
5
  "license": "AGPL-3.0+",
6
6
  "repository": {
7
7
  "type": "git",
@@ -16,12 +16,13 @@
16
16
  "build"
17
17
  ],
18
18
  "dependencies": {
19
+ "@mcrowe/minibloom": "^0.2.0",
19
20
  "connect-gzip-static": "^4.2.1",
20
21
  "cookie-parser": "^1.4.7",
21
22
  "express": "~5.2.1",
22
- "mime-types": "^3.0.2",
23
23
  "fs-extra": "^7.0.0",
24
24
  "http-proxy-middleware": "^3.0.3",
25
+ "mime-types": "^3.0.2",
25
26
  "nthen": "0.1.8",
26
27
  "otpauth": "^9.4.1",
27
28
  "pull-stream": "^3.6.1",
@@ -61,6 +62,7 @@
61
62
  "build:core": "TYPE=core rollup -c",
62
63
  "build:storage": "TYPE=storage rollup -c",
63
64
  "build:http": "TYPE=http rollup -c",
65
+ "build:eviction": "TYPE=eviction rollup -c",
64
66
  "tests": "node --test tests/",
65
67
  "test": "node tests/runAll.js",
66
68
  "start": "node index.js",
package/readme.md CHANGED
@@ -90,12 +90,8 @@ node index.js --server [serverId value]
90
90
  The directory [`tests`](tests/) contains some unit and integration tests scripts
91
91
  and files.
92
92
 
93
- - [`interface.test.js`](tests/interface.test.js): test the communication
94
- interface by implementing a simple ping-pong protocol that computes the time it
95
- takes to go back and forth in the network.
96
-
97
93
  The aforementioned tests can be run with the following command (make sure to
98
94
  have installed the dependencies with `npm install` beforehand):
99
95
  ```bash
100
- npm run tests
96
+ npm run test
101
97
  ```