diff --git a/ui/app/components/tool-actions-form.js b/ui/app/components/tool-actions-form.js
deleted file mode 100644
index b6407255b6..0000000000
--- a/ui/app/components/tool-actions-form.js
+++ /dev/null
@@ -1,156 +0,0 @@
-/**
- * Copyright (c) HashiCorp, Inc.
- * SPDX-License-Identifier: BUSL-1.1
- */
-
-import { match } from '@ember/object/computed';
-import { service } from '@ember/service';
-import Component from '@ember/component';
-import { setProperties, computed, set } from '@ember/object';
-import { addSeconds, parseISO } from 'date-fns';
-import { capitalize } from '@ember/string';
-
-const DEFAULTS = {
- token: null,
- rewrap_token: null,
- errors: null,
- wrap_info: null,
- creation_time: null,
- creation_ttl: null,
- data: '{\n}',
- unwrap_data: null,
- details: null,
- wrapTTL: null,
- sum: null,
- random_bytes: null,
- input: null,
-};
-
-const WRAPPING_ENDPOINTS = ['lookup', 'wrap', 'unwrap', 'rewrap'];
-
-export default Component.extend(DEFAULTS, {
- flashMessages: service(),
- store: service(),
- // putting these attrs here so they don't get reset when you click back
- // random
- bytes: 32,
- // hash
- format: 'base64',
- algorithm: 'sha2-256',
- data: '{\n}',
- tagName: '',
-
- didReceiveAttrs() {
- this._super(...arguments);
- this.checkAction();
- },
-
- selectedAction: null,
-
- reset() {
- if (this.isDestroyed || this.isDestroying) {
- return;
- }
- setProperties(this, DEFAULTS);
- },
-
- checkAction() {
- const currentAction = this.selectedAction;
- const oldAction = this.oldSelectedAction;
-
- if (currentAction !== oldAction) {
- this.reset();
- }
- set(this, 'oldSelectedAction', currentAction);
- },
-
- dataIsEmpty: match('data', new RegExp(DEFAULTS.data)),
-
- expirationDate: computed('creation_time', 'creation_ttl', function () {
- const { creation_time, creation_ttl } = this;
- if (!(creation_time && creation_ttl)) {
- return null;
- }
- // returns new Date with seconds added.
- return addSeconds(parseISO(creation_time), creation_ttl);
- }),
-
- handleError(e) {
- set(this, 'errors', e.errors);
- },
-
- handleSuccess(resp, action) {
- let props = {};
- const secret = (resp && resp.data) || resp.auth;
- if (secret && action === 'unwrap') {
- const details = {
- 'Request ID': resp.request_id,
- 'Lease ID': resp.lease_id || 'None',
- Renewable: resp.renewable ? 'Yes' : 'No',
- 'Lease Duration': resp.lease_duration || 'None',
- };
- props = { ...props, unwrap_data: secret, details: details };
- }
- props = { ...props, ...secret };
- if (resp && resp.wrap_info) {
- const keyName = action === 'rewrap' ? 'rewrap_token' : 'token';
- props = { ...props, [keyName]: resp.wrap_info.token };
- }
- setProperties(this, props);
- this.flashMessages.success(`${capitalize(action)} was successful.`);
- },
-
- getData() {
- const action = this.selectedAction;
- if (WRAPPING_ENDPOINTS.includes(action)) {
- return this.dataIsEmpty ? { token: (this.token || '').trim() } : JSON.parse(this.data);
- }
- if (action === 'random') {
- return { bytes: this.bytes, format: this.format };
- }
- if (action === 'hash') {
- return { input: this.input, format: this.format, algorithm: this.algorithm };
- }
- },
-
- actions: {
- doSubmit(evt) {
- evt.preventDefault();
- const action = this.selectedAction;
- const wrapTTL = action === 'wrap' ? this.wrapTTL : null;
- const data = this.getData();
- setProperties(this, {
- errors: null,
- wrap_info: null,
- creation_time: null,
- creation_ttl: null,
- });
-
- this.store
- .adapterFor('tools')
- .toolAction(action, data, { wrapTTL })
- .then(
- (resp) => this.handleSuccess(resp, action),
- (...errArgs) => this.handleError(...errArgs)
- );
- },
-
- onClear() {
- this.reset();
- },
-
- onBack(properties) {
- // only reset specific properties so user can reuse input data and repeat the action
- if (this.isDestroyed || this.isDestroying) {
- return;
- }
- properties.forEach((prop) => {
- set(this, prop, DEFAULTS[prop]);
- });
- },
-
- onChange(param, value) {
- set(this, param, value);
- },
- },
-});
diff --git a/ui/app/templates/components/tool-actions-form.hbs b/ui/app/templates/components/tool-actions-form.hbs
deleted file mode 100644
index cb73f511c9..0000000000
--- a/ui/app/templates/components/tool-actions-form.hbs
+++ /dev/null
@@ -1,22 +0,0 @@
-{{!
- Copyright (c) HashiCorp, Inc.
- SPDX-License-Identifier: BUSL-1.1
-~}}
-
-
\ No newline at end of file
diff --git a/ui/app/templates/vault/cluster/tools/tool.hbs b/ui/app/templates/vault/cluster/tools/tool.hbs
index 609ff360f7..1644af49e1 100644
--- a/ui/app/templates/vault/cluster/tools/tool.hbs
+++ b/ui/app/templates/vault/cluster/tools/tool.hbs
@@ -3,4 +3,18 @@
SPDX-License-Identifier: BUSL-1.1
~}}
-
\ No newline at end of file
+{{#if (eq this.selectedAction "hash")}}
+
+{{else if (eq this.selectedAction "random")}}
+
+{{else if (eq this.selectedAction "rewrap")}}
+
+{{else if (eq this.selectedAction "unwrap")}}
+
+{{else if (eq this.selectedAction "lookup")}}
+
+{{else if (eq this.selectedAction "wrap")}}
+
+{{else}}
+
+{{/if}}
\ No newline at end of file
diff --git a/ui/tests/acceptance/tools-test.js b/ui/tests/acceptance/tools-test.js
index d5d7741c7b..bb0b4aea3d 100644
--- a/ui/tests/acceptance/tools-test.js
+++ b/ui/tests/acceptance/tools-test.js
@@ -3,17 +3,7 @@
* SPDX-License-Identifier: BUSL-1.1
*/
-import {
- click,
- fillIn,
- find,
- findAll,
- currentURL,
- visit,
- settled,
- waitUntil,
- waitFor,
-} from '@ember/test-helpers';
+import { click, fillIn, find, findAll, currentURL, visit, waitUntil } from '@ember/test-helpers';
import { module, test } from 'qunit';
import { setupApplicationTest } from 'ember-qunit';
import { toolsActions } from 'vault/helpers/tools-actions';
@@ -24,153 +14,164 @@ import { setupMirage } from 'ember-cli-mirage/test-support';
import { GENERAL } from 'vault/tests/helpers/general-selectors';
import { TOOLS_SELECTORS as TS } from 'vault/tests/helpers/tools-selectors';
+const createTokenStore = () => {
+ let token;
+ return {
+ set(val) {
+ token = val;
+ },
+ get() {
+ return token;
+ },
+ };
+};
+const DATA_TO_WRAP = JSON.stringify({ tools: 'tests' });
+
module('Acceptance | tools', function (hooks) {
setupApplicationTest(hooks);
setupMirage(hooks);
- hooks.beforeEach(function () {
- return authPage.login();
+ hooks.beforeEach(async function () {
+ await authPage.login();
+ return visit('/vault/tools');
});
- const DATA_TO_WRAP = JSON.stringify({ tools: 'tests' });
- const TOOLS_ACTIONS = toolsActions();
-
- var createTokenStore = () => {
- let token;
- return {
- set(val) {
- token = val;
- },
- get() {
- return token;
- },
- };
- };
-
- test('tools functionality', async function (assert) {
- var tokenStore = createTokenStore();
- await visit('/vault/tools');
-
- assert.strictEqual(currentURL(), '/vault/tools/wrap', 'forwards to the first action');
- TOOLS_ACTIONS.forEach((action) => {
- assert.dom(GENERAL.navLink(capitalize(action))).exists(`${action} link renders`);
- });
-
- await waitFor('.CodeMirror');
- codemirror().setValue(DATA_TO_WRAP);
-
- // wrap
- await click(TS.submit);
- const wrappedToken = await waitUntil(() => find(TS.toolsInput('wrapping-token')));
- tokenStore.set(wrappedToken.innerText);
-
- // lookup
- await click(GENERAL.navLink('Lookup'));
-
- await fillIn(TS.toolsInput('wrapping-token'), tokenStore.get());
- await click(TS.submit);
- await waitUntil(() => findAll('[data-test-component="info-table-row"]').length >= 3);
- assert.dom(GENERAL.infoRowValue('Creation path')).hasText('sys/wrapping/wrap', 'show creation path row');
- assert.dom(GENERAL.infoRowValue('Creation time')).exists();
- assert.dom(GENERAL.infoRowValue('Creation TTL')).hasText('1800', 'show creation ttl row');
-
- // rewrap
- await click(GENERAL.navLink('Rewrap'));
-
- await fillIn(TS.toolsInput('wrapping-token'), tokenStore.get());
- await click(TS.submit);
- const rewrappedToken = await waitUntil(() => find(TS.toolsInput('rewrapped-token')));
- assert.ok(rewrappedToken.value, 'has a new re-wrapped token');
- assert.notEqual(rewrappedToken.value, tokenStore.get(), 're-wrapped token is not the wrapped token');
- tokenStore.set(rewrappedToken.value);
- await settled();
-
- // unwrap
- await click(GENERAL.navLink('Unwrap'));
-
- await fillIn(TS.toolsInput('wrapping-token'), tokenStore.get());
- await click(TS.submit);
- await waitFor('.CodeMirror');
- assert.deepEqual(
- JSON.parse(codemirror().getValue()),
- JSON.parse(DATA_TO_WRAP),
- 'unwrapped data equals input data'
- );
- await waitUntil(() => find(TS.tab('details')));
- await click(TS.tab('details'));
- await click(TS.tab('data'));
- assert.deepEqual(
- JSON.parse(codemirror().getValue()),
- JSON.parse(DATA_TO_WRAP),
- 'data tab still has unwrapped data'
- );
- //random
- await click(GENERAL.navLink('Random'));
-
- assert.dom(TS.toolsInput('bytes')).hasValue('32', 'defaults to 32 bytes');
- await click(TS.submit);
- const randomBytes = await waitUntil(() => find(TS.toolsInput('random-bytes')));
- assert.ok(randomBytes.value, 'shows the returned value of random bytes');
-
- // hash
- await click(GENERAL.navLink('Hash'));
-
- await fillIn(TS.toolsInput('hash-input'), 'foo');
- await click('[data-test-transit-b64-toggle="input"]');
-
- await click(TS.submit);
- let sumInput = await waitUntil(() => find(TS.toolsInput('sum')));
- assert
- .dom(sumInput)
- .hasValue('LCa0a2j/xo/5m0U8HTBBNBNCLXBkg7+g+YpeiGJm564=', 'hashes the data, encodes input');
- await click(TS.button('Back'));
-
- await fillIn(TS.toolsInput('hash-input'), 'e2RhdGE6ImZvbyJ9');
-
- await click(TS.submit);
- sumInput = await waitUntil(() => find(TS.toolsInput('sum')));
- assert
- .dom(sumInput)
- .hasValue('JmSi2Hhbgu2WYOrcOyTqqMdym7KT3sohCwAwaMonVrc=', 'hashes the data, passes b64 input through');
+ test('it navigates to each action link', async function (assert) {
+ assert.strictEqual(currentURL(), '/vault/tools/wrap', 'forwards from "vault/tools" to the first action');
+ for (const action of toolsActions()) {
+ await click(GENERAL.navLink(capitalize(action)));
+ assert.strictEqual(currentURL(), `/vault/tools/${action}`, `it navigates to ${action}`);
+ }
});
- const AUTH_RESPONSE = {
- request_id: '39802bc4-235c-2f0b-87f3-ccf38503ac3e',
- lease_id: '',
- renewable: false,
- lease_duration: 0,
- data: null,
- wrap_info: null,
- warnings: null,
- auth: {
- client_token: 'ecfc2758-588e-981d-50f4-a25883bbf03c',
- accessor: '6299780b-f2b2-1a3f-7b83-9d3d67629249',
- policies: ['root'],
- metadata: null,
- lease_duration: 0,
- renewable: false,
- entity_id: '',
- },
- };
+ module('cross tool workflow', function () {
+ test('it wraps data, performs lookup, rewraps and then unwraps data', async function (assert) {
+ const tokenStore = createTokenStore();
- test('ensure unwrap with auth block works properly', async function (assert) {
- this.server.post('/sys/wrapping/unwrap', () => {
- return AUTH_RESPONSE;
+ await waitUntil(() => find('.CodeMirror'));
+ codemirror().setValue(DATA_TO_WRAP);
+
+ await click(TS.submit);
+ const wrappedToken = await waitUntil(() => find(TS.toolsInput('wrapping-token')));
+ tokenStore.set(wrappedToken.innerText);
+
+ // lookup
+ await click(GENERAL.navLink('Lookup'));
+
+ await fillIn(TS.toolsInput('wrapping-token'), tokenStore.get());
+ await click(TS.submit);
+ await waitUntil(() => findAll('[data-test-component="info-table-row"]').length >= 3);
+ assert
+ .dom(GENERAL.infoRowValue('Creation path'))
+ .hasText('sys/wrapping/wrap', 'show creation path row');
+ assert.dom(GENERAL.infoRowValue('Creation time')).exists();
+ assert.dom(GENERAL.infoRowValue('Creation TTL')).hasText('1800', 'show creation ttl row');
+
+ // rewrap
+ await click(GENERAL.navLink('Rewrap'));
+
+ await fillIn(TS.toolsInput('wrapping-token'), tokenStore.get());
+ await click(TS.submit);
+ await waitUntil(() => find(TS.toolsInput('rewrapped-token')));
+ const rewrappedToken = find(TS.toolsInput('rewrapped-token')).innerText;
+ assert.notEqual(rewrappedToken, tokenStore.get(), 're-wrapped token is not the wrapped token');
+ tokenStore.set(rewrappedToken);
+
+ // unwrap
+ await click(GENERAL.navLink('Unwrap'));
+
+ await fillIn(TS.toolsInput('unwrap-token'), tokenStore.get());
+ await click(TS.submit);
+ await waitUntil(() => find('.CodeMirror'));
+ assert.deepEqual(
+ JSON.parse(codemirror().getValue()),
+ JSON.parse(DATA_TO_WRAP),
+ 'unwrapped data equals input data'
+ );
+ await waitUntil(() => find(TS.tab('details')));
+ await click(TS.tab('details'));
+ await click(TS.tab('data'));
+ assert.deepEqual(
+ JSON.parse(codemirror().getValue()),
+ JSON.parse(DATA_TO_WRAP),
+ 'data tab still has unwrapped data'
+ );
});
- await visit('/vault/tools');
+ });
- //unwrap
- await click(GENERAL.navLink('Unwrap'));
+ module('random', function () {
+ test('it generates random bytes', async function (assert) {
+ await click(GENERAL.navLink('Random'));
+ assert.dom(TS.toolsInput('bytes')).hasValue('32', 'defaults to 32 bytes');
+ await click(TS.submit);
+ const randomBytes = await waitUntil(() => find(TS.toolsInput('random-bytes')));
+ assert.strictEqual(randomBytes.innerText.length, 44, 'shows the returned value of random bytes');
+ });
+ });
- await fillIn(TS.toolsInput('wrapping-token'), 'sometoken');
- await click(TS.submit);
+ module('hash', function () {
+ test('it generates hash', async function (assert) {
+ await click(GENERAL.navLink('Hash'));
- await waitFor('.CodeMirror');
- assert.deepEqual(
- JSON.parse(codemirror().getValue()),
- AUTH_RESPONSE.auth,
- 'unwrapped data equals input data'
- );
+ await fillIn(TS.toolsInput('hash-input'), 'foo');
+ await click(TS.toolsInput('b64-toggle'));
+ assert.dom(TS.toolsInput('hash-input')).hasValue('Zm9v', 'it base64 encodes input');
+ await click(TS.submit);
+ let sumInput = await waitUntil(() => find(TS.toolsInput('sum')));
+ assert
+ .dom(sumInput)
+ .hasText('LCa0a2j/xo/5m0U8HTBBNBNCLXBkg7+g+YpeiGJm564=', 'hashes the data, encodes input');
+ await click(TS.button('Done'));
+
+ await waitUntil(() => find(TS.toolsInput('hash-input')));
+ assert.dom(TS.toolsInput('hash-input')).hasText('', 'it clears input on done');
+ await fillIn(TS.toolsInput('hash-input'), 'e2RhdGE6ImZvbyJ9');
+
+ await click(TS.submit);
+ sumInput = await waitUntil(() => find(TS.toolsInput('sum')));
+ assert
+ .dom(sumInput)
+ .hasText('JmSi2Hhbgu2WYOrcOyTqqMdym7KT3sohCwAwaMonVrc=', 'hashes the data, passes b64 input through');
+ });
+ });
+
+ module('unwrap', function () {
+ test('it unwraps with auth block', async function (assert) {
+ const AUTH_RESPONSE = {
+ request_id: '39802bc4-235c-2f0b-87f3-ccf38503ac3e',
+ lease_id: '',
+ renewable: false,
+ lease_duration: 0,
+ data: null,
+ wrap_info: null,
+ warnings: null,
+ auth: {
+ client_token: 'ecfc2758-588e-981d-50f4-a25883bbf03c',
+ accessor: '6299780b-f2b2-1a3f-7b83-9d3d67629249',
+ policies: ['root'],
+ metadata: null,
+ lease_duration: 0,
+ renewable: false,
+ entity_id: '',
+ },
+ };
+ this.server.post('/sys/wrapping/unwrap', () => {
+ return AUTH_RESPONSE;
+ });
+
+ // unwrap
+ await click(GENERAL.navLink('Unwrap'));
+
+ await fillIn(TS.toolsInput('unwrap-token'), 'sometoken');
+ await click(TS.submit);
+
+ await waitUntil(() => find('.CodeMirror'));
+ assert.deepEqual(
+ JSON.parse(codemirror().getValue()),
+ AUTH_RESPONSE.auth,
+ 'unwrapped data equals input data'
+ );
+ });
});
module('wrap', function () {
@@ -178,7 +179,7 @@ module('Acceptance | tools', function (hooks) {
const tokenStore = createTokenStore();
await visit('/vault/tools/wrap');
- await waitFor('.CodeMirror');
+ await waitUntil(() => find('.CodeMirror'));
codemirror().setValue(DATA_TO_WRAP);
// initial wrap
@@ -195,18 +196,18 @@ module('Acceptance | tools', function (hooks) {
// so when users attempted to wrap data again the payload was actually empty and unwrapping the token returned {token: ""}
// it is user desired behavior that the form does not clear on back, and that wrapping can be immediately repeated
// we use lookup to check our token from the second wrap returns the unwrapped data we expect
- await click(GENERAL.navLink('Lookup'));
- await fillIn(TS.toolsInput('wrapping-token'), tokenStore.get());
+ await click(GENERAL.navLink('Unwrap'));
+ await fillIn(TS.toolsInput('unwrap-token'), tokenStore.get());
await click(TS.submit);
- await waitUntil(() => findAll('[data-test-component="info-table-row"]').length >= 3);
- assert.dom(GENERAL.infoRowValue('Creation TTL')).hasText('1800', 'show creation ttl row');
+ await waitUntil(() => find('.CodeMirror'));
+ assert.strictEqual(codemirror().getValue(' '), '{ "tools": "tests" }', 'it renders unwrapped data');
});
test('it sends wrap ttl', async function (assert) {
const tokenStore = createTokenStore();
await visit('/vault/tools/wrap');
- await waitFor('.CodeMirror');
+ await waitUntil(() => find('.CodeMirror'));
codemirror().setValue(DATA_TO_WRAP);
// update to non-default ttl
@@ -217,7 +218,7 @@ module('Acceptance | tools', function (hooks) {
const wrappedToken = await waitUntil(() => find(TS.toolsInput('wrapping-token')));
tokenStore.set(wrappedToken.innerText);
- // lookup to check unwrapped data is what we expect
+ // lookup to check ttl is what we expect
await click(GENERAL.navLink('Lookup'));
await fillIn(TS.toolsInput('wrapping-token'), tokenStore.get());
await click(TS.submit);