propro-utils 1.4.77 → 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 +55 -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,8 +3,12 @@ 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');
|
|
9
13
|
const { Router } = require('express');
|
|
10
14
|
|
|
@@ -21,10 +25,11 @@ const { Router } = require('express');
|
|
|
21
25
|
* @param {string} [options.appName=process.env.APP_NAME] - The application name.
|
|
22
26
|
* @param {string} [options.appUrl] - The URL of the client application.
|
|
23
27
|
* @param {Schema} [userSchema] - The user schema to perform the operations on.
|
|
28
|
+
* @param {RedisClient} [redisClient] - The Redis client used for caching.
|
|
24
29
|
* @returns {Function} - Express middleware function.
|
|
25
30
|
*/
|
|
26
31
|
class AuthMiddleware {
|
|
27
|
-
constructor(options = {}, userSchema) {
|
|
32
|
+
constructor(options = {}, userSchema, redisClient) {
|
|
28
33
|
this.options = {
|
|
29
34
|
secret: options.secret || 'RESTFULAPIs',
|
|
30
35
|
authUrl: options.authUrl || process.env.AUTH_URL,
|
|
@@ -36,6 +41,7 @@ class AuthMiddleware {
|
|
|
36
41
|
appUrl: options.appUrl || process.env.APP_URL,
|
|
37
42
|
};
|
|
38
43
|
this.userSchema = userSchema;
|
|
44
|
+
this.redisClient = redisClient;
|
|
39
45
|
this.router = Router();
|
|
40
46
|
this.initializeRoutes();
|
|
41
47
|
}
|
|
@@ -50,7 +56,11 @@ class AuthMiddleware {
|
|
|
50
56
|
this.router.patch('/api/profile/email', this.handleEmailUpdate);
|
|
51
57
|
this.router.patch('api/profile/2fa', this.handleTwoFactorAuth);
|
|
52
58
|
this.router.patch('/api/profile/avatar', this.handleAvatarUpdate);
|
|
53
|
-
this.router.patch(
|
|
59
|
+
this.router.patch(
|
|
60
|
+
'api/app/settings',
|
|
61
|
+
authValidation(this.redisClient, this.userSchema, ['user']),
|
|
62
|
+
this.handleAppSettings
|
|
63
|
+
);
|
|
54
64
|
}
|
|
55
65
|
|
|
56
66
|
handleAuth = (req, res) => {
|
|
@@ -127,7 +137,8 @@ class AuthMiddleware {
|
|
|
127
137
|
try {
|
|
128
138
|
await this.logoutUser(refreshToken);
|
|
129
139
|
clearAuthCookies(res);
|
|
130
|
-
|
|
140
|
+
return this.handleAuth(req, res);
|
|
141
|
+
// this.res.status(200).json({ redirectUrl: this.constructRedirectUrl() });
|
|
131
142
|
} catch (error) {
|
|
132
143
|
console.error('Error logging out:', error);
|
|
133
144
|
res.status(500).json({ error: 'Failed to logout' });
|
|
@@ -163,7 +174,10 @@ class AuthMiddleware {
|
|
|
163
174
|
|
|
164
175
|
handleProfileUpdate = async (req, res) => {
|
|
165
176
|
try {
|
|
166
|
-
const response = await this.proxyToAuthServer(
|
|
177
|
+
const response = await this.proxyToAuthServer(
|
|
178
|
+
req,
|
|
179
|
+
'/api/v1/accounts/profile'
|
|
180
|
+
);
|
|
167
181
|
res.status(response.status).json(response.data);
|
|
168
182
|
} catch (error) {
|
|
169
183
|
this.handleProxyError(error, res);
|
|
@@ -207,7 +221,7 @@ class AuthMiddleware {
|
|
|
207
221
|
try {
|
|
208
222
|
const response = await this.proxyToAuthServer(
|
|
209
223
|
req,
|
|
210
|
-
'/api/v1/
|
|
224
|
+
'/api/v1/accounts/avatar'
|
|
211
225
|
);
|
|
212
226
|
res.status(response.status).json(response.data);
|
|
213
227
|
} catch (error) {
|
|
@@ -245,7 +259,41 @@ class AuthMiddleware {
|
|
|
245
259
|
handleAppSettings = async (req, res) => {
|
|
246
260
|
try {
|
|
247
261
|
const { settings } = req.body;
|
|
248
|
-
|
|
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
|
+
});
|
|
249
297
|
} catch (error) {
|
|
250
298
|
console.error('Error updating app settings:', error);
|
|
251
299
|
res.status(500).json({ error: 'Failed to update app settings' });
|