diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index 4e7b4fe1b..efb20d796 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -6,6 +6,11 @@ in development
Changed
~~~~~~~
+* Changed how secrets are handled in the UI from type=password
+ to using CSS webkit-text-security.
+
+ Contributed by @fdrab
+
* Updated various dependencies (security). #1009, #1020
Contributed by @enykeev
diff --git a/modules/st2-auto-form/auto-form.component.js b/modules/st2-auto-form/auto-form.component.js
index e3a355c26..5ce3cd2fe 100644
--- a/modules/st2-auto-form/auto-form.component.js
+++ b/modules/st2-auto-form/auto-form.component.js
@@ -23,7 +23,6 @@ import IntegerField from './fields/integer';
import BooleanField from './fields/boolean';
import StringField from './fields/string';
import ObjectField from './fields/object';
-import PasswordField from './fields/password';
import EnumField from './fields/enum';
import './style.css';
@@ -57,10 +56,6 @@ export default class AutoForm extends React.Component {
case 'boolean':
return BooleanField;
case 'string':
- if (field.secret) {
- return PasswordField;
- }
-
return StringField;
case 'object':
return ObjectField;
diff --git a/modules/st2-auto-form/fields/base.js b/modules/st2-auto-form/fields/base.js
index ca9051727..4cd7ddd43 100644
--- a/modules/st2-auto-form/fields/base.js
+++ b/modules/st2-auto-form/fields/base.js
@@ -45,6 +45,7 @@ export class BaseTextField extends React.Component {
spec: PropTypes.object,
value: PropTypes.any,
disabled: PropTypes.bool,
+ visible: PropTypes.bool,
onChange: PropTypes.func,
'data-test': PropTypes.string,
}
@@ -54,6 +55,7 @@ export class BaseTextField extends React.Component {
this.state = {
value: this.toStateValue(this.props.value),
+ visible: false,
};
}
@@ -105,6 +107,10 @@ export class BaseTextField extends React.Component {
}
}
+ visibilityToggle() {
+ this.setState({visible: !this.state.visible})
+ }
+
emitChange() {
return this.props.onChange(this.fromStateValue(this.state.value));
}
@@ -113,18 +119,22 @@ export class BaseTextField extends React.Component {
const { icon } = this.constructor;
const { invalid } = this.state;
const { spec={} } = this.props;
- const wrapperProps = Object.assign({}, this.props);
+ const wrapperProps = Object.assign({}, this.props, {
+ visibilityToggle: () => this.visibilityToggle(),
+ visible: this.state.visible,
+ });
if (invalid) {
wrapperProps.invalid = invalid;
}
const inputProps = {
- className: 'st2-auto-form__field',
- type: spec.secret ? 'password' : 'text',
+ className: spec.secret && !this.state.visible ? 'st2-auto-form__field--secret' : 'st2-auto-form__field',
+ type: 'text',
placeholder:this.toStateValue(spec.default),
disabled: this.props.disabled,
value: this.state.value,
+ spellCheck: spec.secret && !this.state.visible ? false : true,
onChange: (e) => this.handleChange(e, e.target.value),
'data-test': this.props['data-test'],
};
@@ -135,7 +145,7 @@ export class BaseTextField extends React.Component {
return (
-
+
);
}
@@ -145,19 +155,23 @@ export class BaseTextareaField extends BaseTextField {
render() {
const { icon } = this.constructor;
const { invalid } = this.state;
- const { spec={} } = this.props;
+ const { spec = {} } = this.props;
- const wrapperProps = Object.assign({}, this.props);
+ const wrapperProps = Object.assign({}, this.props, {
+ visibilityToggle: () => this.visibilityToggle(),
+ visible: this.state.visible,
+ });
if (invalid) {
wrapperProps.invalid = invalid;
}
const inputProps = {
- className: 'st2-auto-form__field',
+ className: spec.secret && !this.state.visible ? 'st2-auto-form__field--secret' : 'st2-auto-form__field',
placeholder: this.toStateValue(spec.default),
disabled: this.props.disabled,
value: this.state.value,
+ spellCheck: spec.secret && !this.state.visible ? false : true,
onChange: (e) => this.handleChange(e, e.target.value),
minRows: 1,
maxRows: 10,
@@ -170,7 +184,7 @@ export class BaseTextareaField extends BaseTextField {
return (
-
+
);
}
diff --git a/modules/st2-auto-form/fields/index.js b/modules/st2-auto-form/fields/index.js
index fea9e37fc..5a591d8c2 100644
--- a/modules/st2-auto-form/fields/index.js
+++ b/modules/st2-auto-form/fields/index.js
@@ -19,7 +19,6 @@ import EnumField from './enum';
import IntegerField from './integer';
import NumberField from './number';
import ObjectField from './object';
-import PasswordField from './password';
import StringField from './string';
import SelectField from './select';
import ColorStringField from './color-string';
@@ -31,7 +30,6 @@ export {
IntegerField,
NumberField,
ObjectField,
- PasswordField,
StringField,
SelectField,
ColorStringField,
diff --git a/modules/st2-auto-form/fields/integer.js b/modules/st2-auto-form/fields/integer.js
index 63a1c02f1..e08de20b4 100644
--- a/modules/st2-auto-form/fields/integer.js
+++ b/modules/st2-auto-form/fields/integer.js
@@ -72,6 +72,6 @@ export default class IntegerField extends BaseTextField {
}
}
- return v && !validator.isInt(v) && `'${v}' is not an integer`;
+ return v && !validator.isInt(v) && `'${spec.secret ? "*".repeat(v.length) : v}' is not an integer`;
}
}
diff --git a/modules/st2-auto-form/fields/number.js b/modules/st2-auto-form/fields/number.js
index 4e959d531..2463e70ed 100644
--- a/modules/st2-auto-form/fields/number.js
+++ b/modules/st2-auto-form/fields/number.js
@@ -48,7 +48,7 @@ export default class NumberField extends BaseTextField {
if (invalid !== void 0) {
return invalid;
}
-
- return v && !validator.isFloat(v) && `'${v}' is not a number`;
+
+ return v && !validator.isFloat(v) && `'${spec.secret ? "*".repeat(v.length) : v}' is not a number`;
}
}
diff --git a/modules/st2-auto-form/fields/password.js b/modules/st2-auto-form/fields/password.js
deleted file mode 100644
index ae710d53a..000000000
--- a/modules/st2-auto-form/fields/password.js
+++ /dev/null
@@ -1,27 +0,0 @@
-// Copyright 2019 Extreme Networks, Inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-import { BaseTextField } from './base';
-
-export default class PasswordField extends BaseTextField {
- static icon = '**'
-
- fromStateValue(v) {
- return v !== '' ? v : void 0;
- }
-
- toStateValue(v) {
- return v || '';
- }
-}
diff --git a/modules/st2-auto-form/style.css b/modules/st2-auto-form/style.css
index 7d254be34..859d39c7b 100644
--- a/modules/st2-auto-form/style.css
+++ b/modules/st2-auto-form/style.css
@@ -17,6 +17,11 @@
margin-bottom: 12px;
}
+ &__wrapper-block {
+ display: flex;
+ align-items: center;
+ }
+
&__title {
font-size: 15px;
line-height: 18px;
@@ -70,6 +75,21 @@
&:hover {
color: var(--aqua-base);
}
+
+ &:before {
+ font-family: "brocadeicons";
+ font-size: 18px;
+ font-weight: normal;
+ font-style: normal;
+ line-height: 36px;
+
+ display: flex;
+
+ vertical-align: middle;
+ pointer-events: none;
+
+ color: var(--grey-base);
+ }
}
&__field {
@@ -88,6 +108,21 @@
background-color: white;
box-shadow: 0 1px 0 var(--grey-lighten-2);
+ &--secret {
+ font-weight: normal;
+ font-family: Roboto, sans-serif;
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+ width: 100%;
+
+ color: black;
+ border: none;
+ outline: 0;
+ box-shadow: 0 1px 0 var(--grey-lighten-2);
+ -webkit-text-security: disc;
+ }
+
&&[disabled] {
cursor: default;
@@ -144,7 +179,8 @@
color: black;
}
- &__text-field &__field {
+ &__text-field &__field,
+ &__text-field &__field--secret {
font-size: 13px;
line-height: 18px;
@@ -152,16 +188,16 @@
overflow-x: hidden;
overflow-y: scroll;
- padding: 9px 12px;
+ padding: 9px 40px 9px 9px;
resize: none;
cursor: text;
word-wrap: break-word;
- max-height:50px;
+ max-height:100px;
&::-webkit-scrollbar {
width: 13px;
height: 13px;
-
+
background-color: transparent;
}
@@ -171,6 +207,7 @@
background-color: rgba(117, 117, 117, .3);
background-clip: padding-box;
+
&:hover {
background-color: rgba(117, 117, 117, .7);
}
@@ -249,7 +286,6 @@
padding: 0 10px 0 0;
content: "\e91c";
- vertical-align: middle;
pointer-events: none;
color: black;
diff --git a/modules/st2-auto-form/wrappers.js b/modules/st2-auto-form/wrappers.js
index 9e8f88ce9..98c118701 100644
--- a/modules/st2-auto-form/wrappers.js
+++ b/modules/st2-auto-form/wrappers.js
@@ -171,15 +171,41 @@ export class TextFieldWrapper extends React.Component {
children: PropTypes.element.isRequired,
icon: PropTypes.string,
labelClass: PropTypes.string,
+ visible: PropTypes.bool,
+ visibilityToggle: PropTypes.func,
}
+ handleVisibilityToggle() {
+ this.props.visibilityToggle && this.props.visibilityToggle()
+ }
+
+
render() {
+ const buttonProps = {
+ icon: this.props.visible ? 'view2' : 'view',
+ title: this.props.visible ? 'hide value' : 'see value',
+ onClick: () => this.handleVisibilityToggle(),
+ };
+
+ const blockProps = {
+ className: 'st2-auto-form__wrapper-block',
+ };
+
const line = (