Skip to content

feat(server): GET method guard plugin#347

Merged
dinwwwh merged 2 commits intomainfrom
feat/server/get-method-guard-plugin
Apr 9, 2025
Merged

feat(server): GET method guard plugin#347
dinwwwh merged 2 commits intomainfrom
feat/server/get-method-guard-plugin

Conversation

@dinwwwh
Copy link
Copy Markdown
Member

@dinwwwh dinwwwh commented Apr 9, 2025

Summary by CodeRabbit

  • New Features
    • Introduced a security enhancement to restrict unauthorized GET requests.
    • Added a new sidebar entry for the GET Method Guard Plugin.
  • Documentation
    • Expanded documentation for the GET Method Guard Plugin.
    • Enhanced guidance on CSRF prevention and updated the description of the Simple CSRF Protection Plugin.
  • Tests
    • Implemented tests to validate the behavior of the new GET Method Guard Plugin.

@vercel
Copy link
Copy Markdown

vercel Bot commented Apr 9, 2025

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Comments Updated (UTC)
orpc ✅ Ready (Inspect) Visit Preview 💬 Add feedback Apr 9, 2025 4:00am

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 9, 2025

Walkthrough

This pull request introduces a new "GET Method Guard" functionality into the project. It updates documentation by adding a sidebar entry and new pages explaining the plugin, along with enhancements to related security topics. In the server package, a new plugin is implemented to restrict GET requests based on procedure configuration and is accompanied by tests to validate its behavior. Additionally, exports are updated to include the new plugin, ensuring it is accessible from the module index.

Changes

File(s) Change Summary
apps/content/{.vitepress/config.ts, docs/advanced/rpc-protocol.md, docs/plugins/get-method-guard.md, docs/plugins/simple-csrf-protection.md} Added a sidebar entry for "GET method guard", inserted informational notes on CSRF prevention, introduced a new documentation page for the plugin, and updated the CSRF protection plugin description.
packages/server/src/plugins/{get-method-guard.ts, get-method-guard.test.ts, index.ts} Introduced the GetMethodGuardPlugin implementation with its options and interceptors, added test cases to validate its behavior, and updated module exports to include the new plugin.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant Server
    participant GETGuard as GetMethodGuardPlugin

    Client->>Server: Send HTTP Request (GET/POST)
    Server->>GETGuard: Invoke interceptors
    alt GET request for non-GET endpoint
        GETGuard-->>Server: Reject with error (405)
        Server-->>Client: Respond 405 Method Not Allowed
    else GET request for GET endpoint
        GETGuard-->>Server: Validate and allow request
        Server-->>Client: Respond 200 OK
    else Non-GET request
        GETGuard-->>Server: Bypass GET check
        Server-->>Client: Respond 200 OK
    end
Loading

Possibly related PRs

  • unnoq/orpc#220: Modifies the StandardHandlerInterceptorOptions type, aligning with the GET method guard functionality and its integration into the request handling pipeline.

Poem

In a code field I hop with cheer,
A GET guard plugin now appears,
Securing calls with steadfast might,
Protecting routes from CSRF's bite,
I nimbly traverse each function tight,
Celebrating changes with a bunny delight! 🐰💫

✨ Finishing Touches
  • 📝 Generate Docstrings

🪧 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.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai plan to trigger planning for file edits and PR creation.
  • @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.

@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 9, 2025

Codecov Report

Attention: Patch coverage is 97.05882% with 1 line in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
packages/server/src/plugins/index.ts 0.00% 1 Missing ⚠️

📢 Thoughts on this report? Let us know!

@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new Bot commented Apr 9, 2025

More templates

@orpc/arktype

npm i https://pkg.pr.new/@orpc/arktype@347

@orpc/client

npm i https://pkg.pr.new/@orpc/client@347

@orpc/contract

npm i https://pkg.pr.new/@orpc/contract@347

@orpc/openapi

npm i https://pkg.pr.new/@orpc/openapi@347

@orpc/openapi-client

npm i https://pkg.pr.new/@orpc/openapi-client@347

@orpc/react

npm i https://pkg.pr.new/@orpc/react@347

@orpc/react-query

npm i https://pkg.pr.new/@orpc/react-query@347

@orpc/shared

npm i https://pkg.pr.new/@orpc/shared@347

@orpc/server

npm i https://pkg.pr.new/@orpc/server@347

@orpc/solid-query

npm i https://pkg.pr.new/@orpc/solid-query@347

@orpc/standard-server

npm i https://pkg.pr.new/@orpc/standard-server@347

@orpc/standard-server-fetch

npm i https://pkg.pr.new/@orpc/standard-server-fetch@347

@orpc/standard-server-node

npm i https://pkg.pr.new/@orpc/standard-server-node@347

@orpc/svelte-query

npm i https://pkg.pr.new/@orpc/svelte-query@347

@orpc/valibot

npm i https://pkg.pr.new/@orpc/valibot@347

@orpc/vue-colada

npm i https://pkg.pr.new/@orpc/vue-colada@347

@orpc/vue-query

npm i https://pkg.pr.new/@orpc/vue-query@347

@orpc/zod

npm i https://pkg.pr.new/@orpc/zod@347

commit: 62e57b9

Copy link
Copy Markdown

@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 (6)
apps/content/docs/plugins/get-method-guard.md (2)

18-24: Consider adding explicit import for os

The code example correctly demonstrates how to mark a procedure to accept GET requests, but it doesn't show where os comes from. Consider adding an explicit import statement to make the example more complete.

-import { os } from '@orpc/server'
+// Import the route builder
+import { os } from '@orpc/server'

26-39: Add documentation about the customizable error option

The setup example is clear and demonstrates how to integrate the plugin. However, the documentation doesn't mention that the error thrown can be customized, which is a feature provided by the implementation.

Consider adding a section about customizing the error:

## Customizing the Error

You can customize the error thrown when a GET request is made to a procedure that doesn't allow it:

```ts
import { GetMethodGuardPlugin } from '@orpc/server/plugins'
import { ORPCError } from '@orpc/contract'

const handler = new RPCHandler(router, {
  plugins: [
    new GetMethodGuardPlugin({
      error: new ORPCError('FORBIDDEN', 'GET method is not allowed for this procedure')
    })
  ],
})
packages/server/src/plugins/get-method-guard.test.ts (1)

1-58: Consider adding a test for custom error options

The tests cover the basic functionality well but don't test the ability to customize the error via the options passed to the plugin constructor. Consider adding a test case that verifies custom error options work correctly.

it('should use custom error when provided', async () => {
  const customErrorHandler = new RPCHandler({
    ping: os.handler(() => 'pong'),
  }, {
    plugins: [
      new GetMethodGuardPlugin({
        error: new ORPCError('FORBIDDEN', 'Custom error message')
      }),
    ],
  })

  const response = await customErrorHandler.handle(
    new Request('http://localhost/ping?data=%7B%7D')
  )
  
  expect(response).toEqual({ 
    matched: true, 
    response: expect.objectContaining({
      status: 403, // FORBIDDEN status
    }) 
  })
  
  const responseBody = await response.response.json()
  expect(responseBody.error.message).toBe('Custom error message')
})
packages/server/src/plugins/get-method-guard.ts (3)

20-20: Consider documenting the high order value

The order value is set very high (7,000,000) without explanation. While this likely ensures the plugin runs after most others, it would be helpful to document why this specific value was chosen.

-  order = 7_000_000
+  /**
+   * High order value ensures this plugin runs after most others,
+   * allowing other plugins to modify the request/context first.
+   */
+  order = 7_000_000

43-45: Consider consistent error type usage

The plugin uses TypeError for context corruption but ORPCError for method violations. Consider using ORPCError consistently for both cases to provide a uniform error handling experience.

-        throw new TypeError('[GetMethodGuardPlugin] GET method guard context has been corrupted or modified by another plugin or interceptor')
+        throw new ORPCError('INTERNAL_SERVER_ERROR', '[GetMethodGuardPlugin] GET method guard context has been corrupted or modified by another plugin or interceptor')

26-29: Add array type check before using unshift

The code initializes rootInterceptors and clientInterceptors if they're undefined, but doesn't verify they're arrays before calling unshift. While standard handler options should ensure they're arrays, a defensive check would make the code more robust.

    options.rootInterceptors ??= []
    options.clientInterceptors ??= []
+    
+    if (!Array.isArray(options.rootInterceptors) || !Array.isArray(options.clientInterceptors)) {
+      throw new TypeError('[GetMethodGuardPlugin] rootInterceptors and clientInterceptors must be arrays')
+    }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2f2dbaa and 054159c.

📒 Files selected for processing (7)
  • apps/content/.vitepress/config.ts (1 hunks)
  • apps/content/docs/advanced/rpc-protocol.md (1 hunks)
  • apps/content/docs/plugins/get-method-guard.md (1 hunks)
  • apps/content/docs/plugins/simple-csrf-protection.md (1 hunks)
  • packages/server/src/plugins/get-method-guard.test.ts (1 hunks)
  • packages/server/src/plugins/get-method-guard.ts (1 hunks)
  • packages/server/src/plugins/index.ts (1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (2)
packages/server/src/plugins/get-method-guard.test.ts (2)
packages/server/src/builder.ts (1)
  • os (245-261)
packages/server/src/plugins/get-method-guard.ts (1)
  • GetMethodGuardPlugin (17-56)
packages/server/src/plugins/get-method-guard.ts (4)
packages/server/src/context.ts (1)
  • Context (1-1)
packages/server/src/adapters/standard/plugin.ts (1)
  • StandardHandlerPlugin (4-7)
packages/server/src/adapters/standard/handler.ts (1)
  • StandardHandlerOptions (25-47)
packages/contract/src/config.ts (1)
  • fallbackContractConfig (20-26)
🪛 GitHub Check: codecov/patch
packages/server/src/plugins/index.ts

[warning] 3-3: packages/server/src/plugins/index.ts#L3
Added line #L3 was not covered by tests

🔇 Additional comments (18)
packages/server/src/plugins/index.ts (1)

3-3: LGTM: New export added correctly.

The export for the new GET Method Guard plugin has been properly added to the plugins index file, maintaining the alphabetical ordering of exports.

🧰 Tools
🪛 GitHub Check: codecov/patch

[warning] 3-3: packages/server/src/plugins/index.ts#L3
Added line #L3 was not covered by tests

apps/content/docs/advanced/rpc-protocol.md (1)

32-34: Well-placed security information.

This info block provides valuable security guidance in the appropriate context. The CSRF prevention link to MDN documentation and reference to the GET Method Guard plugin enhance the security consciousness of developers using the RPC protocol.

apps/content/.vitepress/config.ts (1)

113-113: LGTM: Sidebar navigation entry added correctly.

The navigation entry for the GET Method Guard plugin is properly positioned in the Plugins section, following the existing pattern of other plugin entries.

apps/content/docs/plugins/simple-csrf-protection.md (3)

3-3: Improved description with clearer security context.

The enhanced description provides better context about the plugin's purpose in preventing CSRF attacks.


6-6: Title updated for consistency.

Adding "Plugin" to the title maintains consistency with other plugin documentation.


8-8: Enhanced introduction with educational link.

The expanded introduction paragraph provides a clearer explanation of CSRF protection with a helpful link to MDN documentation.

apps/content/docs/plugins/get-method-guard.md (4)

1-4: Good choice of title and meta description!

The title and description clearly communicate the purpose of the plugin. The description effectively summarizes the security benefits and the specific problem it addresses (CSRF risks).


6-8: Introduction establishes the security context well

The introduction effectively explains the plugin's purpose and links to relevant documentation about RPC Protocol and CSRF prevention, which helps developers understand the security context.


10-12: "When to Use" section provides clear guidance

This section properly explains the specific scenarios where the plugin is beneficial, focusing on applications that store sensitive data in cookies with certain SameSite settings.


14-16: "How it works" section is straightforward and precise

The explanation of the plugin's behavior is concise and clear, making it easy for developers to understand the core functionality.

packages/server/src/plugins/get-method-guard.test.ts (4)

1-16: Test setup is comprehensive

The test setup creates a handler with:

  1. A procedure not marked as GET-allowed ('ping')
  2. A procedure explicitly marked as GET-allowed ('pong')
  3. The GetMethodGuardPlugin properly configured
  4. A test interceptor

This covers the necessary scenarios for testing the plugin's functionality.


18-32: Tests correctly verify GET method restrictions

The test properly verifies:

  1. GET requests to non-GET procedures return 405
  2. POST requests to the same procedure return 200

This confirms the core functionality of the plugin.


34-38: Test confirms GET method is allowed for marked procedures

This test properly verifies that a GET request to a procedure explicitly marked as GET returns a 200 OK response, confirming the plugin allows proper GET requests.


40-57: Test for context corruption is thorough

The test correctly verifies that when an interceptor modifies the context in a way that removes the plugin's context symbol, the handler responds with a 500 error, ensuring robustness against potential interceptor conflicts.

packages/server/src/plugins/get-method-guard.ts (4)

15-15: Symbol naming is clear and follows conventions

The symbol name clearly indicates its purpose and follows standard naming conventions with uppercase and underscores, making it easy to identify in debugging contexts.


17-24: Class implementation follows good practices

The class correctly:

  1. Implements the StandardHandlerPlugin interface
  2. Uses generics to maintain type safety
  3. Provides a default error while allowing customization
  4. Has a high order value to ensure it runs after other plugins

No issues with the implementation.


26-40: Root interceptor implementation is robust

The root interceptor correctly:

  1. Checks if the request method is GET
  2. Preserves the original context while adding the method information
  3. Uses a symbol to avoid name collisions

This implementation ensures the context is properly augmented without losing existing information.


42-54: Client interceptor implementation has good error handling

The client interceptor:

  1. Verifies the context hasn't been corrupted
  2. Retrieves the procedure method with a fallback mechanism
  3. Throws the appropriate error when GET requests are made to non-GET procedures
  4. Only throws errors when necessary (doesn't affect other methods)

The implementation is secure and follows good practices.

Comment thread packages/server/src/plugins/get-method-guard.ts
Copy link
Copy Markdown

@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: 0

🧹 Nitpick comments (1)
packages/server/src/plugins/get-method-guard.ts (1)

5-13: Consider simplifying the error property type.

You could directly type error as ORPCError rather than InstanceType<typeof ORPCError> to avoid any potential confusion.

 export interface GetMethodGuardPluginOptions {
-  error?: InstanceType<typeof ORPCError>
+  error?: ORPCError
 }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 054159c and 62e57b9.

📒 Files selected for processing (1)
  • packages/server/src/plugins/get-method-guard.ts (1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (1)
packages/server/src/plugins/get-method-guard.ts (4)
packages/server/src/context.ts (1)
  • Context (1-1)
packages/server/src/adapters/standard/plugin.ts (1)
  • StandardHandlerPlugin (4-7)
packages/server/src/adapters/standard/handler.ts (1)
  • StandardHandlerOptions (25-47)
packages/contract/src/config.ts (1)
  • fallbackContractConfig (20-26)
🔇 Additional comments (4)
packages/server/src/plugins/get-method-guard.ts (4)

1-3: Module imports appear correct and consistent.

The imports for types and utilities are well-structured. No further issues are noted here.


26-40: Valid approach to setting GET context in the handler.

Unshifting an interceptor that injects the isGetMethod flag into the context is a clean way to handle method checks early in the pipeline. This looks good.


42-55: Logic for enforcing GET restrictions is well-structured.

The second interceptor correctly checks for a GET request and ensures the procedure is allowed to use GET. Throwing the configured error is appropriate here.


20-20:

Details

✅ Verification successful

Confirm plugin execution priority.

The order is set to a large value (7_000_000). Make sure it is intentional so that this plugin runs at the desired point in the pipeline.

Please verify that the plugin’s priority aligns with your intended execution order. If it’s misplaced, you may need to adjust this value.


🏁 Script executed:

#!/bin/bash
# Search for other plugin `order` properties to ensure the chosen priority does not conflict.
rg --multiline 'order\s*=\s*\d+'

Length of output: 420


Plugin execution priority verified

The get-method-guard.ts plugin's order is set to 7_000_000, which correctly positions it after the batch plugins (order 5_000_000) and before the CSRF and CORS plugins (orders 8_000_000 and 9_000_000 respectively). This ordering appears intentional and aligns with the desired execution sequence for your pipeline. Please confirm once more that this sequence is aligned with the overall plugin dependency and execution strategy.

@dinwwwh dinwwwh merged commit 3ee2e95 into main Apr 9, 2025
7 of 8 checks passed
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.

1 participant