propro-utils 1.3.46 → 1.3.48

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,39 +1,87 @@
1
- require("dotenv").config();
2
- const axios = require("axios");
3
- const {getOrSetCache} = require("../utils/redis");
1
+ require('dotenv').config();
2
+ const axios = require('axios');
3
+ const { getOrSetCache } = require('../utils/redis');
4
+ const { checkIfUserExists } = require('./account_info');
4
5
 
5
- const authValidation = (redisClient, requiredPermissions = []) => {
6
- return async (req, res, next) => {
7
- try {
8
- const accessToken = req.cookies['x-access-token'] || req.headers.authorization?.split(" ")[1];
6
+ /**
7
+ * Middleware for authenticating and authorizing API requests.
8
+ * It validates an access token and checks for required permissions using both a Redis cache
9
+ * and propro authentication service.
10
+ *
11
+ * @param {object} redisClient - The Redis client used for caching permission data.
12
+ * @param {object} userSchema - The user schema/model object.
13
+ * @param {string[]} [requiredPermissions=[]] - An array of permissions required to access the endpoint.
14
+ * This function first attempts to retrieve the account's permissions from the cache.
15
+ * If the cache is empty or expired, it fetches permissions from propro authentication service
16
+ * and updates the cache. If the access token is invalid or does not grant the required permissions,
17
+ * the request is rejected.
18
+ *
19
+ * @returns {function} A middleware function that takes Express.js request (req), response (res),
20
+ * and next function parameters. The middleware validates the access token and permissions.
21
+ * If validation is successful, it adds the account ID and req.user to the request object (req.account) and
22
+ * calls `next()` to pass control to the next middleware. If validation fails, it responds with
23
+ * an error message and a 403 status code.
24
+ *
25
+ * Usage of the middleware requires an environment variable `AUTH_URL` to be set, pointing to the
26
+ * authentication service's URL. The function leverages async/await for asynchronous operations
27
+ * and tries to handle errors gracefully, reporting them through the next middleware in the chain.
28
+ *
29
+ * @example
30
+ * // Applying authValidation middleware
31
+ * const redisClient = require('./redisClient');
32
+ * app.use('/api/protected-route', authValidation(redisClient, ['admin', 'user']), (req, res) => {
33
+ * res.json({ message: 'You have access to protected data' });
34
+ * });
35
+ */
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];
9
42
 
10
- if (!accessToken) {
11
- return res.status(403).json({ error: "Access token is required" });
12
- }
43
+ if (!accessToken) {
44
+ return res.status(403).json({ error: 'Access token is required' });
45
+ }
13
46
 
14
- const fetchPermission = async () => {
15
- const response = await axios.post(`${process.env.AUTH_URL}/api/v1/auth/validateToken`, {
16
- accessToken: accessToken,
17
- requiredPermissions: requiredPermissions
18
- });
19
- return response.data;
20
- }
21
- const cacheKey = `account:permissions:${accessToken}`;
22
- const { accountId, validPermissions } = await getOrSetCache(redisClient, cacheKey, fetchPermission, 1800);
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
+ );
23
64
 
24
- if (!validPermissions) {
25
- return res.status(403).json({ error: "Invalid permissions" });
26
- }
65
+ if (!validPermissions) {
66
+ return res.status(403).json({ error: 'Invalid permissions' });
67
+ }
27
68
 
28
- req.account = accountId;
29
- next();
30
- } catch (error) {
31
- if (error.response && error.response.status) {
32
- next(new Error(error.response.data.message));
33
- }
34
- next(new Error('Error validating token'));
35
- }
36
- };
69
+ req.account = accountId;
70
+
71
+ const user = await checkIfUserExists(userSchema, accountId);
72
+ if (!user) {
73
+ return res.status(403).json({ error: 'User not found' });
74
+ }
75
+ console.log('user', user);
76
+ req.user = user.id;
77
+ next();
78
+ } catch (error) {
79
+ if (error.response && error.response.status) {
80
+ next(new Error(error.response.data.message));
81
+ }
82
+ next(new Error('Error validating token'));
83
+ }
84
+ };
37
85
  };
38
86
 
39
- module.exports = authValidation;
87
+ module.exports = authValidation;
@@ -1,6 +1,6 @@
1
- require("dotenv").config();
2
- const axios = require("axios");
3
- const {getOrSetCache} = require("../utils/redis");
1
+ require('dotenv').config();
2
+ const axios = require('axios');
3
+ const { getOrSetCache } = require('../utils/redis');
4
4
  const { v4: uuidv4 } = require('uuid');
5
5
 
6
6
  /**
@@ -14,62 +14,70 @@ const { v4: uuidv4 } = require('uuid');
14
14
  * @throws {Error} - If there is an error retrieving the account profile data or validating the token
15
15
  */
16
16
  const getAccountProfile = async (redisClient, userSchema, accountId) => {
17
- try {
18
- const accessToken = req.cookies['x-access-token'] || req.headers.authorization?.split(" ")[1];
17
+ try {
18
+ const accessToken =
19
+ req.cookies['x-access-token'] || req.headers.authorization?.split(' ')[1];
19
20
 
20
- if (!accessToken) {
21
- throw new Error("Access token is required");
22
- }
23
-
24
- const fetchPermission = async () => {
25
- const response = await axios.get(`${process.env.AUTH_URL}/api/v1/account/profile`, {
26
- headers: {
27
- Authorization: `Bearer ${accessToken}`,
28
- },
29
- params: {
30
- accountId
31
- }
32
- });
33
- return response.data;
34
- }
35
- const cacheKey = `account:info:${accountId}`;
36
- const { profileData } = await getOrSetCache(redisClient, cacheKey, fetchPermission, 1800);
21
+ if (!accessToken) {
22
+ throw new Error('Access token is required');
23
+ }
37
24
 
38
- if (!profileData) {
39
- throw new Error("Invalid permissions");
40
- }
25
+ const fetchPermission = async () => {
26
+ const response = await axios.get(
27
+ `${process.env.AUTH_URL}/api/v1/account/profile`,
28
+ {
29
+ headers: {
30
+ Authorization: `Bearer ${accessToken}`,
31
+ },
32
+ params: {
33
+ accountId,
34
+ },
35
+ }
36
+ );
37
+ return response.data;
38
+ };
39
+ const cacheKey = `account:info:${accountId}`;
40
+ const { profileData } = await getOrSetCache(
41
+ redisClient,
42
+ cacheKey,
43
+ fetchPermission,
44
+ 1800
45
+ );
41
46
 
42
- return profileData;
47
+ if (!profileData) {
48
+ throw new Error('Invalid permissions');
49
+ }
43
50
 
44
- } catch (error) {
45
- if (error.response && error.response.status) {
46
- throw new Error(error.response.data.message);
47
- }
48
- throw new Error('Error validating token');
49
- }
51
+ return profileData;
52
+ } catch (error) {
53
+ if (error.response && error.response.status) {
54
+ throw new Error(error.response.data.message);
55
+ }
56
+ throw new Error('Error validating token');
57
+ }
50
58
  };
51
59
 
52
-
53
60
  /**
54
61
  * Checks if a user exists based on the given account ID.
55
62
  * If the user does not exist, creates a new user with the given account ID.
56
63
  *
57
64
  * @param {Schema} userSchema - The user schema to perform the operations on.
58
65
  * @param {string} accountId - The account ID of the user to check/create.
59
- * @returns {Promise<void>} - A promise that resolves once the check/create operation is done.
66
+ * @returns {Promise<user>} - A promise that resolves once the check/create operation is done.
60
67
  */
61
68
  const checkIfUserExists = async (userSchema, accountId) => {
62
- const user = await userSchema.findOne({ accountId });
63
- if (!user) {
64
- await userSchema.create({
65
- accountId,
66
- id: uuidv4(),
67
- verified: false,
68
- });
69
- }
69
+ const user = await userSchema.findOne({ accountId });
70
+ if (!user) {
71
+ await userSchema.create({
72
+ accountId,
73
+ id: uuidv4(),
74
+ verified: false,
75
+ });
76
+ }
77
+ return user;
70
78
  };
71
79
 
72
80
  module.exports = {
73
- getAccountProfile,
74
- checkIfUserExists
75
- }
81
+ getAccountProfile,
82
+ checkIfUserExists,
83
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "propro-utils",
3
- "version": "1.3.46",
3
+ "version": "1.3.48",
4
4
  "description": "Auth middleware for propro-auth",
5
5
  "main": "src/index.js",
6
6
  "scripts": {
@@ -107,7 +107,6 @@ function proproAuthMiddleware(options = {}, userSchema) {
107
107
  return res.status(400).send('No code received');
108
108
  }
109
109
 
110
- console.log('code', code);
111
110
  const { tokens, account, redirectUrl } = await exchangeToken(
112
111
  authUrl,
113
112
  code,
@@ -116,14 +115,8 @@ function proproAuthMiddleware(options = {}, userSchema) {
116
115
  redirectUri
117
116
  );
118
117
 
119
- console.log('account', account);
120
- console.log('tokens', tokens);
121
- console.log('redirectUrl', redirectUrl);
122
-
123
118
  await checkIfUserExists(userSchema, account.accountId);
124
119
 
125
- console.log('User exists');
126
-
127
120
  const currentDateTime = new Date();
128
121
 
129
122
  const refreshMaxAge =