spec-3nweb-server 1.6.4 → 1.7.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.
Files changed (66) hide show
  1. package/README.md +0 -1
  2. package/build/3nstorage/resources/sessions.d.ts +2 -2
  3. package/build/3nstorage/resources/store.d.ts +1 -1
  4. package/build/3nstorage/resources/users.d.ts +15 -15
  5. package/build/admin/admin-app.d.ts +1 -1
  6. package/build/admin/admin-app.js +4 -1
  7. package/build/admin/resources/users.d.ts +3 -3
  8. package/build/admin/signup-tokens.d.ts +1 -1
  9. package/build/asmail/resources/delivery-sessions.d.ts +3 -3
  10. package/build/asmail/resources/inbox.d.ts +9 -9
  11. package/build/asmail/resources/recipients.d.ts +18 -18
  12. package/build/asmail/resources/sessions.d.ts +2 -2
  13. package/build/asmail/routes/delivery/sender-authorization.d.ts +1 -1
  14. package/build/asmail/routes/delivery/start-session.d.ts +1 -1
  15. package/build/config/cli/index.d.ts +9 -0
  16. package/build/config/cli/index.js +68 -0
  17. package/build/config/cli/run-cmd.d.ts +10 -0
  18. package/build/config/cli/run-cmd.js +69 -0
  19. package/build/config/cli/signup-cmd.d.ts +17 -0
  20. package/build/config/cli/signup-cmd.js +194 -0
  21. package/build/config/cli/user-cmd.d.ts +9 -0
  22. package/build/config/cli/user-cmd.js +55 -0
  23. package/build/config/cli/utils.d.ts +45 -0
  24. package/build/config/cli/utils.js +52 -0
  25. package/build/config/from-yaml.d.ts +2 -0
  26. package/build/config/from-yaml.js +28 -0
  27. package/build/config/letsencrypt.d.ts +7 -0
  28. package/build/config/letsencrypt.js +62 -0
  29. package/build/config/signup.d.ts +15 -0
  30. package/build/config/signup.js +133 -0
  31. package/build/lib-common/byte-streaming/common.d.ts +2 -2
  32. package/build/lib-common/byte-streaming/common.js +5 -5
  33. package/build/lib-common/exceptions/file.d.ts +1 -1
  34. package/build/lib-common/ipc/generic-ipc.d.ts +7 -7
  35. package/build/lib-common/ipc/generic-ipc.js +6 -6
  36. package/build/lib-common/objs-on-disk/file-layout.d.ts +4 -4
  37. package/build/lib-common/objs-on-disk/utils.d.ts +3 -3
  38. package/build/lib-common/processes.d.ts +1 -1
  39. package/build/lib-common/service-api/ipc-api.d.ts +6 -6
  40. package/build/lib-common/service-api/web-socket-base.d.ts +1 -1
  41. package/build/lib-server/middleware/error-handler.d.ts +1 -1
  42. package/build/lib-server/resources/dns.d.ts +1 -1
  43. package/build/lib-server/resources/dns.js +48 -10
  44. package/build/lib-server/resources/sessions.d.ts +2 -2
  45. package/build/lib-server/resources/user-files.d.ts +1 -1
  46. package/build/lib-server/routes/pub-key-login/start-exchange.d.ts +4 -4
  47. package/build/lib-server/routes/sessions/mid-auth.d.ts +1 -1
  48. package/build/lib-server/routes/sessions/start.d.ts +4 -4
  49. package/build/lib-server/web-sockets/app.d.ts +1 -1
  50. package/build/lib-server/web-sockets/app.js +6 -6
  51. package/build/lib-server/web-sockets/server-events.d.ts +1 -1
  52. package/build/lib.d.ts +1 -1
  53. package/build/lib.js +3 -5
  54. package/build/mailerId/resources/certifier.d.ts +1 -1
  55. package/build/mailerId/resources/sessions.d.ts +1 -1
  56. package/build/main.js +196 -45
  57. package/build/mock/node-child-ipc.d.ts +2 -2
  58. package/build/mock/run-in-proc.js +6 -3
  59. package/build/services.d.ts +4 -2
  60. package/build/services.js +15 -6
  61. package/package.json +16 -3
  62. package/postinstall.js +25 -0
  63. package/build/run-config.d.ts +0 -10
  64. package/build/run-config.js +0 -146
  65. package/build/run.d.ts +0 -1
  66. package/build/run.js +0 -45
@@ -586,14 +586,14 @@ function makeSubscribingClient(channel, comm) {
586
586
  }
587
587
  exports.makeSubscribingClient = makeSubscribingClient;
588
588
  class MultiObserverWrap {
589
+ get done() {
590
+ return this.isDone;
591
+ }
589
592
  constructor() {
590
593
  this.isDone = false;
591
594
  this.obs = new Set();
592
595
  Object.seal(this);
593
596
  }
594
- get done() {
595
- return this.isDone;
596
- }
597
597
  add(obs) {
598
598
  if (this.isDone) {
599
599
  throw new Error(`Cannot add observer, as this source is already done`);
@@ -645,15 +645,15 @@ exports.MultiObserverWrap = MultiObserverWrap;
645
645
  Object.freeze(MultiObserverWrap.prototype);
646
646
  Object.freeze(MultiObserverWrap);
647
647
  class SingleObserverWrap {
648
+ get done() {
649
+ return this.isDone;
650
+ }
648
651
  constructor() {
649
652
  this.isDone = false;
650
653
  this.obs = undefined;
651
654
  this.detach = () => this.setDone();
652
655
  Object.seal(this);
653
656
  }
654
- get done() {
655
- return this.isDone;
656
- }
657
657
  set(obs) {
658
658
  if (this.isDone) {
659
659
  throw new Error(`Cannot add observer, as this source is already done`);
@@ -4,10 +4,10 @@ export interface HeaderChunkInfo {
4
4
  len: number;
5
5
  fileOfs: number;
6
6
  }
7
- export declare type NotOnDiskFiniteChunk = NewSegsChunk | BaseSegsChunk;
8
- export declare type OnDiskChunk = NewSegsChunkOnDisk | BaseSegsChunkOnDisk;
9
- export declare type FiniteSegsChunk = OnDiskChunk | NotOnDiskFiniteChunk;
10
- export declare type SegsChunk = OnDiskChunk | NotOnDiskFiniteChunk | NewEndlessSegsChunk;
7
+ export type NotOnDiskFiniteChunk = NewSegsChunk | BaseSegsChunk;
8
+ export type OnDiskChunk = NewSegsChunkOnDisk | BaseSegsChunkOnDisk;
9
+ export type FiniteSegsChunk = OnDiskChunk | NotOnDiskFiniteChunk;
10
+ export type SegsChunk = OnDiskChunk | NotOnDiskFiniteChunk | NewEndlessSegsChunk;
11
11
  export interface FiniteChunk {
12
12
  thisVerOfs: number;
13
13
  len: number;
@@ -14,10 +14,10 @@ export interface ChunkWithSegs {
14
14
  len: number;
15
15
  segsOfs: number;
16
16
  }
17
- export declare type Chunk = ChunkWithHeader | ChunkWithSegs;
17
+ export type Chunk = ChunkWithHeader | ChunkWithSegs;
18
18
  export declare function streamToObjFile(file: ObjVersionFile, content: Chunk[], src: Readable, maxBufferLen: number): Promise<void>;
19
19
  export declare function chunksInOrderedStream(len: number, headerLen: undefined | number, segsOfs: number): Chunk[];
20
- export declare type ObjPipe = (outStream: NodeJS.WritableStream) => Promise<void>;
21
- export declare type GetObjFile = (objId: string | null, version: number) => Promise<ObjVersionFile>;
20
+ export type ObjPipe = (outStream: NodeJS.WritableStream) => Promise<void>;
21
+ export type GetObjFile = (objId: string | null, version: number) => Promise<ObjVersionFile>;
22
22
  export declare function makeObjPipe(file: ObjVersionFile, header: boolean, segsOfs: number, segsLen: number, objId: string | null, getObjFile: GetObjFile): ObjPipe;
23
23
  export declare function makeNoBaseObjPipe(file: ObjVersionFile, header: boolean, segsOfs: number, segsLen: number): ObjPipe;
@@ -29,7 +29,7 @@ export declare function finalizeAsync<T>(promise: Promise<T>, fin: () => Promise
29
29
  * later time. Scheduler needs a not-yet-started activity, as scheduler has
30
30
  * control action's start.
31
31
  */
32
- export declare type Action<T> = () => Promise<T>;
32
+ export type Action<T> = () => Promise<T>;
33
33
  /**
34
34
  * This is a container of processes, labeled by some ids. It allows to track if
35
35
  * there is a process already in progress with a given id. And, it allows to
@@ -1,9 +1,9 @@
1
- export declare type Envelope = web3n.ipc.Envelope;
2
- export declare type EventEnvelope<T> = web3n.ipc.EventEnvelope<T>;
3
- export declare type EventEndEnvelope = web3n.ipc.EventEndEnvelope;
4
- export declare type EventException = web3n.ipc.EventException;
5
- export declare type RequestEnvelope<T> = web3n.ipc.RequestEnvelope<T>;
6
- export declare type ReplyEnvelope<T> = web3n.ipc.ReplyEnvelope<T>;
1
+ export type Envelope = web3n.ipc.Envelope;
2
+ export type EventEnvelope<T> = web3n.ipc.EventEnvelope<T>;
3
+ export type EventEndEnvelope = web3n.ipc.EventEndEnvelope;
4
+ export type EventException = web3n.ipc.EventException;
5
+ export type RequestEnvelope<T> = web3n.ipc.RequestEnvelope<T>;
6
+ export type ReplyEnvelope<T> = web3n.ipc.ReplyEnvelope<T>;
7
7
  export declare namespace events {
8
8
  namespace subscribe {
9
9
  const REQ_NAME = "subscribe";
@@ -16,7 +16,7 @@ export interface EventEnvelope<T> {
16
16
  eventChannel: string;
17
17
  eventPayload: T;
18
18
  }
19
- export declare type Envelope = RequestEnvelope<any> | ReplyEnvelope<any> | EventEnvelope<any>;
19
+ export type Envelope = RequestEnvelope<any> | ReplyEnvelope<any> | EventEnvelope<any>;
20
20
  export declare namespace events {
21
21
  const MISSED_EVENTS_CHANNEL = "missed-events";
22
22
  const SUBSCRIBE_REQ_NAME = "subscribe";
@@ -11,6 +11,6 @@ export interface HttpError extends ErrorWithCause {
11
11
  * @param cause
12
12
  */
13
13
  export declare function makeErr(code: number, msg: string, cause?: any): HttpError;
14
- export declare type ErrLogger = (err: any, req: Request) => void;
14
+ export type ErrLogger = (err: any, req: Request) => void;
15
15
  export declare function makeErrHandler(log?: ErrLogger): ErrorRequestHandler;
16
16
  export declare function makeErrLoggerToConsole(srvName: string): ErrLogger;
@@ -2,5 +2,5 @@ export declare const SC: {
2
2
  RECORDS_MISSING: string;
3
3
  DOMAIN_NOT_FOUND: string;
4
4
  };
5
- export declare type ServiceLabel = 'asmail' | 'mailerid' | '3nstorage';
5
+ export type ServiceLabel = 'asmail' | 'mailerid' | '3nstorage';
6
6
  export declare function get3NWebRecords(address: string, serviceLabel: ServiceLabel): Promise<string>;
@@ -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
@@ -22,8 +22,8 @@ export interface Request<T> extends express.Request {
22
22
  export interface BaseRequest<T> extends http.IncomingMessage {
23
23
  session: Session<T>;
24
24
  }
25
- export declare type CheckSession<T> = (req: BaseRequest<T>) => Promise<boolean>;
26
- export declare type GenerateSession<T> = () => Promise<Session<T>>;
25
+ export type CheckSession<T> = (req: BaseRequest<T>) => Promise<boolean>;
26
+ export type GenerateSession<T> = () => Promise<Session<T>>;
27
27
  export interface Factory<T> {
28
28
  generate: GenerateSession<T>;
29
29
  ensureAuthorizedSession(): express.RequestHandler;
@@ -15,7 +15,7 @@ export declare abstract class UserFiles {
15
15
  getParam<T>(paramFileName: string): Promise<T>;
16
16
  setParam<T>(paramFileName: string, param: T): Promise<void>;
17
17
  }
18
- export declare type ObjPipe = (outStream: NodeJS.WritableStream) => Promise<void>;
18
+ export type ObjPipe = (outStream: NodeJS.WritableStream) => Promise<void>;
19
19
  export interface ObjReader {
20
20
  len: number;
21
21
  /**
@@ -10,7 +10,7 @@ export interface SessionParams extends UserParams {
10
10
  sessionKey: Uint8Array;
11
11
  serverVerificationBytes: Uint8Array;
12
12
  }
13
- export declare type Request = SessReq<SessionParams>;
13
+ export type Request = SessReq<SessionParams>;
14
14
  export interface UserPKeyAndKeyGenParams {
15
15
  pkey: Uint8Array;
16
16
  params?: any;
@@ -22,7 +22,7 @@ export interface UserPKeyAndKeyGenParams {
22
22
  * Else, if incoming id is not ok, undefined is returned.
23
23
  * @params initUserId is a an incoming string, that should be an id
24
24
  */
25
- export declare type CheckAndTransformUserId = (initUserId: string) => string | undefined;
25
+ export type CheckAndTransformUserId = (initUserId: string) => string | undefined;
26
26
  /**
27
27
  * This returns a promise of user public key and related parameters.
28
28
  * If user is not found, undefined is returned.
@@ -30,8 +30,8 @@ export declare type CheckAndTransformUserId = (initUserId: string) => string | u
30
30
  * @param kid is a key id that should be used at login. Undefined value
31
31
  * indicates that default key should be used.
32
32
  */
33
- export declare type GetUserPKeyAndKeyGenParams = (userId: string, kid: string | undefined) => Promise<UserPKeyAndKeyGenParams | undefined>;
34
- export declare type ComputeDHSharedKey = (userKey: Uint8Array) => {
33
+ export type GetUserPKeyAndKeyGenParams = (userId: string, kid: string | undefined) => Promise<UserPKeyAndKeyGenParams | undefined>;
34
+ export type ComputeDHSharedKey = (userKey: Uint8Array) => {
35
35
  dhsharedKey: Uint8Array;
36
36
  serverPubKey: Uint8Array;
37
37
  };
@@ -6,7 +6,7 @@ import { SignedLoad } from '../../../lib-common/jwkeys';
6
6
  * Autherization failure may be due to either, invalid MailerId credentials, or
7
7
  * due to other service's restriction(s) on users.
8
8
  */
9
- export declare type MidAuthorizer = (rpDomain: string, sessionId: string, userId: string, mailerIdAssertion: SignedLoad, userCert: SignedLoad, provCert: SignedLoad) => Promise<boolean>;
9
+ export type MidAuthorizer = (rpDomain: string, sessionId: string, userId: string, mailerIdAssertion: SignedLoad, userCert: SignedLoad, provCert: SignedLoad) => Promise<boolean>;
10
10
  /**
11
11
  * @param relyingPartyDomain is a domain of service, for which this assertion
12
12
  * check is done. Usually, it is this site's domain, which we set explicitly.
@@ -1,6 +1,6 @@
1
1
  import { RequestHandler } from 'express';
2
2
  import { GenerateSession, Request as SessionReq, SessionParams } from '../../resources/sessions';
3
- export declare type Request = SessionReq<SessionParams>;
3
+ export type Request = SessionReq<SessionParams>;
4
4
  /**
5
5
  * This function checks overall shape of a given user id, possibly
6
6
  * transforming it to some canonical form, used by the service.
@@ -8,9 +8,9 @@ export declare type Request = SessionReq<SessionParams>;
8
8
  * Else, if incoming id is not ok, undefined is returned.
9
9
  * @params initUserId is a an incoming string, that should be an id
10
10
  */
11
- export declare type CheckAndTransformUserId = (initUserId: string) => string | undefined;
12
- export declare type UserExists = (userId: string) => Promise<boolean>;
13
- export declare type Redirect = (userId: string) => Promise<string>;
11
+ export type CheckAndTransformUserId = (initUserId: string) => string | undefined;
12
+ export type UserExists = (userId: string) => Promise<boolean>;
13
+ export type Redirect = (userId: string) => Promise<string>;
14
14
  /**
15
15
  * This returns route handler that creates sessions for a given userId, with
16
16
  * potential redirect for a named user.
@@ -5,7 +5,7 @@ import * as https from 'https';
5
5
  import * as express from 'express';
6
6
  import * as WebSocket from 'ws';
7
7
  import { CheckSession, SessionParams } from '../resources/sessions';
8
- export declare type HttpServer = http.Server | https.Server;
8
+ export type HttpServer = http.Server | https.Server;
9
9
  export declare class UserSockets {
10
10
  checkSession: CheckSession<SessionParams>;
11
11
  /**
@@ -209,6 +209,12 @@ class PingSender {
209
209
  Object.freeze(PingSender.prototype);
210
210
  Object.freeze(PingSender);
211
211
  class AppWithWSs {
212
+ get sockServer() {
213
+ if (!this.socks) {
214
+ this.socks = new UserSocketsServer();
215
+ }
216
+ return this.socks;
217
+ }
212
218
  constructor(httpApp) {
213
219
  this.server = undefined;
214
220
  this.closingProc = undefined;
@@ -216,12 +222,6 @@ class AppWithWSs {
216
222
  this.http = (httpApp ? httpApp : express());
217
223
  Object.seal(this);
218
224
  }
219
- get sockServer() {
220
- if (!this.socks) {
221
- this.socks = new UserSocketsServer();
222
- }
223
- return this.socks;
224
- }
225
225
  addWS(path, socks) {
226
226
  if (typeof path === 'string') {
227
227
  socks.path = ensureSlashesOnFront(path);
@@ -1,6 +1,6 @@
1
1
  import * as WebSocket from 'ws';
2
2
  import { SocketIPCs } from './app';
3
- export declare type EventsSink<T> = (userId: string, channel: string, event: T) => void;
3
+ export type EventsSink<T> = (userId: string, channel: string, event: T) => void;
4
4
  export declare class ServerEvents<T> implements SocketIPCs {
5
5
  ipcChannel: string | undefined;
6
6
  private eventChannels;
package/build/lib.d.ts CHANGED
@@ -1,5 +1,5 @@
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 { addSingleUserSignup } from './config/signup';
4
4
  export import errors = require('./lib-server/middleware/error-handler');
5
5
  export * as mock from './mock/run-in-proc';
package/build/lib.js CHANGED
@@ -16,16 +16,14 @@
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.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 signup_1 = require("./config/signup");
26
+ Object.defineProperty(exports, "addSingleUserSignup", { enumerable: true, get: function () { return signup_1.addSingleUserSignup; } });
29
27
  exports.errors = require("./lib-server/middleware/error-handler");
30
28
  exports.mock = require("./mock/run-in-proc");
31
29
  Object.freeze(exports);
@@ -6,7 +6,7 @@ export interface RootCerts {
6
6
  current: SignedLoad;
7
7
  previous: SignedLoad[];
8
8
  }
9
- export declare type ICertify = (userPKey: JsonKey, address: string, validFor?: number) => {
9
+ export type ICertify = (userPKey: JsonKey, address: string, validFor?: number) => {
10
10
  userCert: SignedLoad;
11
11
  provCert: SignedLoad;
12
12
  };
@@ -1,7 +1,7 @@
1
1
  import { Factory } from '../../lib-server/resources/sessions';
2
2
  import { SessionParams } from '../../lib-server/routes/pub-key-login/start-exchange';
3
3
  export { Request } from '../../lib-server/routes/pub-key-login/start-exchange';
4
- export declare type SessionsFactory = Factory<SessionParams>;
4
+ export type SessionsFactory = Factory<SessionParams>;
5
5
  /**
6
6
  * This returns factory, that works properly in a single process application,
7
7
  * clearing up sessions that past given timeout.
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
+ }
@@ -2,7 +2,7 @@
2
2
  import * as cProcs from 'child_process';
3
3
  import { RequestServer, RequestingClient } from '../lib-common/ipc/generic-ipc';
4
4
  export { RequestEnvelope, RequestHandler } from '../lib-common/ipc/generic-ipc';
5
- export declare type IPCToChild = RequestingClient;
6
- export declare type IPCToParent = RequestServer;
5
+ export type IPCToChild = RequestingClient;
6
+ export type IPCToParent = RequestServer;
7
7
  export declare function commToChild(channel: string, child: cProcs.ChildProcess): IPCToChild;
8
8
  export declare function commToParent(channel: string): IPCToParent;