Skip to content

Commit

Permalink
backport of commit e122ce8
Browse files Browse the repository at this point in the history
  • Loading branch information
hashishaw authored Dec 13, 2023
1 parent 11acfeb commit e653cc8
Show file tree
Hide file tree
Showing 7 changed files with 85 additions and 9 deletions.
3 changes: 3 additions & 0 deletions changelog/24513.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:bug
ui: fix KV v2 details view defaulting to JSON view when secret value includes `{`
```
20 changes: 20 additions & 0 deletions ui/lib/core/addon/utils/advanced-secret.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: MPL-2.0
*/

/**
* Method to check whether the secret value is a nested object (returns true)
* All other values return false
* @param value string or stringified JSON
* @returns boolean
*/
export function isAdvancedSecret(value) {
try {
const json = JSON.parse(value);
if (Array.isArray(json)) return false;
return Object.values(json).some((value) => typeof value !== 'string');
} catch (e) {
return false;
}
}
6 changes: 6 additions & 0 deletions ui/lib/core/app/utils/advanced-secret.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/

export { default } from 'core/utils/advanced-secret';
6 changes: 2 additions & 4 deletions ui/lib/kv/addon/components/page/secret/details.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { inject as service } from '@ember/service';
import { task } from 'ember-concurrency';
import { waitFor } from '@ember/test-waiters';
import { isDeleted } from 'kv/utils/kv-deleted';
import { isAdvancedSecret } from 'core/utils/advanced-secret';

/**
* @module KvSecretDetails renders the key/value data of a KV secret.
Expand Down Expand Up @@ -40,10 +41,7 @@ export default class KvSecretDetails extends Component {
constructor() {
super(...arguments);
this.originalSecret = JSON.stringify(this.args.secret.secretData || {});
if (this.originalSecret.lastIndexOf('{') > 0) {
// Dumb way to check if there's a nested object in the secret
this.secretDataIsAdvanced = true;
}
this.secretDataIsAdvanced = isAdvancedSecret(this.originalSecret);
}

@action
Expand Down
6 changes: 2 additions & 4 deletions ui/lib/kv/addon/components/page/secret/edit.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { tracked } from '@glimmer/tracking';
import { task } from 'ember-concurrency';
import { inject as service } from '@ember/service';
import errorMessage from 'vault/utils/error-message';
import { isAdvancedSecret } from 'core/utils/advanced-secret';

/**
* @module KvSecretEdit is used for creating a new version of a secret
Expand Down Expand Up @@ -43,10 +44,7 @@ export default class KvSecretEdit extends Component {
constructor() {
super(...arguments);
this.originalSecret = JSON.stringify(this.args.secret.secretData || {});
if (this.originalSecret.lastIndexOf('{') > 0) {
// Dumb way to check if there's a nested object in the secret
this.secretDataIsAdvanced = true;
}
this.secretDataIsAdvanced = isAdvancedSecret(this.originalSecret);
}

get showOldVersionAlert() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,7 @@ module('Acceptance | kv-v2 workflow | edge cases', function (hooks) {
assert.dom(PAGE.list.item()).exists({ count: 2 }, 'two secrets are listed');
});

test('complex values default to JSON display', async function (assert) {
test('advanced secret values default to JSON display', async function (assert) {
await visit(`/vault/secrets/${this.backend}/kv/create`);
await fillIn(FORM.inputByAttr('path'), 'complex');

Expand All @@ -279,6 +279,17 @@ module('Acceptance | kv-v2 workflow | edge cases', function (hooks) {
assert.dom(FORM.toggleJson).isDisabled();
assert.dom(FORM.toggleJson).isChecked();
});
test('does not register as advanced when value includes {', async function (assert) {
await visit(`/vault/secrets/${this.backend}/kv/create`);
await fillIn(FORM.inputByAttr('path'), 'not-advanced');

await fillIn(FORM.keyInput(), 'foo');
await fillIn(FORM.maskedValueInput(), '{bar}');
await click(FORM.saveBtn);
await click(PAGE.detail.createNewVersion);
assert.dom(FORM.toggleJson).isNotDisabled();
assert.dom(FORM.toggleJson).isNotChecked();
});
});

// NAMESPACE TESTS
Expand Down
40 changes: 40 additions & 0 deletions ui/tests/unit/utils/advanced-secret-test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/

import { isAdvancedSecret } from 'core/utils/advanced-secret';
import { module, test } from 'qunit';

module('Unit | Utility | advanced-secret', function () {
test('it returns false for non-valid JSON', function (assert) {
assert.expect(5);
let result;
['some-string', 'character{string', '{value}', '[blah]', 'multi\nline\nstring'].forEach((value) => {
result = isAdvancedSecret('some-string');
assert.false(result, `returns false for ${value}`);
});
});

test('it returns false for single-level objects', function (assert) {
assert.expect(3);
let result;
[{ single: 'one' }, { first: '1', two: 'three' }, ['my', 'array']].forEach((value) => {
result = isAdvancedSecret(JSON.stringify(value));
assert.false(result, `returns false for object ${JSON.stringify(value)}`);
});
});

test('it returns true for any nested object', function (assert) {
assert.expect(3);
let result;
[
{ single: { one: 'uno' } },
{ first: ['this', 'counts\ntoo'] },
{ deeply: { nested: { item: 1 } } },
].forEach((value) => {
result = isAdvancedSecret(JSON.stringify(value));
assert.true(result, `returns true for object ${JSON.stringify(value)}`);
});
});
});

0 comments on commit e653cc8

Please sign in to comment.