Skip to content

Commit b654691

Browse files
committed
Remote guides - resovle config ’*’ to default whitelist
1 parent 5b5e487 commit b654691

File tree

5 files changed

+188
-3
lines changed

5 files changed

+188
-3
lines changed

src/shared/modules/commands/commandsDuck.js

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,8 @@ import {
3030
extractWhitelistFromConfigString,
3131
addProtocolsToUrlList,
3232
firstSuccessPromise,
33-
serialExecution
33+
serialExecution,
34+
resolveWhitelistWildcard
3435
} from 'services/utils'
3536
import helper from 'services/commandInterpreterHelper'
3637
import { addHistory } from '../history/historyDuck'
@@ -45,7 +46,8 @@ import {
4546
UPDATE_SETTINGS,
4647
getAvailableSettings,
4748
fetchMetaData,
48-
getRemoteContentHostnameWhitelist
49+
getRemoteContentHostnameWhitelist,
50+
getDefaultRemoteContentHostnameWhitelist
4951
} from '../dbMeta/dbMetaDuck'
5052
import { APP_START, USER_CLEAR } from 'shared/modules/app/appDuck'
5153
import { add as addFrame } from 'shared/modules/stream/streamDuck'
@@ -256,7 +258,14 @@ export const fetchGuideFromWhitelistEpic = (some$, store) =>
256258
}
257259
const whitelistStr = getRemoteContentHostnameWhitelist(store.getState())
258260
const whitelist = extractWhitelistFromConfigString(whitelistStr)
259-
const urlWhitelist = addProtocolsToUrlList(whitelist)
261+
const defaultWhitelist = extractWhitelistFromConfigString(
262+
getDefaultRemoteContentHostnameWhitelist(store.getState())
263+
)
264+
const resolvedWildcardWhitelist = resolveWhitelistWildcard(
265+
whitelist,
266+
defaultWhitelist
267+
)
268+
const urlWhitelist = addProtocolsToUrlList(resolvedWildcardWhitelist)
260269
const guidesUrls = urlWhitelist.map(url => url + '/' + action.url)
261270
return firstSuccessPromise(guidesUrls, url => {
262271
// Get first successful fetch
Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
/*
2+
* Copyright (c) 2002-2018 "Neo4j, Inc"
3+
* Network Engine for Objects in Lund AB [http://neotechnology.com]
4+
*
5+
* This file is part of Neo4j.
6+
*
7+
* Neo4j is free software: you can redistribute it and/or modify
8+
* it under the terms of the GNU General Public License as published by
9+
* the Free Software Foundation, either version 3 of the License, or
10+
* (at your option) any later version.
11+
*
12+
* This program is distributed in the hope that it will be useful,
13+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15+
* GNU General Public License for more details.
16+
*
17+
* You should have received a copy of the GNU General Public License
18+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
19+
*/
20+
21+
/* global jest, describe, afterEach, test, expect */
22+
import { createEpicMiddleware } from 'redux-observable'
23+
import { createBus } from 'suber'
24+
import {
25+
fetchGuideFromWhitelistAction,
26+
fetchGuideFromWhitelistEpic
27+
} from './commandsDuck'
28+
29+
jest.mock('services/remote', () => {
30+
const orig = require.requireActual('services/remote')
31+
return {
32+
...orig,
33+
get: jest.fn()
34+
}
35+
})
36+
const remote = require.requireMock('services/remote')
37+
38+
jest.mock('shared/modules/dbMeta/dbMetaDuck', () => {
39+
const orig = require.requireActual('shared/modules/dbMeta/dbMetaDuck')
40+
return {
41+
...orig,
42+
getRemoteContentHostnameWhitelist: jest.fn(),
43+
getDefaultRemoteContentHostnameWhitelist: jest.fn()
44+
}
45+
})
46+
const dbMeta = require.requireMock('shared/modules/dbMeta/dbMetaDuck')
47+
48+
describe('fetchGuideFromWhitelistEpic', () => {
49+
afterEach(() => {
50+
remote.get.mockReset()
51+
dbMeta.getRemoteContentHostnameWhitelist.mockReset()
52+
dbMeta.getDefaultRemoteContentHostnameWhitelist.mockReset()
53+
})
54+
55+
it('resolves * to default whitelist when looking for a guide', done => {
56+
// Given
57+
const bus = createBus()
58+
bus.applyReduxMiddleware(createEpicMiddleware(fetchGuideFromWhitelistEpic))
59+
remote.get.mockImplementation(() => Promise.reject(new Error('test')))
60+
dbMeta.getRemoteContentHostnameWhitelist.mockImplementation(() => '*')
61+
dbMeta.getDefaultRemoteContentHostnameWhitelist.mockImplementation(
62+
() => 'testurl1.test, testurl2.test'
63+
)
64+
const $$responseChannel = 'test-channel'
65+
const action = fetchGuideFromWhitelistAction('reco')
66+
action.$$responseChannel = $$responseChannel
67+
bus.one($$responseChannel, res => {
68+
// Then
69+
expect(dbMeta.getRemoteContentHostnameWhitelist).toHaveBeenCalledTimes(1)
70+
expect(
71+
dbMeta.getDefaultRemoteContentHostnameWhitelist
72+
).toHaveBeenCalledTimes(1)
73+
expect(remote.get).toHaveBeenCalledTimes(4) // 2 times per hostname
74+
expect(remote.get).toHaveBeenCalledWith('http://testurl1.test/reco', {
75+
'cache-control': 'no-cache',
76+
pragma: 'no-cache'
77+
})
78+
expect(remote.get).toHaveBeenCalledWith('https://testurl1.test/reco', {
79+
'cache-control': 'no-cache',
80+
pragma: 'no-cache'
81+
})
82+
expect(remote.get).toHaveBeenCalledWith('http://testurl2.test/reco', {
83+
'cache-control': 'no-cache',
84+
pragma: 'no-cache'
85+
})
86+
expect(remote.get).toHaveBeenCalledWith('https://testurl2.test/reco', {
87+
'cache-control': 'no-cache',
88+
pragma: 'no-cache'
89+
})
90+
done()
91+
})
92+
bus.send(action.type, action)
93+
})
94+
it('does not change behavior when * isnt involved', done => {
95+
// Given
96+
const bus = createBus()
97+
bus.applyReduxMiddleware(createEpicMiddleware(fetchGuideFromWhitelistEpic))
98+
remote.get.mockImplementation(() => Promise.reject(new Error('test')))
99+
dbMeta.getRemoteContentHostnameWhitelist.mockImplementation(
100+
() => 'configurl1.test'
101+
)
102+
103+
dbMeta.getDefaultRemoteContentHostnameWhitelist.mockImplementation(
104+
() => 'test1.test, test2.test'
105+
)
106+
const $$responseChannel = 'test-channel'
107+
const action = fetchGuideFromWhitelistAction('reco')
108+
action.$$responseChannel = $$responseChannel
109+
bus.one($$responseChannel, res => {
110+
// Then
111+
expect(dbMeta.getRemoteContentHostnameWhitelist).toHaveBeenCalledTimes(1)
112+
expect(
113+
dbMeta.getDefaultRemoteContentHostnameWhitelist
114+
).toHaveBeenCalledTimes(1)
115+
expect(remote.get).toHaveBeenCalledTimes(2)
116+
expect(remote.get).toHaveBeenCalledWith('http://configurl1.test/reco', {
117+
'cache-control': 'no-cache',
118+
pragma: 'no-cache'
119+
})
120+
expect(remote.get).toHaveBeenCalledWith('https://configurl1.test/reco', {
121+
'cache-control': 'no-cache',
122+
pragma: 'no-cache'
123+
})
124+
done()
125+
})
126+
bus.send(action.type, action)
127+
})
128+
})

src/shared/modules/dbMeta/dbMetaDuck.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,8 @@ export const credentialsTimeout = state =>
8686
export const getRemoteContentHostnameWhitelist = state =>
8787
getAvailableSettings(state)['browser.remote_content_hostname_whitelist'] ||
8888
initialState.settings['browser.remote_content_hostname_whitelist']
89+
export const getDefaultRemoteContentHostnameWhitelist = () =>
90+
initialState.settings['browser.remote_content_hostname_whitelist']
8991
export const shouldRetainConnectionCredentials = state => {
9092
const settings = getAvailableSettings(state)
9193
const conf = settings['browser.retain_connection_credentials']

src/shared/services/utils.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,15 @@ export const addProtocolsToUrlList = list => {
181181
}, [])
182182
}
183183

184+
export const resolveWhitelistWildcard = (list, resolveTo = []) => {
185+
return list.reduce((all, entry) => {
186+
if (entry && entry.trim() === '*') {
187+
entry = resolveTo
188+
}
189+
return all.concat(entry)
190+
}, [])
191+
}
192+
184193
export const getUrlInfo = url => {
185194
let protocolMissing = false
186195

src/shared/services/utils.test.js

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -369,6 +369,43 @@ describe('utils', () => {
369369
])
370370
})
371371
})
372+
describe('resolveWhitelistWildcard', () => {
373+
test('Resolves * to given urls', () => {
374+
// Given
375+
const input = ['*']
376+
const resolveTo = ['guides.neo4j.com', 'localhost']
377+
378+
// When
379+
const res = utils.resolveWhitelistWildcard(input, resolveTo)
380+
381+
// Then
382+
expect(res).toEqual(['guides.neo4j.com', 'localhost'])
383+
})
384+
test('Resolves * to given urls when in a list', () => {
385+
// Given
386+
const input = [
387+
'http://test.com',
388+
'oskarhane.com',
389+
'*',
390+
null,
391+
'https://mysite.com/guides'
392+
]
393+
const resolveTo = ['guides.neo4j.com', 'localhost']
394+
395+
// When
396+
const res = utils.resolveWhitelistWildcard(input, resolveTo)
397+
398+
// Then
399+
expect(res).toEqual([
400+
'http://test.com',
401+
'oskarhane.com',
402+
'guides.neo4j.com',
403+
'localhost',
404+
null,
405+
'https://mysite.com/guides'
406+
])
407+
})
408+
})
372409
describe('hostIsAllowed', () => {
373410
test('should respect host whitelist', () => {
374411
// Given

0 commit comments

Comments
 (0)