From 624b7ff14b9b84a7b7b3ee8c9f2bf601e38b2bc2 Mon Sep 17 00:00:00 2001 From: Erez Rokah Date: Tue, 26 May 2020 11:50:09 +0300 Subject: [PATCH] feat: add allowed_hosts support in local_backend (#3805) --- .../src/actions/__tests__/config.spec.js | 19 ++++++++++++ .../netlify-cms-core/src/actions/config.js | 8 +++-- .../constants/__tests__/configSchema.spec.js | 31 +++++++++++++------ .../src/constants/configSchema.js | 6 +++- website/content/docs/beta-features.md | 4 ++- 5 files changed, 54 insertions(+), 14 deletions(-) diff --git a/packages/netlify-cms-core/src/actions/__tests__/config.spec.js b/packages/netlify-cms-core/src/actions/__tests__/config.spec.js index 777e1c96..7157b2d7 100644 --- a/packages/netlify-cms-core/src/actions/__tests__/config.spec.js +++ b/packages/netlify-cms-core/src/actions/__tests__/config.spec.js @@ -491,6 +491,25 @@ describe('config', () => { assetFetchCalled(url); }); + + it('should use local_backend allowed_hosts', async () => { + const allowed_hosts = ['192.168.0.1']; + window.location = { hostname: '192.168.0.1' }; + global.fetch = jest.fn().mockResolvedValue({ + json: jest.fn().mockResolvedValue({ + repo: 'test-repo', + publish_modes: ['simple', 'editorial_workflow'], + type: 'local_git', + }), + }); + await expect(detectProxyServer({ allowed_hosts })).resolves.toEqual({ + proxyUrl: 'http://192.168.0.1:8081/api/v1', + publish_modes: ['simple', 'editorial_workflow'], + type: 'local_git', + }); + + assetFetchCalled('http://192.168.0.1:8081/api/v1'); + }); }); describe('handleLocalBackend', () => { diff --git a/packages/netlify-cms-core/src/actions/config.js b/packages/netlify-cms-core/src/actions/config.js index 9470dcb3..34f15949 100644 --- a/packages/netlify-cms-core/src/actions/config.js +++ b/packages/netlify-cms-core/src/actions/config.js @@ -186,12 +186,14 @@ export function mergeConfig(config) { } export async function detectProxyServer(localBackend) { - if (location.hostname === 'localhost' || location.hostname === '127.0.0.1') { + const allowedHosts = ['localhost', '127.0.0.1', ...(localBackend?.allowed_hosts || [])]; + if (allowedHosts.includes(location.hostname)) { let proxyUrl; + const defaultUrl = 'http://localhost:8081/api/v1'; if (localBackend === true) { - proxyUrl = 'http://localhost:8081/api/v1'; + proxyUrl = defaultUrl; } else if (isPlainObject(localBackend)) { - proxyUrl = localBackend.url; + proxyUrl = localBackend.url || defaultUrl.replace('localhost', location.hostname); } try { console.log(`Looking for Netlify CMS Proxy Server at '${proxyUrl}'`); diff --git a/packages/netlify-cms-core/src/constants/__tests__/configSchema.spec.js b/packages/netlify-cms-core/src/constants/__tests__/configSchema.spec.js index bc249750..0462f368 100644 --- a/packages/netlify-cms-core/src/constants/__tests__/configSchema.spec.js +++ b/packages/netlify-cms-core/src/constants/__tests__/configSchema.spec.js @@ -129,27 +129,40 @@ describe('config', () => { it('should throw if local_backend is not a boolean or plain object', () => { expect(() => { - validateConfig(merge(validConfig, { local_backend: [] })); + validateConfig({ ...validConfig, local_backend: [] }); }).toThrowError("'local_backend' should be boolean"); }); - it('should throw if local_backend is a plain object but missing url property', () => { + it('should throw if local_backend url is not a string', () => { expect(() => { - validateConfig(merge(validConfig, { local_backend: {} })); - }).toThrowError("'local_backend' should be object"); + validateConfig({ ...validConfig, local_backend: { url: [] } }); + }).toThrowError("'local_backend.url' should be string"); + }); + + it('should throw if local_backend allowed_hosts is not a string array', () => { + expect(() => { + validateConfig({ ...validConfig, local_backend: { allowed_hosts: [true] } }); + }).toThrowError("'local_backend.allowed_hosts[0]' should be string"); }); it('should not throw if local_backend is a boolean', () => { expect(() => { - validateConfig(merge(validConfig, { local_backend: true })); + validateConfig({ ...validConfig, local_backend: true }); }).not.toThrowError(); }); - it('should not throw if local_backend is a plain object with url property', () => { + it('should not throw if local_backend is a plain object with url string property', () => { expect(() => { - validateConfig( - merge(validConfig, { local_backend: { url: 'http://localhost:8081/api/v1' } }), - ); + validateConfig({ ...validConfig, local_backend: { url: 'http://localhost:8081/api/v1' } }); + }).not.toThrowError(); + }); + + it('should not throw if local_backend is a plain object with allowed_hosts string array property', () => { + expect(() => { + validateConfig({ + ...validConfig, + local_backend: { allowed_hosts: ['192.168.0.1'] }, + }); }).not.toThrowError(); }); diff --git a/packages/netlify-cms-core/src/constants/configSchema.js b/packages/netlify-cms-core/src/constants/configSchema.js index 17392cf4..dd31a8c1 100644 --- a/packages/netlify-cms-core/src/constants/configSchema.js +++ b/packages/netlify-cms-core/src/constants/configSchema.js @@ -73,8 +73,12 @@ const getConfigSchema = () => ({ type: 'object', properties: { url: { type: 'string', examples: ['http://localhost:8081/api/v1'] }, + allowed_hosts: { + type: 'array', + items: { type: 'string' }, + }, }, - required: ['url'], + additionalProperties: false, }, ], }, diff --git a/website/content/docs/beta-features.md b/website/content/docs/beta-features.md index 880ce5dd..3cd1d1f9 100644 --- a/website/content/docs/beta-features.md +++ b/website/content/docs/beta-features.md @@ -25,9 +25,11 @@ backend: # when using the default proxy server port local_backend: true -# when using a custom proxy server port local_backend: + # when using a custom proxy server port url: http://localhost:8082/api/v1 + # when accessing the local site from a host other than 'localhost' or '127.0.0.1' + allowed_hosts: ['192.168.0.1'] ``` 4. Start your local development server (e.g. run `gatsby develop`).