@ejfdelgado/ejflab-back 1.22.2 → 1.24.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.
- package/package.json +1 -1
- package/srv/AuthorizationSrv.mjs +52 -0
- package/srv/SocketIOCall.mjs +41 -8
- package/srv/common/FirebasConfig.mjs +66 -11
- package/srv/common/Usuario.mjs +29 -8
package/package.json
CHANGED
package/srv/AuthorizationSrv.mjs
CHANGED
@@ -140,6 +140,58 @@ export class AuthorizationSrv {
|
|
140
140
|
});
|
141
141
|
}
|
142
142
|
|
143
|
+
static isUserInGroupInternal(user, groups, and) {
|
144
|
+
if (!user) {
|
145
|
+
return false;
|
146
|
+
}
|
147
|
+
const currentGroups = user.groups;
|
148
|
+
const notMeet = groups.filter((group) => {
|
149
|
+
if (currentGroups.indexOf(group) >= 0) {
|
150
|
+
return false;
|
151
|
+
}
|
152
|
+
return true;
|
153
|
+
});
|
154
|
+
if (and) {
|
155
|
+
//All must have
|
156
|
+
return notMeet.length == 0;
|
157
|
+
} else {
|
158
|
+
// At least one
|
159
|
+
return notMeet.length < groups.length;
|
160
|
+
}
|
161
|
+
}
|
162
|
+
|
163
|
+
static isUserInAllGroup(groups) {
|
164
|
+
return async (req, res, next) => {
|
165
|
+
if (res.locals.user) {
|
166
|
+
// Hay usuario
|
167
|
+
const cumple = this.isUserInGroupInternal(res.locals.user, groups, true);
|
168
|
+
if (cumple) {
|
169
|
+
next();
|
170
|
+
} else {
|
171
|
+
res.status(403).send({ message: `User not allowed` });
|
172
|
+
}
|
173
|
+
} else {
|
174
|
+
res.status(403).send({ message: `User not authenticated` });
|
175
|
+
}
|
176
|
+
}
|
177
|
+
}
|
178
|
+
|
179
|
+
static isUserInSomeGroup(groups) {
|
180
|
+
return async (req, res, next) => {
|
181
|
+
if (res.locals.user) {
|
182
|
+
// Hay usuario
|
183
|
+
const cumple = this.isUserInGroupInternal(res.locals.user, groups, false);
|
184
|
+
if (cumple) {
|
185
|
+
next();
|
186
|
+
} else {
|
187
|
+
res.status(403).send({ message: `User not allowed` });
|
188
|
+
}
|
189
|
+
} else {
|
190
|
+
res.status(403).send({ message: `User not authenticated` });
|
191
|
+
}
|
192
|
+
}
|
193
|
+
}
|
194
|
+
|
143
195
|
static hasPagePermisions(listaOr) {
|
144
196
|
return async (req, res, next) => {
|
145
197
|
if (listaOr.length == 0) {
|
package/srv/SocketIOCall.mjs
CHANGED
@@ -35,6 +35,8 @@ import { OpenVideoChatProcessor } from "./callprocessors/OpenVideoChatProcessor.
|
|
35
35
|
import { CloseVideoChatProcessor } from "./callprocessors/CloseVideoChatProcessor.mjs";
|
36
36
|
import { IncludeOtherPeersProcessor } from "./callprocessors/IncludeOtherPeersProcessor.mjs";
|
37
37
|
|
38
|
+
import stream from "stream";
|
39
|
+
|
38
40
|
export class SocketIOCall {
|
39
41
|
static io;
|
40
42
|
static mutex = new Mutex();
|
@@ -417,7 +419,7 @@ export class SocketIOCall {
|
|
417
419
|
decoded = decode(buffer);
|
418
420
|
}
|
419
421
|
//console.log(decoded);
|
420
|
-
const { processorMethod, room, channel } = decoded;
|
422
|
+
const { processorMethod, room, channel, data } = decoded;
|
421
423
|
const parts = /(^[^\d\.]+)(\d*)\.(.*)$/.exec(processorMethod);
|
422
424
|
if (!parts) {
|
423
425
|
throw Error(`processorMethod ${processorMethod} does not matches /(^[^\d\.]+)(\d*)\.(.*)$/`);
|
@@ -490,17 +492,48 @@ export class SocketIOCall {
|
|
490
492
|
const encoded = encode(decoded);
|
491
493
|
const buffer = Buffer.from(encoded);
|
492
494
|
console.log(`POST to ${postUrl}...`);
|
493
|
-
|
495
|
+
let isStream = false;
|
496
|
+
if (decoded.data?.streaming) {
|
497
|
+
isStream = true;
|
498
|
+
options['responseType'] = 'stream';
|
499
|
+
console.log("Prepare to receive streaming...");
|
500
|
+
}
|
501
|
+
const fullUrl = `${postUrl}/syncprocess`;
|
502
|
+
console.log(fullUrl);
|
503
|
+
const temp = await axios.post(fullUrl, buffer, options);
|
494
504
|
console.log(`POST to ${postUrl}... OK!`);
|
495
|
-
|
505
|
+
//console.log('Response status:', temp.status);
|
506
|
+
//console.log('Response headers:', temp.headers);
|
507
|
+
promesa = Promise.resolve({ data: temp.data, isStream });
|
496
508
|
}
|
497
509
|
|
498
|
-
|
499
510
|
const respuesta = await promesa;
|
500
|
-
|
501
|
-
status
|
502
|
-
|
503
|
-
|
511
|
+
if (!respuesta.isStream) {
|
512
|
+
res.status(200).send({
|
513
|
+
status: "ok",
|
514
|
+
response: respuesta
|
515
|
+
});
|
516
|
+
} else {
|
517
|
+
|
518
|
+
res.status(200);
|
519
|
+
res.setHeader('Content-Type', 'text/plain; charset=UTF-8');
|
520
|
+
res.setHeader('Transfer-Encoding', 'chunked');
|
521
|
+
|
522
|
+
const pass = new stream.PassThrough();
|
523
|
+
pass.on('data', (temp) => {
|
524
|
+
res.write(temp);
|
525
|
+
res.flush();
|
526
|
+
}).on("error", (error) => {
|
527
|
+
res.end();
|
528
|
+
}).on("finish", () => {
|
529
|
+
res.end();
|
530
|
+
});
|
531
|
+
stream.pipeline(
|
532
|
+
respuesta.data,
|
533
|
+
pass,
|
534
|
+
(err) => { }
|
535
|
+
);
|
536
|
+
}
|
504
537
|
}
|
505
538
|
|
506
539
|
static async introspect(req, res, next) {
|
@@ -5,6 +5,48 @@ import { Usuario } from './Usuario.mjs';
|
|
5
5
|
import fs from "fs";
|
6
6
|
import { General } from './General.mjs';
|
7
7
|
import { MyConstants } from '@ejfdelgado/ejflab-common/src/MyConstants.js';
|
8
|
+
import jwt from 'jsonwebtoken';
|
9
|
+
import jwksClient from 'jwks-rsa';
|
10
|
+
|
11
|
+
const AUTH_PROVIDER = process.env.AUTH_PROVIDER;
|
12
|
+
const MICROSOFT_CLIENT_ID = process.env.MICROSOFT_CLIENT_ID;
|
13
|
+
const MICROSOFT_TENANT = process.env.MICROSOFT_TENANT;
|
14
|
+
|
15
|
+
const microsoftClient = jwksClient({
|
16
|
+
jwksUri: `https://login.microsoftonline.com/${MICROSOFT_TENANT}/discovery/v2.0/keys`,
|
17
|
+
});
|
18
|
+
|
19
|
+
// Helper to get the signing key
|
20
|
+
function getMicrosoftKey(header, callback) {
|
21
|
+
microsoftClient.getSigningKey(header.kid, (err, key) => {
|
22
|
+
if (err) {
|
23
|
+
return callback(err);
|
24
|
+
}
|
25
|
+
const signingKey = key.getPublicKey();
|
26
|
+
callback(null, signingKey);
|
27
|
+
});
|
28
|
+
}
|
29
|
+
|
30
|
+
function verifyMicrosoftToken(token) {
|
31
|
+
return new Promise((resolve, reject) => {
|
32
|
+
jwt.verify(
|
33
|
+
token,
|
34
|
+
getMicrosoftKey,
|
35
|
+
{
|
36
|
+
algorithms: ['RS256'], // Tokens are typically signed with RS256
|
37
|
+
audience: MICROSOFT_CLIENT_ID, // Replace with your application's client ID
|
38
|
+
issuer: `https://login.microsoftonline.com/${MICROSOFT_TENANT}/v2.0`, // Replace with your tenant's issuer
|
39
|
+
//issuer: `https://sts.windows.net/${MICROSOFT_TENANT}/`
|
40
|
+
},
|
41
|
+
(err, decoded) => {
|
42
|
+
if (err) {
|
43
|
+
return reject(err);
|
44
|
+
}
|
45
|
+
resolve(decoded);
|
46
|
+
}
|
47
|
+
);
|
48
|
+
});
|
49
|
+
}
|
8
50
|
|
9
51
|
function getFirebaseConfig() {
|
10
52
|
const firebaseJson = fs.readFileSync(MyConstants.FIREBASE_CONFIG_FILE, { encoding: "utf8" });
|
@@ -54,17 +96,30 @@ async function checkAutenticated(req) {
|
|
54
96
|
reject(new MyError("Missing Authorization header.", 403));
|
55
97
|
return;
|
56
98
|
}
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
99
|
+
if (AUTH_PROVIDER == "microsoft") {
|
100
|
+
verifyMicrosoftToken(sessionToken)
|
101
|
+
.then((decodedToken) => {
|
102
|
+
resolve({
|
103
|
+
decodedToken,
|
104
|
+
sessionToken,
|
105
|
+
});
|
106
|
+
})
|
107
|
+
.catch((error) => {
|
108
|
+
reject(new MyError(error.message, 403));
|
63
109
|
});
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
110
|
+
} else if (AUTH_PROVIDER == "google") {
|
111
|
+
getAuth()
|
112
|
+
.verifyIdToken(sessionToken)
|
113
|
+
.then((decodedToken) => {
|
114
|
+
resolve({
|
115
|
+
decodedToken,
|
116
|
+
sessionToken,
|
117
|
+
});
|
118
|
+
})
|
119
|
+
.catch((error) => {
|
120
|
+
reject(new MyError(error.message, 403));
|
121
|
+
});
|
122
|
+
}
|
68
123
|
});
|
69
124
|
}
|
70
125
|
|
@@ -107,7 +162,7 @@ async function checkAuthenticatedSilent(req, res, next) {
|
|
107
162
|
res.locals.user = new Usuario(res.locals.token);
|
108
163
|
await next();
|
109
164
|
} catch (err) {
|
110
|
-
|
165
|
+
console.log(err);
|
111
166
|
res.locals.token = null;
|
112
167
|
res.locals.user = null;
|
113
168
|
await next();
|
package/srv/common/Usuario.mjs
CHANGED
@@ -5,6 +5,8 @@ import { MyStore } from "./MyStore.mjs";
|
|
5
5
|
import { General } from "./General.mjs";
|
6
6
|
import { MalaPeticionException } from "../MyError.mjs";
|
7
7
|
|
8
|
+
const AUTH_PROVIDER = process.env.AUTH_PROVIDER;
|
9
|
+
const groupIdMap = JSON.parse("AUTH_GROUP_ID_MAP" in process.env ? process.env.AUTH_GROUP_ID_MAP : "{}");
|
8
10
|
const USER_TYPE = "user";
|
9
11
|
|
10
12
|
export class Usuario {
|
@@ -12,20 +14,39 @@ export class Usuario {
|
|
12
14
|
id = null;
|
13
15
|
email = null;
|
14
16
|
phone = null;
|
17
|
+
groups = [];
|
15
18
|
constructor(token) {
|
16
19
|
this.metadatos = token;
|
17
20
|
if (this.metadatos != null) {
|
18
21
|
if (this.metadatos.email) {
|
19
22
|
this.email = this.metadatos.email;
|
20
23
|
}
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
24
|
+
if (AUTH_PROVIDER == "microsoft") {
|
25
|
+
this.id = token.oid;
|
26
|
+
this.email = token.preferred_username;
|
27
|
+
if (token.groups instanceof Array) {
|
28
|
+
this.groups = token.groups.map((idGroup) => {
|
29
|
+
if (idGroup in groupIdMap) {
|
30
|
+
return groupIdMap[idGroup];
|
31
|
+
}
|
32
|
+
return idGroup;
|
33
|
+
});
|
34
|
+
}
|
35
|
+
//console.log(`id: ${this.id}`);
|
36
|
+
//console.log(`email: ${this.email}`);
|
37
|
+
//console.log(`groups: ${JSON.stringify(this.groups)}`);
|
38
|
+
} else {
|
39
|
+
if ("firebase" in this.metadatos) {
|
40
|
+
const contenedor = this.metadatos["firebase"];
|
41
|
+
const identidades = contenedor["identities"];
|
42
|
+
if ("email" in identidades) {
|
43
|
+
this.id = identidades["email"][0];
|
44
|
+
this.email = this.id;
|
45
|
+
} else if ("phone" in identidades) {
|
46
|
+
this.id = identidades["phone"][0];
|
47
|
+
this.phone = this.id;
|
48
|
+
}
|
49
|
+
}
|
29
50
|
}
|
30
51
|
}
|
31
52
|
}
|