@canmingir/link-express 1.7.2 → 1.7.5
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/bin/cli.js +30 -0
- package/package.json +3 -3
- package/src/event/server/server.js +53 -0
- package/src/routes/oauth.ts +43 -36
package/bin/cli.js
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const args = process.argv.slice(2);
|
|
4
|
+
const command = args[0];
|
|
5
|
+
|
|
6
|
+
function parseArgs(args) {
|
|
7
|
+
const options = {};
|
|
8
|
+
for (let i = 1; i < args.length; i++) {
|
|
9
|
+
if (args[i].startsWith("-p") || args[i].startsWith("--port")) {
|
|
10
|
+
options.port = args[i + 1];
|
|
11
|
+
i++;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
return options;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
if (command === "start") {
|
|
18
|
+
const options = parseArgs(args);
|
|
19
|
+
if (options.port) {
|
|
20
|
+
process.env.PORT = options.port;
|
|
21
|
+
}
|
|
22
|
+
require("../src/event/server/server.js");
|
|
23
|
+
} else {
|
|
24
|
+
console.log("Usage: event-listener start [-p <port>]");
|
|
25
|
+
console.log("\nCommands:");
|
|
26
|
+
console.log(" start Start the event server");
|
|
27
|
+
console.log("\nOptions:");
|
|
28
|
+
console.log(" -p, --port Port to listen on (default: 8080)");
|
|
29
|
+
process.exit(1);
|
|
30
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@canmingir/link-express",
|
|
3
|
-
"version": "1.7.
|
|
3
|
+
"version": "1.7.5",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "index.ts",
|
|
6
6
|
"types": "index.ts",
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
},
|
|
32
32
|
"author": "NucTeam",
|
|
33
33
|
"bin": {
|
|
34
|
-
"event-listener": "./bin/
|
|
34
|
+
"event-listener": "./bin/cli.js"
|
|
35
35
|
},
|
|
36
36
|
"exports": {
|
|
37
37
|
".": "./index.ts",
|
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
"./sequelize": "./src/sequelize.ts",
|
|
44
44
|
"./event": "./src/event/serc/Event.ts",
|
|
45
45
|
"./event/client": "./src/event/client/index.ts",
|
|
46
|
-
"./event/server": "./src/event/server/server.
|
|
46
|
+
"./event/server": "./src/event/server/server.js"
|
|
47
47
|
},
|
|
48
48
|
"scripts": {
|
|
49
49
|
"prepare": "tsx prepare.ts",
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const { Server } = require("socket.io");
|
|
4
|
+
const http = require("http");
|
|
5
|
+
|
|
6
|
+
const server = http.createServer();
|
|
7
|
+
const io = new Server(server, {
|
|
8
|
+
cors: { origin: "*" },
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
const subscriptions = {};
|
|
12
|
+
|
|
13
|
+
io.on("connection", (socket) => {
|
|
14
|
+
console.log("Client connected:", socket.id);
|
|
15
|
+
|
|
16
|
+
socket.on("subscribe", (type) => {
|
|
17
|
+
if (!subscriptions[type]) subscriptions[type] = new Set();
|
|
18
|
+
subscriptions[type].add(socket.id);
|
|
19
|
+
console.log(`Socket ${socket.id} subscribed to ${type}`);
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
socket.on("unsubscribe", (type) => {
|
|
23
|
+
if (subscriptions[type]) {
|
|
24
|
+
subscriptions[type].delete(socket.id);
|
|
25
|
+
if (subscriptions[type].size === 0) delete subscriptions[type];
|
|
26
|
+
console.log(`Socket ${socket.id} unsubscribed from ${type}`);
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
socket.on("publish", ({ type, payload }) => {
|
|
31
|
+
console.log(`Publish: ${type}`, payload);
|
|
32
|
+
if (subscriptions[type]) {
|
|
33
|
+
subscriptions[type].forEach((sid) => {
|
|
34
|
+
if (sid !== socket.id) {
|
|
35
|
+
io.to(sid).emit("event", { type, payload });
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
socket.on("disconnect", () => {
|
|
42
|
+
Object.keys(subscriptions).forEach((type) => {
|
|
43
|
+
subscriptions[type].delete(socket.id);
|
|
44
|
+
if (subscriptions[type].size === 0) delete subscriptions[type];
|
|
45
|
+
});
|
|
46
|
+
console.log("Client disconnected:", socket.id);
|
|
47
|
+
});
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
const PORT = process.env.PORT || 8080;
|
|
51
|
+
server.listen(PORT, () => {
|
|
52
|
+
console.log(`Event server listening on port ${PORT}`);
|
|
53
|
+
});
|
package/src/routes/oauth.ts
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { AuthenticationError, AuthorizationError } from "../error";
|
|
2
2
|
import express, { Request, Response } from "express";
|
|
3
|
-
|
|
3
|
+
|
|
4
|
+
import Joi from "joi";
|
|
5
|
+
import Permission from "../models/Permission.model";
|
|
4
6
|
import axios from "axios";
|
|
5
7
|
import config from "../config";
|
|
6
|
-
import
|
|
7
|
-
import Permission from "../models/Permission.model";
|
|
8
|
+
import jwt from "jsonwebtoken";
|
|
8
9
|
|
|
9
10
|
const router = express.Router();
|
|
10
11
|
|
|
@@ -17,33 +18,39 @@ if (!project) {
|
|
|
17
18
|
router.post(
|
|
18
19
|
"/",
|
|
19
20
|
async (req: Request, res: Response): Promise<Response | void> => {
|
|
20
|
-
const {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
21
|
+
const {
|
|
22
|
+
appId,
|
|
23
|
+
projectId,
|
|
24
|
+
code,
|
|
25
|
+
refreshToken,
|
|
26
|
+
redirectUri,
|
|
27
|
+
identityProvider,
|
|
28
|
+
} = Joi.attempt(
|
|
29
|
+
req.body,
|
|
30
|
+
Joi.object({
|
|
31
|
+
appId: Joi.string().required(),
|
|
32
|
+
projectId: Joi.string().optional(),
|
|
33
|
+
code: Joi.string().optional(),
|
|
34
|
+
refreshToken: Joi.string().optional(),
|
|
35
|
+
redirectUri: Joi.string().optional(),
|
|
36
|
+
identityProvider: Joi.string().required(),
|
|
37
|
+
})
|
|
38
|
+
.required()
|
|
39
|
+
.options({ stripUnknown: true })
|
|
40
|
+
) as {
|
|
41
|
+
appId: string;
|
|
42
|
+
projectId?: string;
|
|
43
|
+
code?: string;
|
|
44
|
+
refreshToken?: string;
|
|
45
|
+
redirectUri?: string;
|
|
46
|
+
identityProvider: string;
|
|
47
|
+
};
|
|
41
48
|
|
|
42
49
|
if (!code && !refreshToken) {
|
|
43
50
|
return res.status(400).send("Missing OAuth Code and Refresh Token");
|
|
44
51
|
}
|
|
45
52
|
|
|
46
|
-
const providerConfig = project.oauth?.providers[
|
|
53
|
+
const providerConfig = project.oauth?.providers[identityProvider] as {
|
|
47
54
|
clientId: string;
|
|
48
55
|
tokenUrl: string;
|
|
49
56
|
userUrl: string;
|
|
@@ -68,7 +75,7 @@ router.post(
|
|
|
68
75
|
params.append("client_id", providerConfig.clientId);
|
|
69
76
|
params.append(
|
|
70
77
|
"client_secret",
|
|
71
|
-
process.env[`${
|
|
78
|
+
process.env[`${identityProvider.toUpperCase()}_CLIENT_SECRET`] as string
|
|
72
79
|
);
|
|
73
80
|
params.append("code", code);
|
|
74
81
|
params.append("redirect_uri", redirectUri);
|
|
@@ -136,7 +143,7 @@ router.post(
|
|
|
136
143
|
fallbackField: project.oauth?.jwt.identifier,
|
|
137
144
|
});
|
|
138
145
|
throw new Error(
|
|
139
|
-
`Cannot find user identifier in ${
|
|
146
|
+
`Cannot find user identifier in ${identityProvider} OAuth response`
|
|
140
147
|
);
|
|
141
148
|
}
|
|
142
149
|
|
|
@@ -153,7 +160,7 @@ router.post(
|
|
|
153
160
|
sub: userId,
|
|
154
161
|
iss: "nuc",
|
|
155
162
|
aid: appId,
|
|
156
|
-
|
|
163
|
+
identityProvider: identityProvider,
|
|
157
164
|
iat: Math.floor(Date.now() / 1000),
|
|
158
165
|
},
|
|
159
166
|
process.env.JWT_SECRET as string,
|
|
@@ -168,7 +175,7 @@ router.post(
|
|
|
168
175
|
oid: permissions[0].organizationId,
|
|
169
176
|
aid: appId,
|
|
170
177
|
rls: permissions.map((permission) => permission.role),
|
|
171
|
-
|
|
178
|
+
identityProvider: identityProvider,
|
|
172
179
|
iat: Math.floor(Date.now() / 1000),
|
|
173
180
|
},
|
|
174
181
|
process.env.JWT_SECRET as string,
|
|
@@ -181,7 +188,7 @@ router.post(
|
|
|
181
188
|
sub: userId,
|
|
182
189
|
iss: "nuc",
|
|
183
190
|
aid: appId,
|
|
184
|
-
|
|
191
|
+
identityProvider: identityProvider,
|
|
185
192
|
iat: Math.floor(Date.now() / 1000),
|
|
186
193
|
},
|
|
187
194
|
process.env.JWT_SECRET as string,
|
|
@@ -214,16 +221,16 @@ router.get("/user", async (req: Request, res: Response): Promise<Response> => {
|
|
|
214
221
|
|
|
215
222
|
const decoded = jwt.verify(token, process.env.JWT_SECRET as string) as {
|
|
216
223
|
sub: string;
|
|
217
|
-
|
|
224
|
+
identityProvider: string;
|
|
218
225
|
};
|
|
219
226
|
const userId = decoded.sub;
|
|
220
|
-
const
|
|
227
|
+
const identityProvider = decoded.identityProvider;
|
|
221
228
|
|
|
222
|
-
if (!userId || !
|
|
229
|
+
if (!userId || !identityProvider) {
|
|
223
230
|
return res.status(401).end();
|
|
224
231
|
}
|
|
225
232
|
|
|
226
|
-
const providerConfig = project.oauth?.providers[
|
|
233
|
+
const providerConfig = project.oauth?.providers[identityProvider] as {
|
|
227
234
|
userUrl: string;
|
|
228
235
|
userFields: {
|
|
229
236
|
name: string;
|
|
@@ -250,7 +257,7 @@ router.get("/user", async (req: Request, res: Response): Promise<Response> => {
|
|
|
250
257
|
const userFieldMapping = providerConfig.userFields;
|
|
251
258
|
const userDetails = {
|
|
252
259
|
id: userId,
|
|
253
|
-
|
|
260
|
+
identityProvider: identityProvider,
|
|
254
261
|
name: (userResponse.data[userFieldMapping.name] as string) || null,
|
|
255
262
|
displayName:
|
|
256
263
|
(userResponse.data[userFieldMapping.displayName] as string) || null,
|