Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

UI/obscure secret on input #11284

Merged
merged 39 commits into from
Apr 22, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
3c61d00
new font and add as font-family to be used in masked-input
Monkeychip Apr 5, 2021
41f8fdb
clean up logic
Monkeychip Apr 5, 2021
e5da277
refactor for displayOnly
Monkeychip Apr 6, 2021
fe19949
start cert masking
Monkeychip Apr 7, 2021
f83052f
work on certificates
Monkeychip Apr 9, 2021
6fbe8e8
upload cert work
Monkeychip Apr 9, 2021
757125e
fix global styling
Monkeychip Apr 9, 2021
3f94dc3
Merge branch 'master' into ui/obscure-secret-on-input
Monkeychip Apr 9, 2021
f0258aa
fix styling for class no longer used
Monkeychip Apr 9, 2021
bbea570
make mask by default and remove option
Monkeychip Apr 9, 2021
5f4da99
glimmerize start and certificate on LDAP a file field
Monkeychip Apr 12, 2021
7d50d2c
glimmerize actions
Monkeychip Apr 12, 2021
e164076
first part of glimmerizing text-file still need to do some clean up
Monkeychip Apr 12, 2021
a6ac780
not doing awesome over here
Monkeychip Apr 13, 2021
862497c
getting ready to un-glimmer
Monkeychip Apr 14, 2021
88437a2
unglimmerize
Monkeychip Apr 14, 2021
9188361
remove placeholder based on conversations with design
Monkeychip Apr 14, 2021
e190d1f
clean up text-file
Monkeychip Apr 14, 2021
92242f9
cleanup
Monkeychip Apr 14, 2021
df32ee0
fix class bindings
Monkeychip Apr 14, 2021
ae3bdb0
handle class binding
Monkeychip Apr 14, 2021
71243f0
set up for test
Monkeychip Apr 14, 2021
d9d56d9
fix elementId
Monkeychip Apr 14, 2021
27cb0a3
track down index
Monkeychip Apr 14, 2021
e68f1c1
update masked-input test
Monkeychip Apr 15, 2021
fd1284d
add more to the masked-input test
Monkeychip Apr 15, 2021
ea88707
test-file test
Monkeychip Apr 15, 2021
5a51d55
fix broken test
Monkeychip Apr 15, 2021
b6598e2
clear old style
Monkeychip Apr 15, 2021
3110d3f
clean up
Monkeychip Apr 15, 2021
b8c52fc
remove pgp key masked font, this really needs to be refactored to tex…
Monkeychip Apr 16, 2021
44db29b
changelog
Monkeychip Apr 16, 2021
11e50a5
resolve merge conflict
Monkeychip Apr 16, 2021
7190c08
cover other certificate view
Monkeychip Apr 20, 2021
b9e4390
add allowCopy
Monkeychip Apr 20, 2021
e52fdb1
address some pr styling comments
Monkeychip Apr 21, 2021
ccd028e
improve test coverage
Monkeychip Apr 21, 2021
fb38f21
fix some issues
Monkeychip Apr 21, 2021
0b8dc91
add attr.options.masked
Monkeychip Apr 22, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions changelog/11284.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:improvement
ui: Obscure secret values on input and displayOnly fields like certificates.
```
142 changes: 71 additions & 71 deletions ui/app/components/text-file.js
Original file line number Diff line number Diff line change
@@ -1,84 +1,84 @@
import Component from '@ember/component';
import Component from '@glimmer/component';
import { set } from '@ember/object';
import { action } from '@ember/object';
import { tracked } from '@glimmer/tracking';
import { guidFor } from '@ember/object/internals';

export default Component.extend({
'data-test-component': 'text-file',
classNames: ['box', 'is-fullwidth', 'is-marginless', 'is-shadowless'],
classNameBindings: ['inputOnly:is-paddingless'],
/**
* @module TextFile
* `TextFile` components are file upload components where you can either toggle to upload a file or enter text.
*
* @example
* <TextFile
* @inputOnly={{true}}
* @helpText="help text"
* @file={{object}}
* @onChange={{action "someOnChangeFunction"}}
* @label={{"string"}}
* />
*
* @param [inputOnly] {bool} - When true, only the file input will be rendered
* @param [helpText] {string} - Text underneath label.
* @param file {object} - * Object in the shape of:
* {
* value: 'file contents here',
Monkeychip marked this conversation as resolved.
Show resolved Hide resolved
* fileName: 'nameOfFile.txt',
* enterAsText: boolean ability to enter as text
* }
* @param [onChange=Function.prototype] {Function|action} - A function to call when the value of the input changes.
* @param [label=null] {string} - Text to use as the label for the file input. If null, a default will be rendered.
*/

/*
* @public
* @param Object
* Object in the shape of:
* {
* value: 'file contents here',
* fileName: 'nameOfFile.txt',
* enterAsText: bool
* }
*/
file: null,
export default class TextFile extends Component {
fileHelpText = 'Select a file from your computer';
textareaHelpText = 'Enter the value as text';
elementId = guidFor(this);
index = '';

index: null,
onChange: () => {},
@tracked file = null;
@tracked showValue = false;

/*
* @public
* @param Boolean
* When true, only the file input will be rendered
*/
inputOnly: false,

/*
* @public
* @param String
* Text to use as the label for the file input
* If null, a default will be rendered
*/
label: null,

/*
* @public
* @param String
* Text to use as help under the file input
* If null, a default will be rendered
*/
fileHelpText: 'Select a file from your computer',

/*
* @public
* @param String
* Text to use as help under the textarea in text-input mode
* If null, a default will be rendered
*/
textareaHelpText: 'Enter the value as text',
get inputOnly() {
return this.args.inputOnly || false;
}
get label() {
return this.args.label || null;
}

readFile(file) {
const reader = new FileReader();
reader.onload = () => this.setFile(reader.result, file.name);
reader.readAsText(file);
},
}

setFile(contents, filename) {
this.onChange(this.index, { value: contents, fileName: filename });
},
this.args.onChange(this.index, { value: contents, fileName: filename });
}

actions: {
pickedFile(e) {
const { files } = e.target;
if (!files.length) {
return;
}
for (let i = 0, len = files.length; i < len; i++) {
this.readFile(files[i]);
}
},
updateData(e) {
const file = this.file;
set(file, 'value', e.target.value);
this.onChange(this.index, this.file);
},
clearFile() {
this.onChange(this.index, { value: '' });
},
},
});
@action
pickedFile(e) {
e.preventDefault();
const { files } = e.target;
if (!files.length) {
return;
}
for (let i = 0, len = files.length; i < len; i++) {
this.readFile(files[i]);
}
}
@action
updateData(e) {
e.preventDefault();
let file = this.args.file;
set(file, 'value', e.target.value);
this.args.onChange(this.index, file);
}
@action
clearFile() {
this.args.onChange(this.index, { value: '' });
}
@action
toggleMask() {
this.showValue = !this.showValue;
}
}
2 changes: 1 addition & 1 deletion ui/app/models/auth-config/ldap.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ export default AuthConfig.extend({
useOpenAPI: true,
certificate: attr({
label: 'Certificate',
editType: 'textarea',
editType: 'file',
Copy link
Contributor Author

@Monkeychip Monkeychip Apr 16, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a certificate and needed to be a file upload with option to add as text with masked input.
image

}),
fieldGroups: computed('newFields', function() {
let groups = [
Expand Down
1 change: 1 addition & 0 deletions ui/app/models/pki-ca-certificate.js
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@ export default Certificate.extend({
csr: attr('string', {
editType: 'textarea',
label: 'CSR',
masked: true,
}),
expiration: attr(),

Expand Down
10 changes: 8 additions & 2 deletions ui/app/models/pki-certificate.js
Original file line number Diff line number Diff line change
Expand Up @@ -63,14 +63,20 @@ export default Model.extend({
defaultValue: false,
}),

certificate: attr('string'),
certificate: attr('string', {
masked: true,
}),
issuingCa: attr('string', {
label: 'Issuing CA',
masked: true,
}),
caChain: attr('string', {
label: 'CA chain',
masked: true,
}),
privateKey: attr('string', {
masked: true,
}),
privateKey: attr('string'),
privateKeyType: attr('string'),
serialNumber: attr('string'),

Expand Down
9 changes: 9 additions & 0 deletions ui/app/styles/app.scss
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
@import 'ember-basic-dropdown';
@import 'ember-power-select';
@import './core';

@mixin font-face($name) {
@font-face {
font-family: $name;
src: url('/ui/fonts/#{$name}.woff2') format('woff2'), url('/ui/fonts/#{$name}.woff') format('woff');
}
}

@include font-face('obscure');
13 changes: 4 additions & 9 deletions ui/app/styles/components/masked-input.scss
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
.masked-font {
color: $ui-gray-300;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have the masked-font defined in the form.scss however the color is overridden when it cascades to this level.

}

.masked-input {
display: flex;
align-items: center;
}

.masked-input.masked.display-only,
.masked-input:not(.masked) {
align-items: start;
}

.has-label .masked-input {
padding-top: $spacing-s;
}
Expand Down Expand Up @@ -91,10 +90,6 @@
color: $grey-light;
}

.masked-input:not(.masked) .masked-input-toggle {
color: $blue;
}

.masked-input .input:focus + .masked-input-toggle {
background: rgba($white, 0.95);
}
14 changes: 14 additions & 0 deletions ui/app/styles/components/text-file.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
.text-file {
.has-icon-right {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adding toggle display icon
image

display: flex;
width: 97%;

.textarea {
line-height: inherit;
}
}
.button.masked-input-toggle,
.button.copy-button {
display: flex;
}
}
1 change: 1 addition & 0 deletions ui/app/styles/core.scss
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@
@import './components/splash-page';
@import './components/status-menu';
@import './components/tabs';
@import './components/text-file';
@import './components/token-expire-warning';
@import './components/toolbar';
@import './components/tool-tip';
Expand Down
7 changes: 7 additions & 0 deletions ui/app/styles/core/forms.scss
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,13 @@ label {
}
}

.masked-font {
font-family: obscure;
font-size: $size-medium;
letter-spacing: 2px;
color: $ui-gray-300;
Monkeychip marked this conversation as resolved.
Show resolved Hide resolved
}

.label {
color: $grey-darker;
text-transform: uppercase;
Expand Down
34 changes: 32 additions & 2 deletions ui/app/templates/components/config-pki-ca.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,27 @@
</h2>
{{#if (or model.certificate model.csr)}}
{{#each model.attrs as |attr|}}
{{info-table-row data-test-table-row label=(capitalize (or attr.options.label (humanize (dasherize attr.name)))) value=(get model attr.name)}}
{{#if attr.options.masked}}
<InfoTableRow @label={{capitalize (or attr.options.label (humanize (dasherize attr.name)))}} @value={{get model attr.name}}>
<MaskedInput
@value={{get model attr.name}}
@displayOnly={{true}}
@allowCopy={{true}}
/>
</InfoTableRow>
{{else if (eq attr.name "expiration")}}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While I was in here, I made it so the expiration was human readable. See Expiration row.
image

{{info-table-row
data-test-table-row
label=(capitalize (or attr.options.label (humanize (dasherize attr.name))))
value=(date-format (get model attr.name) 'MMM dd, yyyy hh:mm:ss a')
}}
{{else}}
{{info-table-row
data-test-table-row
label=(capitalize (or attr.options.label (humanize (dasherize attr.name))))
value=(get model attr.name)
}}
{{/if}}
{{/each}}
<div class="field is-grouped box is-fullwidth is-bottomless">
<div class="control">
Expand Down Expand Up @@ -70,7 +90,17 @@
data-test-warning
/>
{{#each model.attrs as |attr|}}
{{info-table-row data-test-table-row label=(capitalize (or attr.options.label (humanize (dasherize attr.name)))) value=(get model attr.name)}}
{{#if attr.options.masked}}
<InfoTableRow @label={{capitalize (or attr.options.label (humanize (dasherize attr.name)))}} @value={{get model attr.name}}>
<MaskedInput
@value={{get model attr.name}}
@displayOnly={{true}}
@allowCopy={{true}}
/>
</InfoTableRow>
{{else}}
{{info-table-row data-test-table-row label=(capitalize (or attr.options.label (humanize (dasherize attr.name)))) value=(get model attr.name)}}
{{/if}}
{{/each}}
<div class="field is-grouped box is-fullwidth is-bottomless">
<div class="control">
Expand Down
2 changes: 2 additions & 0 deletions ui/app/templates/components/generate-credentials.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -49,12 +49,14 @@
(eq attr.name "secretKey")
(eq attr.name "securityToken")
(eq attr.name "privateKey")
attr.options.masked
)}}
<InfoTableRow @label={{capitalize (or attr.options.label (humanize (dasherize attr.name)))}} @value={{get model attr.name}}>
<MaskedInput
@value={{get model attr.name}}
@name={{attr.name}}
@displayOnly={{true}}
@allowCopy={{true}}
/>
</InfoTableRow>
{{else}}
Expand Down
12 changes: 11 additions & 1 deletion ui/app/templates/components/pki-cert-show.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,17 @@
{{#if (eq attr.type "object")}}
<InfoTableRow @label={{capitalize (or attr.options.label (humanize (dasherize attr.name)))}} @value={{stringify (get model attr.name)}} />
{{else}}
<InfoTableRow @label={{capitalize (or attr.options.label (humanize (dasherize attr.name)))}} @value={{get model attr.name}} />
{{#if attr.options.masked}}
<InfoTableRow @label={{capitalize (or attr.options.label (humanize (dasherize attr.name)))}} @value={{get model attr.name}}>
<MaskedInput
@value={{get model attr.name}}
@displayOnly={{true}}
@allowCopy={{true}}
/>
</InfoTableRow>
{{else}}
<InfoTableRow @label={{capitalize (or attr.options.label (humanize (dasherize attr.name)))}} @value={{get model attr.name}} />
{{/if}}
{{/if}}
{{/each}}
</div>
Expand Down
Loading