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.
@@ -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.77",
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,8 +3,12 @@ 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');
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('api/app/settings', this.handleAppSettings);
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
- res.status(200).json({ redirectUrl: this.constructRedirectUrl() });
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(req, '/api/v1/profile');
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/profile/avatar'
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
- 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
+ });
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' });