propro-utils 1.7.0 → 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.0",
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();
@@ -100,78 +100,39 @@ const setAuthCookies = async (res, tokens, account, user, appUrl) => {
100
100
 
101
101
  // Domain configuration
102
102
  let domain;
103
- let isSecureConnection = false;
104
103
  try {
105
- // Handle URLs that don't include the protocol
106
- let processedAppUrl = appUrl;
107
- if (
108
- appUrl &&
109
- !appUrl.startsWith("http://") &&
110
- !appUrl.startsWith("https://")
111
- ) {
112
- processedAppUrl = `https://${appUrl}`;
104
+ domain = appUrl ? new URL(appUrl).hostname : undefined;
105
+ if (domain?.includes('mapmap.app')) {
106
+ domain = '.mapmap.app';
113
107
  }
114
-
115
- const urlObj = new URL(processedAppUrl);
116
- domain = urlObj.hostname;
117
- isSecureConnection = urlObj.protocol === "https:";
118
-
119
- if (domain?.includes("mapmap.app")) {
120
- domain = ".mapmap.app";
121
- }
122
- if (domain?.includes("localhost")) {
108
+ if (domain?.includes('localhost')) {
123
109
  domain = undefined;
124
- isSecureConnection = false;
125
110
  }
126
- if (domain?.includes("propro.so")) {
127
- // Set root domain for all propro.so subdomains
128
- domain = ".propro.so";
111
+ if (domain?.includes('propro.so')) {
112
+ domain = 'propro.so';
129
113
  }
130
-
131
- console.log("Cookie configuration:", {
132
- domain,
133
- isSecure: isSecureConnection,
134
- protocol: urlObj.protocol,
135
- originalUrl: appUrl,
136
- processedUrl: processedAppUrl,
137
- hostname: urlObj.hostname,
138
- });
139
114
  } catch (error) {
140
- console.error("Invalid appUrl:", { error, appUrl });
115
+ console.error('Invalid appUrl:', { error, appUrl });
141
116
  domain = undefined;
142
- isSecureConnection = false;
143
117
  }
144
118
 
145
- // Determine if we're in a local development environment
146
- const isLocalhost =
147
- !domain || domain === "localhost" || domain.includes("localhost");
148
-
149
- // Base attributes that work across domains
150
119
  const commonAttributes = {
151
- secure: true, // Always use secure in production
152
- sameSite: "None", // Required for cross-domain
153
- domain: domain,
154
- path: "/",
155
- httpOnly: false,
156
- expires: new Date(Date.now() + 365 * 24 * 60 * 60 * 1000),
120
+ secure: true,
121
+ sameSite: 'None',
122
+ domain,
123
+ path: '/',
157
124
  };
158
125
 
159
126
  const httpOnlyCookies = {
160
- "x-refresh-token": {
127
+ 'x-refresh-token': {
161
128
  value: tokens.refresh.token,
162
129
  maxAge: refreshMaxAge,
163
130
  httpOnly: true,
164
- secure: true,
165
- sameSite: "None",
166
- domain: domain,
167
131
  },
168
- "x-access-token": {
132
+ 'x-access-token': {
169
133
  value: tokens.access.token,
170
134
  maxAge: accessMaxAge,
171
135
  httpOnly: true,
172
- secure: true,
173
- sameSite: "None",
174
- domain: domain,
175
136
  },
176
137
  };
177
138
 
@@ -183,80 +144,47 @@ const setAuthCookies = async (res, tokens, account, user, appUrl) => {
183
144
  user: {
184
145
  value: safeStringify(sanitizedUser),
185
146
  maxAge: refreshMaxAge,
186
- httpOnly: false,
187
- secure: true,
188
- sameSite: "None",
189
- domain: domain,
190
147
  },
191
148
  account: {
192
149
  value: safeStringify(sanitizedAccount),
193
150
  maxAge: refreshMaxAge,
194
- httpOnly: false,
195
- secure: true,
196
- sameSite: "None",
197
- domain: domain,
198
151
  },
199
152
  has_account_token: {
200
- value: JSON.stringify({ value: "true", expires: accessMaxAge }),
153
+ value: JSON.stringify({ value: 'true', expires: accessMaxAge }),
201
154
  maxAge: accessMaxAge,
202
- httpOnly: false,
203
- secure: true,
204
- sameSite: "None",
205
- domain: domain,
206
155
  },
207
156
  };
208
157
 
209
158
  try {
210
- // Set each cookie individually with full attributes
211
159
  Object.entries({ ...httpOnlyCookies, ...regularCookies }).forEach(
212
160
  ([name, config]) => {
213
- // Ensure all required attributes are explicitly set
214
- const cookieConfig = {
161
+ res.cookie(name, config.value, {
215
162
  ...commonAttributes,
216
163
  ...config,
217
- domain: domain, // Explicitly set domain for each cookie
218
- };
219
-
220
- res.cookie(name, config.value, cookieConfig);
221
-
222
- // Also try setting without domain for root domain
223
- if (domain === ".propro.so") {
224
- const rootConfig = { ...cookieConfig };
225
- delete rootConfig.domain;
226
- res.cookie(name, config.value, rootConfig);
227
- }
164
+ });
228
165
  }
229
166
  );
230
167
 
231
- // Skip extension cookie setting if not in extension context
232
- try {
233
- const extensionCookiePromises = Object.entries({
234
- ...httpOnlyCookies,
235
- ...regularCookies,
236
- }).map(([name, config]) => {
237
- return setChromeExtensionCookie({
238
- url: `https://${
239
- domain?.startsWith(".") ? domain.slice(1) : domain || "propro.so"
240
- }`,
241
- name,
242
- value: config.value,
243
- secure: true,
244
- httpOnly: !!config.httpOnly,
245
- sameSite: "no_restriction",
246
- path: "/",
247
- expirationDate: Math.floor((Date.now() + config.maxAge) / 1000),
248
- domain: domain,
249
- });
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'}`,
250
182
  });
183
+ });
251
184
 
252
- Promise.allSettled(extensionCookiePromises).catch(() => {
253
- // Ignore extension errors
254
- });
255
- } catch (error) {
256
- // Ignore extension errors
257
- }
185
+ await Promise.allSettled(extensionCookiePromises);
258
186
 
259
- console.log("Auth cookies set successfully", {
187
+ console.log('Auth cookies set successfully', {
260
188
  domain,
261
189
  sameSite: commonAttributes.sameSite,
262
190
  cookieNames: [
@@ -265,11 +193,11 @@ const setAuthCookies = async (res, tokens, account, user, appUrl) => {
265
193
  ],
266
194
  });
267
195
  } catch (error) {
268
- console.error("Error setting cookies:", {
196
+ console.error('Error setting cookies:', {
269
197
  error: error.message,
270
198
  stack: error.stack,
271
199
  });
272
- throw new Error("Failed to set authentication cookies");
200
+ throw new Error('Failed to set authentication cookies');
273
201
  }
274
202
  };
275
203
 
@@ -278,104 +206,59 @@ const setAuthCookies = async (res, tokens, account, user, appUrl) => {
278
206
  */
279
207
  const clearAuthCookies = async (res, appUrl) => {
280
208
  let domain;
281
- let isSecureConnection = false;
282
209
  try {
283
- // Handle URLs that don't include the protocol
284
- let processedAppUrl = appUrl;
285
- if (
286
- appUrl &&
287
- !appUrl.startsWith("http://") &&
288
- !appUrl.startsWith("https://")
289
- ) {
290
- processedAppUrl = `https://${appUrl}`;
210
+ domain = appUrl ? new URL(appUrl).hostname : undefined;
211
+ if (domain?.includes('mapmap.app')) {
212
+ domain = '.mapmap.app';
291
213
  }
292
-
293
- const urlObj = new URL(processedAppUrl);
294
- domain = urlObj.hostname;
295
- isSecureConnection = urlObj.protocol === "https:";
296
-
297
- if (domain?.includes("mapmap.app")) {
298
- domain = ".mapmap.app";
299
- }
300
- if (domain?.includes("localhost")) {
214
+ if (domain?.includes('localhost')) {
301
215
  domain = undefined;
302
- isSecureConnection = false;
303
- }
304
- if (domain?.includes("propro.so")) {
305
- domain = ".propro.so";
306
216
  }
307
-
308
- console.log("Clear cookies configuration:", {
309
- domain,
310
- isSecure: isSecureConnection,
311
- protocol: urlObj.protocol,
312
- originalUrl: appUrl,
313
- processedUrl: processedAppUrl,
314
- hostname: urlObj.hostname,
315
- });
316
217
  } catch (error) {
317
- console.error("Invalid appUrl:", error);
218
+ console.error('Invalid appUrl:', error);
318
219
  domain = undefined;
319
- isSecureConnection = false;
320
220
  }
321
221
 
322
222
  const commonAttributes = {
323
223
  secure: true,
324
- sameSite: "None",
325
- domain: domain,
326
- path: "/",
327
- httpOnly: false,
328
- expires: new Date(0),
224
+ sameSite: 'None',
225
+ domain,
226
+ path: '/',
329
227
  };
330
228
 
331
229
  const cookieNames = [
332
- "x-refresh-token",
333
- "x-access-token",
334
- "user",
335
- "account",
336
- "has_account_token",
230
+ 'x-refresh-token',
231
+ 'x-access-token',
232
+ 'user',
233
+ 'account',
234
+ 'has_account_token',
337
235
  ];
338
236
 
339
- // Clear cookies with domain
340
- cookieNames.forEach((cookieName) => {
237
+ // Clear web cookies
238
+ cookieNames.forEach(cookieName => {
341
239
  res.clearCookie(cookieName, commonAttributes);
342
-
343
- // Also try clearing without domain for root domain
344
- if (domain === ".propro.so") {
345
- const rootAttributes = { ...commonAttributes };
346
- delete rootAttributes.domain;
347
- res.clearCookie(cookieName, rootAttributes);
348
- }
349
240
  });
350
241
 
351
242
  try {
352
- // Skip extension cookie clearing if not in extension context
353
243
  const extensionClearPromises = cookieNames.map(
354
- (name) =>
355
- new Promise((resolve) => {
244
+ name =>
245
+ new Promise(resolve => {
356
246
  chrome.cookies.remove(
357
247
  {
358
- url: `https://${
359
- domain?.startsWith(".")
360
- ? domain.slice(1)
361
- : domain || "propro.so"
362
- }`,
248
+ url: `https://${domain || 'mapmap.app'}`,
363
249
  name,
364
- domain: domain,
365
250
  },
366
251
  resolve
367
252
  );
368
253
  })
369
254
  );
370
255
 
371
- Promise.allSettled(extensionClearPromises).catch(() => {
372
- // Ignore extension errors
373
- });
256
+ await Promise.allSettled(extensionClearPromises);
374
257
  } catch (error) {
375
258
  // Not in extension context, ignore
376
259
  }
377
260
 
378
- console.log("Auth cookies cleared successfully", {
261
+ console.log('Auth cookies cleared successfully', {
379
262
  domain,
380
263
  cookieNames,
381
264
  sameSite: commonAttributes.sameSite,