propro-utils 1.7.1 → 1.7.2

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,11 +1,11 @@
1
- require("dotenv").config();
2
- const axios = require("axios");
3
- const { getOrSetCache } = require("../utils/redis");
4
- const { v4: uuidv4 } = require("uuid");
5
- const ServiceManager = require("../utils/serviceManager");
1
+ require('dotenv').config();
2
+ const axios = require('axios');
3
+ const { getOrSetCache } = require('../utils/redis');
4
+ const { v4: uuidv4 } = require('uuid');
5
+ const ServiceManager = require('../utils/serviceManager');
6
6
  const defaultUserGlobalStyleShortcuts =
7
- require("./defaultUserGlobalStyleShortcuts.json").defaultGlobalStyleShortcuts;
8
- const defaultFolders = require("./defaultFolders.json").defaultFolders;
7
+ require('./defaultUserGlobalStyleShortcuts.json').defaultGlobalStyleShortcuts;
8
+ const defaultFolders = require('./defaultFolders.json').defaultFolders;
9
9
 
10
10
  /**
11
11
  * Retrieves the account profile data from the authentication server and caches it using Redis.
@@ -20,10 +20,10 @@ const defaultFolders = require("./defaultFolders.json").defaultFolders;
20
20
  const getAccountProfile = async (redisClient, userSchema, accountId) => {
21
21
  try {
22
22
  const accessToken =
23
- req.cookies["x-access-token"] || req.headers.authorization?.split(" ")[1];
23
+ req.cookies['x-access-token'] || req.headers.authorization?.split(' ')[1];
24
24
 
25
25
  if (!accessToken) {
26
- throw new Error("Access token is required");
26
+ throw new Error('Access token is required');
27
27
  }
28
28
 
29
29
  const fetchPermission = async () => {
@@ -49,7 +49,7 @@ const getAccountProfile = async (redisClient, userSchema, accountId) => {
49
49
  );
50
50
 
51
51
  if (!profileData) {
52
- throw new Error("Invalid permissions");
52
+ throw new Error('Invalid permissions');
53
53
  }
54
54
 
55
55
  return profileData;
@@ -57,10 +57,58 @@ const getAccountProfile = async (redisClient, userSchema, accountId) => {
57
57
  if (error.response && error.response.status) {
58
58
  throw new Error(error.response.data.message);
59
59
  }
60
- throw new Error("Error validating token");
60
+ throw new Error('Error validating token');
61
61
  }
62
62
  };
63
63
 
64
+ /**
65
+ * Consolidates multiple UserGlobalStyles documents for an account into one
66
+ * @param {string} accountId - The account ID to consolidate styles for
67
+ * @returns {Promise<Object>} The consolidated UserGlobalStyles document
68
+ */
69
+ async function consolidateGlobalStyles(accountId) {
70
+ const userStyleSchema = await ServiceManager.getService('UserStyleSchema');
71
+
72
+ // Find all global styles for this account
73
+ const allStyles = await userStyleSchema
74
+ .find({ accountId })
75
+ .sort({ createdAt: 1 });
76
+
77
+ if (allStyles.length <= 1) {
78
+ return allStyles[0];
79
+ }
80
+
81
+ // Use the first document as the main one and merge shortcuts from others
82
+ const mainStyle = allStyles[0];
83
+ const uniqueShortcuts = new Map();
84
+
85
+ // Merge all shortcuts, keeping the latest version of each shortcut by ID
86
+ allStyles.forEach(style => {
87
+ style.styleShortcuts.forEach(shortcut => {
88
+ uniqueShortcuts.set(shortcut.id.toString(), shortcut);
89
+ });
90
+ });
91
+
92
+ // Update the main style document with consolidated shortcuts
93
+ mainStyle.styleShortcuts = Array.from(uniqueShortcuts.values());
94
+ await mainStyle.save();
95
+
96
+ // Delete other style documents
97
+ await userStyleSchema.deleteMany({
98
+ accountId,
99
+ _id: { $ne: mainStyle._id },
100
+ });
101
+
102
+ // Update user reference if needed
103
+ const userSchema = await ServiceManager.getService('UserSchema');
104
+ await userSchema.updateMany(
105
+ { accountId },
106
+ { userGlobalStyles: mainStyle._id }
107
+ );
108
+
109
+ return mainStyle;
110
+ }
111
+
64
112
  /**
65
113
  * Creates a new user global styles document with default style shortcuts.
66
114
  *
@@ -69,6 +117,13 @@ const getAccountProfile = async (redisClient, userSchema, accountId) => {
69
117
  * @returns {Promise<Object>} A promise that resolves to the created user global styles object.
70
118
  */
71
119
  async function createUserGlobalStyles(userStyleSchema, accountId) {
120
+ // First check if any existing styles need to be consolidated
121
+ const existingStyles = await userStyleSchema.find({ accountId });
122
+
123
+ if (existingStyles.length > 0) {
124
+ return await consolidateGlobalStyles(accountId);
125
+ }
126
+
72
127
  return await userStyleSchema.create({
73
128
  id: uuidv4(),
74
129
  styleShortcuts: defaultUserGlobalStyleShortcuts,
@@ -85,8 +140,8 @@ async function createUserGlobalStyles(userStyleSchema, accountId) {
85
140
  */
86
141
  async function createDefaultFolders(folderSchema, accountId) {
87
142
  try {
88
- console.log("Creating default folders for user:", accountId);
89
- const folderPromises = defaultFolders.map((folder) =>
143
+ console.log('Creating default folders for user:', accountId);
144
+ const folderPromises = defaultFolders.map(folder =>
90
145
  folderSchema.create({
91
146
  ...folder,
92
147
  user_id: accountId,
@@ -94,17 +149,17 @@ async function createDefaultFolders(folderSchema, accountId) {
94
149
  );
95
150
  return Promise.all(folderPromises);
96
151
  } catch (error) {
97
- console.error("Error in createDefaultFolders:", error);
98
- throw new Error("Failed to create default folders");
152
+ console.error('Error in createDefaultFolders:', error);
153
+ throw new Error('Failed to create default folders');
99
154
  }
100
155
  }
101
156
 
102
157
  const DEFAULT_THEME = {
103
- canvasBackground: "#000000",
158
+ canvasBackground: '#1E1D1D',
104
159
  defaultItemWidth: 200,
105
- defaultColor: "#ffffff",
106
- fontSize: "16px",
107
- name: "Default Theme",
160
+ defaultColor: '#ffffff',
161
+ fontSize: '16px',
162
+ name: 'Default Theme',
108
163
  isDefault: true,
109
164
  };
110
165
 
@@ -116,152 +171,79 @@ const DEFAULT_THEME = {
116
171
  * @returns {Promise<Object>} A promise that resolves to the complete user object
117
172
  * @throws {Error} If there's an issue with database operations or invalid input
118
173
  */
119
- const checkIfUserExists = async (accountId) => {
120
- console.log("Starting checkIfUserExists for accountId:", accountId);
121
-
174
+ const checkIfUserExists = async accountId => {
122
175
  // Input validation
123
- if (!accountId || typeof accountId !== "string") {
124
- console.warn("Invalid accountId provided:", accountId);
125
- throw new Error("Invalid accountId provided");
176
+ if (!accountId || typeof accountId !== 'string') {
177
+ console.warn('Invalid accountId provided:', accountId);
178
+ throw new Error('Invalid accountId provided');
126
179
  }
127
180
 
128
181
  try {
129
- console.log("Loading schemas...");
130
- // Load all required schemas in parallel
131
182
  const schemaResults = await Promise.all([
132
- ServiceManager.getService("UserSchema"),
133
- ServiceManager.getService("UserStyleSchema"),
134
- ServiceManager.getService("FolderSchema"),
135
- ServiceManager.getService("ThemeSchema"),
183
+ ServiceManager.getService('UserSchema'),
184
+ ServiceManager.getService('UserStyleSchema'),
185
+ ServiceManager.getService('FolderSchema'),
186
+ ServiceManager.getService('ThemeSchema'),
136
187
  ]);
137
188
 
138
189
  const [userSchema, userStyleSchema, folderSchema, themeSchema] =
139
190
  schemaResults;
140
191
 
141
- // Log the status of each schema
142
- console.log("Schema loading results:", {
143
- userSchema: userSchema ? "Loaded" : "Not available",
144
- userStyleSchema: userStyleSchema ? "Loaded" : "Not available",
145
- folderSchema: folderSchema ? "Loaded" : "Not available",
146
- themeSchema: themeSchema ? "Loaded" : "Not available",
147
- });
148
-
149
192
  if (!userSchema) {
150
- throw new Error("UserSchema service not available");
193
+ throw new Error('UserSchema service not available');
151
194
  }
152
195
 
153
196
  // Optional schemas warning
154
197
  if (!userStyleSchema) {
155
198
  console.warn(
156
- "UserStyleSchema service not available - style features will be skipped"
199
+ 'UserStyleSchema service not available - style features will be skipped'
157
200
  );
158
201
  }
159
202
  if (!folderSchema) {
160
203
  console.warn(
161
- "FolderSchema service not available - folder features will be skipped"
204
+ 'FolderSchema service not available - folder features will be skipped'
162
205
  );
163
206
  }
164
207
  if (!themeSchema) {
165
208
  console.warn(
166
- "ThemeSchema service not available - theme features will be skipped"
209
+ 'ThemeSchema service not available - theme features will be skipped'
167
210
  );
168
211
  }
169
212
 
170
- console.log("Schema loading and validation complete");
171
-
172
- // Find existing user without excluding fields we need to check
173
- const user = await userSchema.findOne({ accountId }).lean();
174
-
175
- console.log("User lookup result:", user ? "User found" : "User not found");
213
+ // Find existing user with populated fields
214
+ const user = await userSchema
215
+ .findOne({ accountId })
216
+ .select('-theme -folderList -userGlobalStyles -mapList')
217
+ .lean();
176
218
 
177
219
  if (user) {
178
- console.log("Updating existing user data...");
179
220
  const updates = [];
180
221
 
181
- // Handle userGlobalStyles - check properly if styles exist in the database
222
+ // Handle userGlobalStyles
182
223
  if (userStyleSchema) {
183
- // Check if the user has a userGlobalStyles reference
184
- const hasStyleReference = user.userGlobalStyles != null;
185
-
186
- if (hasStyleReference) {
187
- // Verify the referenced style document actually exists
188
- const styleExists = await userStyleSchema.exists({
189
- _id: user.userGlobalStyles,
190
- });
191
-
192
- if (!styleExists) {
193
- console.log(
194
- "User has style reference but document not found, creating new styles..."
195
- );
196
- updates.push(
197
- createUserGlobalStyles(userStyleSchema, accountId).then(
198
- async (styles) => {
199
- console.log("UserGlobalStyles created successfully");
200
- await userSchema.updateOne(
201
- { _id: user._id },
202
- { userGlobalStyles: styles._id }
203
- );
204
- return styles;
205
- }
206
- )
207
- );
208
- } else {
209
- // Style exists, check if it has shortcuts
210
- const styleDoc = await userStyleSchema.findById(
211
- user.userGlobalStyles
212
- );
213
- if (
214
- !styleDoc.styleShortcuts ||
215
- styleDoc.styleShortcuts.length === 0
216
- ) {
217
- console.log("Updating empty styleShortcuts with defaults...");
218
- updates.push(
219
- userStyleSchema.updateOne(
220
- { _id: user.userGlobalStyles },
221
- { styleShortcuts: defaultUserGlobalStyleShortcuts }
222
- )
223
- );
224
- }
225
- }
226
- } else {
227
- // No style reference, create new styles
228
- console.log("Creating missing userGlobalStyles...");
229
- updates.push(
230
- createUserGlobalStyles(userStyleSchema, accountId).then(
231
- async (styles) => {
232
- console.log("UserGlobalStyles created successfully");
233
- await userSchema.updateOne(
234
- { _id: user._id },
235
- { userGlobalStyles: styles._id }
236
- );
237
- return styles;
238
- }
239
- )
240
- );
241
- }
224
+ // Consolidate any duplicate global styles
225
+ await consolidateGlobalStyles(accountId);
242
226
  }
243
227
 
244
228
  // Handle folders
245
229
  if (folderSchema) {
246
- console.log("Checking folders...");
247
230
  updates.push(
248
231
  (async () => {
249
232
  const existingFolders = await folderSchema
250
233
  .find({ user_id: user.id })
251
- .select("name")
234
+ .select('name')
252
235
  .lean();
253
236
 
254
- console.log("Existing folders count:", existingFolders.length);
255
237
  const existingFolderNames = new Set(
256
- existingFolders.map((f) => f.name)
238
+ existingFolders.map(f => f.name)
257
239
  );
258
240
  const foldersToCreate = defaultFolders.filter(
259
- (folder) => !existingFolderNames.has(folder.name)
241
+ folder => !existingFolderNames.has(folder.name)
260
242
  );
261
243
 
262
244
  if (foldersToCreate.length > 0) {
263
245
  return folderSchema.insertMany(
264
- foldersToCreate.map((folder) => ({
246
+ foldersToCreate.map(folder => ({
265
247
  ...folder,
266
248
  user_id: user.id,
267
249
  }))
@@ -273,15 +255,13 @@ const checkIfUserExists = async (accountId) => {
273
255
 
274
256
  // Handle themes
275
257
  if (themeSchema) {
276
- console.log("Checking themes...");
277
258
  updates.push(
278
259
  (async () => {
279
260
  const defaultThemeExists = await themeSchema.exists({
280
- name: "Default Theme",
261
+ name: 'Default Theme',
281
262
  accountId,
282
263
  });
283
264
 
284
- console.log("Default theme exists:", defaultThemeExists);
285
265
  if (!defaultThemeExists) {
286
266
  const defaultTheme = await themeSchema.create({
287
267
  ...DEFAULT_THEME,
@@ -301,12 +281,13 @@ const checkIfUserExists = async (accountId) => {
301
281
  }
302
282
 
303
283
  // Wait for all updates to complete
304
- console.log("Waiting for all updates to complete...");
305
284
  await Promise.all(updates);
306
- console.log("All updates completed successfully");
307
285
 
308
- // Return fresh user data after updates
309
- return userSchema.findOne({ accountId }).lean();
286
+ // Return fresh user data after updates, excluding specified fields
287
+ return userSchema
288
+ .findOne({ accountId })
289
+ .select('-theme -folderList -userGlobalStyles -mapList')
290
+ .lean();
310
291
  }
311
292
 
312
293
  // Create new user with all associated data
@@ -317,7 +298,7 @@ const checkIfUserExists = async (accountId) => {
317
298
  let userGlobalStyles;
318
299
  if (userStyleSchema) {
319
300
  creationTasks.push(
320
- createUserGlobalStyles(userStyleSchema, accountId).then((styles) => {
301
+ createUserGlobalStyles(userStyleSchema, accountId).then(styles => {
321
302
  userGlobalStyles = styles;
322
303
  return styles;
323
304
  })
@@ -335,8 +316,8 @@ const checkIfUserExists = async (accountId) => {
335
316
  userId,
336
317
  id: uuidv4(),
337
318
  })
338
- .then((theme) => {
339
- console.log("Created theme:", theme);
319
+ .then(theme => {
320
+ console.log('Created theme:', theme);
340
321
  defaultTheme = theme;
341
322
  return theme;
342
323
  })
@@ -360,10 +341,12 @@ const checkIfUserExists = async (accountId) => {
360
341
  await createDefaultFolders(folderSchema, newUser.id);
361
342
  }
362
343
 
363
- console.log("Operation completed successfully");
364
- return userSchema.findById(newUser._id).lean();
344
+ return userSchema
345
+ .findById(newUser._id)
346
+ .select('-theme -folderList -userGlobalStyles -mapList')
347
+ .lean();
365
348
  } catch (error) {
366
- console.error("Detailed error in checkIfUserExists:", {
349
+ console.error('Detailed error in checkIfUserExists:', {
367
350
  accountId,
368
351
  errorName: error.name,
369
352
  errorMessage: error.message,
@@ -374,7 +357,44 @@ const checkIfUserExists = async (accountId) => {
374
357
  }
375
358
  };
376
359
 
360
+ const updateUserGlobalStyleShortcuts = async (userId, shortcutId, shortcut) => {
361
+ try {
362
+ const user = await userSchema
363
+ .findOne({ id: userId })
364
+ .populate('userGlobalStyles');
365
+ if (!user) {
366
+ throw new Error('User not found');
367
+ }
368
+
369
+ // Ensure we have consolidated styles
370
+ const consolidatedStyles = await consolidateGlobalStyles(user.accountId);
371
+
372
+ // Find the index of the shortcut to update
373
+ const shortcutIndex = consolidatedStyles.styleShortcuts.findIndex(
374
+ s => s.id.toString() === shortcutId
375
+ );
376
+
377
+ if (shortcutIndex === -1) {
378
+ // If the shortcut doesn't exist, add it
379
+ consolidatedStyles.styleShortcuts.push(shortcut);
380
+ } else {
381
+ // If the shortcut exists, update it
382
+ consolidatedStyles.styleShortcuts[shortcutIndex] = {
383
+ ...consolidatedStyles.styleShortcuts[shortcutIndex],
384
+ ...shortcut,
385
+ };
386
+ }
387
+
388
+ await consolidatedStyles.save();
389
+ return consolidatedStyles;
390
+ } catch (error) {
391
+ console.error('Error updating user global style shortcuts:', error);
392
+ throw error;
393
+ }
394
+ };
395
+
377
396
  module.exports = {
378
397
  getAccountProfile,
379
398
  checkIfUserExists,
399
+ updateUserGlobalStyleShortcuts,
380
400
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "propro-utils",
3
- "version": "1.7.1",
3
+ "version": "1.7.2",
4
4
  "description": "Auth middleware for propro-auth",
5
5
  "main": "src/index.js",
6
6
  "scripts": {
@@ -46,7 +46,6 @@
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",
50
49
  "nodemailer": "^6.9.7",
51
50
  "nodemailer-mailgun-transport": "^2.1.5",
52
51
  "querystring": "^0.2.1",
@@ -168,7 +168,7 @@ class AuthMiddleware {
168
168
 
169
169
  setAuthCookies(res, tokens, account, user, this.options.appUrl);
170
170
 
171
- res.redirect(formatRedirectUrl(this.options.appUrl));
171
+ res.redirect(formatRedirectUrl(this.options.redirectUri));
172
172
  } catch (error) {
173
173
  console.error('Error in callback:', error);
174
174
  res.status(500).send('Internal Server Error');
@@ -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();
@@ -99,47 +99,37 @@ const setAuthCookies = async (res, tokens, account, user, appUrl) => {
99
99
  new Date(tokens.access.expires).getTime() - currentDateTime.getTime();
100
100
 
101
101
  // Domain configuration
102
- let isSecureConnection = false;
102
+ let domain;
103
103
  try {
104
- // Handle URLs that don't include the protocol
105
- let processedAppUrl = appUrl;
106
- if (
107
- appUrl &&
108
- !appUrl.startsWith("http://") &&
109
- !appUrl.startsWith("https://")
110
- ) {
111
- processedAppUrl = `https://${appUrl}`;
104
+ domain = appUrl ? new URL(appUrl).hostname : undefined;
105
+ if (domain?.includes('mapmap.app')) {
106
+ domain = '.mapmap.app';
107
+ }
108
+ if (domain?.includes('localhost')) {
109
+ domain = undefined;
110
+ }
111
+ if (domain?.includes('propro.so')) {
112
+ domain = 'propro.so';
112
113
  }
113
-
114
- const urlObj = new URL(processedAppUrl);
115
- isSecureConnection = urlObj.protocol === "https:";
116
-
117
- console.log("Cookie configuration:", {
118
- isSecure: isSecureConnection,
119
- protocol: urlObj.protocol,
120
- originalUrl: appUrl,
121
- processedUrl: processedAppUrl,
122
- hostname: urlObj.hostname,
123
- });
124
114
  } catch (error) {
125
- console.error("Invalid appUrl:", { error, appUrl });
126
- isSecureConnection = false;
115
+ console.error('Invalid appUrl:', { error, appUrl });
116
+ domain = undefined;
127
117
  }
128
118
 
129
- // Base cookie attributes without domain specification
130
119
  const commonAttributes = {
131
120
  secure: true,
132
- sameSite: "None",
133
- path: "/",
121
+ sameSite: 'None',
122
+ domain,
123
+ path: '/',
134
124
  };
135
125
 
136
126
  const httpOnlyCookies = {
137
- "x-refresh-token": {
127
+ 'x-refresh-token': {
138
128
  value: tokens.refresh.token,
139
129
  maxAge: refreshMaxAge,
140
130
  httpOnly: true,
141
131
  },
142
- "x-access-token": {
132
+ 'x-access-token': {
143
133
  value: tokens.access.token,
144
134
  maxAge: accessMaxAge,
145
135
  httpOnly: true,
@@ -154,59 +144,48 @@ const setAuthCookies = async (res, tokens, account, user, appUrl) => {
154
144
  user: {
155
145
  value: safeStringify(sanitizedUser),
156
146
  maxAge: refreshMaxAge,
157
- httpOnly: false,
158
147
  },
159
148
  account: {
160
149
  value: safeStringify(sanitizedAccount),
161
150
  maxAge: refreshMaxAge,
162
- httpOnly: false,
163
151
  },
164
152
  has_account_token: {
165
- value: JSON.stringify({ value: "true", expires: accessMaxAge }),
153
+ value: JSON.stringify({ value: 'true', expires: accessMaxAge }),
166
154
  maxAge: accessMaxAge,
167
- httpOnly: false,
168
155
  },
169
156
  };
170
157
 
171
158
  try {
172
- // Set each cookie individually
173
159
  Object.entries({ ...httpOnlyCookies, ...regularCookies }).forEach(
174
160
  ([name, config]) => {
175
- const cookieConfig = {
161
+ res.cookie(name, config.value, {
176
162
  ...commonAttributes,
177
163
  ...config,
178
- };
179
-
180
- res.cookie(name, config.value, cookieConfig);
164
+ });
181
165
  }
182
166
  );
183
167
 
184
- // Handle extension cookies if in extension context
185
- try {
186
- const extensionCookiePromises = Object.entries({
187
- ...httpOnlyCookies,
188
- ...regularCookies,
189
- }).map(([name, config]) => {
190
- return setChromeExtensionCookie({
191
- url: processedAppUrl,
192
- name,
193
- value: config.value,
194
- secure: true,
195
- httpOnly: !!config.httpOnly,
196
- sameSite: "no_restriction",
197
- path: "/",
198
- expirationDate: Math.floor((Date.now() + config.maxAge) / 1000),
199
- });
168
+ const extensionCookiePromises = Object.entries({
169
+ ...httpOnlyCookies,
170
+ ...regularCookies,
171
+ }).map(([name, config]) => {
172
+ return setChromeExtensionCookie({
173
+ url: `https://${domain || 'propro.so'}`,
174
+ name,
175
+ value: config.value,
176
+ secure: true,
177
+ httpOnly: !!config.httpOnly,
178
+ sameSite: 'no_restriction',
179
+ path: '/',
180
+ expirationDate: Math.floor((Date.now() + config.maxAge) / 1000),
181
+ domain: domain?.startsWith('.') ? domain : `.${domain || 'propro.so'}`,
200
182
  });
183
+ });
201
184
 
202
- Promise.allSettled(extensionCookiePromises).catch(() => {
203
- // Ignore extension errors
204
- });
205
- } catch (error) {
206
- // Ignore extension errors
207
- }
185
+ await Promise.allSettled(extensionCookiePromises);
208
186
 
209
- console.log("Auth cookies set successfully", {
187
+ console.log('Auth cookies set successfully', {
188
+ domain,
210
189
  sameSite: commonAttributes.sameSite,
211
190
  cookieNames: [
212
191
  ...Object.keys(httpOnlyCookies),
@@ -214,11 +193,11 @@ const setAuthCookies = async (res, tokens, account, user, appUrl) => {
214
193
  ],
215
194
  });
216
195
  } catch (error) {
217
- console.error("Error setting cookies:", {
196
+ console.error('Error setting cookies:', {
218
197
  error: error.message,
219
198
  stack: error.stack,
220
199
  });
221
- throw new Error("Failed to set authentication cookies");
200
+ throw new Error('Failed to set authentication cookies');
222
201
  }
223
202
  };
224
203
 
@@ -226,77 +205,61 @@ const setAuthCookies = async (res, tokens, account, user, appUrl) => {
226
205
  * Clears cookies from both web and extension contexts
227
206
  */
228
207
  const clearAuthCookies = async (res, appUrl) => {
229
- let isSecureConnection = false;
208
+ let domain;
230
209
  try {
231
- // Handle URLs that don't include the protocol
232
- let processedAppUrl = appUrl;
233
- if (
234
- appUrl &&
235
- !appUrl.startsWith("http://") &&
236
- !appUrl.startsWith("https://")
237
- ) {
238
- processedAppUrl = `https://${appUrl}`;
210
+ domain = appUrl ? new URL(appUrl).hostname : undefined;
211
+ if (domain?.includes('mapmap.app')) {
212
+ domain = '.mapmap.app';
213
+ }
214
+ if (domain?.includes('localhost')) {
215
+ domain = undefined;
239
216
  }
240
-
241
- const urlObj = new URL(processedAppUrl);
242
- isSecureConnection = urlObj.protocol === "https:";
243
-
244
- console.log("Clear cookies configuration:", {
245
- isSecure: isSecureConnection,
246
- protocol: urlObj.protocol,
247
- originalUrl: appUrl,
248
- processedUrl: processedAppUrl,
249
- hostname: urlObj.hostname,
250
- });
251
217
  } catch (error) {
252
- console.error("Invalid appUrl:", error);
253
- isSecureConnection = false;
218
+ console.error('Invalid appUrl:', error);
219
+ domain = undefined;
254
220
  }
255
221
 
256
222
  const commonAttributes = {
257
223
  secure: true,
258
- sameSite: "None",
259
- path: "/",
260
- expires: new Date(0),
224
+ sameSite: 'None',
225
+ domain,
226
+ path: '/',
261
227
  };
262
228
 
263
229
  const cookieNames = [
264
- "x-refresh-token",
265
- "x-access-token",
266
- "user",
267
- "account",
268
- "has_account_token",
230
+ 'x-refresh-token',
231
+ 'x-access-token',
232
+ 'user',
233
+ 'account',
234
+ 'has_account_token',
269
235
  ];
270
236
 
271
- // Clear cookies with domain
272
- cookieNames.forEach((cookieName) => {
237
+ // Clear web cookies
238
+ cookieNames.forEach(cookieName => {
273
239
  res.clearCookie(cookieName, commonAttributes);
274
240
  });
275
241
 
276
242
  try {
277
- // Handle extension cookies if in extension context
278
243
  const extensionClearPromises = cookieNames.map(
279
- (name) =>
280
- new Promise((resolve) => {
244
+ name =>
245
+ new Promise(resolve => {
281
246
  chrome.cookies.remove(
282
247
  {
283
- url: processedAppUrl,
248
+ url: `https://${domain || 'mapmap.app'}`,
284
249
  name,
285
- secure: true,
286
250
  },
287
251
  resolve
288
252
  );
289
253
  })
290
254
  );
291
255
 
292
- Promise.allSettled(extensionClearPromises).catch(() => {
293
- // Ignore extension errors
294
- });
256
+ await Promise.allSettled(extensionClearPromises);
295
257
  } catch (error) {
296
258
  // Not in extension context, ignore
297
259
  }
298
260
 
299
- console.log("Auth cookies cleared successfully", {
261
+ console.log('Auth cookies cleared successfully', {
262
+ domain,
300
263
  cookieNames,
301
264
  sameSite: commonAttributes.sameSite,
302
265
  });