Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Peter/split cookie #229

Merged
merged 17 commits into from
Nov 15, 2024
Merged

Peter/split cookie #229

merged 17 commits into from
Nov 15, 2024

Conversation

peterphanouvong
Copy link
Collaborator

@peterphanouvong peterphanouvong commented Oct 29, 2024

Explain your changes

  • split cookie to handle larger cookie sizes

Checklist

🛟 If you need help, consider asking for advice over in the Kinde community.

Copy link
Contributor

coderabbitai bot commented Oct 29, 2024

Walkthrough

The pull request introduces significant changes across multiple files, primarily focusing on the refactoring of the setup function to improve user claims retrieval from tokens. The previous asynchronous calls have been replaced with direct property accesses from the tokens. Additionally, a new factory function for organization data retrieval has been added, and enhancements to session management have been implemented, including better cookie handling and error management. The changes also include the addition of new tests for the generateOrganizationObject function and the removal of outdated tests for the generateUserObject function.

Changes

File Change Summary
src/handlers/setup.ts Refactored setup function to retrieve user claims directly from tokens; added error check for claims.
src/session/getOrganization.js Deleted file containing factory function for organization data retrieval based on session information.
src/session/getOrganization.ts Added factory function to fetch organization data using session tokens; includes error handling.
src/session/sessionManager.js Enhanced session item handling and cookie management; added MAX_LENGTH constant and splitString function. Updated methods for better error handling and cleanup.
src/utils/generateOrganizationObject.ts Introduced getOrgProperty function for modular property retrieval; modified generateOrganizationObject to use this new function.
tests/frontend/generate-organization-object.test.ts New test suite for generateOrganizationObject covering various scenarios.
tests/frontend/generate-user-object.test.ts New test suite for generateUserObject function covering various scenarios.
tests/frontend/utils.test.ts Removed entire test suite for generateUserObject function.
src/routerClients/PagesRouterClient.js Updated session management logic to use pageRouterSessionManager instead of sessionManager.
src/session/getUser.ts Modified getUserFactory to clarify handling of id_token by introducing an intermediate variable.

Possibly related PRs

Suggested reviewers

  • DaveOrDead
  • peterphanouvong

Warning

There were issues while running some tools. Please review the errors and either fix the tool’s configuration or disable the tool if it’s a critical failure.

🔧 eslint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

src/session/sessionManager.js

Oops! Something went wrong! :(

ESLint: 8.57.1

ESLint couldn't find the plugin "eslint-plugin-jest".

(The package "eslint-plugin-jest" was not found when loaded as a Node module from the directory "".)

It's likely that the plugin isn't installed correctly. Try reinstalling by running the following:

npm install eslint-plugin-jest@latest --save-dev

The plugin "eslint-plugin-jest" was referenced from the config file in ".eslintrc.json".

If you still can't figure out the problem, please stop by https://eslint.org/chat/help to chat with the team.


Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@peterphanouvong peterphanouvong marked this pull request as draft October 29, 2024 07:41
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 9

🧹 Outside diff range and nitpick comments (9)
src/utils/generateOrganizationObject.ts (1)

10-29: Consider size optimization for session storage.

Given that this PR aims to address cookie size limitations, consider implementing property filtering to reduce the size of the organization object when stored in session:

  1. Allow specifying which properties to include
  2. Omit undefined properties

Example implementation:

export const generateOrganizationObject = (
  idToken: KindeIdToken,
  accessToken: KindeAccessToken,
  // Optional parameter to specify which properties to include
  includeProperties?: OrgPropertyKey[]
) => {
  // ... existing validation ...

  const properties = Object.fromEntries(
    propertyKeys
      .filter(({ key }) => 
        !includeProperties || includeProperties.includes(key))
      .map(({ key }) => [
        key,
        getOrgProperty(key, idToken, accessToken),
      ])
      .filter(([_, value]) => value !== undefined)
  );

  return {
    orgCode: accessToken.org_code,
    orgName: accessToken.org_name,
    ...(Object.keys(properties).length > 0 && { properties }),
  };
};
src/session/getOrganization.ts (1)

6-16: Enhance JSDoc documentation for better clarity.

While the basic documentation is present, consider adding:

  • Description of the function's purpose
  • Error scenarios and return values
  • Parameter descriptions
 /**
+ * Factory function that creates an organization data retriever.
+ * Handles session token retrieval and organization object generation.
  * @callback getOrganization
+ * @throws {Error} When ID token or access token is missing
  * @returns {Promise<import('../../types').KindeOrganization | null>}
  */

 /**
- *
+ * Creates a function to retrieve organization data from session tokens.
  * @param {import('next').NextApiRequest} [req] - Next.js request object
  * @param {import('next').NextApiResponse} [res] - Next.js response object
  * @returns {getOrganization}
  */
src/handlers/setup.ts (1)

Line range hint 71-89: Enhance error handling for cookie-related failures.

Since we're dealing with cookie size limitations, we should add specific error handling for cookie storage failures.

Add cookie-specific error handling:

   } catch (error) {
     if (config.isDebugMode) {
       console.debug(error);
     }
 
+    // Handle cookie storage errors
+    if (error.message?.includes('cookie') || error.message?.includes('storage')) {
+      return routerClient.json(
+        {
+          error: 'Session storage failed - data size might exceed limits',
+          needsRefresh: true
+        },
+        {status: 413}
+      );
+    }
+
     if (error.code == 'ERR_JWT_EXPIRED') {
tests/frontend/generate-organization-object.test.ts (1)

1-2: Remove unnecessary comment about function location.

The comment "Assuming the function is exported from utils file" suggests uncertainty about the import path. If the import works, the comment is unnecessary; if there's uncertainty, it should be verified.

-import {generateOrganizationObject} from '../../src/utils/generateOrganizationObject'; // Assuming the function is exported from utils file
+import {generateOrganizationObject} from '../../src/utils/generateOrganizationObject';
tests/frontend/generate-user-object.test.ts (1)

1-2: Remove unnecessary comment in import statement.

The comment "Assuming the function is exported from utils file" is redundant as the import path clearly indicates the source.

-import {generateUserObject} from '../../src/utils/generateUserObject'; // Assuming the function is exported from utils file
+import {generateUserObject} from '../../src/utils/generateUserObject';
src/session/sessionManager.js (4)

Line range hint 201-223: Implement splitting logic in pageRouterSessionManager's setSessionItem

The setSessionItem function in pageRouterSessionManager does not include the logic to split large itemValue strings into multiple cookies. This inconsistency can lead to issues when storing large session items in the Page Router context.

Consider implementing the same splitting logic used in appRouterSessionManager to handle large session items consistently across both router types. This ensures that large session data is properly stored and retrieved.


Line range hint 185-197: Update getSessionItem in pageRouterSessionManager to handle split cookies

The getSessionItem function in pageRouterSessionManager retrieves the session item directly from req.cookies[itemKey] without accounting for items that may be split across multiple cookies (e.g., itemKey0, itemKey1, etc.).

To accurately reconstruct session items that have been split, update the function to concatenate values from all relevant cookies:

     getSessionItem: (itemKey) => {
-        const itemValue = req.cookies[itemKey];
+        let itemValue = '';
+        let index = 0;
+        let key = `${String(itemKey)}${index}`;
+        while (req.cookies[key]) {
+            itemValue += req.cookies[key];
+            index++;
+            key = `${String(itemKey)}${index}`;
+        }
         if (itemValue) {
             try {
                 const jsonValue = JSON.parse(itemValue);

Line range hint 225-237: Modify removeSessionItem to delete all cookie segments

In the removeSessionItem function of pageRouterSessionManager, only the base cookie with itemKey is deleted. If the session item was stored in multiple cookies due to splitting, the additional segments remain.

Adjust the function to remove all cookies that start with itemKey:

     removeSessionItem: (itemKey) => {
+        const cookies = req.cookies;
+        Object.keys(cookies).forEach((key) => {
+            if (key.startsWith(`${String(itemKey)}`)) {
+                res?.setHeader('Set-Cookie', [
+                    cookie.serialize(key, '', {
+                        domain: config.cookieDomain ? config.cookieDomain : undefined,
+                        maxAge: -1,
+                        ...GLOBAL_COOKIE_OPTIONS
+                    })
+                ]);
+            }
+        });
     },

27-38: Ensure splitString handles non-string inputs gracefully

The splitString function assumes that str is a string. If str is null, undefined, or not a string, it could cause runtime errors.

Consider adding a type check or converting str to a string to enhance robustness:

 const splitString = (str, length) => {
+    if (typeof str !== 'string') {
+        str = String(str || '');
+    }
     if (length <= 0) {
         return [];
     }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between f2d783f and de69bf2.

📒 Files selected for processing (9)
  • src/handlers/setup.ts (1 hunks)
  • src/session/getOrganization.js (0 hunks)
  • src/session/getOrganization.ts (1 hunks)
  • src/session/isAuthenticated.js (1 hunks)
  • src/session/sessionManager.js (6 hunks)
  • src/utils/generateOrganizationObject.ts (1 hunks)
  • tests/frontend/generate-organization-object.test.ts (1 hunks)
  • tests/frontend/generate-user-object.test.ts (1 hunks)
  • tests/frontend/utils.test.ts (0 hunks)
💤 Files with no reviewable changes (2)
  • src/session/getOrganization.js
  • tests/frontend/utils.test.ts
🔇 Additional comments (9)
src/session/isAuthenticated.js (1)

3-3: LGTM! Clean integration with sessionManager.

The changes effectively integrate the new sessionManager for token retrieval while maintaining the existing authentication logic. This aligns well with the PR's objective of handling larger cookie sizes.

Let's verify the sessionManager integration:

Also applies to: 12-14

✅ Verification successful

Let me gather more information about the sessionManager implementation since the previous results don't show its complete implementation.


Let me check the implementation details of the sessionManager to verify it properly handles cookie splitting.


Verified: sessionManager implementation properly handles cookie splitting

The implementation in sessionManager.js correctly implements cookie splitting functionality:

  • Uses splitString function to split large values into chunks of 3000 bytes
  • Properly handles both storage and retrieval of split cookies
  • Maintains consistent cookie management across App Router and Pages Router
  • Correctly implements cleanup of split cookies during removal
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify consistent usage of sessionManager across the codebase
# and ensure it's properly implemented for token retrieval

# Check if sessionManager is consistently used for access_token retrieval
rg -A 3 "getSessionItem.*access_token"

# Verify the sessionManager implementation exists and handles cookie splitting
ast-grep --pattern 'export const sessionManager = ($req, $res) => {
  $$$
  getSessionItem($$$) {
    $$$
  }
  $$$
}'

Length of output: 807


Script:

#!/bin/bash
# Search for sessionManager implementation
rg -l "sessionManager"

# Look for the actual implementation with more context
rg -A 10 "export.*sessionManager"

# Check if there are any other files importing sessionManager
rg "import.*sessionManager"

Length of output: 3188


Script:

#!/bin/bash
# Get the complete implementation of sessionManager
cat src/session/sessionManager.js

# Check for cookie splitting related code
rg -A 5 "splitCookie|joinCookie|cookie.*split"

Length of output: 6438

src/utils/generateOrganizationObject.ts (1)

7-9: LGTM!

The basic organization fields are correctly mapped from the access token.

src/session/getOrganization.ts (3)

1-5: LGTM! Imports are well-organized and complete.

The imports include all necessary dependencies and follow a logical organization pattern.


1-44: Verify alignment with cookie size management.

The implementation aligns with the PR objective of handling larger cookie sizes by separating token retrieval and using a factory pattern. However, we should verify that the sessionManager properly implements cookie splitting for larger tokens.

#!/bin/bash
# Check sessionManager implementation for cookie handling
rg -A 10 "sessionManager.*getSessionItem" --type typescript

17-44: 🛠️ Refactor suggestion

Consider enhancing error handling and performance.

The implementation is generally solid, but there are a few areas for improvement:

  1. Consider caching session items to reduce async calls:
 export const getOrganizationFactory = (req, res) => async () => {
+  const session = sessionManager(req, res);
   try {
-    const idTokenString = await sessionManager(req, res).getSessionItem(
+    const idTokenString = await session.getSessionItem(
       'id_token'
     );
     // ... rest of the code
-    const accessTokenString = await sessionManager(req, res).getSessionItem(
+    const accessTokenString = await session.getSessionItem(
  1. Consider more specific error handling:
   try {
     // ... existing code
   } catch (error) {
+    const errorMessage = error instanceof Error ? error.message : 'Unknown error';
     if (config.isDebugMode) {
-      console.error(error);
+      console.error(`Organization retrieval failed: ${errorMessage}`);
     }
     return null;
   }

Let's verify the token validation approach:

src/handlers/setup.ts (1)

Line range hint 32-89: Consider response size optimization for cookie storage.

Given that this PR aims to address cookie size limitations, we should optimize the response structure to minimize the data stored in cookies. Consider:

  1. Removing redundant data (e.g., both raw and decoded tokens)
  2. Implementing selective claim storage
  3. Flattening nested structures

Let's verify the potential cookie size impact:

tests/frontend/generate-organization-object.test.ts (2)

1-198: Verify the connection to cookie splitting functionality.

While these tests are well-structured, it's not immediately clear how they relate to the PR's objective of implementing cookie splitting for larger cookie sizes. Could you clarify if this organization object generation is part of the cookie size optimization strategy?

#!/bin/bash
# Look for related cookie handling code
rg -l "cookie|setCookie|getCookie" --type ts

4-136: Consider sanitizing sensitive information in test data.

The mock data contains what appears to be real email addresses, URLs, and potentially real organization codes. Consider using clearly fictional data (e.g., test@example.com) for test cases.

tests/frontend/generate-user-object.test.ts (1)

1-363: Verify the connection between these tests and cookie splitting functionality.

While these tests thoroughly cover the generateUserObject function, it's unclear how they relate to the PR's objective of implementing cookie splitting for larger sizes. We should verify if this is part of a larger change set.

Let's check for related changes:

src/utils/generateOrganizationObject.ts Outdated Show resolved Hide resolved
src/utils/generateOrganizationObject.ts Outdated Show resolved Hide resolved
src/handlers/setup.ts Outdated Show resolved Hide resolved
tests/frontend/generate-user-object.test.ts Show resolved Hide resolved
tests/frontend/generate-user-object.test.ts Show resolved Hide resolved
src/session/sessionManager.js Outdated Show resolved Hide resolved
src/session/sessionManager.js Outdated Show resolved Hide resolved
src/session/sessionManager.js Outdated Show resolved Hide resolved
@DanielRivers DanielRivers marked this pull request as ready for review October 30, 2024 08:59
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 8

🧹 Outside diff range and nitpick comments (4)
src/session/getOrganization.ts (1)

6-16: Enhance JSDoc documentation for better clarity.

Consider adding more detailed documentation:

  • Document error cases and when null is returned
  • Add descriptions for req/res parameters
  • Include example usage
 /**
+ * Factory function that creates an organization data retriever
+ * @param {import('next').NextApiRequest} [req] - The Next.js request object
+ * @param {import('next').NextApiResponse} [res] - The Next.js response object
+ * @returns {getOrganization} A function that retrieves organization data
+ * @throws {Error} When tokens are missing
+ * @example
+ * const getOrganization = getOrganizationFactory(req, res);
+ * const org = await getOrganization();
  */
src/routerClients/PagesRouterClient.js (1)

Line range hint 1-85: Consider documenting the session management strategy.

Given that this change is part of a larger session management improvement, it would be valuable to:

  1. Add JSDoc comments explaining the session management strategy and cookie handling approach
  2. Document any breaking changes or migration steps if moving from sessionManager to pageRouterSessionManager
src/session/sessionManager.js (2)

47-58: Simplify control flow in sessionManager function

The nested if conditions in the sessionManager function can be simplified for better readability.

Consider refactoring as follows:

 export const sessionManager = async (req, res) => {
   try {
     if (!req || isAppRouter(req)) {
       const cookieStore = await cookies(req, res);
       return appRouterSessionManager(cookieStore);
     } else {
       return pageRouterSessionManager(req, res);
     }
   } catch (error) {
     console.error('Failed to initialize session manager:', error);
     throw error;
   }
 };

80-98: Handle JSON parsing errors more effectively in getSessionItem

In the getSessionItem function, the error handling for JSON parsing can be improved to provide more insightful debugging information.

Consider logging the problematic itemValue when parsing fails:

 try {
   const jsonValue = JSON.parse(itemValue);
   if (typeof jsonValue === 'object') {
     return jsonValue;
   }
 } catch (err) {
+  if (config.isDebugMode)
+    console.error('Failed to parse session item JSON:', err, 'Item Value:', itemValue);
 }
 return itemValue;
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between de69bf2 and 6d59b43.

📒 Files selected for processing (6)
  • src/handlers/setup.ts (1 hunks)
  • src/routerClients/PagesRouterClient.js (2 hunks)
  • src/session/getOrganization.ts (1 hunks)
  • src/session/getUser.ts (1 hunks)
  • src/session/sessionManager.js (7 hunks)
  • src/utils/generateOrganizationObject.ts (1 hunks)
🔇 Additional comments (13)
src/session/getUser.ts (2)

14-15: LGTM! Improved code clarity with explicit token variable.

The introduction of the rawToken variable improves code readability by making the token handling flow more explicit.


14-15: Verify cookie size handling implementation.

Given that this PR's objective is to handle cookie splitting for larger sizes, we should verify if this token retrieval implementation properly handles split cookies.

✅ Verification successful

Let me check the cookie handling implementation more specifically by looking at the session manager implementation.


Based on the session manager implementation, I can now provide a final response regarding the cookie splitting concern.

Cookie splitting is properly implemented for handling large tokens

The session manager has built-in support for handling large cookies through cookie splitting:

  • A MAX_LENGTH constant of 3000 bytes is defined to stay within cookie size limits
  • The splitString utility function splits large values into chunks
  • Both appRouterSessionManager and pageRouterSessionManager implementations:
    • Split large values during storage using splitString(itemValueString, MAX_LENGTH)
    • Concatenate split values during retrieval by iterating through indexed cookies
    • Handle cleanup of all split cookies during removal
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Look for cookie splitting implementation in session management
# Expected: Find evidence of cookie size handling in session manager

# Check sessionManager implementation for cookie handling
echo "Checking session manager implementation..."
rg -A 10 "sessionManager" src/

# Look for cookie-related configurations or utilities
echo "Checking for cookie-related configurations..."
rg -l "cookie" src/

Length of output: 27938


Script:

#!/bin/bash
# Check session manager implementation for cookie handling
echo "Checking session manager implementation..."
cat src/session/sessionManager.js

# Check cookie-related configurations
echo "Checking cookie configurations..."
cat src/config/index.js

Length of output: 11785

src/utils/generateOrganizationObject.ts (2)

1-9: LGTM! Well-structured type definitions.

The type definitions provide good type safety and the property keys are comprehensive for organization data.


21-37: Consider cookie size implications and add validation.

  1. The previous review comment about validating required fields (org_code, org_name) is still applicable.

  2. Given that this PR aims to address cookie size limitations:

  • Consider implementing property filtering to include only non-null values
  • Add size monitoring for the generated object

Here's a suggested implementation that addresses both concerns:

 export const generateOrganizationObject = (
   idToken: KindeIdToken,
   accessToken: KindeAccessToken
 ) => {
+  if (!accessToken.org_code || !accessToken.org_name) {
+    throw new Error('Missing required organization fields in access token');
+  }
+
+  const properties = {
+    city: getOrgProperty('city', idToken, accessToken),
+    industry: getOrgProperty('industry', idToken, accessToken),
+    postcode: getOrgProperty('postcode', idToken, accessToken),
+    state_region: getOrgProperty('state_region', idToken, accessToken),
+    street_address: getOrgProperty('street_address', idToken, accessToken),
+    street_address_2: getOrgProperty('street_address_2', idToken, accessToken)
+  };
+
+  // Filter out undefined properties to reduce object size
+  const filteredProperties = Object.fromEntries(
+    Object.entries(properties).filter(([_, value]) => value !== undefined)
+  );
+
   return {
     orgCode: accessToken.org_code,
     orgName: accessToken.org_name,
-    properties: {
-      city: getOrgProperty('city', idToken, accessToken),
-      industry: getOrgProperty('industry', idToken, accessToken),
-      postcode: getOrgProperty('postcode', idToken, accessToken),
-      state_region: getOrgProperty('state_region', idToken, accessToken),
-      street_address: getOrgProperty('street_address', idToken, accessToken),
-      street_address_2: getOrgProperty('street_address_2', idToken, accessToken)
-    }
+    properties: filteredProperties
   };
 };
src/session/getOrganization.ts (2)

1-5: LGTM! Clean and well-organized imports.

The imports are properly structured with clear separation between runtime dependencies and type imports.


17-44: Verify session manager's cookie handling capacity.

Given the PR's objective to handle larger cookie sizes, we should verify the session manager's implementation.

src/routerClients/PagesRouterClient.js (2)

46-46: LGTM! Verify integration with cookie splitting functionality.

The switch to pageRouterSessionManager aligns with the PR's objective to improve cookie handling. The implementation maintains the same interface while potentially enabling better cookie size management.

Let's verify the implementation of the new session manager:

#!/bin/bash
# Description: Check pageRouterSessionManager implementation for cookie splitting logic
rg -A 10 "pageRouterSessionManager\s*=\s*" "src/session/sessionManager"

3-6: Verify if both session manager imports are necessary.

Both pageRouterSessionManager and sessionManager are imported, but only pageRouterSessionManager is used. Consider removing the unused sessionManager import to keep the code clean.

Let's check if sessionManager is used elsewhere in the file:

src/handlers/setup.ts (2)

23-34: Verify alignment with PR objectives.

The PR's objective is to implement cookie splitting for larger cookie sizes, but the changes focus on direct token claim access. While this might be related, it's not immediately clear how these changes address the cookie size issue.

Could you please clarify:

  1. How do these token claim access changes relate to cookie splitting?
  2. Are there additional changes needed to implement the cookie splitting functionality?

Let's check for cookie-related code:

#!/bin/bash
# Search for cookie-related implementations
rg -A 5 "cookie|split.*cookie|sessionManager.*set"

23-30: Consider adding token validation before accessing claims.

Direct access to token claims without validation could expose the application to security risks if the tokens are malformed or tampered with. Consider adding token validation using the JWT signature and expiry checks before accessing the claims.

Let's verify if token validation is implemented elsewhere:

Consider implementing a token validation middleware that:

  1. Verifies the JWT signature
  2. Checks token expiration
  3. Validates required claim presence and types
src/session/sessionManager.js (3)

108-120: Delete all existing cookies with prefix itemKey before setting new values

In the setSessionItem function, existing cookies with keys starting with itemKey are not deleted before setting new values. This can leave stale cookie segments if the new value has fewer segments than the old value.


27-38: Optimize the splitString function using regular expressions


149-160: Verify cookie deletion logic in destroySession

Ensure that all cookies matching the prefixes in COOKIE_LIST are correctly identified and deleted.

Run the following script to confirm that cookies are properly deleted:

✅ Verification successful

Cookie deletion logic in destroySession is correctly implemented

The implementation correctly:

  • Uses cookieStore.getAll() to fetch all cookies
  • Checks each cookie name against the COOKIE_LIST prefixes using startsWith
  • Deletes matching cookies by setting empty value and maxAge: 0
  • Applies consistent cookie options including domain and global settings
  • Handles both App Router and Page Router scenarios
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for any cookies that should be deleted but remain.

# Test: List all cookies matching COOKIE_LIST prefixes.
# Expect: No cookies should be listed after destroySession is called.

COOKIE_PREFIXES=("ac-state-key" "id_token_payload" "id_token" "access_token_payload" "access_token" "user" "refresh_token" "post_login_redirect_url")
for prefix in "${COOKIE_PREFIXES[@]}"; do
  grep -r "^Set-Cookie: $prefix" .
done

Length of output: 803


Script:

#!/bin/bash
# Let's verify the cookie deletion logic by checking:
# 1. The COOKIE_LIST constant definition
# 2. The cookie deletion implementation
# 3. Any tests related to cookie deletion

# Check for COOKIE_LIST definition
rg "COOKIE_LIST.*=.*\[" -A 5

# Check for cookie deletion implementation
ast-grep --pattern 'cookieStore.set($name, $value, $options)'

# Look for test files related to session/cookie management
fd "test|spec" --type f | rg -i "session|cookie"

Length of output: 445


Script:

#!/bin/bash
# Let's check for more cookie-related code and tests with broader patterns

# Check for cookie-related code in sessionManager.js
rg "cookie" -i src/session/sessionManager.js -B 2 -A 2

# Look for cookie-related test files with a more permissive pattern
fd -e test.js -e spec.js | xargs rg "cookie" -i -l

# Check for any cookie store usage
ast-grep --pattern 'cookieStore.$_($$$)'

Length of output: 8052

src/utils/generateOrganizationObject.ts Show resolved Hide resolved
src/session/getOrganization.ts Show resolved Hide resolved
src/session/getOrganization.ts Show resolved Hide resolved
src/session/getOrganization.ts Show resolved Hide resolved
src/handlers/setup.ts Show resolved Hide resolved
src/session/sessionManager.js Show resolved Hide resolved
src/session/sessionManager.js Show resolved Hide resolved
src/session/sessionManager.js Show resolved Hide resolved
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Outside diff range and nitpick comments (2)
src/utils/generateOrganizationObject.ts (1)

21-41: Implementation aligns with PR objectives for cookie size optimization.

The function efficiently retrieves organization properties by:

  1. Only including necessary fields in the returned object
  2. Using a consistent property access pattern
  3. Properly handling missing or undefined values

This implementation supports the PR's goal of managing cookie sizes by ensuring efficient data structure.

Consider these additional optimizations if cookie size remains a concern:

  1. Implement property filtering to exclude null/undefined values
  2. Add compression for longer string values
  3. Consider implementing property versioning for backward compatibility
src/session/sessionManager.js (1)

125-139: Remove redundant deletion in removeSessionItem

In the removeSessionItem function, deleting itemKey before iterating over all cookies starting with itemKey is unnecessary since the loop will handle it. Removing the redundant deletion simplifies the code.

Apply this diff to streamline the function:

-if (cookieStore.has(itemKey)) {
-  cookieStore.delete(itemKey);
-}
 cookieStore
   .getAll()
   .map((c) => c.name)
   .forEach((key) => {
     if (key.startsWith(`${String(itemKey)}`)) {
       cookieStore.set(key, '', {
         domain: config.cookieDomain ? config.cookieDomain : undefined,
         maxAge: 0,
         ...GLOBAL_COOKIE_OPTIONS
       });
     }
   });
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between 6d59b43 and cf8de27.

📒 Files selected for processing (2)
  • src/session/sessionManager.js (7 hunks)
  • src/utils/generateOrganizationObject.ts (1 hunks)
🔇 Additional comments (7)
src/utils/generateOrganizationObject.ts (2)

1-9: LGTM! Well-structured type definitions.

The type definitions are clear and provide good type safety for the organization properties.


11-19: Consider handling edge case when both values are falsy.

The current implementation returns the first truthy value or undefined. However, if both idValue and accessValue are falsy but exist (e.g., empty string), the function might not behave as expected.

Let's verify if there are any cases where empty strings are valid values:

src/session/sessionManager.js (5)

29-34: Efficient implementation of splitString function

The splitString function efficiently splits a string into chunks using a regular expression, which improves performance over iterative methods.


231-245: ⚠️ Potential issue

Correct usage of res.setHeader in setSessionItem

Passing a third argument (options object) to res.setHeader is incorrect. The method accepts only the header name and value. You should apply the options within the cookie serialization.

Apply this diff to fix the header setting:

 res?.setHeader(
   'Set-Cookie',
   [
     ...(cookies.filter((cookie) => !cookie.startsWith(`${itemKey}`)) || []),
     ...splitString(itemValueString, MAX_LENGTH).map((value, index) => {
       return cookie.serialize(
         itemKey + (index === 0 ? '' : index),
         value,
         {
           domain: config.cookieDomain ? config.cookieDomain : undefined,
           ...GLOBAL_COOKIE_OPTIONS,
           maxAge: TWENTY_NINE_DAYS
         }
       );
     })
-  ],
-  {
-    domain: config.cookieDomain ? config.cookieDomain : undefined,
-    ...GLOBAL_COOKIE_OPTIONS,
-    maxAge: TWENTY_NINE_DAYS
-  }
+  ]
 );

Likely invalid or redundant comment.


291-304: Verify the comprehensive deletion of session cookies in destroySession

Ensure that all cookies listed in COOKIE_LIST are being properly deleted during session destruction.

Run the following script to confirm that all cookies are removed:

✅ Verification successful

Let me check the actual implementation of cookie deletion by examining the COOKIE_LIST constant and the destroySession function.


Let me check the complete COOKIE_LIST definition to ensure all session-related cookies are included.


Session cookies are properly handled during destruction

The implementation correctly handles the deletion of all session-related cookies:

  • The COOKIE_LIST array includes all essential session cookies: ac-state-key, id_token_payload, id_token, access_token_payload, access_token, user, refresh_token, and post_login_redirect_url
  • The destroySession function properly iterates through all cookies and removes those that match any prefix in COOKIE_LIST
  • Cookie deletion is implemented with appropriate options:
    • Sets empty value
    • Uses correct domain from config
    • Sets negative/zero maxAge to ensure immediate expiration
    • Includes global cookie options
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify that all cookies in COOKIE_LIST are deleted.

# Expected result: No cookies matching COOKIE_LIST remain.

for cookie_name in 'ac-state-key' 'id_token_payload' 'id_token' 'access_token_payload' 'access_token' 'user' 'refresh_token' 'post_login_redirect_url'; do
  grep -rl "$cookie_name" src/
done

Length of output: 2804


Script:

#!/bin/bash
# Check the COOKIE_LIST definition and destroySession implementation
rg "COOKIE_LIST\s*=" src/ -A 2
rg "destroySession" src/session/sessionManager.js -A 20

Length of output: 1403


Script:

#!/bin/bash
# Get the complete COOKIE_LIST definition
rg "COOKIE_LIST\s*=" src/session/sessionManager.js -A 10

Length of output: 239


291-304: ⚠️ Potential issue

Filter out undefined values in destroySession

In the destroySession function, when mapping over Object.keys(req.cookies), some entries may return undefined if they don't match the COOKIE_LIST criteria. To prevent potential errors, filter out any undefined values before setting the header.

Apply this diff to ensure only valid cookies are processed:

 res?.setHeader('Set-Cookie', [
   ...Object.keys(req.cookies).map((c) => {
     if (COOKIE_LIST.some((substr) => c.startsWith(substr))) {
       return cookie.serialize(c.split('=')[0], '', {
         domain: config.cookieDomain ? config.cookieDomain : undefined,
         maxAge: -1,
         ...GLOBAL_COOKIE_OPTIONS
       });
     }
+    return null;
   }).filter(Boolean)
 ]);

Likely invalid or redundant comment.


276-288: ⚠️ Potential issue

Ensure all cookies starting with itemKey are removed in removeSessionItem

When modifying the Set-Cookie header, ensure that you're removing all cookies that start with itemKey. Currently, you're iterating over cookies, which may not include all existing cookies. To comprehensively delete all matching cookies, include cookies from req.cookies.

Apply this diff to enhance cookie removal:

 res?.setHeader('Set-Cookie', [
+  ...Object.keys(req.cookies).map((c) => {
+    if (c.startsWith(`${itemKey}`)) {
+      return cookie.serialize(c, '', {
+        domain: config.cookieDomain ? config.cookieDomain : undefined,
+        maxAge: -1,
+        ...GLOBAL_COOKIE_OPTIONS
+      });
+    }
+  }).filter(Boolean),
   ...cookies.map((c) => {
     if (c.startsWith(`${itemKey}`)) {
       return cookie.serialize(c.split('=')[0], '', {
         domain: config.cookieDomain ? config.cookieDomain : undefined,
         maxAge: -1,
         ...GLOBAL_COOKIE_OPTIONS
       });
     } else {
       return c;
     }
   })
 ]);

Likely invalid or redundant comment.

src/session/sessionManager.js Show resolved Hide resolved
src/session/sessionManager.js Show resolved Hide resolved
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Outside diff range and nitpick comments (2)
src/session/sessionManager.js (2)

29-34: Add input validation to splitString function

The function should validate that the input string is not null/undefined before processing.

Consider this enhanced implementation:

 const splitString = (str, length) => {
+  if (!str) {
+    return [];
+  }
   if (length <= 0) {
     return [];
   }
   return str.match(new RegExp(`.{1,${length}}`, 'g')) || [];  
 };

84-93: Enhance error handling for JSON parsing

The current implementation silently ignores JSON parsing errors. Consider logging the actual parsing error in debug mode.

       try {
         const jsonValue = JSON.parse(itemValue);
         if (typeof jsonValue === 'object') {
           return jsonValue;
         }
-      } catch (err) {}
+      } catch (err) {
+        if (config.isDebugMode) {
+          console.error('JSON parsing failed:', err);
+        }
+      }
       return itemValue;
     } catch (error) {
       if (config.isDebugMode)
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between cf8de27 and e8f51c1.

📒 Files selected for processing (1)
  • src/session/sessionManager.js (8 hunks)
🧰 Additional context used
📓 Learnings (1)
src/session/sessionManager.js (1)
Learnt from: DanielRivers
PR: kinde-oss/kinde-auth-nextjs#229
File: src/session/sessionManager.js:74-91
Timestamp: 2024-11-12T02:26:20.896Z
Learning: In `src/session/sessionManager.js`, within the `getSessionItem` method, not including the `0` in the index for the first item key is intentional.
🔇 Additional comments (3)
src/session/sessionManager.js (3)

44-54: LGTM! Clean router-specific session manager initialization

The conditional logic properly handles both Next.js App Router and Pages Router scenarios.


174-197: LGTM! Consistent implementation with app router version

The getSessionItem implementation correctly mirrors the app router version, including the intentional behavior of not including '0' in the first item key.


214-251: Remove redundant options object in setHeader call

The setHeader call includes a redundant options object that should be removed as noted in past reviews.

src/session/sessionManager.js Outdated Show resolved Hide resolved
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Outside diff range and nitpick comments (3)
src/session/sessionManager.js (3)

Line range hint 17-24: Consider moving sensitive cookie names to a secure configuration

The COOKIE_LIST contains sensitive token names. Consider moving these to a secure configuration file to centralize security-sensitive constants.


44-54: Enhance error handling with specific error types

The current error handling simply re-throws the error. Consider:

  1. Creating specific error types for different failure scenarios
  2. Adding context to the error
   } catch (error) {
-    throw error;
+    throw new SessionManagerError(
+      `Failed to initialize session manager: ${error.message}`,
+      { cause: error }
+    );
   }

122-129: Optimize cookie cleanup with filter and batch operations

The current implementation iterates through all cookies individually. Consider using filter and batch operations:

-    cookieStore
-      .getAll()
-      .map((c) => c.name)
-      .forEach((key) => {
-        if (key.startsWith(`${String(itemKey)}`)) {
-          cookieStore.delete(key);
-        }
-      });
+    const keysToDelete = cookieStore
+      .getAll()
+      .map((c) => c.name)
+      .filter(key => key.startsWith(`${String(itemKey)}`));
+    
+    keysToDelete.forEach(key => cookieStore.delete(key));
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between e8f51c1 and c42b661.

📒 Files selected for processing (1)
  • src/session/sessionManager.js (8 hunks)
🧰 Additional context used
📓 Learnings (1)
src/session/sessionManager.js (1)
Learnt from: DanielRivers
PR: kinde-oss/kinde-auth-nextjs#229
File: src/session/sessionManager.js:74-91
Timestamp: 2024-11-12T02:26:20.896Z
Learning: In `src/session/sessionManager.js`, within the `getSessionItem` method, not including the `0` in the index for the first item key is intentional.
🔇 Additional comments (1)
src/session/sessionManager.js (1)

27-34: Validate MAX_LENGTH against browser and server limits

The MAX_LENGTH constant of 3000 needs validation:

  1. Verify it's below browser cookie size limits (typically 4096 bytes)
  2. Consider server-side limitations
  3. Account for cookie header overhead

Additionally, the splitString function should validate input types:

src/session/sessionManager.js Show resolved Hide resolved
src/session/sessionManager.js Show resolved Hide resolved
src/session/sessionManager.js Show resolved Hide resolved
@DanielRivers DanielRivers merged commit 81421b4 into main Nov 15, 2024
3 checks passed
@coderabbitai coderabbitai bot mentioned this pull request Nov 15, 2024
2 tasks
This was referenced Nov 21, 2024
@coderabbitai coderabbitai bot mentioned this pull request Dec 17, 2024
2 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants