From 9b3b20c96be5ee1aad21708820b1d1b87388c241 Mon Sep 17 00:00:00 2001 From: Keith Grant Date: Fri, 24 Apr 2020 15:21:04 -0700 Subject: [PATCH] mask passwords in launch preview step --- .../components/LaunchPrompt/PreviewStep.jsx | 11 ++- .../components/LaunchPrompt/SurveyStep.jsx | 5 +- .../components/LaunchPrompt/mergeExtraVars.js | 13 +-- .../LaunchPrompt/mergeExtraVars.test.js | 18 +++- .../components/PromptDetail/PromptDetail.jsx | 87 +------------------ 5 files changed, 35 insertions(+), 99 deletions(-) diff --git a/awx/ui_next/src/components/LaunchPrompt/PreviewStep.jsx b/awx/ui_next/src/components/LaunchPrompt/PreviewStep.jsx index 711a52ee02..981c05e076 100644 --- a/awx/ui_next/src/components/LaunchPrompt/PreviewStep.jsx +++ b/awx/ui_next/src/components/LaunchPrompt/PreviewStep.jsx @@ -1,17 +1,22 @@ import React from 'react'; import { useFormikContext } from 'formik'; +import yaml from 'js-yaml'; import PromptDetail from '@components/PromptDetail'; -import { encodeExtraVars } from './mergeExtraVars'; +import mergeExtraVars, { maskPasswords } from './mergeExtraVars'; function PreviewStep({ resource, config, survey }) { const { values } = useFormikContext(); + const passwordFields = survey.spec + .filter(q => q.type === 'password') + .map(q => q.variable); + const masked = maskPasswords(values.survey, passwordFields); return ( ); diff --git a/awx/ui_next/src/components/LaunchPrompt/SurveyStep.jsx b/awx/ui_next/src/components/LaunchPrompt/SurveyStep.jsx index 5cd158ad59..451836ba8d 100644 --- a/awx/ui_next/src/components/LaunchPrompt/SurveyStep.jsx +++ b/awx/ui_next/src/components/LaunchPrompt/SurveyStep.jsx @@ -1,7 +1,6 @@ -import React, { useCallback, useEffect, useState } from 'react'; +import React, { useEffect, useState } from 'react'; import { withI18n } from '@lingui/react'; import { Formik, useField } from 'formik'; -import { JobTemplatesAPI, WorkflowJobTemplatesAPI } from '@api'; import { Form, FormGroup, @@ -12,8 +11,6 @@ import { import FormField, { FieldTooltip } from '@components/FormField'; import AnsibleSelect from '@components/AnsibleSelect'; import ContentLoading from '@components/ContentLoading'; -import ContentError from '@components/ContentError'; -import useRequest from '@util/useRequest'; import { required, minMaxValue, diff --git a/awx/ui_next/src/components/LaunchPrompt/mergeExtraVars.js b/awx/ui_next/src/components/LaunchPrompt/mergeExtraVars.js index 681dc8a059..b5e8fe1442 100644 --- a/awx/ui_next/src/components/LaunchPrompt/mergeExtraVars.js +++ b/awx/ui_next/src/components/LaunchPrompt/mergeExtraVars.js @@ -8,9 +8,12 @@ export default function mergeExtraVars(extraVars, survey = {}) { }; } -// TODO: "safe" version that obscures passwords for preview step - -export function encodeExtraVars(extraVars, survey = {}) { - const vars = mergeExtraVars(extraVars, survey); - return yaml.safeDump(vars); +export function maskPasswords(vars, passwordKeys) { + const updated = { ...vars }; + passwordKeys.forEach(key => { + if (updated[key]) { + updated[key] = '········'; + } + }); + return updated; } diff --git a/awx/ui_next/src/components/LaunchPrompt/mergeExtraVars.test.js b/awx/ui_next/src/components/LaunchPrompt/mergeExtraVars.test.js index 55f37088bb..ef1420fb06 100644 --- a/awx/ui_next/src/components/LaunchPrompt/mergeExtraVars.test.js +++ b/awx/ui_next/src/components/LaunchPrompt/mergeExtraVars.test.js @@ -1,4 +1,4 @@ -import mergeExtraVars from './mergeExtraVars'; +import mergeExtraVars, { maskPasswords } from './mergeExtraVars'; describe('mergeExtraVars', () => { test('should handle yaml string', () => { @@ -31,4 +31,20 @@ describe('mergeExtraVars', () => { bar: 'baz', }); }); + + describe('maskPasswords', () => { + test('should mask password fields', () => { + const vars = { + one: 'alpha', + two: 'bravo', + three: 'charlie', + }; + + expect(maskPasswords(vars, ['one', 'three'])).toEqual({ + one: '········', + two: 'bravo', + three: '········', + }); + }); + }); }); diff --git a/awx/ui_next/src/components/PromptDetail/PromptDetail.jsx b/awx/ui_next/src/components/PromptDetail/PromptDetail.jsx index b9d0011f3f..d874ffecbd 100644 --- a/awx/ui_next/src/components/PromptDetail/PromptDetail.jsx +++ b/awx/ui_next/src/components/PromptDetail/PromptDetail.jsx @@ -76,86 +76,7 @@ function omitOverrides(resource, overrides) { return clonedResource; } -// TODO: When prompting is hooked up, update function -// to filter based on prompt overrides -function partitionPromptDetails(resource, userResponses, launchConfig) { - const { defaults = {} } = launchConfig; - const overrides = {}; - - if (launchConfig.ask_credential_on_launch) { - let isEqual; - const defaultCreds = defaults.credentials; - const currentCreds = resource?.summary_fields?.credentials; - - if (defaultCreds?.length === currentCreds?.length) { - isEqual = currentCreds.every(cred => { - return defaultCreds.some(item => item.id === cred.id); - }); - } else { - isEqual = false; - } - - if (!isEqual) { - overrides.credentials = resource?.summary_fields?.credentials; - } - } - if (launchConfig.ask_diff_mode_on_launch) { - if (defaults.diff_mode !== resource.diff_mode) { - overrides.diff_mode = resource.diff_mode; - } - } - if (launchConfig.ask_inventory_on_launch) { - if (defaults.inventory.id !== resource.inventory) { - overrides.inventory = resource?.summary_fields?.inventory; - } - } - if (launchConfig.ask_job_type_on_launch) { - if (defaults.job_type !== resource.job_type) { - overrides.job_type = resource.job_type; - } - } - if (launchConfig.ask_limit_on_launch) { - if (defaults.limit !== resource.limit) { - overrides.limit = resource.limit; - } - } - if (launchConfig.ask_scm_branch_on_launch) { - if (defaults.scm_branch !== resource.scm_branch) { - overrides.scm_branch = resource.scm_branch; - } - } - if (launchConfig.ask_skip_tags_on_launch) { - if (defaults.skip_tags !== resource.skip_tags) { - overrides.skip_tags = resource.skip_tags; - } - } - if (launchConfig.ask_tags_on_launch) { - if (defaults.job_tags !== resource.job_tags) { - overrides.job_tags = resource.job_tags; - } - } - if (launchConfig.ask_variables_on_launch) { - if (defaults.extra_vars !== resource.extra_vars) { - overrides.extra_vars = resource.extra_vars; - } - } - if (launchConfig.ask_verbosity_on_launch) { - if (defaults.verbosity !== resource.verbosity) { - overrides.verbosity = resource.verbosity; - } - } - - const withoutOverrides = omitOverrides(resource, overrides); - - return [withoutOverrides, overrides]; -} - -function PromptDetail({ - i18n, - resource, - launchConfig = {}, - promptResponses = {}, -}) { +function PromptDetail({ i18n, resource, launchConfig = {}, overrides = {} }) { const VERBOSITY = { 0: i18n._(t`0 (Normal)`), 1: i18n._(t`1 (Verbose)`), @@ -164,12 +85,6 @@ function PromptDetail({ 4: i18n._(t`4 (Connection Debug)`), }; - // const [details, overrides] = partitionPromptDetails( - // resource, - // promptResponses, - // launchConfig - // ); - const overrides = promptResponses; const details = omitOverrides(resource, overrides); const hasOverrides = Object.keys(overrides).length > 0;