propro-utils 1.4.18 → 1.4.20
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/package.json +1 -1
- package/src/server/index.js +23 -15
- package/src/server/middleware/verifyToken.js +87 -82
package/package.json
CHANGED
package/src/server/index.js
CHANGED
|
@@ -107,6 +107,7 @@ function proproAuthMiddleware(options = {}, userSchema) {
|
|
|
107
107
|
return res.status(400).send('No code received');
|
|
108
108
|
}
|
|
109
109
|
|
|
110
|
+
console.log('code', code);
|
|
110
111
|
const {tokens, account, redirectUrl} = await exchangeToken(
|
|
111
112
|
authUrl,
|
|
112
113
|
code,
|
|
@@ -150,16 +151,7 @@ function proproAuthMiddleware(options = {}, userSchema) {
|
|
|
150
151
|
|
|
151
152
|
console.log('redirectUrl', redirectUrl);
|
|
152
153
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
if (!redirectUrl.startsWith('http://') && !redirectUrl.startsWith('https://')) {
|
|
156
|
-
if (redirectUrl.includes('localhost')) {
|
|
157
|
-
urlToRedirect = `http://${redirectUrl}`;
|
|
158
|
-
} else {
|
|
159
|
-
urlToRedirect = `https://${redirectUrl}`;
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
|
|
154
|
+
const urlToRedirect = formatRedirectUrl(clientUrl);
|
|
163
155
|
|
|
164
156
|
console.log('urlToRedirect', urlToRedirect);
|
|
165
157
|
|
|
@@ -184,15 +176,31 @@ function proproAuthMiddleware(options = {}, userSchema) {
|
|
|
184
176
|
function constructRedirectUrl(clientUrl, appName, clientId, redirectUri) {
|
|
185
177
|
console.log('constructRedirectUrl', clientUrl, appName, clientId, redirectUri);
|
|
186
178
|
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
179
|
+
const urlToRedirect = formatRedirectUrl(clientUrl)
|
|
180
|
+
|
|
181
|
+
return `${urlToRedirect}/signin?response_type=code&appName=${appName}&client_id=${clientId}&redirect_uri=${encodeURIComponent(redirectUri)}`;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Formats the redirect URL by adding 'http://' or 'https://' if necessary.
|
|
186
|
+
*
|
|
187
|
+
* @param {string} redirectUrl - The URL to be redirected.
|
|
188
|
+
* @return {string} The formatted redirect URL.
|
|
189
|
+
*/
|
|
190
|
+
function formatRedirectUrl(redirectUrl) {
|
|
191
|
+
let urlToRedirect;
|
|
192
|
+
|
|
193
|
+
if (!redirectUrl.startsWith('http://') && !redirectUrl.startsWith('https://')) {
|
|
194
|
+
if (redirectUrl.includes('localhost')) {
|
|
195
|
+
urlToRedirect = `http://${redirectUrl}`;
|
|
190
196
|
} else {
|
|
191
|
-
|
|
197
|
+
urlToRedirect = `https://${redirectUrl}`;
|
|
192
198
|
}
|
|
199
|
+
} else {
|
|
200
|
+
urlToRedirect = redirectUrl;
|
|
193
201
|
}
|
|
194
202
|
|
|
195
|
-
return
|
|
203
|
+
return urlToRedirect;
|
|
196
204
|
}
|
|
197
205
|
|
|
198
206
|
|
|
@@ -8,28 +8,28 @@ const tokenCache = new Map();
|
|
|
8
8
|
* @param {string} secret - The secret used to sign the JWT.
|
|
9
9
|
* @returns {object|null} - The decoded payload of the JWT if it is valid, or null if it is not valid.
|
|
10
10
|
*/
|
|
11
|
-
async function verifyJWT(token, secret= "thisisasamplesecret") {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
11
|
+
async function verifyJWT(token, secret = "thisisasamplesecret") {
|
|
12
|
+
try {
|
|
13
|
+
return jwt.verify(token, secret);
|
|
14
|
+
} catch (err) {
|
|
15
|
+
if (err.name === 'TokenExpiredError') {
|
|
16
|
+
const newTokenData = await callTokenEndpoint(token);
|
|
17
|
+
return newTokenData ? jwt.verify(newTokenData, secret) : null;
|
|
18
|
+
}
|
|
19
|
+
return null;
|
|
18
20
|
}
|
|
19
|
-
return null;
|
|
20
|
-
}
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
async function callTokenEndpoint(token) {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
24
|
+
try {
|
|
25
|
+
const response = await axios.post(`${process.env.AUTH_URL}/api/v1/tokens`, {
|
|
26
|
+
refreshToken: token,
|
|
27
|
+
});
|
|
28
|
+
return response.data.tokens ? response.data.tokens.access.token : null;
|
|
29
|
+
} catch (error) {
|
|
30
|
+
console.error('Error during token refresh:', error);
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
33
|
}
|
|
34
34
|
|
|
35
35
|
/**
|
|
@@ -42,27 +42,32 @@ async function callTokenEndpoint(token) {
|
|
|
42
42
|
* @returns {Promise<Object>} - The response data containing the access token.
|
|
43
43
|
*/
|
|
44
44
|
async function exchangeToken(
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
45
|
+
authUrl,
|
|
46
|
+
code,
|
|
47
|
+
clientId,
|
|
48
|
+
clientSecret,
|
|
49
|
+
redirectUri
|
|
50
50
|
) {
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
51
|
+
try {
|
|
52
|
+
const response = await axios.post(
|
|
53
|
+
authUrl + "/api/v1/auth/authorize",
|
|
54
|
+
{
|
|
55
|
+
grantType: "authorization_code",
|
|
56
|
+
code: code,
|
|
57
|
+
redirectUri: redirectUri,
|
|
58
|
+
clientId: clientId,
|
|
59
|
+
clientSecret: clientSecret,
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
headers: {"Content-Type": "application/json"},
|
|
63
|
+
}
|
|
64
|
+
);
|
|
64
65
|
|
|
65
|
-
|
|
66
|
+
return response.data;
|
|
67
|
+
} catch (error) {
|
|
68
|
+
console.error("Error exchanging token:", error);
|
|
69
|
+
return null;
|
|
70
|
+
}
|
|
66
71
|
}
|
|
67
72
|
|
|
68
73
|
/**
|
|
@@ -71,49 +76,49 @@ async function exchangeToken(
|
|
|
71
76
|
* @returns {Function} - Express middleware function
|
|
72
77
|
*/
|
|
73
78
|
const VerifyAccount = (requiredPermissions) => {
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
+
return async (req, res, next) => {
|
|
80
|
+
const accessToken = req.headers.authorization?.split(" ")[1];
|
|
81
|
+
if (!accessToken) {
|
|
82
|
+
return res.status(401).json({error: "Access token is required"});
|
|
83
|
+
}
|
|
79
84
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
+
// Check if token is in cache
|
|
86
|
+
if (tokenCache.has(accessToken)) {
|
|
87
|
+
req.user = tokenCache.get(accessToken);
|
|
88
|
+
return next();
|
|
89
|
+
}
|
|
85
90
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
91
|
+
try {
|
|
92
|
+
const decoded = jwt.verify(accessToken, process.env.JWT_SECRET);
|
|
93
|
+
if (!isValid(decoded, requiredPermissions)) {
|
|
94
|
+
return res.status(403).json({error: "Invalid permissions"});
|
|
95
|
+
}
|
|
96
|
+
tokenCache.set(accessToken, decoded);
|
|
97
|
+
req.user = decoded;
|
|
98
|
+
return next();
|
|
99
|
+
} catch (error) {
|
|
100
|
+
try {
|
|
101
|
+
const userResponse = await axios.get(
|
|
102
|
+
`${process.env.AUTH_URL}/api/user`,
|
|
103
|
+
{
|
|
104
|
+
headers: {
|
|
105
|
+
Authorization: `Bearer ${accessToken}`,
|
|
106
|
+
},
|
|
107
|
+
}
|
|
108
|
+
);
|
|
104
109
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
110
|
+
if (!isValid(userResponse.data, requiredPermissions)) {
|
|
111
|
+
return res.status(403).json({error: "Invalid permissions"});
|
|
112
|
+
}
|
|
108
113
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
114
|
+
tokenCache.set(accessToken, userResponse.data);
|
|
115
|
+
req.user = userResponse.data;
|
|
116
|
+
return next();
|
|
117
|
+
} catch (networkError) {
|
|
118
|
+
return res.status(500).json({error: "Error validating token"});
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
};
|
|
117
122
|
};
|
|
118
123
|
|
|
119
124
|
/**
|
|
@@ -123,13 +128,13 @@ const VerifyAccount = (requiredPermissions) => {
|
|
|
123
128
|
* @returns {boolean} - Returns true if the decoded token has all the required permissions, false otherwise.
|
|
124
129
|
*/
|
|
125
130
|
function isValid(decodedToken, requiredPermissions) {
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
131
|
+
return requiredPermissions.every((permission) =>
|
|
132
|
+
decodedToken.permissions.includes(permission)
|
|
133
|
+
);
|
|
129
134
|
}
|
|
130
135
|
|
|
131
136
|
module.exports = {
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
137
|
+
VerifyAccount,
|
|
138
|
+
exchangeToken,
|
|
139
|
+
verifyJWT,
|
|
135
140
|
};
|