Skip to content

Commit 1a89a61

Browse files
committed
fix: allow debugger to connect with custom hosts
1 parent ad237ed commit 1a89a61

File tree

3 files changed

+90
-21
lines changed

3 files changed

+90
-21
lines changed
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import securityHeadersMiddleware from '../securityHeadersMiddleware';
2+
3+
describe('securityHeadersMiddleware', () => {
4+
let req, res, next;
5+
6+
beforeEach(() => {
7+
req = {
8+
headers: {},
9+
};
10+
res = {
11+
setHeader: () => {},
12+
};
13+
next = jest.fn();
14+
});
15+
16+
afterEach(() => {
17+
jest.clearAllMocks();
18+
});
19+
20+
it('should block requests from different origins', () => {
21+
req.headers.origin = 'https://example.com';
22+
const middleware = securityHeadersMiddleware({});
23+
middleware(req, res, next);
24+
expect(next).toHaveBeenCalledWith(expect.any(Error));
25+
});
26+
27+
it('should allow requests from localhost', () => {
28+
req.headers.origin = 'http://localhost:3000';
29+
const middleware = securityHeadersMiddleware({});
30+
middleware(req, res, next);
31+
expect(next).toHaveBeenCalled();
32+
});
33+
34+
it('should allow requests from devtools', () => {
35+
req.headers.origin = 'devtools://devtools';
36+
const middleware = securityHeadersMiddleware({});
37+
middleware(req, res, next);
38+
expect(next).toHaveBeenCalled();
39+
});
40+
41+
it('should allow requests from custom host if provided in options', () => {
42+
req.headers.origin = 'http://customhost.com';
43+
const middleware = securityHeadersMiddleware({host: 'customhost.com'});
44+
middleware(req, res, next);
45+
expect(next).toHaveBeenCalled();
46+
});
47+
48+
it('should block requests from custom host if provided in options but not matching', () => {
49+
req.headers.origin = 'http://anotherhost.com';
50+
const middleware = securityHeadersMiddleware({host: 'customhost.com'});
51+
middleware(req, res, next);
52+
expect(next).toHaveBeenCalledWith(expect.any(Error));
53+
});
54+
});

packages/cli-server-api/src/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ export function createDevServerMiddleware(options: MiddlewareOptions) {
4545
const eventsSocketEndpoint = createEventsSocketEndpoint(broadcast);
4646

4747
const middleware = connect()
48-
.use(securityHeadersMiddleware)
48+
.use(securityHeadersMiddleware(options))
4949
// @ts-ignore compression and connect types mismatch
5050
.use(compression())
5151
.use(nocache())

packages/cli-server-api/src/securityHeadersMiddleware.ts

Lines changed: 35 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -6,29 +6,44 @@
66
*/
77
import http from 'http';
88

9-
export default function securityHeadersMiddleware(
9+
type MiddlewareOptions = {
10+
host?: string;
11+
};
12+
13+
type MiddlewareFn = (
1014
req: http.IncomingMessage,
1115
res: http.ServerResponse,
1216
next: (err?: any) => void,
13-
) {
14-
// Block any cross origin request.
15-
if (
16-
typeof req.headers.origin === 'string' &&
17-
!req.headers.origin.match(/^https?:\/\/localhost:/) &&
18-
!req.headers.origin.startsWith('devtools://devtools')
19-
) {
20-
next(
21-
new Error(
22-
'Unauthorized request from ' +
23-
req.headers.origin +
24-
'. This may happen because of a conflicting browser extension. Please try to disable it and try again.',
25-
),
26-
);
27-
return;
28-
}
17+
) => void;
18+
19+
export default function securityHeadersMiddleware(
20+
options: MiddlewareOptions,
21+
): MiddlewareFn {
22+
return (
23+
req: http.IncomingMessage,
24+
res: http.ServerResponse,
25+
next: (err?: any) => void,
26+
) => {
27+
const host = options.host ? options.host : 'localhost';
28+
// Block any cross origin request.
29+
if (
30+
typeof req.headers.origin === 'string' &&
31+
!req.headers.origin.match(new RegExp('^https?://' + host + ':')) &&
32+
!req.headers.origin.startsWith('devtools://devtools')
33+
) {
34+
next(
35+
new Error(
36+
'Unauthorized request from ' +
37+
req.headers.origin +
38+
'. This may happen because of a conflicting browser extension. Please try to disable it and try again.',
39+
),
40+
);
41+
return;
42+
}
2943

30-
// Block MIME-type sniffing.
31-
res.setHeader('X-Content-Type-Options', 'nosniff');
44+
// Block MIME-type sniffing.
45+
res.setHeader('X-Content-Type-Options', 'nosniff');
3246

33-
next();
47+
next();
48+
};
3449
}

0 commit comments

Comments
 (0)