Browse Source

Use a configurable list of password fields

You can now use the `config.js` to specify a list of password fields,
which will be used to rendered inputs as password inputs. Applicable to
options and endpoints fields.

If an option or endpoint field contains the 'password' keyword, the
fields will be rendered as password by default (no need to add it to the
config list).
Sergiu Miclea 6 năm trước cách đây
mục cha
commit
7f2767f0dd

+ 4 - 0
config.js

@@ -73,6 +73,10 @@ const conf: Config = {
   // The list of the users to hide in the UI
   // The list of the users to hide in the UI
   hiddenUsers: ['barbican', 'coriolis'],
   hiddenUsers: ['barbican', 'coriolis'],
 
 
+  // By default, if a field name contains `password` in it (ex.: `user_password`), it will be rendered as a password input
+  // If the field doesn't contain `password` in its name, the following list will be used instead
+  passwordFields: ['private_key_passphrase', 'secret_access_key'],
+
 }
 }
 
 
 export const config = conf
 export const config = conf

+ 1 - 2
src/components/organisms/Endpoint/Endpoint.jsx

@@ -29,7 +29,7 @@ import LoadingButton from '../../molecules/LoadingButton'
 import type { Endpoint as EndpointType } from '../../../types/Endpoint'
 import type { Endpoint as EndpointType } from '../../../types/Endpoint'
 import type { Field } from '../../../types/Field'
 import type { Field } from '../../../types/Field'
 import notificationStore from '../../../stores/NotificationStore'
 import notificationStore from '../../../stores/NotificationStore'
-import endpointStore, { passwordFields } from '../../../stores/EndpointStore'
+import endpointStore from '../../../stores/EndpointStore'
 import providerStore from '../../../stores/ProviderStore'
 import providerStore from '../../../stores/ProviderStore'
 import ObjectUtils from '../../../utils/ObjectUtils'
 import ObjectUtils from '../../../utils/ObjectUtils'
 import Palette from '../../styleUtils/Palette'
 import Palette from '../../styleUtils/Palette'
@@ -387,7 +387,6 @@ class Endpoint extends React.Component<Props, State> {
           validating: this.state.validating,
           validating: this.state.validating,
           disabled: this.state.validating,
           disabled: this.state.validating,
           cancelButtonText: this.props.cancelButtonText,
           cancelButtonText: this.props.cancelButtonText,
-          passwordFields,
           getFieldValue: field => this.getFieldValue(field),
           getFieldValue: field => this.getFieldValue(field),
           highlightRequired: () => this.highlightRequired(),
           highlightRequired: () => this.highlightRequired(),
           handleFieldChange: (field, value) => {
           handleFieldChange: (field, value) => {

+ 2 - 2
src/components/organisms/EndpointDetailsContent/EndpointDetailsContent.jsx

@@ -32,6 +32,7 @@ import StyleProps from '../../styleUtils/StyleProps'
 import Palette from '../../styleUtils/Palette'
 import Palette from '../../styleUtils/Palette'
 import DateUtils from '../../../utils/DateUtils'
 import DateUtils from '../../../utils/DateUtils'
 import LabelDictionary from '../../../utils/LabelDictionary'
 import LabelDictionary from '../../../utils/LabelDictionary'
+import configLoader from '../../../utils/Config'
 
 
 const Wrapper = styled.div`
 const Wrapper = styled.div`
   ${StyleProps.exactWidth(StyleProps.contentWidth)}
   ${StyleProps.exactWidth(StyleProps.contentWidth)}
@@ -83,7 +84,6 @@ type Props = {
   usage: { migrations: MainItem[], replicas: MainItem[] },
   usage: { migrations: MainItem[], replicas: MainItem[] },
   onDeleteClick: () => void,
   onDeleteClick: () => void,
   onValidateClick: () => void,
   onValidateClick: () => void,
-  passwordFields?: string[],
 }
 }
 @observer
 @observer
 class EndpointDetailsContent extends React.Component<Props> {
 class EndpointDetailsContent extends React.Component<Props> {
@@ -133,7 +133,7 @@ class EndpointDetailsContent extends React.Component<Props> {
 
 
       let valueClass = null
       let valueClass = null
 
 
-      if (this.props.passwordFields && this.props.passwordFields.find(fn => fn === key)) {
+      if (configLoader.config.passwordFields.find(fn => fn === key) || key.indexOf('password') > -1) {
         valueClass = <PasswordValue value={value} data-test-id="edContent-connPassword" />
         valueClass = <PasswordValue value={value} data-test-id="edContent-connPassword" />
       } else {
       } else {
         valueClass = this.renderValue(value, `connValue-${key}`)
         valueClass = this.renderValue(value, `connValue-${key}`)

+ 4 - 4
src/components/organisms/WizardOptions/WizardOptions.jsx

@@ -19,6 +19,7 @@ import styled from 'styled-components'
 import { observer } from 'mobx-react'
 import { observer } from 'mobx-react'
 import autobind from 'autobind-decorator'
 import autobind from 'autobind-decorator'
 
 
+import configLoader from '../../../utils/Config'
 import StyleProps from '../../styleUtils/StyleProps'
 import StyleProps from '../../styleUtils/StyleProps'
 import ToggleButtonBar from '../../atoms/ToggleButtonBar'
 import ToggleButtonBar from '../../atoms/ToggleButtonBar'
 import FieldInput from '../../molecules/FieldInput'
 import FieldInput from '../../molecules/FieldInput'
@@ -160,9 +161,8 @@ class WizardOptions extends React.Component<Props> {
     return fieldsSchema
     return fieldsSchema
   }
   }
 
 
-  isPassword(field: Field): boolean {
-    return field.type === 'string' && (!field.enum || field.enum.length === 0) &&
-      field.name.indexOf('password') > -1
+  isPassword(fieldName: string): boolean {
+    return fieldName.indexOf('password') > -1 || Boolean(configLoader.config.passwordFields.find(f => f === fieldName))
   }
   }
 
 
   @autobind
   @autobind
@@ -190,7 +190,7 @@ class WizardOptions extends React.Component<Props> {
         key={field.name}
         key={field.name}
         name={field.name}
         name={field.name}
         type={field.type}
         type={field.type}
-        password={this.isPassword(field)}
+        password={this.isPassword(field.name)}
         enum={field.enum}
         enum={field.enum}
         addNullValue
         addNullValue
         required={field.required}
         required={field.required}

+ 1 - 2
src/components/pages/EndpointDetailsPage/EndpointDetailsPage.jsx

@@ -28,7 +28,7 @@ import EndpointValidation from '../../organisms/EndpointValidation'
 import Endpoint from '../../organisms/Endpoint'
 import Endpoint from '../../organisms/Endpoint'
 import EndpointDuplicateOptions from '../../organisms/EndpointDuplicateOptions'
 import EndpointDuplicateOptions from '../../organisms/EndpointDuplicateOptions'
 
 
-import endpointStore, { passwordFields } from '../../../stores/EndpointStore'
+import endpointStore from '../../../stores/EndpointStore'
 import migrationStore from '../../../stores/MigrationStore'
 import migrationStore from '../../../stores/MigrationStore'
 import replicaStore from '../../../stores/ReplicaStore'
 import replicaStore from '../../../stores/ReplicaStore'
 import userStore from '../../../stores/UserStore'
 import userStore from '../../../stores/UserStore'
@@ -245,7 +245,6 @@ class EndpointDetailsPage extends React.Component<Props, State> {
           />}
           />}
           contentComponent={<EndpointDetailsContent
           contentComponent={<EndpointDetailsContent
             item={endpoint}
             item={endpoint}
-            passwordFields={passwordFields}
             usage={this.state.endpointUsage}
             usage={this.state.endpointUsage}
             loading={endpointStore.connectionInfoLoading || endpointStore.loading}
             loading={endpointStore.connectionInfoLoading || endpointStore.loading}
             connectionInfo={endpointStore.connectionInfo}
             connectionInfo={endpointStore.connectionInfo}

+ 4 - 1
src/plugins/endpoint/azure/ContentPlugin.jsx

@@ -21,6 +21,7 @@ import TextArea from '../../../components/atoms/TextArea'
 import ToggleButtonBar from '../../../components/atoms/ToggleButtonBar'
 import ToggleButtonBar from '../../../components/atoms/ToggleButtonBar'
 import type { Field } from '../../../types/Field'
 import type { Field } from '../../../types/Field'
 
 
+import configLoader from '../../../utils/Config'
 import Palette from '../../../components/styleUtils/Palette'
 import Palette from '../../../components/styleUtils/Palette'
 import StyleProps from '../../../components/styleUtils/StyleProps'
 import StyleProps from '../../../components/styleUtils/StyleProps'
 import KeyboardManager from '../../../utils/KeyboardManager'
 import KeyboardManager from '../../../utils/KeyboardManager'
@@ -207,13 +208,15 @@ class ContentPlugin extends React.Component<Props, State> {
   }
   }
 
 
   renderField(field: Field, customProps?: { value: any, onChange: (value: any) => void }) {
   renderField(field: Field, customProps?: { value: any, onChange: (value: any) => void }) {
+    let isPassword = Boolean(configLoader.config.passwordFields.find(fn => field.name === fn))
+      || field.name.indexOf('password') > -1
     return (
     return (
       <FieldStyled
       <FieldStyled
         {...field}
         {...field}
         width={StyleProps.inputSizes.large.width}
         width={StyleProps.inputSizes.large.width}
         disabled={this.props.disabled}
         disabled={this.props.disabled}
         key={field.name}
         key={field.name}
-        password={field.name === 'password'}
+        password={isPassword}
         highlight={this.props.invalidFields.findIndex(fn => fn === field.name) > -1}
         highlight={this.props.invalidFields.findIndex(fn => fn === field.name) > -1}
         value={this.props.getFieldValue(field)}
         value={this.props.getFieldValue(field)}
         onChange={value => { this.handleFieldChange(field, value) }}
         onChange={value => { this.handleFieldChange(field, value) }}

+ 4 - 2
src/plugins/endpoint/default/ContentPlugin.jsx

@@ -17,6 +17,8 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 import * as React from 'react'
 import * as React from 'react'
 import styled from 'styled-components'
 import styled from 'styled-components'
 
 
+import configLoader from '../../../utils/Config'
+
 import FieldInput from '../../../components/molecules/FieldInput'
 import FieldInput from '../../../components/molecules/FieldInput'
 import type { Field } from '../../../types/Field'
 import type { Field } from '../../../types/Field'
 
 
@@ -55,7 +57,6 @@ type Props = {
   cancelButtonText: string,
   cancelButtonText: string,
   validating: boolean,
   validating: boolean,
   onRef: (contentPlugin: any) => void,
   onRef: (contentPlugin: any) => void,
-  passwordFields?: string[],
 }
 }
 class ContentPlugin extends React.Component<Props> {
 class ContentPlugin extends React.Component<Props> {
   componentDidMount() {
   componentDidMount() {
@@ -83,7 +84,8 @@ class ContentPlugin extends React.Component<Props> {
     let lastField
     let lastField
     let i = 0
     let i = 0
     this.props.connectionInfoSchema.forEach((field, schemaIndex) => {
     this.props.connectionInfoSchema.forEach((field, schemaIndex) => {
-      let isPassword = this.props.passwordFields && this.props.passwordFields.find(fn => fn === field.name)
+      let isPassword = Boolean(configLoader.config.passwordFields.find(fn => field.name === fn))
+        || field.name.indexOf('password') > -1
       const currentField = (
       const currentField = (
         <FieldStyled
         <FieldStyled
           {...field}
           {...field}

+ 3 - 2
src/plugins/endpoint/openstack/ContentPlugin.jsx

@@ -166,14 +166,15 @@ class ContentPlugin extends React.Component<Props, State> {
         || (this.useCurrentUser && field.name !== 'name' && field.name !== 'description' && field.name !== 'openstack_use_current_user')
         || (this.useCurrentUser && field.name !== 'name' && field.name !== 'description' && field.name !== 'openstack_use_current_user')
       let required = this.isFieldRequired(field)
       let required = this.isFieldRequired(field)
         || (this.getApiVersion() > 2 ? field.name === 'user_domain' || field.name === 'project_domain' : false)
         || (this.getApiVersion() > 2 ? field.name === 'user_domain' || field.name === 'project_domain' : false)
-
+      let isPassword = Boolean(configLoader.config.passwordFields.find(fn => field.name === fn))
+        || field.name.indexOf('password') > -1
       const currentField = (
       const currentField = (
         <FieldStyled
         <FieldStyled
           {...field}
           {...field}
           required={required}
           required={required}
+          password={isPassword}
           width={StyleProps.inputSizes.large.width}
           width={StyleProps.inputSizes.large.width}
           disabled={disabled}
           disabled={disabled}
-          password={field.name === 'password'}
           highlight={this.props.invalidFields.findIndex(fn => fn === field.name) > -1}
           highlight={this.props.invalidFields.findIndex(fn => fn === field.name) > -1}
           value={this.getFieldValue(field)}
           value={this.getFieldValue(field)}
           onChange={value => { this.props.handleFieldChange(field, value) }}
           onChange={value => { this.props.handleFieldChange(field, value) }}

+ 0 - 2
src/stores/EndpointStore.js

@@ -18,8 +18,6 @@ import type { Endpoint, Validation, StorageBackend, Storage } from '../types/End
 import notificationStore from './NotificationStore'
 import notificationStore from './NotificationStore'
 import EndpointSource from '../sources/EndpointSource'
 import EndpointSource from '../sources/EndpointSource'
 
 
-export const passwordFields = ['password', 'private_key_passphrase', 'secret_access_key']
-
 const updateEndpoint = (endpoint, endpoints) => endpoints.map(e => {
 const updateEndpoint = (endpoint, endpoints) => endpoints.map(e => {
   if (e.id === endpoint.id) {
   if (e.id === endpoint.id) {
     return { ...endpoint }
     return { ...endpoint }

+ 1 - 0
src/types/Config.js

@@ -14,4 +14,5 @@ export type Config = {
   extraOptionsApiCalls: Array<{ name: string, types: Type[], requiredFields: string[] }>,
   extraOptionsApiCalls: Array<{ name: string, types: Type[], requiredFields: string[] }>,
   providerSortPriority: { [providerName: string]: number },
   providerSortPriority: { [providerName: string]: number },
   hiddenUsers: string[],
   hiddenUsers: string[],
+  passwordFields: string[],
 }
 }