propro-utils 1.6.3 → 1.6.4

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "propro-utils",
3
- "version": "1.6.3",
3
+ "version": "1.6.4",
4
4
  "description": "Auth middleware for propro-auth",
5
5
  "main": "src/index.js",
6
6
  "scripts": {
@@ -46,6 +46,7 @@
46
46
  "jest-mock-axios": "^4.7.3",
47
47
  "jsonwebtoken": "^9.0.2",
48
48
  "multer": "^1.4.5-lts.1",
49
+ "neverthrow": "^8.2.0",
49
50
  "nodemailer": "^6.9.7",
50
51
  "nodemailer-mailgun-transport": "^2.1.5",
51
52
  "querystring": "^0.2.1",
@@ -3,19 +3,19 @@
3
3
  * This module provides functions for setting and clearing authentication cookies.
4
4
  */
5
5
 
6
- const { URL } = require('url');
6
+ const { URL } = require("url");
7
7
 
8
8
  /**
9
9
  * Safely stringify an object, handling circular references
10
10
  * @param {Object} obj - The object to stringify
11
11
  * @return {string} A JSON string representation of the object
12
12
  */
13
- const safeStringify = obj => {
13
+ const safeStringify = (obj) => {
14
14
  const seen = new WeakSet();
15
15
  return JSON.stringify(obj, (key, value) => {
16
- if (typeof value === 'object' && value !== null) {
16
+ if (typeof value === "object" && value !== null) {
17
17
  if (seen.has(value)) {
18
- return '[Circular]';
18
+ return "[Circular]";
19
19
  }
20
20
  seen.add(value);
21
21
  }
@@ -28,7 +28,7 @@ const safeStringify = obj => {
28
28
  * @param {Object} user - The user object to sanitize
29
29
  * @return {Object} A sanitized version of the user object
30
30
  */
31
- const sanitizeUser = user => {
31
+ const sanitizeUser = (user) => {
32
32
  const sanitized = { ...user };
33
33
 
34
34
  delete sanitized.password;
@@ -61,10 +61,10 @@ const sanitizeUser = user => {
61
61
  * @param {Object} details - Cookie details
62
62
  * @returns {Promise} Promise that resolves when cookie is set
63
63
  */
64
- const setChromeExtensionCookie = details => {
64
+ const setChromeExtensionCookie = (details) => {
65
65
  return new Promise((resolve, reject) => {
66
66
  try {
67
- chrome.cookies.set(details, cookie => {
67
+ chrome.cookies.set(details, (cookie) => {
68
68
  if (chrome.runtime.lastError) {
69
69
  reject(chrome.runtime.lastError);
70
70
  } else {
@@ -83,13 +83,13 @@ const setChromeExtensionCookie = details => {
83
83
  */
84
84
  const setAuthCookies = async (res, tokens, account, user, appUrl) => {
85
85
  if (!tokens?.refresh?.token || !tokens?.access?.token) {
86
- throw new Error('Invalid tokens object');
86
+ throw new Error("Invalid tokens object");
87
87
  }
88
88
  if (!account) {
89
- throw new Error('Invalid account object');
89
+ throw new Error("Invalid account object");
90
90
  }
91
91
  if (!user) {
92
- throw new Error('Invalid user object');
92
+ throw new Error("Invalid user object");
93
93
  }
94
94
 
95
95
  const currentDateTime = new Date();
@@ -102,34 +102,38 @@ const setAuthCookies = async (res, tokens, account, user, appUrl) => {
102
102
  let domain;
103
103
  try {
104
104
  domain = appUrl ? new URL(appUrl).hostname : undefined;
105
- if (domain?.includes('mapmap.app')) {
106
- domain = '.mapmap.app';
105
+ if (domain?.includes("mapmap.app")) {
106
+ domain = ".mapmap.app";
107
107
  }
108
- if (domain?.includes('localhost')) {
108
+ if (domain?.includes("localhost")) {
109
109
  domain = undefined;
110
110
  }
111
- if (domain?.includes('propro.so')) {
112
- domain = 'propro.so';
111
+ if (domain?.includes("propro.so")) {
112
+ domain = "propro.so";
113
113
  }
114
114
  } catch (error) {
115
- console.error('Invalid appUrl:', { error, appUrl });
115
+ console.error("Invalid appUrl:", { error, appUrl });
116
116
  domain = undefined;
117
117
  }
118
118
 
119
+ // Determine if we're in a local development environment
120
+ const isLocalhost =
121
+ !domain || domain === "localhost" || domain.includes("localhost");
122
+
119
123
  const commonAttributes = {
120
- secure: true,
121
- sameSite: 'None',
124
+ secure: !isLocalhost, // Only require secure for non-localhost environments
125
+ sameSite: isLocalhost ? "Lax" : "None", // Use Lax for localhost, None for production
122
126
  domain,
123
- path: '/',
127
+ path: "/",
124
128
  };
125
129
 
126
130
  const httpOnlyCookies = {
127
- 'x-refresh-token': {
131
+ "x-refresh-token": {
128
132
  value: tokens.refresh.token,
129
133
  maxAge: refreshMaxAge,
130
134
  httpOnly: true,
131
135
  },
132
- 'x-access-token': {
136
+ "x-access-token": {
133
137
  value: tokens.access.token,
134
138
  maxAge: accessMaxAge,
135
139
  httpOnly: true,
@@ -150,7 +154,7 @@ const setAuthCookies = async (res, tokens, account, user, appUrl) => {
150
154
  maxAge: refreshMaxAge,
151
155
  },
152
156
  has_account_token: {
153
- value: JSON.stringify({ value: 'true', expires: accessMaxAge }),
157
+ value: JSON.stringify({ value: "true", expires: accessMaxAge }),
154
158
  maxAge: accessMaxAge,
155
159
  },
156
160
  };
@@ -170,21 +174,21 @@ const setAuthCookies = async (res, tokens, account, user, appUrl) => {
170
174
  ...regularCookies,
171
175
  }).map(([name, config]) => {
172
176
  return setChromeExtensionCookie({
173
- url: `https://${domain || 'propro.so'}`,
177
+ url: `https://${domain || "propro.so"}`,
174
178
  name,
175
179
  value: config.value,
176
180
  secure: true,
177
181
  httpOnly: !!config.httpOnly,
178
- sameSite: 'no_restriction',
179
- path: '/',
182
+ sameSite: "no_restriction",
183
+ path: "/",
180
184
  expirationDate: Math.floor((Date.now() + config.maxAge) / 1000),
181
- domain: domain?.startsWith('.') ? domain : `.${domain || 'propro.so'}`,
185
+ domain: domain?.startsWith(".") ? domain : `.${domain || "propro.so"}`,
182
186
  });
183
187
  });
184
188
 
185
189
  await Promise.allSettled(extensionCookiePromises);
186
190
 
187
- console.log('Auth cookies set successfully', {
191
+ console.log("Auth cookies set successfully", {
188
192
  domain,
189
193
  sameSite: commonAttributes.sameSite,
190
194
  cookieNames: [
@@ -193,11 +197,11 @@ const setAuthCookies = async (res, tokens, account, user, appUrl) => {
193
197
  ],
194
198
  });
195
199
  } catch (error) {
196
- console.error('Error setting cookies:', {
200
+ console.error("Error setting cookies:", {
197
201
  error: error.message,
198
202
  stack: error.stack,
199
203
  });
200
- throw new Error('Failed to set authentication cookies');
204
+ throw new Error("Failed to set authentication cookies");
201
205
  }
202
206
  };
203
207
 
@@ -208,44 +212,48 @@ const clearAuthCookies = async (res, appUrl) => {
208
212
  let domain;
209
213
  try {
210
214
  domain = appUrl ? new URL(appUrl).hostname : undefined;
211
- if (domain?.includes('mapmap.app')) {
212
- domain = '.mapmap.app';
215
+ if (domain?.includes("mapmap.app")) {
216
+ domain = ".mapmap.app";
213
217
  }
214
- if (domain?.includes('localhost')) {
218
+ if (domain?.includes("localhost")) {
215
219
  domain = undefined;
216
220
  }
217
221
  } catch (error) {
218
- console.error('Invalid appUrl:', error);
222
+ console.error("Invalid appUrl:", error);
219
223
  domain = undefined;
220
224
  }
221
225
 
226
+ // Determine if we're in a local development environment
227
+ const isLocalhost =
228
+ !domain || domain === "localhost" || domain.includes("localhost");
229
+
222
230
  const commonAttributes = {
223
- secure: true,
224
- sameSite: 'None',
231
+ secure: !isLocalhost, // Only require secure for non-localhost environments
232
+ sameSite: isLocalhost ? "Lax" : "None", // Use Lax for localhost, None for production
225
233
  domain,
226
- path: '/',
234
+ path: "/",
227
235
  };
228
236
 
229
237
  const cookieNames = [
230
- 'x-refresh-token',
231
- 'x-access-token',
232
- 'user',
233
- 'account',
234
- 'has_account_token',
238
+ "x-refresh-token",
239
+ "x-access-token",
240
+ "user",
241
+ "account",
242
+ "has_account_token",
235
243
  ];
236
244
 
237
245
  // Clear web cookies
238
- cookieNames.forEach(cookieName => {
246
+ cookieNames.forEach((cookieName) => {
239
247
  res.clearCookie(cookieName, commonAttributes);
240
248
  });
241
249
 
242
250
  try {
243
251
  const extensionClearPromises = cookieNames.map(
244
- name =>
245
- new Promise(resolve => {
252
+ (name) =>
253
+ new Promise((resolve) => {
246
254
  chrome.cookies.remove(
247
255
  {
248
- url: `https://${domain || 'mapmap.app'}`,
256
+ url: `https://${domain || "mapmap.app"}`,
249
257
  name,
250
258
  },
251
259
  resolve
@@ -258,7 +266,7 @@ const clearAuthCookies = async (res, appUrl) => {
258
266
  // Not in extension context, ignore
259
267
  }
260
268
 
261
- console.log('Auth cookies cleared successfully', {
269
+ console.log("Auth cookies cleared successfully", {
262
270
  domain,
263
271
  cookieNames,
264
272
  sameSite: commonAttributes.sameSite,