diff --git a/addons/core/translations/en-us.yaml b/addons/core/translations/en-us.yaml
index c1d3bd392..8289bf627 100644
--- a/addons/core/translations/en-us.yaml
+++ b/addons/core/translations/en-us.yaml
@@ -5,6 +5,14 @@ auth:
no-scopes: No scopes were found. To authenticate, ask your administrator to create an scope and grant you access.
choose-org: Choose a scope to authenticate.
authenticating-with-org: "You are authenticating with {name}."
+origin:
+ titles:
+ welcome: Welcome to Boundary
+ descriptions:
+ welcome:
+ get-started: To get started, you'll need to
+ step-1: Enter your controller URL
+ step-2: Use your credentials to authenticate in
titles:
home: Home
iam: IAM
diff --git a/ui/desktop/app/initializers/ipc.js b/ui/desktop/app/initializers/ipc.js
index 1ac9a8287..74e9d8545 100644
--- a/ui/desktop/app/initializers/ipc.js
+++ b/ui/desktop/app/initializers/ipc.js
@@ -1,5 +1,4 @@
import Ember from 'ember';
-import { assert } from '@ember/debug';
import config from '../config/environment';
/**
@@ -25,6 +24,8 @@ class MockIPC {
this.origin = origin;
return this.origin;
}
+
+ connect() {}
}
/**
@@ -40,9 +41,10 @@ export function initialize() {
window.addEventListener('message', async function (event) {
if (event.origin !== window.location.origin) return;
const { method, payload } = event?.data ?? {};
- assert(`IPC requires a method, you passed '${method}'.`, method);
- const response = await mockIPC.invoke(method, payload);
- event.ports[0].postMessage(response);
+ if (method) {
+ const response = await mockIPC.invoke(method, payload);
+ event.ports[0].postMessage(response);
+ }
});
}
}
diff --git a/ui/desktop/app/routes/application.js b/ui/desktop/app/routes/application.js
index 0dc41c9bd..009d73daf 100644
--- a/ui/desktop/app/routes/application.js
+++ b/ui/desktop/app/routes/application.js
@@ -15,7 +15,7 @@ export default class ApplicationRoute extends Route.extend(
// =services
@service session;
- @service ipc;
+ @service origin;
// =attributes
@@ -24,26 +24,13 @@ export default class ApplicationRoute extends Route.extend(
*/
routeIfUnauthenticated = 'index';
- /**
- * @type {ApplicationAdapter}
- */
- get adapter() {
- return this.store.adapterFor('application');
- }
-
/**
* Check that the origin specified in the renderer matches the origin
* reported by the main process. If they differ, update the main process
* origin so that the renderer's CSP can be rewritten to allow requests.
*/
- async beforeModel() {
- const rendererOrigin = this.session.data.origin;
- const mainOrigin = await this.ipc.invoke('getOrigin');
- const isMatch = rendererOrigin === mainOrigin;
- this.adapter.host = rendererOrigin;
- if (rendererOrigin && !isMatch) {
- await this.ipc.invoke('setOrigin', rendererOrigin);
- }
+ beforeModel() {
+ return this.origin.updateOrigin();
}
/**
diff --git a/ui/desktop/app/routes/origin.js b/ui/desktop/app/routes/origin.js
index e46824ef8..a4cd6a621 100644
--- a/ui/desktop/app/routes/origin.js
+++ b/ui/desktop/app/routes/origin.js
@@ -5,8 +5,7 @@ import { action } from '@ember/object';
export default class OriginRoute extends Route {
// =services
- @service session;
- @service ipc;
+ @service origin;
@service intl;
@service notify;
@@ -22,23 +21,17 @@ export default class OriginRoute extends Route {
// =methods
/**
- * Points the API to the specified origin and persists it to the session,
- * as well as the main process. When the main process receives the origin,
- * it is expected that the renderer will be restarted.
+ * Points the API to the specified origin. When the main process receives
+ * the origin, it is expected that the renderer will be restarted.
* @param {string} origin
*/
@action
async setOrigin(origin) {
- this.adapter.host = origin;
- // Check if we have a Boundary endpoint...
try {
- // If scopes load, this could be a Boundary API
- await this.store.query('scope', {});
- this.session.set('data.origin', origin);
- await this.ipc.invoke('setOrigin', origin);
+ await this.origin.setOrigin(origin);
this.replaceWith('index');
} catch (e) {
- // If scopes don't load, we assume this is not a Boundary API
+ // If scopes do not load, we assume this is not a Boundary API
const errorMessage = this.intl.t(
'errors.origin-verification-failed.description'
);
diff --git a/ui/desktop/app/routes/scopes/scope/authenticate.js b/ui/desktop/app/routes/scopes/scope/authenticate.js
index 7e49a5b9b..d328b905b 100644
--- a/ui/desktop/app/routes/scopes/scope/authenticate.js
+++ b/ui/desktop/app/routes/scopes/scope/authenticate.js
@@ -6,6 +6,7 @@ export default class ScopesScopeAuthenticateRoute extends Route {
// =services
@service session;
+ @service origin;
// =methods
@@ -26,4 +27,8 @@ export default class ScopesScopeAuthenticateRoute extends Route {
authMethods: this.store.query('auth-method', { scope_id }),
});
}
+
+ redirect() {
+ if (!this.origin.rendererOrigin) this.replaceWith('index');
+ }
}
diff --git a/ui/desktop/app/routes/scopes/scope/projects/targets.js b/ui/desktop/app/routes/scopes/scope/projects/targets.js
index 393a7d11d..ff9190e77 100644
--- a/ui/desktop/app/routes/scopes/scope/projects/targets.js
+++ b/ui/desktop/app/routes/scopes/scope/projects/targets.js
@@ -1,11 +1,14 @@
import Route from '@ember/routing/route';
import { inject as service } from '@ember/service';
import { all } from 'rsvp';
+import { action } from '@ember/object';
export default class ScopesScopeProjectsTargetsRoute extends Route {
// =services
+ @service ipc;
@service session;
+ @service notify;
// =methods
@@ -35,4 +38,21 @@ export default class ScopesScopeProjectsTargetsRoute extends Route {
};
});
}
+
+ // =actions
+
+ /**
+ * Establish a session to current target.
+ */
+ @action
+ async connect(model) {
+ try {
+ await this.ipc.invoke('connect', {
+ target_id: model.target.id,
+ auth_token: this.session.data.authenticated.token,
+ });
+ } catch(e) {
+ this.notify.error(e.toString(), { closeAfter: null });
+ }
+ }
}
diff --git a/ui/desktop/app/services/origin.js b/ui/desktop/app/services/origin.js
new file mode 100644
index 000000000..5fe141900
--- /dev/null
+++ b/ui/desktop/app/services/origin.js
@@ -0,0 +1,76 @@
+import Service from '@ember/service';
+import { assert } from '@ember/debug';
+import { inject as service } from '@ember/service';
+
+export default class OriginService extends Service {
+
+ // =services
+
+ @service ipc;
+ @service store;
+ @service session;
+
+ // =attributes
+
+ /**
+ * @type {ApplicationAdapter}
+ */
+ get adapter() {
+ return this.store.adapterFor('application');
+ }
+
+ /**
+ * @type {?string}
+ */
+ get rendererOrigin() {
+ return this.session.data.origin;
+ }
+
+ /**
+ * @param {?string} origin
+ */
+ set rendererOrigin(origin) {
+ this.session.set('data.origin', origin);
+ }
+
+ /**
+ * @type {Promise{?string}}
+ */
+ get mainOrigin() {
+ return this.ipc.invoke('getOrigin');
+ }
+
+ // =methods
+
+ /**
+ * Sets the main origin equal to the current renderer origin (if any).
+ */
+ async updateOrigin() {
+ const rendererOrigin = this.rendererOrigin;
+ if (rendererOrigin) await this.setOrigin(rendererOrigin);
+ }
+
+ /**
+ * Validates that the specified origin is a Boundary API. If so, the app is
+ * updated to use the origin. If it is not a Boundary API, or an origin
+ * wasn't specified, throws an error.
+ * @param {string} origin - protocol://host:port
+ */
+ async setOrigin(origin) {
+ const originalHost = this.adapter.host;
+ 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);
+ }
+ } catch (e) {
+ this.adapter.host = originalHost;
+ this.rendererOrigin = null;
+ throw e;
+ }
+ }
+
+}
diff --git a/ui/desktop/app/styles/app.scss b/ui/desktop/app/styles/app.scss
index c50a5abab..7826a721f 100644
--- a/ui/desktop/app/styles/app.scss
+++ b/ui/desktop/app/styles/app.scss
@@ -197,3 +197,9 @@
.nowrap {
white-space: nowrap;
}
+
+.centered {
+ display: inline-block;
+ margin: auto;
+ transform: translate(0%, -20%);
+}
diff --git a/ui/desktop/app/templates/origin.hbs b/ui/desktop/app/templates/origin.hbs
index 5616eccb4..c8615aa41 100644
--- a/ui/desktop/app/templates/origin.hbs
+++ b/ui/desktop/app/templates/origin.hbs
@@ -1,19 +1,30 @@
- {{t 'origin.descriptions.welcome.get-started'}}
+ {{t 'origin.titles.welcome'}}
+
+
+