mirror of
https://github.com/optim-enterprises-bv/vault.git
synced 2025-11-01 02:57:59 +00:00
cherry pick (#23264)
This commit is contained in:
3
changelog/23260.txt
Normal file
3
changelog/23260.txt
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
```release-note:improvement
|
||||||
|
ui: Adds warning before downloading KV v2 secret values
|
||||||
|
```
|
||||||
@@ -34,6 +34,7 @@ import { assert } from '@ember/debug';
|
|||||||
* @param {function} [fetchData] - function that fetches data and returns download content
|
* @param {function} [fetchData] - function that fetches data and returns download content
|
||||||
* @param {string} [extension='txt'] - file extension, the download service uses this to determine the mimetype
|
* @param {string} [extension='txt'] - file extension, the download service uses this to determine the mimetype
|
||||||
* @param {boolean} [stringify=false] - argument to stringify the data before passing to the File constructor
|
* @param {boolean} [stringify=false] - argument to stringify the data before passing to the File constructor
|
||||||
|
* @param {callback} [onSuccess] - callback from parent to invoke if download is successful
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export default class DownloadButton extends Component {
|
export default class DownloadButton extends Component {
|
||||||
@@ -73,6 +74,9 @@ export default class DownloadButton extends Component {
|
|||||||
try {
|
try {
|
||||||
this.download.miscExtension(this.filename, this.content, this.extension);
|
this.download.miscExtension(this.filename, this.content, this.extension);
|
||||||
this.flashMessages.info(`Downloading ${this.filename}`);
|
this.flashMessages.info(`Downloading ${this.filename}`);
|
||||||
|
if (this.args.onSuccess) {
|
||||||
|
this.args.onSuccess();
|
||||||
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.flashMessages.danger(errorMessage(error, 'There was a problem downloading. Please try again.'));
|
this.flashMessages.danger(errorMessage(error, 'There was a problem downloading. Please try again.'));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,15 +35,9 @@
|
|||||||
</CopyButton>
|
</CopyButton>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
{{#if @allowDownload}}
|
{{#if @allowDownload}}
|
||||||
<DownloadButton
|
<button type="button" class="button download-button" {{on "click" (fn (mut this.modalOpen) true)}}>
|
||||||
class="button download-button"
|
<Icon data-test-download-icon @name="download" />
|
||||||
@filename={{or @name "secret-value"}}
|
</button>
|
||||||
@data={{@value}}
|
|
||||||
@stringify={{true}}
|
|
||||||
aria-label="Download secret value"
|
|
||||||
>
|
|
||||||
<Icon @name="download" />
|
|
||||||
</DownloadButton>
|
|
||||||
{{/if}}
|
{{/if}}
|
||||||
<button
|
<button
|
||||||
onclick={{this.toggleMask}}
|
onclick={{this.toggleMask}}
|
||||||
@@ -56,3 +50,33 @@
|
|||||||
<Icon @name={{if this.showValue "eye" "eye-off"}} />
|
<Icon @name={{if this.showValue "eye" "eye-off"}} />
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{{! CONFIRM DOWNLOAD MODAL }}
|
||||||
|
{{#if @allowDownload}}
|
||||||
|
<Modal
|
||||||
|
@title="Download secret value?"
|
||||||
|
@onClose={{action (mut this.modalOpen) false}}
|
||||||
|
@isActive={{this.modalOpen}}
|
||||||
|
@type="warning"
|
||||||
|
>
|
||||||
|
<section class="modal-card-body">
|
||||||
|
This download is
|
||||||
|
<strong>unencrypted</strong>. Are you sure you want to download this secret data as plaintext?
|
||||||
|
</section>
|
||||||
|
<footer class="modal-card-foot modal-card-foot-outlined">
|
||||||
|
<DownloadButton
|
||||||
|
class="button is-primary"
|
||||||
|
@filename={{or @name "secret-value"}}
|
||||||
|
@data={{@value}}
|
||||||
|
@stringify={{true}}
|
||||||
|
aria-label="Download secret value"
|
||||||
|
@onSuccess={{fn (mut this.modalOpen) false}}
|
||||||
|
>
|
||||||
|
Download
|
||||||
|
</DownloadButton>
|
||||||
|
<button type="button" class="button is-secondary" {{on "click" (fn (mut this.modalOpen) false)}}>
|
||||||
|
Cancel
|
||||||
|
</button>
|
||||||
|
</footer>
|
||||||
|
</Modal>
|
||||||
|
{{/if}}
|
||||||
@@ -27,12 +27,14 @@ import autosize from 'autosize';
|
|||||||
* @param name {String} - The key correlated to the value. Used for the download file name.
|
* @param name {String} - The key correlated to the value. Used for the download file name.
|
||||||
* @param [onChange=Callback] {Function|action} - Callback triggered on change, sends new value. Must set the value of @value
|
* @param [onChange=Callback] {Function|action} - Callback triggered on change, sends new value. Must set the value of @value
|
||||||
* @param [allowCopy=false] {bool} - Whether or not the input should render with a copy button.
|
* @param [allowCopy=false] {bool} - Whether or not the input should render with a copy button.
|
||||||
|
* @param [allowDownload=false] {bool} - Renders a download button that prompts a confirmation modal to download the secret value
|
||||||
* @param [displayOnly=false] {bool} - Whether or not to display the value as a display only `pre` element or as an input.
|
* @param [displayOnly=false] {bool} - Whether or not to display the value as a display only `pre` element or as an input.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
export default class MaskedInputComponent extends Component {
|
export default class MaskedInputComponent extends Component {
|
||||||
textareaId = 'textarea-' + guidFor(this);
|
textareaId = 'textarea-' + guidFor(this);
|
||||||
@tracked showValue = false;
|
@tracked showValue = false;
|
||||||
|
@tracked modalOpen = false;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super(...arguments);
|
super(...arguments);
|
||||||
|
|||||||
@@ -6,29 +6,27 @@
|
|||||||
|
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8" />
|
||||||
<title>Vault Tests</title>
|
<title>Vault Tests</title>
|
||||||
<meta name="description" content="">
|
<meta name="description" content="" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
|
||||||
{{content-for "head"}}
|
{{content-for "head"}} {{content-for "test-head"}}
|
||||||
{{content-for "test-head"}}
|
|
||||||
|
|
||||||
<link rel="stylesheet" href="{{rootURL}}assets/vendor.css">
|
<link rel="stylesheet" href="{{rootURL}}assets/vendor.css" />
|
||||||
<link rel="stylesheet" href="{{rootURL}}assets/vault.css">
|
<link rel="stylesheet" href="{{rootURL}}assets/vault.css" />
|
||||||
<link rel="stylesheet" href="{{rootURL}}assets/test-support.css">
|
<link rel="stylesheet" href="{{rootURL}}assets/test-support.css" />
|
||||||
|
|
||||||
{{content-for "head-footer"}}
|
{{content-for "head-footer"}} {{content-for "test-head-footer"}}
|
||||||
{{content-for "test-head-footer"}}
|
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
{{content-for "body"}}
|
{{content-for "body"}} {{content-for "test-body"}}
|
||||||
{{content-for "test-body"}}
|
|
||||||
|
|
||||||
<div id="qunit"></div>
|
<div id="qunit"></div>
|
||||||
<div id="qunit-fixture">
|
<div id="qunit-fixture">
|
||||||
<div id="ember-testing-container">
|
<div id="ember-testing-container">
|
||||||
<div id="ember-testing"></div>
|
<div id="ember-testing"></div>
|
||||||
|
<div id="modal-wormhole"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -38,7 +36,6 @@
|
|||||||
<script src="{{rootURL}}assets/vault.js"></script>
|
<script src="{{rootURL}}assets/vault.js"></script>
|
||||||
<script src="{{rootURL}}assets/tests.js"></script>
|
<script src="{{rootURL}}assets/tests.js"></script>
|
||||||
|
|
||||||
{{content-for "body-footer"}}
|
{{content-for "body-footer"}} {{content-for "test-body-footer"}}
|
||||||
{{content-for "test-body-footer"}}
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
import { module, test } from 'qunit';
|
import { module, test } from 'qunit';
|
||||||
import { setupRenderingTest } from 'ember-qunit';
|
import { setupRenderingTest } from 'ember-qunit';
|
||||||
import { render, focus, triggerKeyEvent, typeIn, fillIn } from '@ember/test-helpers';
|
import { render, focus, triggerKeyEvent, typeIn, fillIn, click } from '@ember/test-helpers';
|
||||||
import { create } from 'ember-cli-page-object';
|
import { create } from 'ember-cli-page-object';
|
||||||
import hbs from 'htmlbars-inline-precompile';
|
import hbs from 'htmlbars-inline-precompile';
|
||||||
import sinon from 'sinon';
|
import sinon from 'sinon';
|
||||||
@@ -44,8 +44,14 @@ module('Integration | Component | masked input', function (hooks) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('it renders a download button when allowDownload is true', async function (assert) {
|
test('it renders a download button when allowDownload is true', async function (assert) {
|
||||||
await render(hbs`<MaskedInput @allowDownload={{true}} />`);
|
await render(hbs`<MaskedInput @allowDownload={{true}} /> <div id="modal-wormhole"></div>
|
||||||
assert.ok(component.downloadButtonIsPresent);
|
`);
|
||||||
|
assert.ok(component.downloadIconIsPresent);
|
||||||
|
|
||||||
|
await click('[data-test-download-icon]');
|
||||||
|
assert.ok(component.downloadButtonIsPresent, 'clicking download icon opens modal with download button');
|
||||||
|
|
||||||
|
assert;
|
||||||
});
|
});
|
||||||
|
|
||||||
test('it shortens all outputs when displayOnly and masked', async function (assert) {
|
test('it shortens all outputs when displayOnly and masked', async function (assert) {
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import { clickable, isPresent } from 'ember-cli-page-object';
|
|||||||
export default {
|
export default {
|
||||||
textareaIsPresent: isPresent('[data-test-textarea]'),
|
textareaIsPresent: isPresent('[data-test-textarea]'),
|
||||||
copyButtonIsPresent: isPresent('[data-test-copy-button]'),
|
copyButtonIsPresent: isPresent('[data-test-copy-button]'),
|
||||||
|
downloadIconIsPresent: isPresent('[data-test-download-icon]'),
|
||||||
downloadButtonIsPresent: isPresent('[data-test-download-button]'),
|
downloadButtonIsPresent: isPresent('[data-test-download-button]'),
|
||||||
toggleMasked: clickable('[data-test-button="toggle-masked"]'),
|
toggleMasked: clickable('[data-test-button="toggle-masked"]'),
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user