propro-utils 1.4.76 → 1.4.78
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/middlewares/access_token.js +44 -44
- package/package.json +1 -1
- package/src/index.js +6 -3
- package/src/server/index.js +56 -7
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
require('dotenv').config();
|
|
2
2
|
const axios = require('axios');
|
|
3
|
-
const {getOrSetCache} = require('../utils/redis');
|
|
4
|
-
const {checkIfUserExists} = require('./account_info');
|
|
3
|
+
const { getOrSetCache } = require('../utils/redis');
|
|
4
|
+
const { checkIfUserExists } = require('./account_info');
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* Middleware for authenticating and authorizing API requests.
|
|
@@ -34,53 +34,53 @@ const {checkIfUserExists} = require('./account_info');
|
|
|
34
34
|
* });
|
|
35
35
|
*/
|
|
36
36
|
const authValidation = (redisClient, userSchema, requiredPermissions = []) => {
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
37
|
+
return async (req, res, next) => {
|
|
38
|
+
try {
|
|
39
|
+
const accessToken =
|
|
40
|
+
req.cookies['x-access-token'] ||
|
|
41
|
+
req.headers.authorization?.split(' ')[1];
|
|
42
42
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
43
|
+
if (!accessToken) {
|
|
44
|
+
return res.status(403).json({ error: 'Access token is required' });
|
|
45
|
+
}
|
|
46
46
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
47
|
+
const fetchPermission = async () => {
|
|
48
|
+
const response = await axios.post(
|
|
49
|
+
`${process.env.AUTH_URL}/api/v1/auth/validateToken`,
|
|
50
|
+
{
|
|
51
|
+
accessToken: accessToken,
|
|
52
|
+
requiredPermissions: requiredPermissions,
|
|
53
|
+
}
|
|
54
|
+
);
|
|
55
|
+
return response.data;
|
|
56
|
+
};
|
|
57
|
+
const cacheKey = `account:permissions:${accessToken}`;
|
|
58
|
+
const { accountId, validPermissions } = await getOrSetCache(
|
|
59
|
+
redisClient,
|
|
60
|
+
cacheKey,
|
|
61
|
+
fetchPermission,
|
|
62
|
+
1800
|
|
63
|
+
);
|
|
64
64
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
65
|
+
if (!validPermissions) {
|
|
66
|
+
return res.status(403).json({ error: 'Invalid permissions' });
|
|
67
|
+
}
|
|
68
68
|
|
|
69
|
-
|
|
69
|
+
req.account = accountId;
|
|
70
70
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
71
|
+
const user = await checkIfUserExists(userSchema, accountId);
|
|
72
|
+
if (!user) {
|
|
73
|
+
return res.status(403).json({ error: 'User not found' });
|
|
74
|
+
}
|
|
75
|
+
req.user = user.id;
|
|
76
|
+
next();
|
|
77
|
+
} catch (error) {
|
|
78
|
+
if (error.response && error.response.status) {
|
|
79
|
+
next(new Error(error.response.data.message));
|
|
80
|
+
}
|
|
81
|
+
next(new Error('Error validating token'));
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
84
|
};
|
|
85
85
|
|
|
86
86
|
module.exports = authValidation;
|
package/package.json
CHANGED
package/src/index.js
CHANGED
|
@@ -29,6 +29,7 @@ let _serverAuth, _clientAuth;
|
|
|
29
29
|
* @param {boolean} [options.useClientAuth=false] - A boolean flag to enable client-side authentication.
|
|
30
30
|
* @param {Object} [options.clientOptions={}] - Configuration options for client-side authentication.
|
|
31
31
|
* @param {Schema} [userSchema] - The user schema to perform the operations on.
|
|
32
|
+
* @param {RedisClient} [redisClient] - The Redis client used for caching.
|
|
32
33
|
*
|
|
33
34
|
* @returns {Function} An Express middleware function.
|
|
34
35
|
* ```
|
|
@@ -43,13 +44,14 @@ let _serverAuth, _clientAuth;
|
|
|
43
44
|
* additionalChecks: async (req) => { },
|
|
44
45
|
* },
|
|
45
46
|
* useClientAuth: false,
|
|
46
|
-
* }, UserSchema));
|
|
47
|
+
* }, UserSchema, redisClient));
|
|
47
48
|
* ```
|
|
48
49
|
*/
|
|
49
50
|
class ProProAuthMiddleware {
|
|
50
|
-
constructor(options = {}, userSchema) {
|
|
51
|
+
constructor(options = {}, userSchema, redisClient) {
|
|
51
52
|
this.options = options;
|
|
52
53
|
this.userSchema = userSchema;
|
|
54
|
+
this.redisClient = redisClient;
|
|
53
55
|
this.serverAuth = null;
|
|
54
56
|
this.clientAuth = null;
|
|
55
57
|
|
|
@@ -77,7 +79,8 @@ class ProProAuthMiddleware {
|
|
|
77
79
|
if (!this.serverAuth) {
|
|
78
80
|
this.serverAuth = new ServerAuth(
|
|
79
81
|
this.options.serverOptions,
|
|
80
|
-
this.userSchema
|
|
82
|
+
this.userSchema,
|
|
83
|
+
this.redisClient
|
|
81
84
|
);
|
|
82
85
|
}
|
|
83
86
|
return this.serverAuth.middleware();
|
package/src/server/index.js
CHANGED
|
@@ -3,9 +3,14 @@ const {
|
|
|
3
3
|
exchangeToken,
|
|
4
4
|
formatRedirectUrl,
|
|
5
5
|
} = require('./middleware/verifyToken');
|
|
6
|
-
const {
|
|
6
|
+
const {
|
|
7
|
+
setAuthCookies,
|
|
8
|
+
clearAuthCookies,
|
|
9
|
+
} = require('./middleware/cookieUtils');
|
|
7
10
|
const { checkIfUserExists } = require('../../middlewares/account_info');
|
|
11
|
+
const authValidation = require('../../middlewares/access_token');
|
|
8
12
|
const axios = require('axios');
|
|
13
|
+
const { Router } = require('express');
|
|
9
14
|
|
|
10
15
|
/**
|
|
11
16
|
* Middleware for handling authentication and authorization.
|
|
@@ -20,10 +25,11 @@ const axios = require('axios');
|
|
|
20
25
|
* @param {string} [options.appName=process.env.APP_NAME] - The application name.
|
|
21
26
|
* @param {string} [options.appUrl] - The URL of the client application.
|
|
22
27
|
* @param {Schema} [userSchema] - The user schema to perform the operations on.
|
|
28
|
+
* @param {RedisClient} [redisClient] - The Redis client used for caching.
|
|
23
29
|
* @returns {Function} - Express middleware function.
|
|
24
30
|
*/
|
|
25
31
|
class AuthMiddleware {
|
|
26
|
-
constructor(options = {}, userSchema) {
|
|
32
|
+
constructor(options = {}, userSchema, redisClient) {
|
|
27
33
|
this.options = {
|
|
28
34
|
secret: options.secret || 'RESTFULAPIs',
|
|
29
35
|
authUrl: options.authUrl || process.env.AUTH_URL,
|
|
@@ -35,6 +41,7 @@ class AuthMiddleware {
|
|
|
35
41
|
appUrl: options.appUrl || process.env.APP_URL,
|
|
36
42
|
};
|
|
37
43
|
this.userSchema = userSchema;
|
|
44
|
+
this.redisClient = redisClient;
|
|
38
45
|
this.router = Router();
|
|
39
46
|
this.initializeRoutes();
|
|
40
47
|
}
|
|
@@ -49,7 +56,11 @@ class AuthMiddleware {
|
|
|
49
56
|
this.router.patch('/api/profile/email', this.handleEmailUpdate);
|
|
50
57
|
this.router.patch('api/profile/2fa', this.handleTwoFactorAuth);
|
|
51
58
|
this.router.patch('/api/profile/avatar', this.handleAvatarUpdate);
|
|
52
|
-
this.router.patch(
|
|
59
|
+
this.router.patch(
|
|
60
|
+
'api/app/settings',
|
|
61
|
+
authValidation(this.redisClient, this.userSchema, ['user']),
|
|
62
|
+
this.handleAppSettings
|
|
63
|
+
);
|
|
53
64
|
}
|
|
54
65
|
|
|
55
66
|
handleAuth = (req, res) => {
|
|
@@ -126,7 +137,8 @@ class AuthMiddleware {
|
|
|
126
137
|
try {
|
|
127
138
|
await this.logoutUser(refreshToken);
|
|
128
139
|
clearAuthCookies(res);
|
|
129
|
-
|
|
140
|
+
return this.handleAuth(req, res);
|
|
141
|
+
// this.res.status(200).json({ redirectUrl: this.constructRedirectUrl() });
|
|
130
142
|
} catch (error) {
|
|
131
143
|
console.error('Error logging out:', error);
|
|
132
144
|
res.status(500).json({ error: 'Failed to logout' });
|
|
@@ -162,7 +174,10 @@ class AuthMiddleware {
|
|
|
162
174
|
|
|
163
175
|
handleProfileUpdate = async (req, res) => {
|
|
164
176
|
try {
|
|
165
|
-
const response = await this.proxyToAuthServer(
|
|
177
|
+
const response = await this.proxyToAuthServer(
|
|
178
|
+
req,
|
|
179
|
+
'/api/v1/accounts/profile'
|
|
180
|
+
);
|
|
166
181
|
res.status(response.status).json(response.data);
|
|
167
182
|
} catch (error) {
|
|
168
183
|
this.handleProxyError(error, res);
|
|
@@ -206,7 +221,7 @@ class AuthMiddleware {
|
|
|
206
221
|
try {
|
|
207
222
|
const response = await this.proxyToAuthServer(
|
|
208
223
|
req,
|
|
209
|
-
'/api/v1/
|
|
224
|
+
'/api/v1/accounts/avatar'
|
|
210
225
|
);
|
|
211
226
|
res.status(response.status).json(response.data);
|
|
212
227
|
} catch (error) {
|
|
@@ -244,7 +259,41 @@ class AuthMiddleware {
|
|
|
244
259
|
handleAppSettings = async (req, res) => {
|
|
245
260
|
try {
|
|
246
261
|
const { settings } = req.body;
|
|
247
|
-
|
|
262
|
+
const userId = req.user;
|
|
263
|
+
|
|
264
|
+
if (!settings || typeof settings !== 'object') {
|
|
265
|
+
return res.status(400).json({ error: 'Invalid settings format' });
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
const user = await this.userSchema.findOne({ id: userId });
|
|
269
|
+
|
|
270
|
+
if (!user) {
|
|
271
|
+
return res.status(404).json({ error: 'User not found' });
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
if (!user.settings) {
|
|
275
|
+
user.settings = {};
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
Object.keys(settings).forEach(key => {
|
|
279
|
+
if (typeof settings[key] === 'object' && settings[key] !== null) {
|
|
280
|
+
user.settings[key] = { ...user.settings[key], ...settings[key] };
|
|
281
|
+
} else {
|
|
282
|
+
user.settings[key] = settings[key];
|
|
283
|
+
}
|
|
284
|
+
});
|
|
285
|
+
|
|
286
|
+
if ('dark_mode' in settings) {
|
|
287
|
+
user.dark_mode = settings.dark_mode;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
await user.save();
|
|
291
|
+
|
|
292
|
+
res.status(200).json({
|
|
293
|
+
message: 'App settings updated successfully',
|
|
294
|
+
settings: user.settings,
|
|
295
|
+
dark_mode: user.dark_mode,
|
|
296
|
+
});
|
|
248
297
|
} catch (error) {
|
|
249
298
|
console.error('Error updating app settings:', error);
|
|
250
299
|
res.status(500).json({ error: 'Failed to update app settings' });
|