mask passwords in launch preview step

This commit is contained in:
Keith Grant
2020-04-24 15:21:04 -07:00
parent 91d4948564
commit 9b3b20c96b
5 changed files with 35 additions and 99 deletions

View File

@@ -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 (
<PromptDetail
resource={resource}
launchConfig={config}
promptResponses={{
overrides={{
...values,
extra_vars: encodeExtraVars(values.extra_vars, values.survey),
extra_vars: yaml.safeDump(mergeExtraVars(values.extra_vars, masked)),
}}
/>
);

View File

@@ -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,

View File

@@ -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;
}

View File

@@ -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: '········',
});
});
});
});

View File

@@ -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;