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

Feature : Added server side verification for all routes . #3491

Open
wants to merge 13 commits into
base: develop
Choose a base branch
from

Conversation

PurnenduMIshra129th
Copy link
Contributor

@PurnenduMIshra129th PurnenduMIshra129th commented Jan 30, 2025

What kind of change does this PR introduce?

Feature

Issue Number:

Fixes #1839

Snapshots/Videos:
here a user is trying to access superAdmin page
image
results after adding serverSide verification
image

here if admin also trying to access superAdmin pages also he will not be able to access
image
results after
image
here we are whitelisting the pages which pages is common between admin and superAdmin so that admin will have limited access to superAdmin pages like' /orglist ' this page can be accessed to admin and superAdmin both.
here see the screenShot
image

If relevant, did you update the documentation?

No

Summary

  • Previously Admin can access all the pages of superAdmin by changing the url because there is no security for routes .
  • Now all the pages accessed by admin, superAdmin, user will be verify by server.
  • If the user is authorized for particular pages then only he will be able to visit.
  • Also previouly we are using localstorage for verification .Now it is replaced by server side.
  • All the pages are verified using jwt via server.
  • If any chance user will try to tamper the jwt as it is genrated by server user will caught and he will not be able to access.

Does this PR introduce a breaking change?

No

Checklist

CodeRabbit AI Review

  • I have reviewed and addressed all critical issues flagged by CodeRabbit AI
  • I have implemented or provided justification for each non-critical suggestion
  • I have documented my reasoning in the PR comments where CodeRabbit AI suggestions were not implemented

Test Coverage

  • I have written tests for all new changes/features
  • I have verified that test coverage meets or exceeds 95%
  • I have run the test suite locally and all tests pass

Other information

-It is more secure than our conventional way.

Have you read the contributing guide?

Yes

Summary by CodeRabbit

Release Notes

  • New Features

    • Added a new GraphQL query VERIFY_ROLE to verify user authorization and role.
    • Introduced a UserRole enumeration and VerifyRoleResponse type for better role management.
  • Documentation

    • Added documentation for the VERIFY_ROLE query and the UserRole enumeration.
    • Updated documentation for the default() functions in the SecuredRoute, SecuredRouteForUser, and PageNotFound components.
    • Updated documentation for the getLanguageName and prettyDate functions.
  • Improvements

    • Enhanced route authentication mechanism using server-side role verification.
    • Improved error handling and loading state management in the SecuredRoute and SecuredRouteForUser components.
  • Bug Fixes

    • Replaced local storage-based authentication with more secure GraphQL query verification.
  • Tests

    • Enhanced unit tests for the SecuredRouteForUser component to include loading and error state handling.
    • Updated test cases in the App component for better clarity and functionality.
    • Integrated Apollo Client into the testing setup for the PageNotFound component.

Copy link
Contributor

coderabbitai bot commented Jan 30, 2025

Walkthrough

The pull request introduces significant enhancements to the authentication and authorization mechanisms for routes. It replaces local storage-based checks with server-side GraphQL queries in components such as SecuredRoute and SecuredRouteForUser. Additionally, a new VERIFY_ROLE GraphQL query has been added to dynamically verify user roles and authorization status, improving the security of route access by validating user permissions through backend verification rather than relying solely on client-side storage.

Changes

File Change Summary
src/GraphQl/Queries/Queries.ts Added new GraphQL query VERIFY_ROLE to retrieve user authorization and role.
src/components/SecuredRoute/SecuredRoute.tsx Replaced local storage authentication with GraphQL query-based role verification.
src/components/UserPortal/SecuredRouteForUser/SecuredRouteForUser.tsx Implemented GraphQL query to check user authorization and role.
docs/docs/auto-docs/... Updated documentation reflecting new function line numbers and query details.

Assessment against linked issues

Objective Addressed Explanation
Backend auth verification for routes [#1839]
Replace local storage auth checks
Secure admin and superadmin routes

Possibly related PRs

  • Added Event Registrants Tab under Event Management Dashboard #2804: The changes in the main PR, which involve adding a new GraphQL query VERIFY_ROLE and its documentation, are related to the retrieved PR that introduces another GraphQL query EVENT_REGISTRANTS in the same file, src/GraphQl/Queries/Queries.ts.
  • Fixes: The Login and Organization Screens  #3309: The changes in the main PR, which involve adding a new GraphQL query VERIFY_ROLE and its documentation, are related to the modifications in the retrieved PR that also involve user role verification through GraphQL queries in the SecuredRoute and SecuredRouteForUser components.
  • feat: Listing the Assigned Tags on the MemberDetail screen #2425: The changes in the main PR, which involve adding a new GraphQL query VERIFY_ROLE, are related to the modifications in the retrieved PR that enhance the MemberDetail screen by listing assigned tags, as both involve updates to GraphQL queries and their integration into components.

Suggested labels

ignore-sensitive-files-pr

Suggested reviewers

  • palisadoes

Poem

🐰 A rabbit's tale of routes secure,
Where GraphQL queries now ensure,
No sneaky access, no storage trick,
Authentication's now slick and quick!
Safe passages through our digital maze 🔒

Tip

🌐 Web search-backed reviews and chat
  • We have enabled web search-based reviews and chat for all users. This feature allows CodeRabbit to access the latest documentation and information on the web.
  • You can disable this feature by setting web_search: false in the knowledge_base settings.
  • Please share any feedback in the Discord discussion.

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 generate docstrings to generate docstrings for this PR. (Beta)
  • @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.

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.

Copy link

Our Pull Request Approval Process

Thanks for contributing!

Testing Your Code

Remember, your PRs won't be reviewed until these criteria are met:

  1. We don't merge PRs with poor code quality.
    1. Follow coding best practices such that CodeRabbit.ai approves your PR.
  2. We don't merge PRs with failed tests.
    1. When tests fail, click on the Details link to learn more.
    2. Write sufficient tests for your changes (CodeCov Patch Test). Your testing level must be better than the target threshold of the repository
    3. Tests may fail if you edit sensitive files. Ask to add the ignore-sensitive-files-pr label if the edits are necessary.
  3. We cannot merge PRs with conflicting files. These must be fixed.

Our policies make our code better.

Reviewers

Do not assign reviewers. Our Queue Monitors will review your PR and assign them.
When your PR has been assigned reviewers contact them to get your code reviewed and approved via:

  1. comments in this PR or
  2. our slack channel

Reviewing Your Code

Your reviewer(s) will have the following roles:

  1. arbitrators of future discussions with other contributors about the validity of your changes
  2. point of contact for evaluating the validity of your work
  3. person who verifies matching issues by others that should be closed.
  4. person who gives general guidance in fixing your tests

CONTRIBUTING.md

Read our CONTRIBUTING.md file. Most importantly:

  1. PRs with issues not assigned to you will be closed by the reviewer
  2. Fix the first comment in the PR so that each issue listed automatically closes

Other

  1. 🎯 Please be considerate of our volunteers' time. Contacting the person who assigned the reviewers is not advised unless they ask for your input. Do not @ the person who did the assignment otherwise.
  2. Read the CONTRIBUTING.md file make

@PurnenduMIshra129th PurnenduMIshra129th changed the title added securitty for routing from server side Feature : Added server side verification for all routes . Jan 30, 2025
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

🧹 Nitpick comments (2)
src/components/UserPortal/SecuredRouteForUser/SecuredRouteForUser.tsx (1)

30-46: Avoid loose equality checks for roles.
Use triple-equals comparisons (===) to minimize type-coercion risks and maintain consistency.

- if (role == 'user') {
+ if (role === 'user') {
src/components/SecuredRoute/SecuredRoute.tsx (1)

19-25: Gracefully handle a missing or invalid token.
Similar to SecuredRouteForUser, ensure you handle the case when getItem('token') returns null or an empty string to avoid potential 401/403 backend errors.

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8b003eb and cc9019d.

📒 Files selected for processing (6)
  • docs/docs/auto-docs/GraphQl/Queries/Queries/variables/VERIFY_ROLE.md (1 hunks)
  • docs/docs/auto-docs/components/SecuredRoute/SecuredRoute/functions/default.md (1 hunks)
  • docs/docs/auto-docs/components/UserPortal/SecuredRouteForUser/SecuredRouteForUser/functions/default.md (1 hunks)
  • src/GraphQl/Queries/Queries.ts (1 hunks)
  • src/components/SecuredRoute/SecuredRoute.tsx (2 hunks)
  • src/components/UserPortal/SecuredRouteForUser/SecuredRouteForUser.tsx (2 hunks)
✅ Files skipped from review due to trivial changes (3)
  • docs/docs/auto-docs/components/SecuredRoute/SecuredRoute/functions/default.md
  • docs/docs/auto-docs/components/UserPortal/SecuredRouteForUser/SecuredRouteForUser/functions/default.md
  • docs/docs/auto-docs/GraphQl/Queries/Queries/variables/VERIFY_ROLE.md
⏰ Context from checks skipped due to timeout of 90000ms (2)
  • GitHub Check: Test Application
  • GitHub Check: Analyse Code With CodeQL (javascript)
🔇 Additional comments (6)
src/components/UserPortal/SecuredRouteForUser/SecuredRouteForUser.tsx (3)

26-28: Check for potential infinite refetch loops.
Using getItem('token') directly inside the dependency array can cause re-renders if the returned value is a new object or if local storage changes frequently. Consider memoizing or storing the token in a state variable to avoid rapid re-fetch calls.


19-25: 🛠️ Refactor suggestion

Ensure fallback behavior when no token is available.
If getItem('token') returns null or an empty value, Authorization: Bearer null may cause backend errors. You may want to gracefully handle missing tokens before passing the headers.

+  const token = getItem('token');
   const { data, loading, error, refetch } = useQuery(VERIFY_ROLE, {
     context: {
       headers: {
-        Authorization: `Bearer ${getItem('token')}`,
+        ...(token ? { Authorization: `Bearer ${token}` } : {}),
       },
     },
   });

1-2: Use consistent import paths and naming conventions.
Make sure that the import path 'GraphQl/Queries/Queries' is spelled consistently across the codebase (GraphQl vs. GraphQL). Also, confirm that you keep a consistent naming pattern for these imports (e.g. import { VERIFY_ROLE } from 'src/GraphQl...').

As a follow-up, you can search the codebase to confirm correct usage:

src/components/SecuredRoute/SecuredRoute.tsx (2)

1-2: Confirm consistent import usage and file casing.
Same as in SecuredRouteForUser, ensure 'GraphQl/Queries/Queries' is spelled with consistent folder-case to avoid cross-platform issues.


26-28: Check for repeated refetch triggers.
Retrieving getItem('token') in the dependency array can lead to frequent re-fetch if the return value changes unexpectedly. Consider using a state variable.

src/GraphQl/Queries/Queries.ts (1)

867-874: Verify alignment with backend schema.
The verifyRole query fields (isAuthorized and role) must match exactly the backend’s resolver fields. Double-check the spelling and data types to prevent runtime errors.

src/components/SecuredRoute/SecuredRoute.tsx Outdated Show resolved Hide resolved
@PurnenduMIshra129th
Copy link
Contributor Author

@palisadoes cheack once this Pr.

Copy link

codecov bot commented Jan 30, 2025

Codecov Report

Attention: Patch coverage is 5.00000% with 19 lines in your changes missing coverage. Please review.

Project coverage is 3.69%. Comparing base (3104525) to head (7c92f64).
Report is 1 commits behind head on develop.

Files with missing lines Patch % Lines
...Portal/SecuredRouteForUser/SecuredRouteForUser.tsx 0.00% 19 Missing ⚠️
Additional details and impacted files
@@           Coverage Diff           @@
##           develop   #3491   +/-   ##
=======================================
  Coverage     3.68%   3.69%           
=======================================
  Files          315     315           
  Lines         8301    8317   +16     
  Branches      1882    1887    +5     
=======================================
+ Hits           306     307    +1     
- Misses        7957    7972   +15     
  Partials        38      38           
Flag Coverage Δ
jest 3.69% <5.00%> (?)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@palisadoes
Copy link
Contributor

Please fix the failing tests, make code rabbit approve your PR and add tests to cover the code modifications

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 comments (1)
src/components/SecuredRoute/SecuredRoute.tsx (1)

Line range hint 55-89: Refactor session timeout logic into a custom hook.

The current implementation uses global variables and direct DOM manipulation, which are anti-patterns in React. Consider moving this logic into a custom hook.

// useSessionTimeout.ts
export const useSessionTimeout = (timeoutMinutes: number, onTimeout: () => void) => {
  useEffect(() => {
    let lastActive = Date.now();
    const timeoutMilliseconds = timeoutMinutes * 60 * 1000;
    
    const handleActivity = () => {
      lastActive = Date.now();
    };
    
    const checkInactivity = () => {
      const timeSinceLastActive = Date.now() - lastActive;
      if (timeSinceLastActive > timeoutMilliseconds) {
        onTimeout();
      }
    };
    
    window.addEventListener('mousemove', handleActivity);
    const interval = setInterval(checkInactivity, 60000);
    
    return () => {
      window.removeEventListener('mousemove', handleActivity);
      clearInterval(interval);
    };
  }, [timeoutMinutes, onTimeout]);
};

// Usage in SecuredRoute
const SecuredRoute = (): JSX.Element => {
  useSessionTimeout(15, () => {
    toast.warn('Kindly relogin as session has expired');
    setItem('IsLoggedIn', 'FALSE');
    window.location.href = '/';
  });
  // ... rest of the component
};
🧹 Nitpick comments (6)
src/components/UserPortal/SecuredRouteForUser/SecuredRouteForUser.spec.tsx (4)

14-17: Consider enhancing the mock setup with type safety.

The mock setup is correct but could benefit from TypeScript types for better type safety and IDE support.

 vi.mock('utils/useLocalstorage', () => ({
   __esModule: true,
-  default: vi.fn(),
+  default: vi.fn<typeof useLocalStorage>(),
 }));

24-39: Enhance mockQuery helper with type safety and flexibility.

The helper function could benefit from TypeScript types and a more flexible token parameter.

-const mockQuery = (role: string, isAuthorized: boolean): MockedResponse => ({
+type Role = 'user' | 'admin' | 'superadmin' | '';
+const mockQuery = (role: Role, isAuthorized: boolean, token = 'mock_token'): MockedResponse => ({
   request: {
     query: VERIFY_ROLE,
     context: {
-      headers: { Authorization: `Bearer mock_token` },
+      headers: { Authorization: `Bearer ${token}` },
     },
   },
   result: {
     data: {
       verifyRole: {
         role,
         isAuthorized,
       },
     },
   },
 });

41-69: Enhance test description and assertions for user role verification.

The test case could be more explicit about what it's verifying and include additional assertions.

-it('renders the route when the user is logged in as a user', async () => {
+it('should render organizations component when authenticated user has user role', async () => {
   // ... existing code ...
   await waitFor(() => {
     expect(screen.getByTestId('organizations-content')).toBeInTheDocument();
+    expect(screen.queryByText(/404/i)).not.toBeInTheDocument();
+    expect(screen.queryByText(/Error/i)).not.toBeInTheDocument();
   });
 });

152-188: Enhance error handling test coverage.

The error handling test could be more comprehensive by testing different error scenarios.

Add test cases for different error scenarios:

it('should handle network errors', async () => {
  (useLocalStorage as Mock).mockReturnValue({
    getItem: vi.fn(() => 'mock_token'),
    setItem: vi.fn(),
  });

  render(
    <MockedProvider
      mocks={[
        {
          request: {
            query: VERIFY_ROLE,
            context: {
              headers: { Authorization: `Bearer mock_token` },
            },
          },
          error: new Error('Network error'),
        },
      ]}
      addTypename={false}
    >
      <MemoryRouter initialEntries={['/user/organizations']}>
        <Routes>
          <Route element={<SecuredRouteForUser />}>
            <Route path="/user/organizations" element={<div>Test Page</div>} />
          </Route>
        </Routes>
      </MemoryRouter>
    </MockedProvider>,
  );

  await waitFor(() => {
    expect(screen.getByText(/Error During Routing/i)).toBeInTheDocument();
    expect(screen.getByText(/Network error/i)).toBeInTheDocument();
  });
});

it('should handle unauthorized responses', async () => {
  (useLocalStorage as Mock).mockReturnValue({
    getItem: vi.fn(() => 'mock_token'),
    setItem: vi.fn(),
  });

  render(
    <MockedProvider
      mocks={[
        {
          request: {
            query: VERIFY_ROLE,
            context: {
              headers: { Authorization: `Bearer mock_token` },
            },
          },
          result: {
            errors: [{ message: 'Unauthorized' }],
          },
        },
      ]}
      addTypename={false}
    >
      <MemoryRouter initialEntries={['/user/organizations']}>
        <Routes>
          <Route element={<SecuredRouteForUser />}>
            <Route path="/user/organizations" element={<div>Test Page</div>} />
          </Route>
        </Routes>
      </MemoryRouter>
    </MockedProvider>,
  );

  await waitFor(() => {
    expect(screen.getByText(/Error During Routing/i)).toBeInTheDocument();
    expect(screen.getByText(/Unauthorized/i)).toBeInTheDocument();
  });
});
src/components/SecuredRoute/SecuredRoute.tsx (2)

31-35: Improve error handling and loading states.

The current error handling shows a generic message. Consider:

  1. Logging the error for debugging
  2. Showing more specific error messages
  3. Adding a retry mechanism
 if (loading) {
-  return <div> Loading.....</div>;
+  return <div>Verifying access...</div>;
 } else if (error) {
+  console.error('Route verification failed:', error);
-  return <div>Error During Routing ...</div>;
+  return (
+    <div>
+      <p>Failed to verify access. Please try again.</p>
+      <button onClick={() => refetch()}>Retry</button>
+    </div>
+  );
 }

40-42: Use strict equality comparison for role checks.

Replace loose equality (==) with strict equality (===) for type-safe comparisons.

-if (role == 'superAdmin') {
+if (role === 'superAdmin') {
   return <Outlet />;
-} else if (role == 'admin') {
+} else if (role === 'admin') {
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between cc9019d and 23ebe30.

📒 Files selected for processing (4)
  • docs/docs/auto-docs/screens/MemberDetail/MemberDetail/functions/getLanguageName.md (1 hunks)
  • docs/docs/auto-docs/screens/MemberDetail/MemberDetail/functions/prettyDate.md (1 hunks)
  • src/components/SecuredRoute/SecuredRoute.tsx (2 hunks)
  • src/components/UserPortal/SecuredRouteForUser/SecuredRouteForUser.spec.tsx (1 hunks)
✅ Files skipped from review due to trivial changes (2)
  • docs/docs/auto-docs/screens/MemberDetail/MemberDetail/functions/prettyDate.md
  • docs/docs/auto-docs/screens/MemberDetail/MemberDetail/functions/getLanguageName.md
⏰ Context from checks skipped due to timeout of 90000ms (2)
  • GitHub Check: Test Application
  • GitHub Check: Analyse Code With CodeQL (javascript)
🔇 Additional comments (2)
src/components/UserPortal/SecuredRouteForUser/SecuredRouteForUser.spec.tsx (1)

103-126: 🛠️ Refactor suggestion

Add test coverage for superadmin role.

The test suite covers user and admin roles but is missing coverage for the superadmin role.

Add a test case for superadmin role:

it('should render PageNotFound when user is a superadmin', async () => {
  (useLocalStorage as Mock).mockReturnValue({
    getItem: vi.fn((key) => (key === 'token' ? 'mock_token' : 'TRUE')),
    setItem: vi.fn(),
  });

  render(
    <MockedProvider mocks={[mockQuery('superadmin', true)]} addTypename={false}>
      <MemoryRouter initialEntries={['/user/organizations']}>
        <Routes>
          <Route element={<SecuredRouteForUser />}>
            <Route path="/user/organizations" element={<PageNotFound />} />
          </Route>
        </Routes>
      </MemoryRouter>
    </MockedProvider>,
  );

  await waitFor(() => {
    expect(screen.getByText(/404/i)).toBeInTheDocument();
    expect(screen.getByText(/notFoundMsg/i)).toBeInTheDocument();
  });
});
src/components/SecuredRoute/SecuredRoute.tsx (1)

38-38: Move restricted routes to a configuration file.

The restrictedRoutesForAdmin array should be moved to a configuration file for better maintainability.

src/components/SecuredRoute/SecuredRoute.tsx Outdated Show resolved Hide resolved
src/components/SecuredRoute/SecuredRoute.tsx Outdated Show resolved Hide resolved
PurnenduMIshra129th and others added 2 commits February 2, 2025 04:14
line 20

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
line 30

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
coderabbitai[bot]
coderabbitai bot previously approved these changes Feb 1, 2025
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 comments (3)
src/screens/PageNotFound/PageNotFound.tsx (1)

28-29: Consider replacing local storage check with server-side verification.

The PR aims to enhance security by implementing server-side verification for all routes. However, this component still relies on local storage for admin status checks, which could potentially bypass the new security measures.

Consider using the new VERIFY_ROLE GraphQL query mentioned in the PR summary to verify the admin status server-side. This would align with the PR's objective of replacing local storage checks with server-side verification.

Example approach:

import { useQuery } from '@apollo/client';
import { VERIFY_ROLE } from 'graphql/queries/auth';

// Replace local storage check with GraphQL query
const { data: roleData } = useQuery(VERIFY_ROLE);
const isAdmin = roleData?.verifyRole?.isAdmin;

// Use isAdmin instead of adminFor in the component
src/components/SecuredRoute/SecuredRoute.tsx (1)

66-92: Improve session timeout implementation.

The current session timeout implementation has potential issues:

  1. Global variables for session management
  2. No cleanup of event listeners
  3. Potential memory leaks from setInterval

Consider moving this logic to a custom hook:

// hooks/useSessionTimeout.ts
import { useEffect } from 'react';
import { toast } from 'react-toastify';
import useLocalStorage from 'utils/useLocalstorage';

export const useSessionTimeout = (timeoutMinutes = 15) => {
  const { setItem } = useLocalStorage();
  
  useEffect(() => {
    let lastActive = Date.now();
    const timeoutMs = timeoutMinutes * 60 * 1000;
    
    const handleActivity = () => {
      lastActive = Date.now();
    };
    
    const checkTimeout = () => {
      const timeSinceLastActive = Date.now() - lastActive;
      if (timeSinceLastActive > timeoutMs) {
        toast.warn('Session expired. Please login again.');
        setItem('IsLoggedIn', 'FALSE');
        window.location.href = '/';
      }
    };
    
    // Add multiple event listeners for better activity tracking
    const events = ['mousemove', 'keydown', 'click', 'touchstart'];
    events.forEach(event => document.addEventListener(event, handleActivity));
    
    const interval = setInterval(checkTimeout, 60000); // Check every minute
    
    return () => {
      events.forEach(event => document.removeEventListener(event, handleActivity));
      clearInterval(interval);
    };
  }, [timeoutMinutes, setItem]);
};
src/App.spec.tsx (1)

74-97: Add test cases for role-based routing.

The current test only verifies navigation to '/orglist'. Add tests for role-based access control.

it('should restrict access based on user role', async () => {
  const restrictedRoutes = ['/member', '/users', '/communityProfile'];
  
  for (const route of restrictedRoutes) {
    window.history.pushState({}, '', route);
    await wait();
    
    // For non-admin users, should show PageNotFound
    expect(screen.getByTestId('page-not-found')).toBeTruthy();
  }
});

it('should allow superAdmin access to all routes', async () => {
  // Use superAdmin mock data
  const routes = ['/orglist', '/member', '/users'];
  
  for (const route of routes) {
    window.history.pushState({}, '', route);
    await wait();
    
    // Should not show PageNotFound
    expect(screen.queryByTestId('page-not-found')).toBeNull();
  }
});
🧹 Nitpick comments (2)
src/components/SecuredRoute/SecuredRoute.tsx (2)

20-27: Enhance error handling for GraphQL query.

The GraphQL query setup looks good, but could benefit from more robust error handling.

 const { data, loading, error, refetch } = useQuery(VERIFY_ROLE, {
   skip: !getItem('token'),
   context: {
     headers: {
       Authorization: `Bearer ${getItem('token')}`,
     },
   },
+  onError: (error) => {
+    console.error('Role verification failed:', error);
+    toast.error('Authentication error. Please try logging in again.');
+  }
 });

41-45: Improve user experience during loading and error states.

The current loading and error messages are too basic. Consider using a proper loading spinner and error component.

-  if (loading) {
-    return <div> Loading.....</div>;
-  } else if (error) {
-    return <div>Error During Routing ...</div>;
-  } else {
+  if (loading) {
+    return <LoadingSpinner message="Verifying access..." />;
+  } else if (error) {
+    return <ErrorComponent message="Access verification failed. Please try again." />;
+  } else {
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 23ebe30 and 603ba56.

📒 Files selected for processing (4)
  • docs/docs/auto-docs/screens/PageNotFound/PageNotFound/functions/default.md (1 hunks)
  • src/App.spec.tsx (1 hunks)
  • src/components/SecuredRoute/SecuredRoute.tsx (2 hunks)
  • src/screens/PageNotFound/PageNotFound.tsx (2 hunks)
✅ Files skipped from review due to trivial changes (1)
  • docs/docs/auto-docs/screens/PageNotFound/PageNotFound/functions/default.md
⏰ Context from checks skipped due to timeout of 90000ms (3)
  • GitHub Check: Check Python Code Style
  • GitHub Check: Test Application
  • GitHub Check: Analyse Code With CodeQL (javascript)
🔇 Additional comments (2)
src/screens/PageNotFound/PageNotFound.tsx (2)

8-8: LGTM!

The SignOut component import aligns with the PR's security enhancements.


33-35: LGTM!

The SignOut component is well-positioned and provides a clear way for users to sign out when they reach a 404 page.

src/components/SecuredRoute/SecuredRoute.tsx Outdated Show resolved Hide resolved
src/App.spec.tsx 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: 2

🧹 Nitpick comments (2)
src/components/UserPortal/SecuredRouteForUser/SecuredRouteForUser.tsx (2)

19-25: Add error handling and retry policy for the GraphQL query.

While the query setup is good, consider these improvements for better error handling:

  1. Add token validation before making the query
  2. Implement a retry policy for network failures
 const { data, loading, error, refetch } = useQuery(VERIFY_ROLE, {
   context: {
     headers: {
       Authorization: `Bearer ${getItem('token')}`,
     },
   },
+  onError: (error) => {
+    console.error('Route verification failed:', error);
+  },
+  retry: 2,
+  retryDelay: (attemptIndex) => Math.min(1000 * Math.pow(2, attemptIndex), 30000),
 });

30-34: Enhance loading and error states for better UX.

The current implementation uses basic text messages. Consider:

  1. Using a proper loading component (e.g., spinner)
  2. Providing more informative error messages
  if (loading) {
-   return <div> Loading.....</div>;
+   return <LoadingSpinner message="Verifying access..." />;
  } else if (error) {
-   return <div>Error During Routing ...</div>;
+   return <ErrorMessage 
+     title="Access Verification Failed"
+     message="Unable to verify your access permissions. Please try refreshing the page."
+   />;
  }
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 603ba56 and b122947.

📒 Files selected for processing (2)
  • src/App.spec.tsx (3 hunks)
  • src/components/UserPortal/SecuredRouteForUser/SecuredRouteForUser.tsx (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/App.spec.tsx
⏰ Context from checks skipped due to timeout of 90000ms (2)
  • GitHub Check: Test Application
  • GitHub Check: Analyse Code With CodeQL (javascript)
🔇 Additional comments (1)
src/components/UserPortal/SecuredRouteForUser/SecuredRouteForUser.tsx (1)

1-3: LGTM! Appropriate imports for server-side verification.

The imports correctly include the necessary Apollo Client and GraphQL dependencies for implementing server-side route verification.

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 comments (1)
src/components/SecuredRoute/SecuredRoute.tsx (1)

66-92: Improve session timeout implementation.

The current session timeout implementation has several issues that should be addressed:

  1. Global event listeners could cause memory leaks
  2. Direct DOM manipulation bypasses React
  3. Hard-coded timeout values reduce maintainability
+// Move to src/config/sessionConfig.ts
+export const SESSION_CONFIG = {
+  timeoutMinutes: 15,
+  inactiveIntervalMinutes: 1
+};

+// Create a new hook: src/hooks/useSessionTimeout.ts
+import { useEffect } from 'react';
+import { useNavigate } from 'react-router-dom';
+import { toast } from 'react-toastify';
+import { SESSION_CONFIG } from 'config/sessionConfig';
+
+export const useSessionTimeout = () => {
+  const navigate = useNavigate();
+
+  useEffect(() => {
+    let lastActive = Date.now();
+    
+    const handleActivity = () => {
+      lastActive = Date.now();
+    };
+
+    const checkInactivity = () => {
+      const currentTime = Date.now();
+      const timeSinceLastActive = currentTime - lastActive;
+      
+      if (timeSinceLastActive > SESSION_CONFIG.timeoutMinutes * 60 * 1000) {
+        toast.warn('Session expired. Please log in again.');
+        setItem('IsLoggedIn', 'FALSE');
+        navigate('/', { replace: true });
+      }
+    };
+
+    // Add event listeners through React
+    window.addEventListener('mousemove', handleActivity);
+    window.addEventListener('keypress', handleActivity);
+    
+    const interval = setInterval(
+      checkInactivity,
+      SESSION_CONFIG.inactiveIntervalMinutes * 60 * 1000
+    );
+
+    // Cleanup
+    return () => {
+      window.removeEventListener('mousemove', handleActivity);
+      window.removeEventListener('keypress', handleActivity);
+      clearInterval(interval);
+    };
+  }, [navigate]);
+};

+// In SecuredRoute component
+const SecuredRoute = (): JSX.Element => {
+  useSessionTimeout();
   // ... rest of the component
 };
-
-// Remove the global timeout logic
-const timeoutMinutes = 15;
-const timeoutMilliseconds = timeoutMinutes * 60 * 1000;
-// ... remove the rest of the timeout logic
♻️ Duplicate comments (1)
src/components/SecuredRoute/SecuredRoute.tsx (1)

46-63: 🛠️ Refactor suggestion

Centralize and enhance role-based access control.

The current implementation with hard-coded routes and nested conditions is difficult to maintain. Consider implementing the previously suggested ROUTE_PERMISSIONS configuration.

+// Move to a separate file: src/config/routePermissions.ts
+export const ROUTE_PERMISSIONS = {
+  superAdmin: ['*'],
+  admin: ['/orglist', '/dashboard', '/events'],
+  user: ['/dashboard', '/profile']
+};

+// In SecuredRoute.tsx
-const restrictedRoutesForAdmin = ['/member', '/users', '/communityProfile'];
+import { ROUTE_PERMISSIONS } from 'config/routePermissions';

 const role = data?.verifyRole?.role || '';
 const isLoggedIn = data?.verifyRole?.isAuthorized ?? false;

-if (isLoggedIn) {
-  if (role == 'superAdmin') {
-    return <Outlet />;
-  } else if (role == 'admin') {
-    if (restrictedRoutesForAdmin.includes(location.pathname)) {
-      return <PageNotFound />;
-    }
-    return <Outlet />;
-  } else {
+if (!isLoggedIn) {
+  return <Navigate to="/" replace />;
+}
+
+const allowedRoutes = ROUTE_PERMISSIONS[role] || [];
+const hasAccess = allowedRoutes.includes('*') || 
+                  allowedRoutes.includes(location.pathname);
+
+if (!hasAccess) {
+  console.warn(`Access denied for ${role} to ${location.pathname}`);
+  if (process.env.NODE_ENV === 'development') {
+    console.debug('Allowed routes:', allowedRoutes);
+  }
+  return <PageNotFound />;
+}
+
+return <Outlet />;
-    return <PageNotFound />;
-  }
-} else {
-  return <Navigate to="/" replace />;
-}
🧹 Nitpick comments (4)
src/components/SecuredRoute/SecuredRoute.tsx (2)

19-39: Enhance error handling for token management.

While the token management implementation is good, consider adding error boundaries and logging for token-related issues.

 const { data, loading, error, refetch } = useQuery(VERIFY_ROLE, {
   skip: !getItem('token'),
   context: {
     headers: {
       Authorization: `Bearer ${getItem('token')}`,
     },
   },
+  onError: (error) => {
+    console.error('Role verification failed:', error);
+    // Consider implementing a retry mechanism
+    if (error.message.includes('jwt expired')) {
+      // Handle expired token
+      setItem('IsLoggedIn', 'FALSE');
+      window.location.href = '/';
+    }
+  }
 });

41-45: Improve loading and error state UI.

The current loading and error messages are too basic. Consider using a proper loading spinner and more informative error messages.

 if (loading) {
-  return <div> Loading.....</div>;
+  return (
+    <div className="loading-container">
+      <LoadingSpinner />
+      <p>Verifying your access...</p>
+    </div>
+  );
 } else if (error) {
-  return <div>Error During Routing ...</div>;
+  return (
+    <div className="error-container">
+      <ErrorIcon />
+      <p>Unable to verify your access. Please try refreshing the page.</p>
+      {process.env.NODE_ENV === 'development' && (
+        <pre>{error.message}</pre>
+      )}
+    </div>
+  );
 }
src/components/UserPortal/SecuredRouteForUser/SecuredRouteForUser.tsx (2)

8-15: Update JSDoc comments to reflect the new implementation.

The component's documentation still references the old local storage based checks (AdminFor). Update it to reflect the new GraphQL-based role verification system.

 /**
  * A component that guards routes by checking if the user is logged in.
- * If the user is logged in and does not have 'AdminFor' set, the child routes are rendered.
+ * If the user is logged in and has an appropriate role (user/admin/superAdmin), the child routes are rendered.
  * If the user is not logged in, they are redirected to the homepage.
- * If the user is logged in but has 'AdminFor' set, a 404 page is shown.
+ * If the user is logged in but has an invalid role, a 404 page is shown.
  *
  * @returns JSX.Element - Rendered component based on user authentication and role.
  */

30-34: Enhance loading and error states.

The current loading and error messages could be more informative and user-friendly.

  if (loading) {
-   return <div> Loading.....</div>;
+   return <div className="loading-spinner">Verifying your access...</div>;
  } else if (error) {
-   return <div>Error During Routing ...</div>;
+   return (
+     <div className="error-message">
+       Unable to verify your access. Please try refreshing the page or contact support if the issue persists.
+     </div>
+   );
  }
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b122947 and e4e3401.

📒 Files selected for processing (3)
  • src/App.spec.tsx (3 hunks)
  • src/components/SecuredRoute/SecuredRoute.tsx (2 hunks)
  • src/components/UserPortal/SecuredRouteForUser/SecuredRouteForUser.tsx (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/App.spec.tsx
⏰ Context from checks skipped due to timeout of 90000ms (2)
  • GitHub Check: Test Application
  • GitHub Check: Analyse Code With CodeQL (javascript)
🔇 Additional comments (3)
src/components/SecuredRoute/SecuredRoute.tsx (1)

1-8: LGTM! Proper imports for GraphQL and routing.

The imports are well-organized and include all necessary dependencies for server-side verification.

src/components/UserPortal/SecuredRouteForUser/SecuredRouteForUser.tsx (2)

26-28: Optimize the useEffect dependency array.

The current implementation could cause unnecessary refetches because getItem('token') creates a new reference on every render.


35-47: 🛠️ Refactor suggestion

Improve role verification logic.

The current implementation could be more robust with strict equality and type-safe role enumeration.

+ enum UserRole {
+   USER = 'user',
+   ADMIN = 'admin',
+   SUPER_ADMIN = 'superAdmin'
+ }

- const role = data?.verifyRole?.role || '';
- const isLoggedIn = data?.verifyRole?.isAuthorized ?? false;
+ const role = data?.verifyRole?.role as UserRole;
+ const isAuthorized = data?.verifyRole?.isAuthorized ?? false;

- if (isLoggedIn) {
+ if (isAuthorized) {
-   if (role == 'user' || role == 'admin' || role == 'superAdmin') {
+   if (Object.values(UserRole).includes(role)) {
      return <Outlet />;
    } else {
      return <PageNotFound />;
    }
  } else {
    return <Navigate to="/" replace />;
  }

Likely invalid or redundant comment.

@PurnenduMIshra129th
Copy link
Contributor Author

@palisadoes Testing of frontend application takes more than 1 hours.Is it is issue or what?And for testing a individual component also takes more than 6-7 minutes

@palisadoes
Copy link
Contributor

  1. Please fix the failing test.
  2. If the tests are taking long to complete, there may be an issue with the code in your PR.
  3. Others have not mentioned this as a concern

@PurnenduMIshra129th
Copy link
Contributor Author

@palisadoes not even the component i have developed except that component where mine will not affect will also takes time individually.Yes today i will fix all these failing test cases.

@PurnenduMIshra129th
Copy link
Contributor Author

@palisadoes i got clarity . why some component taking time not all are taking much time. Just like app.tsx which is render all child component when the test runs it renders all the child component i think that's why this type of component are taking time.

@PurnenduMIshra129th
Copy link
Contributor Author

@palisadoes i am facing this issue of screen flickering . I does not know exact issue why it is making . But guesing it is due mis manage of state or something inside a useEffect and may be refreshToken which is causing infinte re render .

2025-02-05.01-31-11.1.mp4

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 comments (3)
src/screens/PageNotFound/PageNotFound.spec.tsx (1)

54-71: Update test strategy to use GraphQL responses.

The test still relies on local storage (setItem('AdminFor', ...)) for admin verification. Since this PR implements server-side verification, the test should use mocked GraphQL responses instead.

Here's how you can update the test:

 it('should render properly for ADMIN or SUPERADMIN', () => {
-  setItem('AdminFor', [
-    {
-      _id: '6537904485008f171cf29924',
-      __typename: 'Organization',
-    },
-  ]);
+  // Mock the VERIFY_ROLE query response for admin
+  const mockLink = new ApolloLink((operation, forward) => {
+    if (operation.operationName === 'VERIFY_ROLE') {
+      return new Observable((observer) => {
+        observer.next({
+          data: {
+            verifyRole: {
+              isAuthorized: true,
+              role: 'ADMIN'
+            }
+          }
+        });
+        observer.complete();
+      });
+    }
+    return forward(operation);
+  });
+
+  const testClient = new ApolloClient({
+    cache: new InMemoryCache(),
+    link: mockLink
+  });

   render(
-    <ApolloProvider client={client}>
+    <ApolloProvider client={testClient}>
src/components/SecuredRoute/SecuredRoute.tsx (2)

80-82: Prevent memory leaks from event listeners.

The mousemove event listener is added but never removed, which could cause memory leaks.

Wrap the event listener in a useEffect hook:

-document.addEventListener('mousemove', () => {
-  lastActive = Date.now();
-});

+useEffect(() => {
+  const updateLastActive = () => {
+    lastActive = Date.now();
+  };
+  
+  document.addEventListener('mousemove', updateLastActive);
+  return () => {
+    document.removeEventListener('mousemove', updateLastActive);
+  };
+}, []);

85-96: Improve session timeout implementation.

The current implementation using setInterval could cause performance issues and might not clean up properly.

Use React's useEffect for session management:

+const useSessionTimeout = (timeoutMinutes: number, inactiveIntervalMin: number) => {
+  useEffect(() => {
+    let timeoutId: NodeJS.Timeout;
+    
+    const checkInactivity = () => {
+      const currentTime = Date.now();
+      const timeSinceLastActive = currentTime - lastActive;
+      
+      if (timeSinceLastActive > timeoutMinutes * 60 * 1000) {
+        toast.warn('Your session has expired. Please log in again.');
+        setItem('IsLoggedIn', 'FALSE');
+        window.location.href = '/';
+      }
+    };
+    
+    timeoutId = setInterval(checkInactivity, inactiveIntervalMin * 60 * 1000);
+    
+    return () => {
+      clearInterval(timeoutId);
+    };
+  }, [timeoutMinutes, inactiveIntervalMin]);
+};

-setInterval(() => {
-  const currentTime = Date.now();
-  const timeSinceLastActive = currentTime - lastActive;
-
-  if (timeSinceLastActive > timeoutMilliseconds) {
-    toast.warn('Kindly relogin as sessison has expired');
-    window.location.href = '/';
-    setItem('IsLoggedIn', 'FALSE');
-  }
-}, inactiveIntervalMilsec);

+useSessionTimeout(timeoutMinutes, inactiveIntervalMin);
🧹 Nitpick comments (4)
src/screens/PageNotFound/PageNotFound.spec.tsx (1)

34-35: Remove unnecessary whitespace and comment.

The whitespace character and inline comment don't add value and should be removed.

-        {' '}
-        {/* ✅ Add ApolloProvider */}
src/components/CheckIn/types.ts (2)

45-49: Add JSDoc comments for the UserRole enum.

The enum is well-structured but lacks documentation explaining the purpose and usage of each role.

Add JSDoc comments:

+/**
+ * Enum representing user roles in the system.
+ * @enum {string}
+ */
 export enum UserRole {
+  /** Regular user with basic privileges */
   USER = 'user',
+  /** Administrator with elevated privileges */
   ADMIN = 'admin',
+  /** Super administrator with full system access */
   SUPER_ADMIN = 'superAdmin',
 }

51-56: Add JSDoc comments for the VerifyRoleResponse type.

The type definition would benefit from documentation explaining its purpose and structure.

Add JSDoc comments:

+/**
+ * Type representing the response from role verification.
+ * @typedef {Object} VerifyRoleResponse
+ */
 export type VerifyRoleResponse = {
+  /** Object containing authorization details */
   verifyRole: {
+    /** Whether the user is authorized */
     isAuthorized: boolean;
+    /** The user's role in the system */
     role: UserRole;
   };
 };
src/components/UserPortal/SecuredRouteForUser/SecuredRouteForUser.tsx (1)

45-49: Enhance loading and error states.

The current loading and error states could be more informative and user-friendly.

Consider using a loading spinner and more descriptive error messages:

   if (loading) {
-    return <div> Loading.....</div>;
+    return <div className="loading-spinner">Verifying your access...</div>;
   } else if (error) {
-    return <div>Error During Routing ...</div>;
+    return <div className="error-message">
+      Unable to verify your access. Please try refreshing the page.
+      {error.message && <p>Error: {error.message}</p>}
+    </div>;
   }
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e4e3401 and 98ca3b9.

📒 Files selected for processing (8)
  • docs/docs/auto-docs/components/CheckIn/types/enumerations/UserRole.md (1 hunks)
  • docs/docs/auto-docs/components/CheckIn/types/type-aliases/VerifyRoleResponse.md (1 hunks)
  • docs/docs/auto-docs/components/SecuredRoute/SecuredRoute/functions/default.md (1 hunks)
  • docs/docs/auto-docs/components/UserPortal/SecuredRouteForUser/SecuredRouteForUser/functions/default.md (1 hunks)
  • src/components/CheckIn/types.ts (1 hunks)
  • src/components/SecuredRoute/SecuredRoute.tsx (2 hunks)
  • src/components/UserPortal/SecuredRouteForUser/SecuredRouteForUser.tsx (2 hunks)
  • src/screens/PageNotFound/PageNotFound.spec.tsx (2 hunks)
✅ Files skipped from review due to trivial changes (2)
  • docs/docs/auto-docs/components/CheckIn/types/type-aliases/VerifyRoleResponse.md
  • docs/docs/auto-docs/components/CheckIn/types/enumerations/UserRole.md
🚧 Files skipped from review as they are similar to previous changes (2)
  • docs/docs/auto-docs/components/UserPortal/SecuredRouteForUser/SecuredRouteForUser/functions/default.md
  • docs/docs/auto-docs/components/SecuredRoute/SecuredRoute/functions/default.md
🧰 Additional context used
📓 Learnings (2)
src/components/SecuredRoute/SecuredRoute.tsx (1)
Learnt from: PurnenduMIshra129th
PR: PalisadoesFoundation/talawa-admin#3491
File: src/components/UserPortal/SecuredRouteForUser/SecuredRouteForUser.tsx:19-25
Timestamp: 2025-02-04T19:16:17.807Z
Learning: In React components using Apollo Client, avoid defining explicit TypeScript types for GraphQL query responses as they are automatically generated based on the GraphQL schema. Focus on query-specific parameters like `skip` for optimization.
src/components/UserPortal/SecuredRouteForUser/SecuredRouteForUser.tsx (1)
Learnt from: PurnenduMIshra129th
PR: PalisadoesFoundation/talawa-admin#3491
File: src/components/UserPortal/SecuredRouteForUser/SecuredRouteForUser.tsx:19-25
Timestamp: 2025-02-04T19:16:17.807Z
Learning: In React components using Apollo Client, avoid defining explicit TypeScript types for GraphQL query responses as they are automatically generated based on the GraphQL schema. Focus on query-specific parameters like `skip` for optimization.
⏰ Context from checks skipped due to timeout of 90000ms (3)
  • GitHub Check: Test Application
  • GitHub Check: Check Python Code Style
  • GitHub Check: Analyse Code With CodeQL (javascript)
🔇 Additional comments (2)
src/screens/PageNotFound/PageNotFound.spec.tsx (1)

12-18: LGTM! Apollo Client imports are well-organized.

The imports are properly structured with type imports separated from component imports.

src/components/SecuredRoute/SecuredRoute.tsx (1)

52-63: 🛠️ Refactor suggestion

Centralize route permissions configuration.

The route restrictions are hardcoded in the component, making them difficult to maintain.

Move route permissions to a configuration file:

+// src/config/routePermissions.ts
+export const ROUTE_PERMISSIONS = {
+  [UserRole.SUPER_ADMIN]: ['*'],  // Access all routes
+  [UserRole.ADMIN]: ['/orglist', '/events'],  // Restricted access
+  [UserRole.USER]: ['/dashboard', '/profile']  // User-specific routes
+};

-const restrictedRoutesForAdmin = ['/member', '/users', '/communityProfile'];
+import { ROUTE_PERMISSIONS } from 'config/routePermissions';

 if (isAuthorized) {
   if (role == UserRole.SUPER_ADMIN) {
     return <Outlet />;
   } else if (role == UserRole.ADMIN) {
-    if (restrictedRoutesForAdmin.includes(location.pathname)) {
+    if (!ROUTE_PERMISSIONS[UserRole.ADMIN].includes(location.pathname)) {
       return <PageNotFound />;
     }
     return <Outlet />;
   }

Likely invalid or redundant comment.

Comment on lines +21 to +28
const link = new ApolloLink((operation, forward) => {
return forward(operation);
});

const client: ApolloClient<NormalizedCacheObject> = new ApolloClient({
cache: new InMemoryCache(),
link: ApolloLink.from([link]),
});
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add mock responses for authorization scenarios.

The current Apollo Client setup uses a no-op link. Consider adding mock responses to test the component's behavior under different authorization states, especially since this PR implements server-side verification.

Here's how you can enhance the setup:

 const link = new ApolloLink((operation, forward) => {
+  // Mock responses based on the operation
+  if (operation.operationName === 'VERIFY_ROLE') {
+    return new Observable((observer) => {
+      // Simulate different authorization scenarios
+      observer.next({
+        data: {
+          verifyRole: {
+            isAuthorized: true, // or false for different test cases
+            role: 'ADMIN' // or other roles
+          }
+        }
+      });
+      observer.complete();
+    });
+  }
   return forward(operation);
 });
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const link = new ApolloLink((operation, forward) => {
return forward(operation);
});
const client: ApolloClient<NormalizedCacheObject> = new ApolloClient({
cache: new InMemoryCache(),
link: ApolloLink.from([link]),
});
const link = new ApolloLink((operation, forward) => {
// Mock responses based on the operation
if (operation.operationName === 'VERIFY_ROLE') {
return new Observable((observer) => {
// Simulate different authorization scenarios
observer.next({
data: {
verifyRole: {
isAuthorized: true, // or false for different test cases
role: 'ADMIN' // or other roles
}
}
});
observer.complete();
});
}
return forward(operation);
});
const client: ApolloClient<NormalizedCacheObject> = new ApolloClient({
cache: new InMemoryCache(),
link: ApolloLink.from([link]),
});

…ser.tsx


line 57

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
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

🧹 Nitpick comments (3)
src/components/UserPortal/SecuredRouteForUser/SecuredRouteForUser.tsx (3)

2-3: Consider relocating shared types to a common directory.

The VerifyRoleResponse type and UserRole enum are imported from components/CheckIn/types but are used across multiple components. Consider moving these to a shared types directory (e.g., src/types or src/shared/types) to improve maintainability.


21-31: Remove explicit type parameter from useQuery.

As per best practices with Apollo Client, the TypeScript types for GraphQL query responses are automatically generated based on the GraphQL schema. The explicit type parameter VerifyRoleResponse is unnecessary.

- const { data, loading, error, refetch } = useQuery<VerifyRoleResponse>(
+ const { data, loading, error, refetch } = useQuery(

45-49: Enhance loading and error handling.

The current implementation uses basic text messages. Consider:

  1. Using a proper loading component for better UX
  2. Providing more informative error messages to help users understand and resolve issues
  if (loading) {
-   return <div> Loading.....</div>;
+   return <LoadingSpinner message="Verifying access..." />;
  } else if (error) {
-   return <div>Error During Routing ...</div>;
+   return <ErrorMessage 
+     message="Failed to verify access permissions"
+     details={error.message}
+     action={() => refetch()}
+   />;
  }
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 98ca3b9 and 7c92f64.

📒 Files selected for processing (1)
  • src/components/UserPortal/SecuredRouteForUser/SecuredRouteForUser.tsx (2 hunks)
🧰 Additional context used
📓 Learnings (1)
src/components/UserPortal/SecuredRouteForUser/SecuredRouteForUser.tsx (1)
Learnt from: PurnenduMIshra129th
PR: PalisadoesFoundation/talawa-admin#3491
File: src/components/UserPortal/SecuredRouteForUser/SecuredRouteForUser.tsx:19-25
Timestamp: 2025-02-04T19:16:17.807Z
Learning: In React components using Apollo Client, avoid defining explicit TypeScript types for GraphQL query responses as they are automatically generated based on the GraphQL schema. Focus on query-specific parameters like `skip` for optimization.
⏰ Context from checks skipped due to timeout of 90000ms (2)
  • GitHub Check: Test Application
  • GitHub Check: Analyse Code With CodeQL (javascript)

Comment on lines +50 to +66
const { isAuthorized = false, role = '' } = (data as VerifyRoleResponse)
.verifyRole;

if (isAuthorized) {
if (
role == UserRole.USER ||
role == UserRole.ADMIN ||
role == UserRole.SUPER_ADMIN
) {
return <Outlet />;
} else {
return <PageNotFound />;
}
} else {
return <Navigate to="/" replace />;
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Strengthen role verification logic.

Several improvements can enhance the security and reliability of the role verification:

  1. Use strict equality comparison
  2. Remove type assertion by properly typing the query response
  3. Consider handling undefined data explicitly
- const { isAuthorized = false, role = '' } = (data as VerifyRoleResponse)
-   .verifyRole;
+ if (!data?.verifyRole) {
+   return <Navigate to="/" replace />;
+ }
+ 
+ const { isAuthorized, role } = data.verifyRole;

  if (isAuthorized) {
    if (
-     role == UserRole.USER ||
-     role == UserRole.ADMIN ||
-     role == UserRole.SUPER_ADMIN
+     role === UserRole.USER ||
+     role === UserRole.ADMIN ||
+     role === UserRole.SUPER_ADMIN
    ) {
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const { isAuthorized = false, role = '' } = (data as VerifyRoleResponse)
.verifyRole;
if (isAuthorized) {
if (
role == UserRole.USER ||
role == UserRole.ADMIN ||
role == UserRole.SUPER_ADMIN
) {
return <Outlet />;
} else {
return <PageNotFound />;
}
} else {
return <Navigate to="/" replace />;
}
}
if (!data?.verifyRole) {
return <Navigate to="/" replace />;
}
const { isAuthorized, role } = data.verifyRole;
if (isAuthorized) {
if (
role === UserRole.USER ||
role === UserRole.ADMIN ||
role === UserRole.SUPER_ADMIN
) {
return <Outlet />;
} else {
return <PageNotFound />;
}
} else {
return <Navigate to="/" replace />;
}
}

Comment on lines +34 to +43
useEffect(() => {
const newToken = getItem('token');
if (newToken !== token) {
setToken(newToken);
}
}, []);

// Conditional rendering based on authentication status and role
return isLoggedIn === 'TRUE' ? (
<>{adminFor == undefined ? <Outlet /> : <PageNotFound />}</>
) : (
<Navigate to="/" replace />
);
useEffect(() => {
refetch(); // Refetch when token updates
}, [token]);
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Improve token state management.

The current implementation has two potential issues:

  1. The first useEffect with empty dependencies won't react to token changes in localStorage
  2. Using separate effects for token updates and refetch could lead to race conditions

Consider combining the effects:

- useEffect(() => {
-   const newToken = getItem('token');
-   if (newToken !== token) {
-     setToken(newToken);
-   }
- }, []);
-
- useEffect(() => {
-   refetch(); // Refetch when token updates
- }, [token]);

+ useEffect(() => {
+   const newToken = getItem('token');
+   if (newToken !== token) {
+     setToken(newToken);
+     refetch();
+   }
+ }, [getItem('token')]);

Committable suggestion skipped: line range outside the PR's diff.

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