spec-3nweb-server 1.6.4 → 1.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,62 @@
1
+ "use strict";
2
+ /*
3
+ Copyright (C) 2023 3NSoft Inc.
4
+
5
+ This program is free software: you can redistribute it and/or modify it under
6
+ the terms of the GNU General Public License as published by the Free Software
7
+ Foundation, either version 3 of the License, or (at your option) any later
8
+ version.
9
+
10
+ This program is distributed in the hope that it will be useful, but
11
+ WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13
+ See the GNU General Public License for more details.
14
+
15
+ You should have received a copy of the GNU General Public License along with
16
+ this program. If not, see <http://www.gnu.org/licenses/>.
17
+ */
18
+ Object.defineProperty(exports, "__esModule", { value: true });
19
+ exports.sslOptsFromConfig = void 0;
20
+ const fs_1 = require("fs");
21
+ const path_1 = require("path");
22
+ function sslOptsFromConfig(letsencrypt, sslOpts, skipReloadOnCertsChange) {
23
+ if (!sslOpts) {
24
+ sslOpts = {};
25
+ }
26
+ if (letsencrypt) {
27
+ sslOpts.cert = (0, fs_1.readFileSync)((0, path_1.join)(letsencrypt, 'fullchain.pem'));
28
+ sslOpts.key = (0, fs_1.readFileSync)((0, path_1.join)(letsencrypt, 'privkey.pem'));
29
+ if (skipReloadOnCertsChange) {
30
+ return { sslOpts };
31
+ }
32
+ const onCertsUpdate = makeCertsUpdatesWatch();
33
+ return { sslOpts, onCertsUpdate };
34
+ }
35
+ else if (sslOpts.cert && sslOpts.key) {
36
+ sslOpts.cert = (0, fs_1.readFileSync)(sslOpts.cert);
37
+ sslOpts.key = (0, fs_1.readFileSync)(sslOpts.key);
38
+ if (skipReloadOnCertsChange) {
39
+ return { sslOpts };
40
+ }
41
+ const onCertsUpdate = makeCertsUpdatesWatch();
42
+ return { sslOpts, onCertsUpdate };
43
+ }
44
+ else if ((!sslOpts.cert && sslOpts.key)
45
+ || (sslOpts.cert && !sslOpts.key)) {
46
+ throw new Error(`servicesConnect.sslOpts section must have both key and cert fields pointing to respective files.`);
47
+ }
48
+ else {
49
+ return;
50
+ }
51
+ }
52
+ exports.sslOptsFromConfig = sslOptsFromConfig;
53
+ function makeCertsUpdatesWatch(
54
+ // XXX pass locations, or some fs watching object
55
+ ) {
56
+ return listener => {
57
+ // XXX start watching a signal
58
+ const stopWatching = () => { };
59
+ return stopWatching;
60
+ };
61
+ }
62
+ Object.freeze(exports);
@@ -0,0 +1,15 @@
1
+ import { MultiDomainSignupCtx, SingleUserSignupCtx } from "../admin/signup-tokens";
2
+ export declare function addSingleUserSignup(rootFolder: string, userId: string): Promise<string>;
3
+ export declare function addMultiDomainSignup(rootFolder: string, domains: string[]): Promise<string>;
4
+ export declare function readNoTokensFile(noTokenFile: string): Promise<MultiDomainSignupCtx>;
5
+ export declare function readTokenFile(rootFolder: string, tokenId: string): Promise<SingleUserSignupCtx | MultiDomainSignupCtx | undefined>;
6
+ export declare function readAllSignupTokens(rootFolder: string): Promise<{
7
+ singleUserTokens: {
8
+ tokenId: string;
9
+ ctx: SingleUserSignupCtx;
10
+ }[];
11
+ multiUserTokens: {
12
+ tokenId: string;
13
+ ctx: MultiDomainSignupCtx;
14
+ }[];
15
+ }>;
@@ -0,0 +1,132 @@
1
+ "use strict";
2
+ /*
3
+ Copyright (C) 2019 - 2020 3NSoft Inc.
4
+
5
+ This program is free software: you can redistribute it and/or modify it under
6
+ the terms of the GNU General Public License as published by the Free Software
7
+ Foundation, either version 3 of the License, or (at your option) any later
8
+ version.
9
+
10
+ This program is distributed in the hope that it will be useful, but
11
+ WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13
+ See the GNU General Public License for more details.
14
+
15
+ You should have received a copy of the GNU General Public License along with
16
+ this program. If not, see <http://www.gnu.org/licenses/>.
17
+ */
18
+ Object.defineProperty(exports, "__esModule", { value: true });
19
+ exports.readAllSignupTokens = exports.readTokenFile = exports.readNoTokensFile = exports.addMultiDomainSignup = exports.addSingleUserSignup = void 0;
20
+ const async_fs_node_1 = require("../lib-common/async-fs-node");
21
+ const signup_tokens_1 = require("../admin/signup-tokens");
22
+ const server_data_folders_1 = require("../lib-server/resources/server-data-folders");
23
+ const error_1 = require("../lib-common/exceptions/error");
24
+ const path_1 = require("path");
25
+ async function addSingleUserSignup(rootFolder, userId) {
26
+ const token = await (0, signup_tokens_1.generateToken)();
27
+ const ctx = (0, signup_tokens_1.makeSingleUserSignupCtx)(token, userId);
28
+ const fPath = (0, signup_tokens_1.tokenPath)(rootFolder, token);
29
+ try {
30
+ await (0, async_fs_node_1.writeFile)(fPath, JSON.stringify(ctx), { encoding: 'utf8', flag: 'wx' });
31
+ return token;
32
+ }
33
+ catch (exc) {
34
+ if (exc.alreadyExists) {
35
+ return addSingleUserSignup(rootFolder, userId);
36
+ }
37
+ else if (exc.notFound) {
38
+ await (0, async_fs_node_1.mkdir)((0, server_data_folders_1.tokensInRootFolder)(rootFolder))
39
+ .catch((exc) => {
40
+ if (!exc.alreadyExists) {
41
+ throw exc;
42
+ }
43
+ });
44
+ return addSingleUserSignup(rootFolder, userId);
45
+ }
46
+ else {
47
+ throw exc;
48
+ }
49
+ }
50
+ }
51
+ exports.addSingleUserSignup = addSingleUserSignup;
52
+ async function addMultiDomainSignup(rootFolder, domains) {
53
+ const token = await (0, signup_tokens_1.generateToken)();
54
+ const ctx = (0, signup_tokens_1.makeMultiDomainSignupCtx)(domains, token);
55
+ const fPath = (0, signup_tokens_1.tokenPath)(rootFolder, token);
56
+ try {
57
+ await (0, async_fs_node_1.writeFile)(fPath, JSON.stringify(ctx), { encoding: 'utf8', flag: 'wx' });
58
+ return token;
59
+ }
60
+ catch (exc) {
61
+ if (exc.alreadyExists) {
62
+ return addMultiDomainSignup(rootFolder, domains);
63
+ }
64
+ else if (exc.notFound) {
65
+ await (0, async_fs_node_1.mkdir)((0, server_data_folders_1.tokensInRootFolder)(rootFolder))
66
+ .catch((exc) => {
67
+ if (!exc.alreadyExists) {
68
+ throw exc;
69
+ }
70
+ });
71
+ return addMultiDomainSignup(rootFolder, domains);
72
+ }
73
+ else {
74
+ throw exc;
75
+ }
76
+ }
77
+ }
78
+ exports.addMultiDomainSignup = addMultiDomainSignup;
79
+ async function readNoTokensFile(noTokenFile) {
80
+ try {
81
+ const str = await (0, async_fs_node_1.readFile)(noTokenFile, { encoding: 'utf8' });
82
+ return JSON.parse(str);
83
+ }
84
+ catch (err) {
85
+ throw (0, error_1.errWithCause)(err, `Fail to read "no tokens" signup context file ${noTokenFile}`);
86
+ }
87
+ }
88
+ exports.readNoTokensFile = readNoTokensFile;
89
+ async function readTokenFile(rootFolder, tokenId) {
90
+ try {
91
+ const fPath = (0, path_1.join)((0, server_data_folders_1.tokensInRootFolder)(rootFolder), tokenId);
92
+ const str = await (0, async_fs_node_1.readFile)(fPath, { encoding: 'utf8' });
93
+ const ctx = JSON.parse(str);
94
+ if (!ctx.token) {
95
+ return;
96
+ }
97
+ else if (ctx.type === 'multi-domain') {
98
+ return (ctx.domains ? ctx : undefined);
99
+ }
100
+ else if (ctx.type === 'single-user') {
101
+ return (ctx.userId ? ctx : undefined);
102
+ }
103
+ else {
104
+ return;
105
+ }
106
+ }
107
+ catch (err) {
108
+ console.error(err);
109
+ return;
110
+ }
111
+ }
112
+ exports.readTokenFile = readTokenFile;
113
+ async function readAllSignupTokens(rootFolder) {
114
+ const singleUserTokens = [];
115
+ const multiUserTokens = [];
116
+ const tokenIds = await (0, async_fs_node_1.readdir)((0, server_data_folders_1.tokensInRootFolder)(rootFolder));
117
+ for (const tokenId of tokenIds) {
118
+ const ctx = await readTokenFile(rootFolder, tokenId);
119
+ if (!ctx) {
120
+ continue;
121
+ }
122
+ if (ctx.type === 'multi-domain') {
123
+ multiUserTokens.push({ tokenId, ctx });
124
+ }
125
+ else {
126
+ singleUserTokens.push({ tokenId, ctx });
127
+ }
128
+ }
129
+ return { multiUserTokens, singleUserTokens };
130
+ }
131
+ exports.readAllSignupTokens = readAllSignupTokens;
132
+ Object.freeze(exports);
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  /*
3
- Copyright (C) 2015 - 2016 3NSoft Inc.
3
+ Copyright (C) 2015 - 2016, 2023 3NSoft Inc.
4
4
 
5
5
  This program is free software: you can redistribute it and/or modify it under
6
6
  the terms of the GNU General Public License as published by the Free Software
@@ -39,19 +39,57 @@ Object.freeze(DNS_ERR_CODE);
39
39
  */
40
40
  function extractPair(txtRecords, serviceLabel) {
41
41
  for (const txtRecord of txtRecords) {
42
- const txt = txtRecord.join(' ');
43
- const eqPos = txt.indexOf('=');
44
- if (eqPos < 0) {
45
- continue;
46
- }
47
- const name = txt.substring(0, eqPos).trim();
48
- if (name === serviceLabel) {
49
- const value = txt.substring(eqPos + 1).trim();
50
- return value;
42
+ let joinedTXTstanzas = txtRecord.join('');
43
+ let record = getRecordAtStartOf(joinedTXTstanzas);
44
+ while (record) {
45
+ if (record.service === serviceLabel) {
46
+ const value = record.value.trim();
47
+ if (value.length > 0) {
48
+ return value;
49
+ }
50
+ }
51
+ if (record.txtTail) {
52
+ record = getRecordAtStartOf(record.txtTail);
53
+ }
54
+ else {
55
+ break;
56
+ }
51
57
  }
52
58
  }
53
59
  return;
54
60
  }
61
+ const recordsStarts = {
62
+ "3nstorage": '3nstorage=',
63
+ asmail: 'asmail=',
64
+ mailerid: 'mailerid='
65
+ };
66
+ function getRecordAtStartOf(txt) {
67
+ let service = undefined;
68
+ for (const [label, startSeq] of Object.entries(recordsStarts)) {
69
+ if (txt.startsWith(startSeq)) {
70
+ service = label;
71
+ txt = txt.substring(startSeq.length);
72
+ break;
73
+ }
74
+ }
75
+ if (!service) {
76
+ return;
77
+ }
78
+ for (const delimiter of Object.values(recordsStarts)) {
79
+ const endPos = txt.indexOf(delimiter);
80
+ if (endPos >= 0) {
81
+ return {
82
+ service,
83
+ value: txt.substring(0, endPos),
84
+ txtTail: txt.substring(endPos)
85
+ };
86
+ }
87
+ }
88
+ return {
89
+ service,
90
+ value: txt
91
+ };
92
+ }
55
93
  function resolveTxt(domain) {
56
94
  return new Promise((resolve, reject) => {
57
95
  // As of March 2017, docs for node say that texts given in a callback
package/build/lib.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  export { AppWithWSs } from './lib-server/web-sockets/app';
2
2
  export { Configurations, servicesApp, adminApp } from './services';
3
- export { addSingleUserSignup, getConfsFromEnv, getBindParamsFromEnv } from './run-config';
3
+ export { getConfsFromEnv, getBindParamsFromEnv } from './config/from-env';
4
+ export { addSingleUserSignup } from './config/signup';
4
5
  export import errors = require('./lib-server/middleware/error-handler');
5
6
  export * as mock from './mock/run-in-proc';
package/build/lib.js CHANGED
@@ -16,16 +16,17 @@
16
16
  this program. If not, see <http://www.gnu.org/licenses/>.
17
17
  */
18
18
  Object.defineProperty(exports, "__esModule", { value: true });
19
- exports.mock = exports.getBindParamsFromEnv = exports.getConfsFromEnv = exports.addSingleUserSignup = exports.adminApp = exports.servicesApp = exports.AppWithWSs = void 0;
19
+ exports.mock = exports.addSingleUserSignup = exports.getBindParamsFromEnv = exports.getConfsFromEnv = exports.adminApp = exports.servicesApp = exports.AppWithWSs = void 0;
20
20
  var app_1 = require("./lib-server/web-sockets/app");
21
21
  Object.defineProperty(exports, "AppWithWSs", { enumerable: true, get: function () { return app_1.AppWithWSs; } });
22
22
  var services_1 = require("./services");
23
23
  Object.defineProperty(exports, "servicesApp", { enumerable: true, get: function () { return services_1.servicesApp; } });
24
24
  Object.defineProperty(exports, "adminApp", { enumerable: true, get: function () { return services_1.adminApp; } });
25
- var run_config_1 = require("./run-config");
26
- Object.defineProperty(exports, "addSingleUserSignup", { enumerable: true, get: function () { return run_config_1.addSingleUserSignup; } });
27
- Object.defineProperty(exports, "getConfsFromEnv", { enumerable: true, get: function () { return run_config_1.getConfsFromEnv; } });
28
- Object.defineProperty(exports, "getBindParamsFromEnv", { enumerable: true, get: function () { return run_config_1.getBindParamsFromEnv; } });
25
+ var from_env_1 = require("./config/from-env");
26
+ Object.defineProperty(exports, "getConfsFromEnv", { enumerable: true, get: function () { return from_env_1.getConfsFromEnv; } });
27
+ Object.defineProperty(exports, "getBindParamsFromEnv", { enumerable: true, get: function () { return from_env_1.getBindParamsFromEnv; } });
28
+ var signup_1 = require("./config/signup");
29
+ Object.defineProperty(exports, "addSingleUserSignup", { enumerable: true, get: function () { return signup_1.addSingleUserSignup; } });
29
30
  exports.errors = require("./lib-server/middleware/error-handler");
30
31
  exports.mock = require("./mock/run-in-proc");
31
32
  Object.freeze(exports);
package/build/main.js CHANGED
@@ -16,67 +16,218 @@
16
16
  this program. If not, see <http://www.gnu.org/licenses/>.
17
17
  */
18
18
  Object.defineProperty(exports, "__esModule", { value: true });
19
- /*
20
- * This script starts server, according to settings, given in config file.
21
- */
19
+ const cli_1 = require("./config/cli");
20
+ const from_yaml_1 = require("./config/from-yaml");
21
+ const letsencrypt_1 = require("./config/letsencrypt");
22
22
  const lib_1 = require("./lib");
23
- const fs_1 = require("fs");
24
- const async_fs_node_1 = require("./lib-common/async-fs-node");
25
- const child_process_1 = require("child_process");
26
- const processes_1 = require("./lib-common/processes");
27
- const PID_FILE = '/var/3nweb/service.pid';
28
- const confFile = process.argv[2];
29
- if (!confFile) {
30
- console.error(`Configuration file is not given. It should be the first script argument.`);
31
- process.exit(-1);
32
- }
33
- const conf = JSON.parse((0, fs_1.readFileSync)(confFile, 'utf8'));
34
- const noop = () => { };
35
- (async () => {
23
+ const signup_1 = require("./config/signup");
24
+ async function run(conf) {
36
25
  if (!conf.servicesConnect) {
37
- console.error(`No connection settings found in ${confFile}.`);
26
+ console.error(`No connection settings found in ??.`);
38
27
  process.exit(-1);
39
28
  return;
40
29
  }
41
- try {
42
- const prevPidStr = await (0, async_fs_node_1.readFile)(PID_FILE, { encoding: 'utf8' });
43
- const prevPid = Number.parseInt(prevPidStr);
44
- if (!Number.isNaN(prevPid)) {
45
- (0, child_process_1.execSync)(`kill -SIGTERM ${prevPid}`);
46
- while (!!(0, child_process_1.execSync)(`ps ${prevPid} | grep ${prevPid}`)) {
47
- await (0, processes_1.sleep)(1000);
48
- }
49
- await (0, async_fs_node_1.unlink)(PID_FILE).catch(noop);
50
- }
51
- }
52
- catch (err) {
53
- if (!err.notFound) {
54
- throw err;
55
- }
56
- }
57
30
  let app = undefined;
31
+ function createApp(conf) {
32
+ const app = new lib_1.AppWithWSs();
33
+ app.use((0, lib_1.servicesApp)(conf, 'console', 'console'));
34
+ app.use((0, lib_1.adminApp)(conf, 'console', 'console'));
35
+ return app;
36
+ }
58
37
  async function stopProcess() {
59
38
  if (!app) {
60
39
  return;
61
40
  }
62
- app.stop().then(err => console.log(err));
63
- app = undefined;
64
- (0, async_fs_node_1.unlink)(PID_FILE).catch(noop);
41
+ try {
42
+ console.log(`Stopping app ...`);
43
+ await app.stop();
44
+ console.log(`app has stopped.`);
45
+ }
46
+ catch (err) {
47
+ console.log(`app encounter an error, when stopping`);
48
+ console.error(err);
49
+ }
50
+ finally {
51
+ app = undefined;
52
+ }
65
53
  }
66
- try {
67
- app = new lib_1.AppWithWSs();
68
- app.use((0, lib_1.servicesApp)(conf));
69
- app.use((0, lib_1.adminApp)(conf));
70
- const { hostname, port, sslOpts } = conf.servicesConnect;
54
+ async function startAppWithTLS(sslOpts, port, hostname) {
71
55
  await app.start(sslOpts, port, hostname);
72
- console.log(`Started 3NWeb server at address "${hostname}", port ${port}, ${sslOpts ? 'via TLS' : 'without TLS, and requiring TLS reverse proxy infront.'}`);
73
- (0, fs_1.writeFileSync)(PID_FILE, `${process.pid}`);
56
+ console.log(`Started 3NWeb server on port ${port},${hostname ? ` hostname ${hostname},` : ''} with TLS.`);
57
+ }
58
+ async function startAppWithoutTLS(port, hostname) {
59
+ await app.start(undefined, port, hostname);
60
+ console.log(`Started 3NWeb server on port ${port},${hostname ? ` hostname ${hostname},` : ''} without TLS, and requiring TLS reverse proxy infront.`);
61
+ }
62
+ try {
63
+ app = createApp(conf);
64
+ const { hostname, port, letsencrypt, sslOpts, skipReloadOnCertsChange } = conf.servicesConnect;
65
+ const tls = (0, letsencrypt_1.sslOptsFromConfig)(letsencrypt, sslOpts, skipReloadOnCertsChange);
66
+ if (tls) {
67
+ await startAppWithTLS(tls.sslOpts, port, hostname);
68
+ if (!skipReloadOnCertsChange) {
69
+ tls.onCertsUpdate(async (newOpts, originalOpts) => {
70
+ console.log(`Reloading server app server on TLS certificates change`);
71
+ try {
72
+ await stopProcess();
73
+ app = createApp(conf);
74
+ await startAppWithTLS(newOpts, port, hostname);
75
+ }
76
+ catch (err) {
77
+ console.error(err);
78
+ console.log(`Failed to reload with new TLS certs. Attempting to load with original ones.`);
79
+ try {
80
+ await stopProcess();
81
+ app = createApp(conf);
82
+ await startAppWithTLS(originalOpts, port, hostname);
83
+ }
84
+ catch (err) {
85
+ await stopProcess();
86
+ console.error(err);
87
+ process.exit(-500);
88
+ }
89
+ }
90
+ });
91
+ }
92
+ }
93
+ else {
94
+ await startAppWithoutTLS(port, hostname);
95
+ }
74
96
  process.on('SIGINT', stopProcess);
75
97
  process.on('SIGTERM', stopProcess);
76
98
  }
77
99
  catch (err) {
78
- stopProcess();
100
+ await stopProcess();
79
101
  console.error(err);
80
102
  process.exit(-500);
81
103
  }
82
- })();
104
+ }
105
+ function showUsage({ txtToDisplay, exitStatus }) {
106
+ if (exitStatus === 0) {
107
+ console.log(txtToDisplay);
108
+ }
109
+ else {
110
+ console.error(txtToDisplay);
111
+ }
112
+ process.exit(exitStatus);
113
+ }
114
+ function assembleConfig(configPath) {
115
+ if (configPath) {
116
+ return (0, from_yaml_1.readYamlConfFile)(configPath);
117
+ }
118
+ else {
119
+ throw new Error(`Config path must be given`);
120
+ }
121
+ }
122
+ async function displaySignupInfo(conf) {
123
+ if (!conf.signup) {
124
+ console.log(`\nSignup is disabled.\n`);
125
+ }
126
+ else {
127
+ console.log(`\nSignup is enabled.\n`);
128
+ if (conf.signup.noTokenFile) {
129
+ const ctx = await (0, signup_1.readNoTokensFile)(conf.signup.noTokenFile);
130
+ console.log(`Signup of user without token is allowed in domains:\n`, ctx.domains, `\n`);
131
+ }
132
+ else {
133
+ console.log(`Signup of users is allowed only with valid signup tokens.\n`);
134
+ }
135
+ }
136
+ const { multiUserTokens, singleUserTokens } = await (0, signup_1.readAllSignupTokens)(conf.rootFolder);
137
+ console.log(`There are ${multiUserTokens.length} multi-user tokens.\n`);
138
+ console.log(`There are ${singleUserTokens.length} single-user tokens.\n`);
139
+ }
140
+ async function displayTokensList(conf) {
141
+ const { multiUserTokens, singleUserTokens } = await (0, signup_1.readAllSignupTokens)(conf.rootFolder);
142
+ if (multiUserTokens.length > 0) {
143
+ console.log(`\nMulti-user signup tokens:`);
144
+ for (const { tokenId, ctx: { domains } } of multiUserTokens) {
145
+ console.log(` id: ${tokenId} -> domains:`, domains);
146
+ }
147
+ console.log(``);
148
+ }
149
+ else {
150
+ console.log(`\nThere are no multi-user signup tokens.\n`);
151
+ }
152
+ if (singleUserTokens.length > 0) {
153
+ console.log(`Single-user signup tokens:`);
154
+ for (const { tokenId, ctx: { userId } } of singleUserTokens) {
155
+ console.log(` id: ${tokenId} -> user: ${userId}`);
156
+ }
157
+ console.log(``);
158
+ }
159
+ else {
160
+ console.log(`There are no single-user signup tokens.\n`);
161
+ }
162
+ }
163
+ async function displayTokenValue(conf, tokenId) {
164
+ const ctx = await (0, signup_1.readTokenFile)(conf.rootFolder, tokenId);
165
+ if (!ctx) {
166
+ console.error(`Token ${tokenId} is not found.`);
167
+ process.exit(-1);
168
+ }
169
+ else if (ctx.type === 'multi-domain') {
170
+ console.log(`\nMulti-user signup context:`);
171
+ console.log(` domains:`, ctx.domains);
172
+ console.log(` value:`, ctx.token);
173
+ if (ctx.validTill) {
174
+ console.log(` valid till: ${(new Date(ctx.validTill)).toString()}\n`);
175
+ }
176
+ else {
177
+ console.log(``);
178
+ }
179
+ }
180
+ else if (ctx.type === 'single-user') {
181
+ console.log(`\nSingle-user signup context:`);
182
+ console.log(` address:`, ctx.userId);
183
+ console.log(` value:`, ctx.token);
184
+ if (ctx.validTill) {
185
+ console.log(` valid till: ${(new Date(ctx.validTill)).toString()}\n`);
186
+ }
187
+ else {
188
+ console.log(``);
189
+ }
190
+ }
191
+ }
192
+ async function createMultiUserToken(conf, domains) {
193
+ const token = await (0, signup_1.addMultiDomainSignup)(conf.rootFolder, domains);
194
+ console.log(`\nToken value:\n ${token}\n`);
195
+ }
196
+ async function createSingleUserToken(conf, userId) {
197
+ const token = await (0, signup_1.addSingleUserSignup)(conf.rootFolder, userId);
198
+ console.log(`\nToken value:\n ${token}\n`);
199
+ }
200
+ const cmd = (0, cli_1.parseProcessArgv)();
201
+ if (cmd.runCmd) {
202
+ const conf = assembleConfig(cmd.runCmd.config);
203
+ run(conf);
204
+ }
205
+ else if (cmd.signupCmd) {
206
+ const conf = assembleConfig(cmd.signupCmd.config);
207
+ if (cmd.signupCmd.info) {
208
+ displaySignupInfo(conf);
209
+ }
210
+ else if (cmd.signupCmd.listTokens) {
211
+ displayTokensList(conf);
212
+ }
213
+ else if (cmd.signupCmd.showToken) {
214
+ displayTokenValue(conf, cmd.signupCmd.token);
215
+ }
216
+ else if (cmd.signupCmd.createToken) {
217
+ if (cmd.signupCmd.user) {
218
+ createSingleUserToken(conf, cmd.signupCmd.user);
219
+ }
220
+ else {
221
+ createMultiUserToken(conf, cmd.signupCmd.domain);
222
+ }
223
+ }
224
+ else {
225
+ throw new Error(`CLI parser failed to capture invalid command`);
226
+ }
227
+ }
228
+ else if (cmd.showUsage) {
229
+ showUsage(cmd.showUsage);
230
+ }
231
+ else {
232
+ throw new Error(`CLI parser failed to trigger useful action`);
233
+ }
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  /*
3
- Copyright (C) 2020 3NSoft Inc.
3
+ Copyright (C) 2020, 2023 3NSoft Inc.
4
4
 
5
5
  This program is free software: you can redistribute it and/or modify it under
6
6
  the terms of the GNU General Public License as published by the Free Software
@@ -37,8 +37,11 @@ function setTestCertsAndDNS(domains, thisSrvLoc) {
37
37
  for (const domain of domains) {
38
38
  dnsRecs[domain] = [
39
39
  ['asmail', '=', `${thisSrvLoc}/asmail`],
40
- ['mailerid=', `${thisSrvLoc}/mailerid`],
41
- [`3nstorage=${thisSrvLoc}/3nstorage`] // DNS txt without spaces
40
+ [
41
+ 'mailerid=', `${thisSrvLoc}/mailerid`,
42
+ `3nstorage=${thisSrvLoc}/3nstorage`
43
+ ] // two 3NWeb records in one DNS TXT record
44
+ // XXX add other life-like records
42
45
  ];
43
46
  }
44
47
  const dnsMock = new dns_1.DNSMock(dnsRecs);
@@ -12,6 +12,8 @@ export interface Configurations {
12
12
  hostname?: string;
13
13
  port: number;
14
14
  sslOpts?: https.ServerOptions;
15
+ letsencrypt?: string;
16
+ skipReloadOnCertsChange?: boolean;
15
17
  };
16
18
  rootFolder: string;
17
19
  domain: string;
@@ -22,5 +24,5 @@ export interface Configurations {
22
24
  noTokenFile?: string;
23
25
  };
24
26
  }
25
- export declare function servicesApp(conf: Configurations, errLogger?: ErrLogger | 'console'): AppWithWSs;
26
- export declare function adminApp(conf: Configurations, errLogger?: ErrLogger | 'console'): AppWithWSs;
27
+ export declare function servicesApp(conf: Configurations, errLogger?: ErrLogger | 'console', logSetup?: 'console'): AppWithWSs;
28
+ export declare function adminApp(conf: Configurations, errLogger?: ErrLogger | 'console', logSetup?: 'console'): AppWithWSs;
package/build/services.js CHANGED
@@ -24,29 +24,38 @@ const asmail_app_1 = require("./asmail/asmail-app");
24
24
  const _3nstorage_app_1 = require("./3nstorage/3nstorage-app");
25
25
  const admin_app_1 = require("./admin/admin-app");
26
26
  const error_handler_1 = require("./lib-server/middleware/error-handler");
27
- function servicesApp(conf, errLogger) {
27
+ function servicesApp(conf, errLogger, logSetup) {
28
28
  if (!conf.enabledServices || (typeof conf.enabledServices !== 'object')) {
29
29
  throw new Error('Missing enabled-services sections in confs.');
30
30
  }
31
31
  const app = new app_1.AppWithWSs();
32
32
  const midAuthorizer = (0, mailerid_authorizer_1.validator)(); // share, allowing for caching of certs
33
33
  if (conf.enabledServices.mailerId) {
34
- app.http.use('/mailerid', (0, mailerId_app_1.makeApp)(conf.rootFolder, conf.domain, conf.mailerId.certs, (errLogger === 'console') ? (0, error_handler_1.makeErrLoggerToConsole)('mailerid') : errLogger));
34
+ app.http.use('/mailerid', (0, mailerId_app_1.makeApp)(conf.rootFolder, conf.domain, conf.mailerId.certs, (errLogger === 'console') ? (0, error_handler_1.makeErrLoggerToConsole)('MailerId') : errLogger));
35
+ if (logSetup === 'console') {
36
+ console.log(`Enabled MailerId service with provider domain ${conf.domain}`);
37
+ }
35
38
  }
36
39
  if (conf.enabledServices.asmail) {
37
- app.use('/asmail', (0, asmail_app_1.makeApp)(conf.rootFolder, conf.domain, midAuthorizer, (errLogger === 'console') ? (0, error_handler_1.makeErrLoggerToConsole)('asmail') : errLogger));
40
+ app.use('/asmail', (0, asmail_app_1.makeApp)(conf.rootFolder, conf.domain, midAuthorizer, (errLogger === 'console') ? (0, error_handler_1.makeErrLoggerToConsole)('ASMail') : errLogger));
41
+ if (logSetup === 'console') {
42
+ console.log(`Enabled ASMail service with provider domain ${conf.domain}`);
43
+ }
38
44
  }
39
45
  if (conf.enabledServices.storage) {
40
- app.use('/3nstorage', (0, _3nstorage_app_1.makeApp)(conf.rootFolder, conf.domain, midAuthorizer, (errLogger === 'console') ? (0, error_handler_1.makeErrLoggerToConsole)('storage') : errLogger));
46
+ app.use('/3nstorage', (0, _3nstorage_app_1.makeApp)(conf.rootFolder, conf.domain, midAuthorizer, (errLogger === 'console') ? (0, error_handler_1.makeErrLoggerToConsole)('3NStorage') : errLogger));
47
+ if (logSetup === 'console') {
48
+ console.log(`Enabled 3NStorage service with provider domain ${conf.domain}`);
49
+ }
41
50
  }
42
51
  return app;
43
52
  }
44
53
  exports.servicesApp = servicesApp;
45
- function adminApp(conf, errLogger) {
54
+ function adminApp(conf, errLogger, logSetup) {
46
55
  if (errLogger === 'console') {
47
56
  errLogger = (0, error_handler_1.makeErrLoggerToConsole)('3NWeb server admin');
48
57
  }
49
- return new app_1.AppWithWSs((0, admin_app_1.makeApp)(conf, errLogger));
58
+ return new app_1.AppWithWSs((0, admin_app_1.makeApp)(conf, errLogger, logSetup));
50
59
  }
51
60
  exports.adminApp = adminApp;
52
61
  Object.freeze(exports);