diff --git a/ui/desktop/app/services/origin.js b/ui/desktop/app/services/origin.js index 3e397240d..ba280a1ae 100644 --- a/ui/desktop/app/services/origin.js +++ b/ui/desktop/app/services/origin.js @@ -61,7 +61,6 @@ export default class OriginService extends Service { assert(`setOrigin expects a string, you passed ${origin}`, typeof origin === 'string'); try { this.adapter.host = origin; - await this.store.query('scope', {}); this.rendererOrigin = origin; if (origin !== await this.mainOrigin) { await this.ipc.invoke('setOrigin', origin); diff --git a/ui/desktop/electron-app/package.json b/ui/desktop/electron-app/package.json index 0b2588d8f..ee38c837a 100644 --- a/ui/desktop/electron-app/package.json +++ b/ui/desktop/electron-app/package.json @@ -48,6 +48,7 @@ } }, "dependencies": { + "axios": "^0.21.1", "electron-devtools-installer": "^3.1.1", "electron-is-dev": "^1.2.0", "electron-squirrel-startup": "^1.0.0", diff --git a/ui/desktop/electron-app/src/content-security-policy.js b/ui/desktop/electron-app/src/content-security-policy.js index 12c25834d..41bd1e148 100644 --- a/ui/desktop/electron-app/src/content-security-policy.js +++ b/ui/desktop/electron-app/src/content-security-policy.js @@ -1,4 +1,4 @@ -const runtimeSettings = require('./runtime-settings.js'); +const origin = require('./origin.js'); const isDev = require('electron-is-dev'); const csp = { @@ -28,10 +28,9 @@ const generateCSPHeader = () => { const policy = Object.assign({}, csp); // If an origin is specified, add it to the connect-src directive - if (runtimeSettings.origin) { + if (origin.origin) { policy['connect-src'] = policy['connect-src'].slice(); - policy['connect-src'].push(runtimeSettings.origin); - console.log(`[content-security-policy] Including user-specified origin "${runtimeSettings.origin}" to connect-src`); + policy['connect-src'].push(origin.origin); } return Object diff --git a/ui/desktop/electron-app/src/handlers.js b/ui/desktop/electron-app/src/handlers.js index fa3aaf8b1..8345d3ab3 100644 --- a/ui/desktop/electron-app/src/handlers.js +++ b/ui/desktop/electron-app/src/handlers.js @@ -1,18 +1,21 @@ const handle = require('./ipc-handler'); const boundaryCli = require('./boundary-cli'); -const runtimeSettings = require('./runtime-settings.js'); +const origin = require('./origin.js'); /** * Returns the current runtime origin, which is used by the main thread to * rewrite the CSP to allow requests. */ -handle('getOrigin', () => runtimeSettings.origin); +handle('getOrigin', () => origin.origin); /** * Sets the origin to be used in the content security policy and triggers * a main window reload. */ -handle('setOrigin', (requestOrigin) => runtimeSettings.origin = requestOrigin); +handle('setOrigin', async (requestOrigin) => { + await origin.validateOrigin(requestOrigin); + origin.origin = requestOrigin; +}); /** * Check for boundary cli existence diff --git a/ui/desktop/electron-app/src/index.js b/ui/desktop/electron-app/src/index.js index 6b1b5a548..fd434936e 100644 --- a/ui/desktop/electron-app/src/index.js +++ b/ui/desktop/electron-app/src/index.js @@ -7,7 +7,7 @@ const { const { session, app, protocol, BrowserWindow, ipcMain } = require('electron'); require('./handlers.js'); -const runtimeSettings = require('./runtime-settings.js'); +const origin = require('./origin.js'); const { generateCSPHeader } = require('./content-security-policy.js'); const isDev = require('electron-is-dev'); @@ -103,7 +103,7 @@ app.on('ready', async () => { // If the user-specified origin changes, reload the page so that // the CSP can be refreshed with the this source allowed - runtimeSettings.onOriginChange(() => mainWindow.loadURL(emberAppURL)); + origin.onOriginChange(() => mainWindow.loadURL(emberAppURL)); // If you want to open up dev tools programmatically, call // mainWindow.openDevTools(); diff --git a/ui/desktop/electron-app/src/runtime-settings.js b/ui/desktop/electron-app/src/origin.js similarity index 61% rename from ui/desktop/electron-app/src/runtime-settings.js rename to ui/desktop/electron-app/src/origin.js index def591318..3046c93f1 100644 --- a/ui/desktop/electron-app/src/runtime-settings.js +++ b/ui/desktop/electron-app/src/origin.js @@ -1,3 +1,5 @@ +const axios = require('axios'); + // Provides a singleton class instance to enable a consistent view of // runtime settings across the application. @@ -19,6 +21,23 @@ class RuntimeSettings { this.triggerOriginChanged(); } + /** + * + */ + async validateOrigin(origin) { + // If the origin is the Electron origin, it is automatically valid. + if (origin === 'serve://boundary') return true; + // Otherwise, check if scopes can be loaded from the specified origin. + // Scopes are required by the desktop client, so this is a simple smoke + // test to see if the origin is API-compatible with the desktop client. + const scopesEndpoint = `${origin}/v1/scopes`; + try { + await axios.get(scopesEndpoint) + } catch (e) { + throw new Error(`Origin ${origin} could not be validated.`); + } + } + // Quick and dirty event handler pattern to enable the application to respond // when the origin is changed. #originWatchers = []; diff --git a/ui/desktop/electron-app/yarn.lock b/ui/desktop/electron-app/yarn.lock index a9d1c1e6a..4c485a2b9 100644 --- a/ui/desktop/electron-app/yarn.lock +++ b/ui/desktop/electron-app/yarn.lock @@ -494,6 +494,13 @@ aws4@^1.8.0: resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.11.0.tgz#d61f46d83b2519250e2784daf5b09479a8b41c59" integrity sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA== +axios@^0.21.1: + version "0.21.1" + resolved "https://registry.yarnpkg.com/axios/-/axios-0.21.1.tgz#22563481962f4d6bde9a76d516ef0e5d3c09b2b8" + integrity sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA== + dependencies: + follow-redirects "^1.10.0" + balanced-match@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" @@ -1267,6 +1274,11 @@ flora-colossus@^1.0.0: debug "^4.1.1" fs-extra "^7.0.0" +follow-redirects@^1.10.0: + version "1.13.1" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.13.1.tgz#5f69b813376cee4fd0474a3aba835df04ab763b7" + integrity sha512-SSG5xmZh1mkPGyKzjZP8zLjltIfpW32Y5QpdNJyjcfGxK3qo3NDDkZOZSFiGn1A6SclQxY9GzEwAHQ3dmYRWpg== + forever-agent@~0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91"