@sockethub/server 5.0.0-alpha.3 → 5.0.0-alpha.6

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 (127) hide show
  1. package/README.md +54 -60
  2. package/bin/sockethub +4 -3
  3. package/package.json +42 -60
  4. package/res/socket.io.js +4908 -0
  5. package/res/sockethub-client.js +602 -0
  6. package/res/sockethub-client.min.js +19 -0
  7. package/sockethub.config.example.json +2 -3
  8. package/src/bootstrap/init.d.ts +20 -7
  9. package/src/bootstrap/init.test.ts +211 -0
  10. package/src/bootstrap/init.ts +152 -75
  11. package/src/bootstrap/load-platforms.ts +151 -0
  12. package/src/config.test.ts +27 -22
  13. package/src/config.ts +82 -78
  14. package/src/defaults.json +24 -16
  15. package/src/index.ts +67 -27
  16. package/src/janitor.test.ts +211 -0
  17. package/src/janitor.ts +145 -77
  18. package/src/listener.ts +151 -57
  19. package/src/middleware/create-activity-object.test.ts +28 -8
  20. package/src/middleware/create-activity-object.ts +17 -8
  21. package/src/middleware/expand-activity-stream.test.data.ts +332 -346
  22. package/src/middleware/expand-activity-stream.test.ts +65 -66
  23. package/src/middleware/expand-activity-stream.ts +29 -19
  24. package/src/middleware/store-credentials.test.ts +74 -62
  25. package/src/middleware/store-credentials.ts +15 -15
  26. package/src/middleware/validate.test.data.ts +240 -242
  27. package/src/middleware/validate.test.ts +39 -78
  28. package/src/middleware/validate.ts +63 -39
  29. package/src/middleware.test.ts +168 -138
  30. package/src/middleware.ts +62 -43
  31. package/src/platform-instance.test.ts +507 -213
  32. package/src/platform-instance.ts +337 -219
  33. package/src/platform.test.ts +375 -0
  34. package/src/platform.ts +306 -139
  35. package/src/process-manager.ts +75 -51
  36. package/src/routes.test.ts +43 -89
  37. package/src/routes.ts +40 -77
  38. package/src/sentry.test.ts +106 -0
  39. package/src/sentry.ts +19 -0
  40. package/src/sockethub.ts +186 -153
  41. package/src/util.ts +5 -0
  42. package/coverage/tmp/coverage-93126-1649152190997-0.json +0 -1
  43. package/dist/bootstrap/init.d.ts +0 -18
  44. package/dist/bootstrap/init.js +0 -63
  45. package/dist/bootstrap/init.js.map +0 -1
  46. package/dist/bootstrap/platforms.js +0 -75
  47. package/dist/common.d.ts +0 -3
  48. package/dist/common.js +0 -20
  49. package/dist/common.js.map +0 -1
  50. package/dist/config.d.ts +0 -6
  51. package/dist/config.js +0 -102
  52. package/dist/config.js.map +0 -1
  53. package/dist/crypto.d.ts +0 -10
  54. package/dist/crypto.js +0 -38
  55. package/dist/crypto.js.map +0 -1
  56. package/dist/defaults.json +0 -28
  57. package/dist/index.d.ts +0 -2
  58. package/dist/index.js +0 -25
  59. package/dist/index.js.map +0 -1
  60. package/dist/janitor.d.ts +0 -15
  61. package/dist/janitor.js +0 -89
  62. package/dist/janitor.js.map +0 -1
  63. package/dist/listener.d.ts +0 -28
  64. package/dist/listener.js +0 -91
  65. package/dist/listener.js.map +0 -1
  66. package/dist/middleware/create-activity-object.d.ts +0 -6
  67. package/dist/middleware/create-activity-object.js +0 -19
  68. package/dist/middleware/create-activity-object.js.map +0 -1
  69. package/dist/middleware/expand-activity-stream.d.ts +0 -2
  70. package/dist/middleware/expand-activity-stream.js +0 -33
  71. package/dist/middleware/expand-activity-stream.js.map +0 -1
  72. package/dist/middleware/expand-activity-stream.test.data.d.ts +0 -480
  73. package/dist/middleware/expand-activity-stream.test.data.js +0 -360
  74. package/dist/middleware/expand-activity-stream.test.data.js.map +0 -1
  75. package/dist/middleware/store-credentials.d.ts +0 -3
  76. package/dist/middleware/store-credentials.js +0 -19
  77. package/dist/middleware/store-credentials.js.map +0 -1
  78. package/dist/middleware/validate.d.ts +0 -2
  79. package/dist/middleware/validate.js +0 -58
  80. package/dist/middleware/validate.js.map +0 -1
  81. package/dist/middleware/validate.test.data.d.ts +0 -532
  82. package/dist/middleware/validate.test.data.js +0 -263
  83. package/dist/middleware/validate.test.data.js.map +0 -1
  84. package/dist/middleware.d.ts +0 -10
  85. package/dist/middleware.js +0 -54
  86. package/dist/middleware.js.map +0 -1
  87. package/dist/platform-instance.d.ts +0 -77
  88. package/dist/platform-instance.js +0 -211
  89. package/dist/platform-instance.js.map +0 -1
  90. package/dist/platform.d.ts +0 -6
  91. package/dist/platform.js +0 -187
  92. package/dist/platform.js.map +0 -1
  93. package/dist/process-manager.d.ts +0 -11
  94. package/dist/process-manager.js +0 -78
  95. package/dist/process-manager.js.map +0 -1
  96. package/dist/routes.d.ts +0 -13
  97. package/dist/routes.js +0 -83
  98. package/dist/routes.js.map +0 -1
  99. package/dist/sockethub.d.ts +0 -39
  100. package/dist/sockethub.js +0 -119
  101. package/dist/sockethub.js.map +0 -1
  102. package/dist/store.d.ts +0 -5
  103. package/dist/store.js +0 -17
  104. package/dist/store.js.map +0 -1
  105. package/src/bootstrap/platforms.js +0 -75
  106. package/src/common.test.ts +0 -54
  107. package/src/common.ts +0 -14
  108. package/src/config.d.ts +0 -2
  109. package/src/crypto.d.ts +0 -5
  110. package/src/crypto.test.ts +0 -41
  111. package/src/crypto.ts +0 -41
  112. package/src/janitor.d.ts +0 -8
  113. package/src/middleware/validate.d.ts +0 -1
  114. package/src/middleware.d.ts +0 -21
  115. package/src/sockethub.d.ts +0 -1
  116. package/src/store.test.ts +0 -28
  117. package/src/store.ts +0 -17
  118. package/test/init-suite.js +0 -41
  119. package/test/queue.functional.test.js +0 -0
  120. package/test/sockethub-suite.js +0 -25
  121. package/tsconfig.json +0 -18
  122. package/views/examples/dummy.ejs +0 -93
  123. package/views/examples/feeds.ejs +0 -90
  124. package/views/examples/irc.ejs +0 -239
  125. package/views/examples/shared.js +0 -72
  126. package/views/examples/xmpp.ejs +0 -191
  127. package/views/index.ejs +0 -17
package/src/sockethub.ts CHANGED
@@ -1,165 +1,198 @@
1
- import debug from 'debug';
2
- import { Socket } from "socket.io";
3
- import { IActivityStream } from "@sockethub/schemas";
4
-
5
- import crypto from './crypto';
6
- import init from './bootstrap/init';
7
- import middleware from './middleware';
8
- import createActivityObject from "./middleware/create-activity-object";
9
- import expandActivityStream from "./middleware/expand-activity-stream";
10
- import storeCredentials from "./middleware/store-credentials";
11
- import validate from "./middleware/validate";
12
- import janitor from './janitor';
13
- import listener from './listener';
14
- import ProcessManager from "./process-manager";
15
- import PlatformInstance, { platformInstances } from "./platform-instance";
16
- import { getSessionStore } from "./store";
17
-
18
- const log = debug('sockethub:server:core');
19
-
20
-
21
- export interface JobDataDecrypted {
22
- title?: string;
23
- msg: IActivityStream;
24
- sessionId: string;
25
- }
26
-
27
- export interface JobDataEncrypted {
28
- title?: string;
29
- msg: string;
30
- sessionId: string;
31
- }
32
-
33
- export interface JobDecrypted {
34
- data: JobDataDecrypted,
35
- remove?: Function;
36
- }
1
+ import debug from "debug";
2
+ import type { Socket } from "socket.io";
3
+
4
+ import { crypto } from "@sockethub/crypto";
5
+ import { CredentialsStore } from "@sockethub/data-layer";
6
+ import type { CredentialsStoreInterface } from "@sockethub/data-layer";
7
+ import type {
8
+ ActivityStream,
9
+ InternalActivityStream,
10
+ } from "@sockethub/schemas";
11
+
12
+ import getInitObject from "./bootstrap/init.js";
13
+ import config from "./config";
14
+ import janitor from "./janitor.js";
15
+ import listener from "./listener.js";
16
+ import middleware from "./middleware.js";
17
+ import createActivityObject from "./middleware/create-activity-object.js";
18
+ import expandActivityStream from "./middleware/expand-activity-stream.js";
19
+ import storeCredentials from "./middleware/store-credentials.js";
20
+ import validate from "./middleware/validate.js";
21
+ import ProcessManager from "./process-manager.js";
22
+
23
+ const log = debug("sockethub:server:core");
24
+
25
+ type ErrMsg = {
26
+ context: string;
27
+ error: string;
28
+ content: object;
29
+ };
30
+
31
+ function attachError(err: unknown, msg: InternalActivityStream | undefined) {
32
+ const finalError: ErrMsg = {
33
+ context: "error",
34
+ error: err.toString(),
35
+ content: {},
36
+ };
37
37
 
38
- export interface JobEncrypted {
39
- data: JobDataEncrypted,
40
- remove?: Function;
41
- }
38
+ // biome-ignore lint/performance/noDelete: <explanation>
39
+ delete msg.sessionSecret;
42
40
 
43
- function attachError(err, msg) {
44
- if (typeof msg !== 'object') {
45
- msg = { context: 'error' };
46
- }
47
- msg.error = err.toString();
48
- delete msg.sessionSecret;
49
- return msg;
41
+ if (msg) {
42
+ finalError.content = msg;
43
+ }
44
+ return finalError;
50
45
  }
51
46
 
52
47
  class Sockethub {
53
- private readonly parentId: string;
54
- private readonly parentSecret1: string;
55
- private readonly parentSecret2: string;
56
- counter: number;
57
- platforms: Map<string, object>;
58
- status: boolean;
59
- queue: any;
60
- processManager: ProcessManager;
61
-
62
- constructor() {
63
- this.counter = 0;
64
- this.platforms = init.platforms;
65
- this.status = false;
66
- this.parentId = crypto.randToken(16);
67
- this.parentSecret1 = crypto.randToken(16);
68
- this.parentSecret2 = crypto.randToken(16);
69
- this.processManager = new ProcessManager(
70
- this.parentId, this.parentSecret1, this.parentSecret2);
71
- log('session id: ' + this.parentId);
72
- }
73
-
74
- /**
75
- * initialization of Sockethub starts here
76
- */
77
- boot() {
78
- if (this.status) {
79
- return log('Sockethub.boot() called more than once');
80
- } else {
81
- this.status = true;
48
+ private readonly parentId: string;
49
+ private readonly parentSecret1: string;
50
+ private readonly parentSecret2: string;
51
+ counter: number;
52
+ platforms: Map<string, object>;
53
+ status: boolean;
54
+ processManager: ProcessManager;
55
+
56
+ constructor() {
57
+ this.status = false;
58
+ this.parentId = crypto.randToken(16);
59
+ this.parentSecret1 = crypto.randToken(16);
60
+ this.parentSecret2 = crypto.randToken(16);
61
+ log(`session id: ${this.parentId}`);
62
+ }
63
+
64
+ /**
65
+ * initialization of Sockethub starts here
66
+ */
67
+ async boot() {
68
+ if (this.status) {
69
+ return log("Sockethub.boot() called more than once");
70
+ }
71
+ this.status = true;
72
+
73
+ const init = await getInitObject().catch((err) => {
74
+ log(err);
75
+ process.exit(1);
76
+ });
77
+
78
+ this.processManager = new ProcessManager(
79
+ this.parentId,
80
+ this.parentSecret1,
81
+ this.parentSecret2,
82
+ init,
83
+ );
84
+
85
+ this.platforms = init.platforms;
86
+
87
+ log("active platforms: ", [...init.platforms.keys()]);
88
+ listener.start(); // start external services
89
+ janitor.start(); // start cleanup cycle
90
+ log("registering handlers");
91
+ listener.io.on("connection", this.handleIncomingConnection.bind(this));
82
92
  }
83
93
 
84
- log('active platforms: ', [...init.platforms.keys()]);
85
- janitor.clean(); // start cleanup cycle
86
- listener.start(); // start external services
87
- log('registering handlers');
88
- listener.io.on('connection', this.handleIncomingConnection.bind(this));
89
- }
94
+ async shutdown() {
95
+ await janitor.stop();
96
+ }
90
97
 
91
- async removeAllPlatformInstances() {
92
- for (let platform of platformInstances) {
93
- await platform[1].destroy();
98
+ private handleIncomingConnection(socket: Socket) {
99
+ // session-specific debug messages
100
+ const sessionLog = debug(`sockethub:server:core:${socket.id}`);
101
+ const sessionSecret = crypto.randToken(16);
102
+ // stores instance is session-specific
103
+ // stores = getSessionStore(this.parentId, this.parentSecret1, socket.id, sessionSecret);
104
+ const credentialsStore: CredentialsStoreInterface =
105
+ new CredentialsStore(
106
+ this.parentId,
107
+ socket.id,
108
+ this.parentSecret1 + sessionSecret,
109
+ config.get("redis"),
110
+ );
111
+
112
+ sessionLog("socket.io connection");
113
+
114
+ socket.on("disconnect", () => {
115
+ sessionLog("disconnect received from client");
116
+ });
117
+
118
+ socket.on(
119
+ "credentials",
120
+ middleware("credentials")
121
+ .use(expandActivityStream)
122
+ .use(validate("credentials", socket.id))
123
+ .use(storeCredentials(credentialsStore))
124
+ .use((err, data, next) => {
125
+ // error handler
126
+ next(attachError(err, data));
127
+ })
128
+ .use((data, next) => {
129
+ next();
130
+ })
131
+ .done(),
132
+ );
133
+
134
+ // when new activity objects are created on the client side, an event is
135
+ // fired, and we receive a copy on the server side.
136
+ socket.on(
137
+ "activity-object",
138
+ middleware("activity-object")
139
+ .use(validate("activity-object", socket.id))
140
+ .use(createActivityObject)
141
+ .use((err, data, next) => {
142
+ next(attachError(err, data));
143
+ })
144
+ .use((data, next) => {
145
+ next();
146
+ })
147
+ .done(),
148
+ );
149
+
150
+ socket.on(
151
+ "message",
152
+ middleware("message")
153
+ .use(expandActivityStream)
154
+ .use(validate("message", socket.id))
155
+ .use((msg, next) => {
156
+ // The platform thread must find the credentials on their own using the given
157
+ // sessionSecret, which indicates that this specific session (socket
158
+ // connection) has provided credentials.
159
+ msg.sessionSecret = sessionSecret;
160
+ next(msg);
161
+ })
162
+ .use((err, data, next) => {
163
+ next(attachError(err, data));
164
+ })
165
+ .use(async (msg: ActivityStream, next) => {
166
+ const platformInstance = this.processManager.get(
167
+ msg.context,
168
+ msg.actor.id,
169
+ socket.id,
170
+ );
171
+ // job validated and queued, stores socket.io callback for when job is completed
172
+ try {
173
+ const job = await platformInstance.queue.add(
174
+ socket.id,
175
+ msg,
176
+ );
177
+ if (job) {
178
+ platformInstance.completedJobHandlers.set(
179
+ job.title,
180
+ next,
181
+ );
182
+ } else {
183
+ // failed to add job to queue, reject handler immediately
184
+ msg.error = "failed to add job to queue";
185
+ next(msg);
186
+ }
187
+ } catch (err) {
188
+ // Queue is closed (platform terminating) - send error to client
189
+ msg.error = err.message || "platform unavailable";
190
+ next(msg);
191
+ }
192
+ })
193
+ .done(),
194
+ );
94
195
  }
95
- }
96
-
97
- private createJob(socketId: string, platformInstance: PlatformInstance, msg): JobDataEncrypted {
98
- const title = `${msg.context}-${(msg.id) ? msg.id : this.counter++}`;
99
- const job: JobDataEncrypted = {
100
- title: title,
101
- sessionId: socketId,
102
- msg: crypto.encrypt(msg, this.parentSecret1 + this.parentSecret2)
103
- };
104
- return job;
105
- };
106
-
107
- private handleIncomingConnection(socket: Socket) {
108
- // session-specific debug messages
109
- const sessionLog = debug('sockethub:server:core:' + socket.id),
110
- sessionSecret = crypto.randToken(16),
111
- // store instance is session-specific
112
- store = getSessionStore(this.parentId, this.parentSecret1, socket.id, sessionSecret);
113
-
114
- sessionLog(`socket.io connection`);
115
-
116
- socket.on('disconnect', () => {
117
- sessionLog('disconnect received from client');
118
- });
119
-
120
- socket.on('credentials',
121
- middleware('credentials')
122
- .use(expandActivityStream)
123
- .use(validate('credentials', socket.id))
124
- .use(storeCredentials(store, sessionLog))
125
- .use((err, data, next) => {
126
- // error handler
127
- next(attachError(err, data));
128
- }).use((data, next) => { next(); })
129
- .done());
130
-
131
- // when new activity objects are created on the client side, an event is
132
- // fired and we receive a copy on the server side.
133
- socket.on('activity-object',
134
- middleware('activity-object')
135
- .use(validate('activity-object', socket.id))
136
- .use(createActivityObject)
137
- .use((err, data, next) => {
138
- next(attachError(err, data));
139
- }).use((data, next) => { next(); })
140
- .done());
141
-
142
- socket.on('message',
143
- middleware('message')
144
- .use(expandActivityStream)
145
- .use(validate('message', socket.id))
146
- .use((msg, next) => {
147
- // The platform thread must find the credentials on their own using the given
148
- // sessionSecret, which indicates that this specific session (socket
149
- // connection) has provided credentials.
150
- msg.sessionSecret = sessionSecret;
151
- next(msg);
152
- }).use((err, data, next) => {
153
- next(attachError(err, data));
154
- }).use((msg, next) => {
155
- const platformInstance = this.processManager.get(msg.context, msg.actor.id, socket.id);
156
- sessionLog(`queued to channel ${platformInstance.id}`);
157
- const job = this.createJob(socket.id, platformInstance, msg);
158
- // job validated and queued, store socket.io callback for when job is completed
159
- platformInstance.completedJobHandlers.set(job.title, next);
160
- platformInstance.queue.add(job);
161
- }).done());
162
- }
163
196
  }
164
197
 
165
198
  export default Sockethub;
package/src/util.ts ADDED
@@ -0,0 +1,5 @@
1
+ import { dirname } from "node:path";
2
+ import { fileURLToPath } from "node:url";
3
+
4
+ const __filename = fileURLToPath(import.meta.url);
5
+ export const __dirname = dirname(__filename);