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.
@@ -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
- return async (req, res, next) => {
38
- try {
39
- const accessToken =
40
- req.cookies['x-access-token'] ||
41
- req.headers.authorization?.split(' ')[1];
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
- if (!accessToken) {
44
- return res.status(403).json({error: 'Access token is required'});
45
- }
43
+ if (!accessToken) {
44
+ return res.status(403).json({ error: 'Access token is required' });
45
+ }
46
46
 
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
- );
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
- if (!validPermissions) {
66
- return res.status(403).json({error: 'Invalid permissions'});
67
- }
65
+ if (!validPermissions) {
66
+ return res.status(403).json({ error: 'Invalid permissions' });
67
+ }
68
68
 
69
- req.account = accountId;
69
+ req.account = accountId;
70
70
 
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
- };
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "propro-utils",
3
- "version": "1.4.76",
3
+ "version": "1.4.78",
4
4
  "description": "Auth middleware for propro-auth",
5
5
  "main": "src/index.js",
6
6
  "scripts": {
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();
@@ -3,9 +3,14 @@ const {
3
3
  exchangeToken,
4
4
  formatRedirectUrl,
5
5
  } = require('./middleware/verifyToken');
6
- const { setAuthCookies } = require('./middleware/cookieUtils');
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('api/app/settings', this.handleAppSettings);
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
- res.status(200).json({ redirectUrl: this.constructRedirectUrl() });
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(req, '/api/v1/profile');
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/profile/avatar'
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
- res.status(200).json({ message: 'App settings updated successfully' });
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' });