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.
- package/README.md +0 -1
- package/build/3nstorage/resources/sessions.d.ts +2 -2
- package/build/3nstorage/resources/store.d.ts +1 -1
- package/build/3nstorage/resources/users.d.ts +15 -15
- package/build/admin/admin-app.d.ts +1 -1
- package/build/admin/admin-app.js +4 -1
- package/build/admin/resources/users.d.ts +3 -3
- package/build/admin/signup-tokens.d.ts +1 -1
- package/build/asmail/resources/delivery-sessions.d.ts +3 -3
- package/build/asmail/resources/inbox.d.ts +9 -9
- package/build/asmail/resources/recipients.d.ts +18 -18
- package/build/asmail/resources/sessions.d.ts +2 -2
- package/build/asmail/routes/delivery/sender-authorization.d.ts +1 -1
- package/build/asmail/routes/delivery/start-session.d.ts +1 -1
- package/build/config/cli/index.d.ts +9 -0
- package/build/config/cli/index.js +68 -0
- package/build/config/cli/run-cmd.d.ts +10 -0
- package/build/config/cli/run-cmd.js +69 -0
- package/build/config/cli/signup-cmd.d.ts +17 -0
- package/build/config/cli/signup-cmd.js +194 -0
- package/build/config/cli/user-cmd.d.ts +9 -0
- package/build/config/cli/user-cmd.js +55 -0
- package/build/config/cli/utils.d.ts +45 -0
- package/build/config/cli/utils.js +52 -0
- package/build/config/from-yaml.d.ts +2 -0
- package/build/config/from-yaml.js +28 -0
- package/build/config/letsencrypt.d.ts +7 -0
- package/build/config/letsencrypt.js +62 -0
- package/build/config/signup.d.ts +15 -0
- package/build/config/signup.js +133 -0
- package/build/lib-common/byte-streaming/common.d.ts +2 -2
- package/build/lib-common/byte-streaming/common.js +5 -5
- package/build/lib-common/exceptions/file.d.ts +1 -1
- package/build/lib-common/ipc/generic-ipc.d.ts +7 -7
- package/build/lib-common/ipc/generic-ipc.js +6 -6
- package/build/lib-common/objs-on-disk/file-layout.d.ts +4 -4
- package/build/lib-common/objs-on-disk/utils.d.ts +3 -3
- package/build/lib-common/processes.d.ts +1 -1
- package/build/lib-common/service-api/ipc-api.d.ts +6 -6
- package/build/lib-common/service-api/web-socket-base.d.ts +1 -1
- package/build/lib-server/middleware/error-handler.d.ts +1 -1
- package/build/lib-server/resources/dns.d.ts +1 -1
- package/build/lib-server/resources/dns.js +48 -10
- package/build/lib-server/resources/sessions.d.ts +2 -2
- package/build/lib-server/resources/user-files.d.ts +1 -1
- package/build/lib-server/routes/pub-key-login/start-exchange.d.ts +4 -4
- package/build/lib-server/routes/sessions/mid-auth.d.ts +1 -1
- package/build/lib-server/routes/sessions/start.d.ts +4 -4
- package/build/lib-server/web-sockets/app.d.ts +1 -1
- package/build/lib-server/web-sockets/app.js +6 -6
- package/build/lib-server/web-sockets/server-events.d.ts +1 -1
- package/build/lib.d.ts +1 -1
- package/build/lib.js +3 -5
- package/build/mailerId/resources/certifier.d.ts +1 -1
- package/build/mailerId/resources/sessions.d.ts +1 -1
- package/build/main.js +196 -45
- package/build/mock/node-child-ipc.d.ts +2 -2
- package/build/mock/run-in-proc.js +6 -3
- package/build/services.d.ts +4 -2
- package/build/services.js +15 -6
- package/package.json +16 -3
- package/postinstall.js +25 -0
- package/build/run-config.d.ts +0 -10
- package/build/run-config.js +0 -146
- package/build/run.d.ts +0 -1
- 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
|
|
8
|
-
export
|
|
9
|
-
export
|
|
10
|
-
export
|
|
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
|
|
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
|
|
21
|
-
export
|
|
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
|
|
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
|
|
2
|
-
export
|
|
3
|
-
export
|
|
4
|
-
export
|
|
5
|
-
export
|
|
6
|
-
export
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
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
|
|
26
|
-
export
|
|
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
|
|
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
|
|
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
|
|
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
|
|
34
|
-
export
|
|
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
|
|
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
|
|
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
|
|
12
|
-
export
|
|
13
|
-
export
|
|
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
|
|
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
|
|
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
|
|
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.
|
|
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
|
|
26
|
-
Object.defineProperty(exports, "addSingleUserSignup", { enumerable: true, get: function () { return
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
|
24
|
-
|
|
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
|
|
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
|
-
|
|
63
|
-
|
|
64
|
-
|
|
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
|
-
|
|
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
|
|
73
|
-
|
|
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
|
|
6
|
-
export
|
|
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;
|