Skip to content

Commit 8028c80

Browse files
committed
chore: refactor code and declare import type for module
1 parent f048c20 commit 8028c80

File tree

4 files changed

+47
-65
lines changed

4 files changed

+47
-65
lines changed

packages/middleware-allow-request-methods/README.md

Lines changed: 29 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,10 @@ Express middleware that returns 405 (rather than 404) for disallowed request met
66
* [Usage](#usage)
77
* [Configuration options](#configuration-options)
88
* [`options.allowedMethods`](#optionsallowedmethods)
9-
* [`options.message`](#optionsmessage)
10-
* [`options.logger`](#optionslogger)
119
* [Migrating](#migrating)
1210
* [Contributing](#contributing)
1311
* [License](#license)
1412

15-
1613
## Usage
1714

1815
Install `@dotcom-reliability-kit/middleware-allow-request-methods` as a dependency:
@@ -24,30 +21,45 @@ npm install --save @dotcom-reliability-kit/middleware-allow-request-methods
2421
Include in your code:
2522

2623
```js
27-
import allowRequestMethods from '@dotcom-reliability-kit/middleware-allow-request-methods';
24+
import { allowRequestMethods } from '@dotcom-reliability-kit/middleware-allow-request-methods';
2825
// or
29-
const allowRequestMethods = require('@dotcom-reliability-kit/middleware-allow-request-methods');
26+
const { allowRequestMethods } = require('@dotcom-reliability-kit/middleware-allow-request-methods');
3027
```
3128

29+
We recommend always using this middleware globally with app.use as a first middleware in your app. This is because, if a bad actor is making requests to your app to find attack vectors, you throw their request out as early as possible.
30+
31+
Route-specific blocking of methods is an additional layer of protection you can explore. It may be that your app does support POST requests for a form but the main view is GET only. You can filter out further junk requests on a per-route basis by using the app.route('...').all() method or use with a path.
32+
3233
Example usage:
3334

3435
```js
3536
const express = require('express');
36-
const allowRequestMethods = require('@dotcom-reliability-kit/middleware-allow-request-methods');
37+
const { allowRequestMethods } = require('@dotcom-reliability-kit/middleware-allow-request-methods');
3738

3839
const app = express();
3940

40-
// Apply the middleware to specific routes, for example:
41-
app.use('/', allowRequestMethods(['GET'])); // Allow only GET requests on '/'
42-
app.use('/submit', allowRequestMethods(['POST'])); // Allow only POST requests on '/submit'
43-
44-
// Define your routes
45-
app.get('/', (req, res) => {
46-
res.send('Homepage');
47-
});
48-
49-
app.post('/submit', (req, res) => {
50-
res.send('Form submitted');
41+
// Allow only certain request methods for the entire app. If you're
42+
// doing this, it must be above ALL routes you want it to apply to:
43+
app.use(allowRequestMethods({ allowedMethods: ['GET', 'HEAD', 'POST'] }));
44+
45+
// Allow only certain request methods for a specific route, e.g. here
46+
// we only allow `GET` and `HEAD` methods for the home page. Note that
47+
// we have to use `all` for the allowed methods here THEN define the get
48+
// request handler:
49+
app
50+
.route('/')
51+
.all(allowRequestMethods({ allowedMethods: ['GET', 'HEAD'] }))
52+
.get((request, response) => {
53+
response.send('Homepage');
54+
});
55+
56+
// You can also allow methods for a subset of routes. Remember that this
57+
// applies for all routes that START with the value. E.g. the following
58+
// will also only allow POST requests on `/submit/example`:
59+
app.use('/submit', allowRequestMethods({ allowedMethods: ['POST'] }));
60+
61+
app.post('/submit', (request, response) => {
62+
response.send('Form submitted');
5163
});
5264

5365
app.listen(3000, () => console.log('Server running on port 3000'));
@@ -69,32 +81,10 @@ An array of HTTP methods that are allowed for the route. This must be an `Array`
6981

7082
This option defaults to `[]`.
7183

72-
#### `options.message`
73-
74-
A string to be used as the response body when a request is made with an unsupported method.
75-
76-
This option defaults to `'Method Not Allowed'`.
77-
78-
#### `options.logger`
79-
80-
A logger object which implements two methods, `error` and `warn`, which have the following permissive signature:
81-
82-
```ts
83-
type LogMethod = (...logData: any) => any;
84-
```
85-
86-
This is passed directly onto the relevant log-error method, [see the documentation for that package for more details](../log-error/README.md#optionslogger).
87-
88-
## Migrating
89-
90-
Consult the [Migration Guide](./docs/migration.md) if you're trying to migrate to a later major version of this package.
91-
92-
9384
## Contributing
9485

9586
See the [central contributing guide for Reliability Kit](https://github.com/Financial-Times/dotcom-reliability-kit/blob/main/docs/contributing.md).
9687

97-
9888
## License
9989

10090
Licensed under the [MIT](https://github.com/Financial-Times/dotcom-reliability-kit/blob/main/LICENSE) license.<br/>

packages/middleware-allow-request-methods/lib/index.js

Lines changed: 7 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,24 @@
11
const { UserInputError } = require('@dotcom-reliability-kit/errors');
22

33
/**
4-
* @typedef {object} RequestMethodOptions
5-
* @property {string[]} [allowedMethods] The HTTP methods that are allowed i.e. will not throw 405 errors.
6-
* @property {string} [message] The error message text to use if a disallowed method is used.
7-
* @property {import('@dotcom-reliability-kit/log-error').Logger} [logger] The logger to use for logging errors.
4+
* @import { RequestMethodOptions } from '@dotcom-reliability-kit/middleware-allow-request-methods'
85
*/
96

107
/**
11-
* @typedef {import('express').Response} ExpressResponse
8+
* @import { RequestHandler } from 'express'
129
*/
1310

1411
/**
1512
* Create a middleware function to return 405 (rather than 404) for disallowed request methods.
1613
*
1714
* @param {RequestMethodOptions} [options]
18-
* @returns {import('express').RequestHandler} - Returns an Express middleware function.
15+
* @returns {RequestHandler} - Returns an Express middleware function.
1916
*/
20-
function allowRequestMethods(
21-
options = { allowedMethods: [], message: 'Method Not Allowed' }
22-
) {
17+
function allowRequestMethods(options = { allowedMethods: [] }) {
2318
// Check if allowed methods have been specified and are valid
2419
const allowedMethodsSpecified = options?.allowedMethods;
2520
if (
26-
!allowedMethodsSpecified ||
21+
!Array.isArray(allowedMethodsSpecified) ||
2722
allowedMethodsSpecified.length === 0 ||
2823
allowedMethodsSpecified.every((method) => typeof method !== 'string')
2924
) {
@@ -37,15 +32,13 @@ function allowRequestMethods(
3732
);
3833

3934
return function allowRequestMethodsMiddleware(request, response, next) {
40-
// If headers are already sent, pass the error to the default Express error handler
35+
// We can't set the Allow header if headers have already been sent, otherwise the middleware will error
4136
if (!response.headersSent) {
4237
response.header('Allow', normalisedAllowedRequestMethods.join(', '));
4338
}
4439

4540
// If the incoming request method is not in the allowed methods array, then send a 405 error
46-
if (
47-
!normalisedAllowedRequestMethods.includes(request.method.toUpperCase())
48-
) {
41+
if (!normalisedAllowedRequestMethods.includes(request.method)) {
4942
return next(new UserInputError({ statusCode: 405 }));
5043
} else {
5144
// Else if it is, then pass the request to the next() middleware

packages/middleware-allow-request-methods/test/unit/lib/index.spec.js

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -100,17 +100,6 @@ describe('allowRequestMethods', () => {
100100

101101
expect(mockNext).toHaveBeenCalledWith();
102102
});
103-
104-
it('handles case-insensitive method matching', () => {
105-
mockRequest.method = 'get';
106-
const middleware = allowRequestMethods({
107-
allowedMethods: ['GET', 'POST']
108-
});
109-
110-
middleware(mockRequest, mockResponse, mockNext);
111-
112-
expect(mockNext).toHaveBeenCalledWith();
113-
});
114103
});
115104

116105
describe('normaliseAllowedRequestMethods', () => {
Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,11 @@
1-
declare module '@dotcom-reliability-kit/middleware-allow-request-methods' {}
1+
import { RequestHandler } from 'express';
2+
3+
declare module '@dotcom-reliability-kit/middleware-allow-request-methods' {
4+
export type RequestMethodOptions = {
5+
allowedMethods?: string[];
6+
};
7+
8+
declare function allowRequestMethods(
9+
options?: RequestMethodOptions
10+
): RequestHandler;
11+
}

0 commit comments

Comments
 (0)