mirror of
				https://github.com/strapi/strapi.git
				synced 2025-10-31 18:08:11 +00:00 
			
		
		
		
	Add tests and comments and PR co-author credit
Co-Authored-By: Anton Mikaskin <garrakombo@gmail.com> Co-Authored-By: vnguyen42
This commit is contained in:
		
							parent
							
								
									d6965e562c
								
							
						
					
					
						commit
						d11699c79b
					
				| @ -2,9 +2,10 @@ import { Readable } from 'stream'; | ||||
| import type { ILocalFileSourceProviderOptions } from '..'; | ||||
| 
 | ||||
| import { createLocalFileSourceProvider } from '..'; | ||||
| import { isFilePathInDirname, isPathEquivalent, unknownPathToPosix } from '../utils'; | ||||
| 
 | ||||
| describe('Stream assets', () => { | ||||
|   test('returns a stream', () => { | ||||
| describe('File source provider', () => { | ||||
|   test('returns assets stream', () => { | ||||
|     const options: ILocalFileSourceProviderOptions = { | ||||
|       file: { | ||||
|         path: './test-file', | ||||
| @ -21,4 +22,108 @@ describe('Stream assets', () => { | ||||
| 
 | ||||
|     expect(stream instanceof Readable).toBeTruthy(); | ||||
|   }); | ||||
| 
 | ||||
|   describe('utils', () => { | ||||
|     const unknownConversionCases = [ | ||||
|       ['some/path/on/posix', 'some/path/on/posix'], | ||||
|       ['some/path/on/posix/', 'some/path/on/posix/'], | ||||
|       ['some/path/on/posix.jpg', 'some/path/on/posix.jpg'], | ||||
|       ['file.jpg', 'file.jpg'], | ||||
|       ['noextension', 'noextension'], | ||||
|       ['some\\windows\\filename.jpg', 'some/windows/filename.jpg'], | ||||
|       ['some\\windows\\noendingslash', 'some/windows/noendingslash'], | ||||
|       ['some\\windows\\endingslash\\', 'some/windows/endingslash/'], | ||||
|     ]; | ||||
|     test.each(unknownConversionCases)('unknownPathToPosix: %p -> %p', (input, expected) => { | ||||
|       expect(unknownPathToPosix(input)).toEqual(expected); | ||||
|     }); | ||||
| 
 | ||||
|     const isFilePathInDirnameCases: [string, string, boolean][] = [ | ||||
|       // posix paths
 | ||||
|       ['some/path/on/posix', 'some/path/on/posix/file.jpg', true], | ||||
|       ['some/path/on/posix/', 'some/path/on/posix/file.jpg', true], | ||||
|       ['./some/path/on/posix', 'some/path/on/posix/file.jpg', true], | ||||
|       ['some/path/on/posix/', './some/path/on/posix/file.jpg', true], | ||||
|       ['some/path/on/posix/', 'some/path/on/posix/', false], // invalid; second method should include a filename
 | ||||
|       ['some/path/on/posix', 'some/path/on/posix', false], // 'posix' in second case should be interpreted as a filename
 | ||||
|       ['', 'file.jpg', true], | ||||
|       ['', './file.jpg', true], | ||||
|       ['./', './file.jpg', true], | ||||
|       ['noextension', 'noextension', false], // second case is a file
 | ||||
|       ['noextension', './noextension/file.jpg', true], | ||||
|       ['./noextension', './noextension/file.jpg', true], | ||||
|       ['./noextension', 'noextension/file.jpg', true], | ||||
|       ['noextension', 'noextension/noextension', true], | ||||
|       // win32 paths
 | ||||
|       ['some/path/on/win32', 'some\\path\\on\\win32\\file.jpg', true], | ||||
|       ['some/path/on/win32/', 'some\\path\\on\\win32\\file.jpg', true], | ||||
|       ['some/path/on/win32/', 'some\\path\\on\\win32\\', false], // invalid; second method should include a filename
 | ||||
|       ['some/path/on/win32', 'some\\path\\on\\win32', false], // 'win32' in second case should be interpreted as a filename
 | ||||
|       ['', 'file.jpg', true], | ||||
|       ['', '.\\file.jpg', true], | ||||
|       ['./', '.\\file.jpg', true], | ||||
|       ['noextension', 'noextension', false], // second case is a file
 | ||||
|       ['noextension', '.\\noextension\\file.jpg', true], | ||||
|       ['./noextension', '.\\noextension\\file.jpg', true], | ||||
|       ['./noextension', 'noextension\\file.jpg', true], | ||||
|       ['noextension', 'noextension\\noextension', true], | ||||
|     ]; | ||||
|     test.each(isFilePathInDirnameCases)( | ||||
|       'isFilePathInDirname: %p : %p -> %p', | ||||
|       (inputA, inputB, expected) => { | ||||
|         expect(isFilePathInDirname(inputA, inputB)).toEqual(expected); | ||||
|       } | ||||
|     ); | ||||
| 
 | ||||
|     const isPathEquivalentCases: [string, string, boolean][] = [ | ||||
|       // POSITIVES
 | ||||
|       // root level
 | ||||
|       ['file.jpg', 'file.jpg', true], | ||||
|       ['file.jpg', '.\\file.jpg', true], | ||||
|       ['file.jpg', './file.jpg', true], | ||||
|       // cwd root level (posix)
 | ||||
|       ['./file.jpg', 'file.jpg', true], | ||||
|       ['./file.jpg', './file.jpg', true], | ||||
|       ['./file.jpg', '.\\file.jpg', true], | ||||
|       // cwd root level (win32)
 | ||||
|       ['.\\file.jpg', 'file.jpg', true], | ||||
|       ['.\\file.jpg', './file.jpg', true], | ||||
|       ['.\\file.jpg', '.\\file.jpg', true], | ||||
|       // directory with file (posix)
 | ||||
|       ['one/two/file.jpg', 'one/two/file.jpg', true], | ||||
|       ['one/two/file.jpg', './one/two/file.jpg', true], | ||||
|       ['one/two/file.jpg', 'one\\two\\file.jpg', true], | ||||
|       ['one/two/file.jpg', '.\\one\\two\\file.jpg', true], | ||||
|       // cwd with file (posix)
 | ||||
|       ['./one/two/file.jpg', 'one/two/file.jpg', true], | ||||
|       ['./one/two/file.jpg', './one/two/file.jpg', true], | ||||
|       ['./one/two/file.jpg', 'one\\two\\file.jpg', true], | ||||
|       ['./one/two/file.jpg', '.\\one\\two\\file.jpg', true], | ||||
|       // directory with file (win32)
 | ||||
|       ['one\\two\\file.jpg', 'one/two/file.jpg', true], | ||||
|       ['one\\two\\file.jpg', './one/two/file.jpg', true], | ||||
|       ['one\\two\\file.jpg', '.\\one\\two\\file.jpg', true], | ||||
|       ['one\\two\\file.jpg', 'one\\two\\file.jpg', true], | ||||
|       // cwd with file (win32)
 | ||||
|       ['.\\one\\two\\file.jpg', 'one/two/file.jpg', true], | ||||
|       ['.\\one\\two\\file.jpg', './one/two/file.jpg', true], | ||||
|       ['.\\one\\two\\file.jpg', '.\\one\\two\\file.jpg', true], | ||||
|       ['.\\one\\two\\file.jpg', 'one\\two\\file.jpg', true], | ||||
| 
 | ||||
|       // NEGATIVES
 | ||||
|       ['file.jpg', 'one/file.jpg', false], | ||||
|       ['file.jpg', 'one\\file.jpg', false], | ||||
|       ['file.jpg', '/file.jpg', false], | ||||
|       ['file.jpg', '\\file.jpg', false], | ||||
|       ['one/file.jpg', '\\one\\file.jpg', false], | ||||
|       ['one/file.jpg', '/one/file.jpg', false], | ||||
|       ['one/file.jpg', 'file.jpg', false], | ||||
|     ]; | ||||
|     test.each(isPathEquivalentCases)( | ||||
|       'isPathEquivalent: %p : %p -> %p', | ||||
|       (inputA, inputB, expected) => { | ||||
|         expect(isPathEquivalent(inputA, inputB)).toEqual(expected); | ||||
|       } | ||||
|     ); | ||||
|   }); | ||||
| }); | ||||
|  | ||||
| @ -15,7 +15,7 @@ import type { IAsset, IMetadata, ISourceProvider, ProviderType } from '../../../ | ||||
| import { createDecryptionCipher } from '../../../utils/encryption'; | ||||
| import { collect } from '../../../utils/stream'; | ||||
| import { ProviderInitializationError, ProviderTransferError } from '../../../errors/providers'; | ||||
| import { isDirPathEquivalent, isPathEquivalent, unknownPathToPosix } from './utils'; | ||||
| import { isFilePathInDirname, isPathEquivalent, unknownPathToPosix } from './utils'; | ||||
| 
 | ||||
| type StreamItemArray = Parameters<typeof chain>[0]; | ||||
| 
 | ||||
| @ -143,7 +143,7 @@ class LocalFileSourceProvider implements ISourceProvider { | ||||
|             if (entry.type !== 'File') { | ||||
|               return false; | ||||
|             } | ||||
|             return isDirPathEquivalent('assets/uploads', filePath); | ||||
|             return isFilePathInDirname('assets/uploads', filePath); | ||||
|           }, | ||||
|           onentry(entry) { | ||||
|             // TODO: Check if we need to handle win32 paths here for the assets
 | ||||
| @ -203,7 +203,7 @@ class LocalFileSourceProvider implements ISourceProvider { | ||||
|               return false; | ||||
|             } | ||||
| 
 | ||||
|             return isDirPathEquivalent(directory, filePath); | ||||
|             return isFilePathInDirname(directory, filePath); | ||||
|           }, | ||||
| 
 | ||||
|           async onentry(entry) { | ||||
|  | ||||
| @ -12,23 +12,37 @@ import path from 'path'; | ||||
|  * | ||||
|  * */ | ||||
| 
 | ||||
| // Check if the directory of a given filePath (which can be either posix or win32) resolves to the same as the given posix-format path posixDirName
 | ||||
| // We must be able to assume the first argument is a path, otherwise path.dirname will interpret a path without any slashes as the filename
 | ||||
| export const isDirPathEquivalent = (posixDirName: string, filePath: string) => { | ||||
| /** | ||||
|  * Check if the directory of a given filePath (which can be either posix or win32) resolves to the same as the given posix-format path posixDirName | ||||
|  * We must be able to assume the first argument is a path to a directory and the second is a path to a file, otherwise path.dirname will interpret a path without any slashes as the filename | ||||
|  * | ||||
|  * @param {string} posixDirName A posix path pointing to a directory | ||||
|  * @param {string} filePath an unknown filesystem path pointing to a file | ||||
|  * @returns {boolean} is the file located in the given directory | ||||
|  */ | ||||
| export const isFilePathInDirname = (posixDirName: string, filePath: string) => { | ||||
|   const normalizedDir = path.posix.dirname(unknownPathToPosix(filePath)); | ||||
|   return isPathEquivalent(posixDirName, normalizedDir); | ||||
| }; | ||||
| 
 | ||||
| // Check if two paths that can be either in posix or win32 format resolves to the same file
 | ||||
| export const isPathEquivalent = (fileA: string, fileB: string) => { | ||||
| /** | ||||
|  *  Check if two paths that can be either in posix or win32 format resolves to the same file | ||||
|  * | ||||
|  * @param {string} pathA a path that may be either win32 or posix | ||||
|  * @param {string} pathB a path that may be either win32 or posix | ||||
|  * | ||||
|  * @returns {boolean} do paths point to the same place | ||||
|  */ | ||||
| export const isPathEquivalent = (pathA: string, pathB: string) => { | ||||
|   // Check if paths appear to be win32 or posix, and if win32 convert to posix
 | ||||
|   const normalizedPathA = unknownPathToPosix(fileA); | ||||
|   const normalizedPathB = unknownPathToPosix(fileB); | ||||
|   const normalizedPathA = path.posix.normalize(unknownPathToPosix(pathA)); | ||||
|   const normalizedPathB = path.posix.normalize(unknownPathToPosix(pathB)); | ||||
| 
 | ||||
|   return !path.posix.relative(normalizedPathB, normalizedPathA).length; | ||||
| }; | ||||
| 
 | ||||
| /** | ||||
|  *  Convert an unknown format path (win32 or posix) to a posix path | ||||
|  * | ||||
|  * @param {string} filePath a path that may be either win32 or posix | ||||
|  * | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Ben Irvin
						Ben Irvin