UNPKG

@staticcms/proxy-server-lite

Version:
262 lines (223 loc) 7.19 kB
import winston from 'winston'; import { join } from 'path'; import { getSchema, localFsMiddleware } from '.'; import { listRepoFiles } from '../utils/fs'; import type Joi from 'joi'; import type express from 'express'; jest.mock('../utils/fs'); function assetFailure(result: Joi.ValidationResult, expectedMessage: string) { const { error } = result; expect(error).not.toBeNull(); expect(error!.details).toHaveLength(1); const message = error!.details.map(({ message }) => message)[0]; expect(message).toBe(expectedMessage); } const defaultParams = { branch: 'master', }; describe('localFsMiddleware', () => { beforeEach(() => { jest.clearAllMocks(); }); describe('getSchema', () => { it('should throw on path traversal', () => { const schema = getSchema({ repoPath: join('Users', 'user', 'documents', 'code', 'repo') }); assetFailure( schema.validate({ action: 'getEntry', params: { ...defaultParams, path: '../' }, }), '"params.path" must resolve to a path under the configured repository', ); }); it('should not throw on valid path', () => { const schema = getSchema({ repoPath: join('Users', 'user', 'documents', 'code', 'repo') }); const { error } = schema.validate({ action: 'getEntry', params: { ...defaultParams, path: 'src/content/posts/title.md' }, }); expect(error).toBeUndefined(); }); it('should throw on folder traversal', () => { const schema = getSchema({ repoPath: join('Users', 'user', 'documents', 'code', 'repo') }); assetFailure( schema.validate({ action: 'entriesByFolder', params: { ...defaultParams, folder: '../', extension: 'md' }, }), '"params.folder" must resolve to a path under the configured repository', ); }); it('should not throw on valid folder', () => { const schema = getSchema({ repoPath: join('Users', 'user', 'documents', 'code', 'repo') }); const { error } = schema.validate({ action: 'entriesByFolder', params: { ...defaultParams, folder: 'src/posts', extension: 'md' }, }); expect(error).toBeUndefined(); }); it('should throw on media folder traversal', () => { const schema = getSchema({ repoPath: join('Users', 'user', 'documents', 'code', 'repo') }); assetFailure( schema.validate({ action: 'getMedia', params: { ...defaultParams, mediaFolder: '../' }, }), '"params.mediaFolder" must resolve to a path under the configured repository', ); }); it('should not throw on valid folder', () => { const schema = getSchema({ repoPath: join('Users', 'user', 'documents', 'code', 'repo') }); const { error } = schema.validate({ action: 'getMedia', params: { ...defaultParams, mediaFolder: 'static/images' }, }); expect(error).toBeUndefined(); }); }); describe('getMedia', () => { it('should get media files', async () => { (listRepoFiles as jest.Mock).mockResolvedValue([ { file: 'mediaFolder/asset1.jpg', isDirectory: false, }, { file: 'mediaFolder/asset2.jpg', isDirectory: false, }, { file: 'mediaFolder/asset3.jpg', isDirectory: false, }, ]); const json = jest.fn(); const res: express.Response = { json } as unknown as express.Response; const req = { body: { action: 'getMedia', params: { mediaFolder: 'mediaFolder', branch: 'main', }, }, } as express.Request; const repoPath = '.'; await localFsMiddleware({ repoPath, logger: winston.createLogger() })(req, res); expect(json).toHaveBeenCalledTimes(1); expect(json).toHaveBeenCalledWith([ { path: 'mediaFolder/asset1.jpg', url: 'mediaFolder/asset1.jpg', isDirectory: false, }, { path: 'mediaFolder/asset2.jpg', url: 'mediaFolder/asset2.jpg', isDirectory: false, }, { path: 'mediaFolder/asset3.jpg', url: 'mediaFolder/asset3.jpg', isDirectory: false, }, ]); }); it('should translate media path to public path even when media path is absolute', async () => { (listRepoFiles as jest.Mock).mockResolvedValue([ { file: 'mediaFolder/asset1.jpg', isDirectory: false, }, { file: 'mediaFolder/asset2.jpg', isDirectory: false, }, { file: 'mediaFolder/asset3.jpg', isDirectory: false, }, ]); const json = jest.fn(); const res: express.Response = { json } as unknown as express.Response; const req = { body: { action: 'getMedia', params: { mediaFolder: '/mediaFolder', publicFolder: '/publicFolder', branch: 'main', }, }, } as express.Request; const repoPath = '.'; await localFsMiddleware({ repoPath, logger: winston.createLogger() })(req, res); expect(json).toHaveBeenCalledTimes(1); expect(json).toHaveBeenCalledWith([ { path: 'mediaFolder/asset1.jpg', url: '/publicFolder/asset1.jpg', isDirectory: false, }, { path: 'mediaFolder/asset2.jpg', url: '/publicFolder/asset2.jpg', isDirectory: false, }, { path: 'mediaFolder/asset3.jpg', url: '/publicFolder/asset3.jpg', isDirectory: false, }, ]); }); it('should translate media path to public path', async () => { (listRepoFiles as jest.Mock).mockResolvedValue([ { file: 'mediaFolder/asset1.jpg', isDirectory: false, }, { file: 'mediaFolder/asset2.jpg', isDirectory: false, }, { file: 'mediaFolder/asset3.jpg', isDirectory: false, }, ]); const json = jest.fn(); const res: express.Response = { json } as unknown as express.Response; const req = { body: { action: 'getMedia', params: { mediaFolder: 'mediaFolder', publicFolder: '/publicFolder', branch: 'main', }, }, } as express.Request; const repoPath = '.'; await localFsMiddleware({ repoPath, logger: winston.createLogger() })(req, res); expect(json).toHaveBeenCalledTimes(1); expect(json).toHaveBeenCalledWith([ { path: 'mediaFolder/asset1.jpg', url: '/publicFolder/asset1.jpg', isDirectory: false, }, { path: 'mediaFolder/asset2.jpg', url: '/publicFolder/asset2.jpg', isDirectory: false, }, { path: 'mediaFolder/asset3.jpg', url: '/publicFolder/asset3.jpg', isDirectory: false, }, ]); }); }); });