@botfabrik/engine-webclient 4.116.7 → 4.116.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/applySecurityMiddleware.js +17 -36
- package/dist/applySecurityMiddleware.test.js +4 -15
- package/dist/client/assets/index-BtxflGXw.js +75 -0
- package/dist/client/assets/index-BtxflGXw.js.map +1 -0
- package/dist/client/index.html +1 -1
- package/dist/createSessionInfo.test.js +9 -3
- package/dist/embed/bundle.js +2 -2
- package/dist/index.js +1 -1
- package/dist/requestSessionData.test.js +8 -2
- package/dist/types.d.ts +2 -13
- package/package.json +2 -2
- package/dist/client/assets/index-CtCTrwZP.js +0 -75
- package/dist/client/assets/index-CtCTrwZP.js.map +0 -1
|
@@ -8,24 +8,18 @@ import helmet from 'helmet';
|
|
|
8
8
|
* @param baseUrl - The server's own base URL (e.g. "http://localhost:3000").
|
|
9
9
|
*/
|
|
10
10
|
export function applySecurityMiddleware(router, props, baseUrl) {
|
|
11
|
-
const { allowedEmbedOrigins, allowedResourceOrigins } = props;
|
|
12
|
-
// CORS
|
|
13
|
-
// When allowedEmbedOrigins is undefined, all origins are permitted (backward-compatible default).
|
|
14
|
-
// When it is set (even to an empty array), only the listed origins plus the server's own
|
|
15
|
-
// base URL are allowed.
|
|
11
|
+
const { allowedEmbedOrigins = [], allowedResourceOrigins = [] } = props;
|
|
16
12
|
router.use(cors({
|
|
17
|
-
origin:
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
}
|
|
28
|
-
},
|
|
13
|
+
origin: (origin, callback) => {
|
|
14
|
+
// The server's own origin is always allowed.
|
|
15
|
+
const effectiveAllowed = [baseUrl, ...allowedEmbedOrigins];
|
|
16
|
+
if (!origin || effectiveAllowed.includes(origin)) {
|
|
17
|
+
callback(null, true);
|
|
18
|
+
}
|
|
19
|
+
else {
|
|
20
|
+
callback(new Error(`CORS: Origin '${origin}' is not allowed`));
|
|
21
|
+
}
|
|
22
|
+
},
|
|
29
23
|
methods: ['GET', 'POST', 'OPTIONS'],
|
|
30
24
|
allowedHeaders: ['Content-Type', 'Authorization'],
|
|
31
25
|
credentials: true,
|
|
@@ -36,30 +30,17 @@ export function applySecurityMiddleware(router, props, baseUrl) {
|
|
|
36
30
|
directives: {
|
|
37
31
|
defaultSrc: ["'self'"],
|
|
38
32
|
scriptSrc: ["'self'"],
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
styleSrc: allowedResourceOrigins === undefined
|
|
42
|
-
? ["'self'", "'unsafe-inline'", 'https:']
|
|
43
|
-
: ["'self'", "'unsafe-inline'", ...allowedResourceOrigins],
|
|
44
|
-
// images: restrict to allowed resource origins when defined, otherwise allow all HTTPS
|
|
45
|
-
imgSrc: allowedResourceOrigins === undefined
|
|
46
|
-
? ["'self'", 'data:', 'https:']
|
|
47
|
-
: ["'self'", 'data:', ...allowedResourceOrigins],
|
|
33
|
+
styleSrc: ["'self'", "'unsafe-inline'", ...allowedResourceOrigins],
|
|
34
|
+
imgSrc: ["'self'", 'data:', ...allowedResourceOrigins],
|
|
48
35
|
connectSrc: [
|
|
49
36
|
"'self'",
|
|
50
37
|
// allow websocket connections back to the same server
|
|
51
38
|
baseUrl.replace(/^http/, 'ws'),
|
|
52
39
|
baseUrl.replace(/^http/, 'wss'),
|
|
53
40
|
],
|
|
54
|
-
// fonts may be loaded from allowed resource origins (e.g. Google Fonts)
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
? ['*']
|
|
58
|
-
: ["'self'", ...allowedResourceOrigins],
|
|
59
|
-
// when no allowedEmbedOrigins are configured, allow framing from all origins
|
|
60
|
-
frameAncestors: allowedEmbedOrigins === undefined
|
|
61
|
-
? ['*']
|
|
62
|
-
: ["'self'", ...allowedEmbedOrigins],
|
|
41
|
+
// fonts may be loaded from allowed resource origins (e.g. Google Fonts)
|
|
42
|
+
fontSrc: ["'self'", ...allowedResourceOrigins],
|
|
43
|
+
frameAncestors: ["'self'", ...allowedEmbedOrigins],
|
|
63
44
|
// frame-src controls what this page may embed in an iframe.
|
|
64
45
|
// The /embed page loads the chatbot in an iframe on the same server.
|
|
65
46
|
// We include both http and https of the server's base URL because a browser
|
|
@@ -69,7 +50,7 @@ export function applySecurityMiddleware(router, props, baseUrl) {
|
|
|
69
50
|
"'self'",
|
|
70
51
|
baseUrl,
|
|
71
52
|
baseUrl.replace(/^http:/, 'https:'),
|
|
72
|
-
...
|
|
53
|
+
...allowedEmbedOrigins,
|
|
73
54
|
],
|
|
74
55
|
objectSrc: ["'none'"],
|
|
75
56
|
baseUri: ["'self'"],
|
|
@@ -5,12 +5,6 @@ import { applySecurityMiddleware } from './applySecurityMiddleware.js';
|
|
|
5
5
|
const BASE_URL = 'http://localhost:3000';
|
|
6
6
|
describe('security middleware', () => {
|
|
7
7
|
describe('CORS', () => {
|
|
8
|
-
it('allows all origins when allowedEmbedOrigins is undefined', async () => {
|
|
9
|
-
const res = await supertest(makeApp({}))
|
|
10
|
-
.get('/')
|
|
11
|
-
.set('Origin', 'http://any-origin.example.com');
|
|
12
|
-
expect(res.headers['access-control-allow-origin']).toBe('http://any-origin.example.com');
|
|
13
|
-
});
|
|
14
8
|
it('allows the server baseUrl when allowedEmbedOrigins is []', async () => {
|
|
15
9
|
const res = await supertest(makeApp({ allowedEmbedOrigins: [] }))
|
|
16
10
|
.get('/')
|
|
@@ -36,10 +30,6 @@ describe('security middleware', () => {
|
|
|
36
30
|
});
|
|
37
31
|
});
|
|
38
32
|
describe('CSP frame-ancestors', () => {
|
|
39
|
-
it("is '*' when allowedEmbedOrigins is undefined", async () => {
|
|
40
|
-
const res = await supertest(makeApp({})).get('/');
|
|
41
|
-
expect(res.headers['content-security-policy']).toContain('frame-ancestors *');
|
|
42
|
-
});
|
|
43
33
|
it('is "\'self\'" + listed origin when allowedEmbedOrigins is set', async () => {
|
|
44
34
|
const res = await supertest(makeApp({ allowedEmbedOrigins: ['http://example.com'] })).get('/');
|
|
45
35
|
expect(res.headers['content-security-policy']).toContain("frame-ancestors 'self' http://example.com");
|
|
@@ -58,12 +48,11 @@ describe('security middleware', () => {
|
|
|
58
48
|
});
|
|
59
49
|
});
|
|
60
50
|
describe('CSP allowedResourceOrigins', () => {
|
|
61
|
-
it('
|
|
62
|
-
const res = await supertest(makeApp({})).get('/');
|
|
51
|
+
it('restricts styleSrc/imgSrc/fontSrc to self only when allowedResourceOrigins is []', async () => {
|
|
52
|
+
const res = await supertest(makeApp({ allowedResourceOrigins: [] })).get('/');
|
|
63
53
|
const csp = res.headers['content-security-policy'];
|
|
64
|
-
expect(csp).toContain('
|
|
65
|
-
expect(csp).toContain('
|
|
66
|
-
expect(csp).toContain('font-src *');
|
|
54
|
+
expect(csp).not.toContain("'unsafe-inline' https:");
|
|
55
|
+
expect(csp).not.toContain('font-src *');
|
|
67
56
|
});
|
|
68
57
|
it('restricts styleSrc/imgSrc/fontSrc to listed origins when set', async () => {
|
|
69
58
|
const res = await supertest(makeApp({ allowedResourceOrigins: ['https://fonts.googleapis.com'] })).get('/');
|