|
1 | 1 | /* eslint-disable @typescript-eslint/no-non-null-assertion */
|
2 |
| -import { mergeConfig } from '@vendure/core'; |
| 2 | +import { ConfigService, mergeConfig } from '@vendure/core'; |
3 | 3 | import { AssetFragment } from '@vendure/core/e2e/graphql/generated-e2e-admin-types';
|
4 | 4 | import { createTestEnvironment } from '@vendure/testing';
|
| 5 | +import { exec } from 'child_process'; |
5 | 6 | import fs from 'fs-extra';
|
6 | 7 | import gql from 'graphql-tag';
|
7 | 8 | import fetch from 'node-fetch';
|
@@ -193,6 +194,41 @@ describe('AssetServerPlugin', () => {
|
193 | 194 | it('does not error on non-integer height', async () => {
|
194 | 195 | return fetch(`${asset.preview}?h=10.5`);
|
195 | 196 | });
|
| 197 | + |
| 198 | + // https://github.com/vendure-ecommerce/vendure/security/advisories/GHSA-r9mq-3c9r-fmjq |
| 199 | + describe('path traversal', () => { |
| 200 | + function curlWithPathAsIs(url: string) { |
| 201 | + return new Promise<string>((resolve, reject) => { |
| 202 | + // We use curl here rather than node-fetch or any other fetch-type function because |
| 203 | + // those will automatically perform path normalization which will mask the path traversal |
| 204 | + return exec(`curl --path-as-is ${url}`, (err, stdout, stderr) => { |
| 205 | + if (err) { |
| 206 | + reject(err); |
| 207 | + } |
| 208 | + resolve(stdout); |
| 209 | + }); |
| 210 | + }); |
| 211 | + } |
| 212 | + |
| 213 | + function testPathTraversalOnUrl(urlPath: string) { |
| 214 | + return async () => { |
| 215 | + const port = server.app.get(ConfigService).apiOptions.port; |
| 216 | + const result = await curlWithPathAsIs(`http://localhost:${port}/assets${urlPath}`); |
| 217 | + expect(result).not.toContain('@vendure/asset-server-plugin'); |
| 218 | + expect(result.toLowerCase()).toContain('resource not found'); |
| 219 | + }; |
| 220 | + } |
| 221 | + |
| 222 | + it('blocks path traversal 1', testPathTraversalOnUrl(`/../../package.json`)); |
| 223 | + it('blocks path traversal 2', testPathTraversalOnUrl(`/foo/../../../package.json`)); |
| 224 | + it('blocks path traversal 3', testPathTraversalOnUrl(`/foo/../../../foo/../package.json`)); |
| 225 | + it('blocks path traversal 4', testPathTraversalOnUrl(`/%2F..%2F..%2Fpackage.json`)); |
| 226 | + it('blocks path traversal 5', testPathTraversalOnUrl(`/%2E%2E/%2E%2E/package.json`)); |
| 227 | + it('blocks path traversal 6', testPathTraversalOnUrl(`/..//..//package.json`)); |
| 228 | + it('blocks path traversal 7', testPathTraversalOnUrl(`/.%2F.%2F.%2Fpackage.json`)); |
| 229 | + it('blocks path traversal 8', testPathTraversalOnUrl(`/..\\\\..\\\\package.json`)); |
| 230 | + it('blocks path traversal 9', testPathTraversalOnUrl(`/\\\\\\..\\\\\\..\\\\\\package.json`)); |
| 231 | + }); |
196 | 232 | });
|
197 | 233 |
|
198 | 234 | describe('deletion', () => {
|
@@ -268,7 +304,7 @@ describe('AssetServerPlugin', () => {
|
268 | 304 | // https://github.com/vendure-ecommerce/vendure/issues/1563
|
269 | 305 | it('falls back to binary preview if image file cannot be processed', async () => {
|
270 | 306 | const filesToUpload = [path.join(__dirname, 'fixtures/assets/bad-image.jpg')];
|
271 |
| - const { createAssets }: CreateAssets.Mutation = await adminClient.fileUploadMutation({ |
| 307 | + const { createAssets }: CreateAssetsMutation = await adminClient.fileUploadMutation({ |
272 | 308 | mutation: CREATE_ASSETS,
|
273 | 309 | filePaths: filesToUpload,
|
274 | 310 | mapVariables: filePaths => ({
|
|
0 commit comments