mirror of
				https://github.com/optim-enterprises-bv/vault.git
				synced 2025-10-31 02:28:09 +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 {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 {callback} [onSuccess] - callback from parent to invoke if download is successful | ||||
|  */ | ||||
|  | ||||
| export default class DownloadButton extends Component { | ||||
| @@ -73,6 +74,9 @@ export default class DownloadButton extends Component { | ||||
|     try { | ||||
|       this.download.miscExtension(this.filename, this.content, this.extension); | ||||
|       this.flashMessages.info(`Downloading ${this.filename}`); | ||||
|       if (this.args.onSuccess) { | ||||
|         this.args.onSuccess(); | ||||
|       } | ||||
|     } catch (error) { | ||||
|       this.flashMessages.danger(errorMessage(error, 'There was a problem downloading. Please try again.')); | ||||
|     } | ||||
|   | ||||
| @@ -35,15 +35,9 @@ | ||||
|     </CopyButton> | ||||
|   {{/if}} | ||||
|   {{#if @allowDownload}} | ||||
|     <DownloadButton | ||||
|       class="button download-button" | ||||
|       @filename={{or @name "secret-value"}} | ||||
|       @data={{@value}} | ||||
|       @stringify={{true}} | ||||
|       aria-label="Download secret value" | ||||
|     > | ||||
|       <Icon @name="download" /> | ||||
|     </DownloadButton> | ||||
|     <button type="button" class="button download-button" {{on "click" (fn (mut this.modalOpen) true)}}> | ||||
|       <Icon data-test-download-icon @name="download" /> | ||||
|     </button> | ||||
|   {{/if}} | ||||
|   <button | ||||
|     onclick={{this.toggleMask}} | ||||
| @@ -55,4 +49,34 @@ | ||||
|   > | ||||
|     <Icon @name={{if this.showValue "eye" "eye-off"}} /> | ||||
|   </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 [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 [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. | ||||
|  * | ||||
|  */ | ||||
| export default class MaskedInputComponent extends Component { | ||||
|   textareaId = 'textarea-' + guidFor(this); | ||||
|   @tracked showValue = false; | ||||
|   @tracked modalOpen = false; | ||||
|  | ||||
|   constructor() { | ||||
|     super(...arguments); | ||||
|   | ||||
| @@ -6,29 +6,27 @@ | ||||
|  | ||||
| <html> | ||||
|   <head> | ||||
|     <meta charset="utf-8"> | ||||
|     <meta charset="utf-8" /> | ||||
|     <title>Vault Tests</title> | ||||
|     <meta name="description" content=""> | ||||
|     <meta name="viewport" content="width=device-width, initial-scale=1"> | ||||
|     <meta name="description" content="" /> | ||||
|     <meta name="viewport" content="width=device-width, initial-scale=1" /> | ||||
|  | ||||
|     {{content-for "head"}} | ||||
|     {{content-for "test-head"}} | ||||
|     {{content-for "head"}} {{content-for "test-head"}} | ||||
|  | ||||
|     <link rel="stylesheet" href="{{rootURL}}assets/vendor.css"> | ||||
|     <link rel="stylesheet" href="{{rootURL}}assets/vault.css"> | ||||
|     <link rel="stylesheet" href="{{rootURL}}assets/test-support.css"> | ||||
|     <link rel="stylesheet" href="{{rootURL}}assets/vendor.css" /> | ||||
|     <link rel="stylesheet" href="{{rootURL}}assets/vault.css" /> | ||||
|     <link rel="stylesheet" href="{{rootURL}}assets/test-support.css" /> | ||||
|  | ||||
|     {{content-for "head-footer"}} | ||||
|     {{content-for "test-head-footer"}} | ||||
|     {{content-for "head-footer"}} {{content-for "test-head-footer"}} | ||||
|   </head> | ||||
|   <body> | ||||
|     {{content-for "body"}} | ||||
|     {{content-for "test-body"}} | ||||
|     {{content-for "body"}} {{content-for "test-body"}} | ||||
|  | ||||
|     <div id="qunit"></div> | ||||
|     <div id="qunit-fixture"> | ||||
|       <div id="ember-testing-container"> | ||||
|         <div id="ember-testing"></div> | ||||
|         <div id="modal-wormhole"></div> | ||||
|       </div> | ||||
|     </div> | ||||
|  | ||||
| @@ -38,7 +36,6 @@ | ||||
|     <script src="{{rootURL}}assets/vault.js"></script> | ||||
|     <script src="{{rootURL}}assets/tests.js"></script> | ||||
|  | ||||
|     {{content-for "body-footer"}} | ||||
|     {{content-for "test-body-footer"}} | ||||
|     {{content-for "body-footer"}} {{content-for "test-body-footer"}} | ||||
|   </body> | ||||
| </html> | ||||
|   | ||||
| @@ -5,7 +5,7 @@ | ||||
|  | ||||
| import { module, test } from '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 hbs from 'htmlbars-inline-precompile'; | ||||
| 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) { | ||||
|     await render(hbs`<MaskedInput @allowDownload={{true}} />`); | ||||
|     assert.ok(component.downloadButtonIsPresent); | ||||
|     await render(hbs`<MaskedInput @allowDownload={{true}} /> <div id="modal-wormhole"></div> | ||||
| `); | ||||
|     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) { | ||||
|   | ||||
| @@ -8,6 +8,7 @@ import { clickable, isPresent } from 'ember-cli-page-object'; | ||||
| export default { | ||||
|   textareaIsPresent: isPresent('[data-test-textarea]'), | ||||
|   copyButtonIsPresent: isPresent('[data-test-copy-button]'), | ||||
|   downloadIconIsPresent: isPresent('[data-test-download-icon]'), | ||||
|   downloadButtonIsPresent: isPresent('[data-test-download-button]'), | ||||
|   toggleMasked: clickable('[data-test-button="toggle-masked"]'), | ||||
| }; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 claire bontempo
					claire bontempo