Skip to content

Commit fe379d0

Browse files
dhavaljrajparaDhaval Rajpara
andauthored
RANGER-5303 : Implement White-space Input Validation Across Ranger UI Forms (#775)
Co-authored-by: Dhaval Rajpara <dhavalrajpara@apache.org>
1 parent 3cca692 commit fe379d0

16 files changed

Lines changed: 239 additions & 123 deletions

File tree

security-admin/src/main/webapp/react-webapp/src/components/CommonComponents.jsx

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -568,3 +568,12 @@ export const ModalLoader = () => {
568568
</h4>
569569
);
570570
};
571+
572+
export const trimInputValue = (e, input) => {
573+
const value = e.target.value;
574+
const trimmed = value.trim();
575+
if (value !== trimmed) {
576+
input.onChange(trimmed);
577+
}
578+
input.onBlur(e); // Always call onBlur to trigger validation
579+
};

security-admin/src/main/webapp/react-webapp/src/components/CreatableField.jsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,8 @@ const CreatableField = (props) => {
5252
};
5353

5454
const createOption = (label) => ({
55-
value: label,
56-
label: label
55+
value: label.trim(),
56+
label: label.trim()
5757
});
5858

5959
const handleInputChange = (value) => {

security-admin/src/main/webapp/react-webapp/src/components/Editable.jsx

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -231,7 +231,7 @@ const CustomCondition = (props) => {
231231
const expressionVal = (val) => {
232232
let value = null;
233233
if (val != "" && typeof val != "object") {
234-
valRef.current[m.name] = val;
234+
valRef.current[m.name] = val.trim();
235235
return (value = val);
236236
}
237237
return value !== null ? value : "";
@@ -264,6 +264,12 @@ const CustomCondition = (props) => {
264264
key={m.name}
265265
value={expressionVal(selectedJSCondVal)}
266266
onChange={(e) => textAreaHandleChange(e, m.name)}
267+
onBlur={(e) => {
268+
textAreaHandleChange(
269+
{ target: { value: e.target.value.trim() } },
270+
m.name
271+
);
272+
}}
267273
isInvalid={validExpression.state}
268274
/>
269275
{validExpression.state && (
@@ -295,14 +301,33 @@ const CustomCondition = (props) => {
295301
<b>{m.label}:</b>
296302
<CreatableSelect
297303
{...selectProps}
298-
defaultValue={
299-
selectedInputVal == "" ? null : selectedInputVal
300-
}
301-
onChange={(e) => handleChange(e, m.name)}
304+
value={selectedInputVal || null}
305+
onChange={(e) => {
306+
setSelectVal(e);
307+
handleChange(e, m.name);
308+
}}
302309
placeholder=""
303310
width="500px"
304311
isClearable={false}
305312
styles={selectInputCustomStyles}
313+
formatCreateLabel={(inputValue) =>
314+
`Create "${inputValue.trim()}"`
315+
}
316+
onCreateOption={(inputValue) => {
317+
const trimmedValue = inputValue.trim();
318+
if (trimmedValue) {
319+
const newOption = {
320+
label: trimmedValue,
321+
value: trimmedValue
322+
};
323+
const currentValues = selectedInputVal || [];
324+
const newValues = Array.isArray(currentValues)
325+
? [...currentValues, newOption]
326+
: [newOption];
327+
setSelectVal(newValues);
328+
tagAccessData(newValues, m.name);
329+
}
330+
}}
306331
/>
307332
</Form.Group>
308333
</div>

security-admin/src/main/webapp/react-webapp/src/utils/XAEnums.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -586,7 +586,7 @@ export const RegexValidation = {
586586
/^([A-Za-z0-9_]|[\u00C0-\u017F])([a-z0-9,._\-+/@= ]|[\u00C0-\u017F])+$/i,
587587
regexExpressionForFirstAndLastName:
588588
/^([A-Za-z0-9_]|[\u00C0-\u017F])([a-zA-Z0-9\s_. -@]|[\u00C0-\u017F])+$/i,
589-
regexforNameValidation: /^[a-zA-Z0-9_-][a-zA-Z0-9\s_-]{0,254}$/,
589+
regexForNameValidation: /^[a-zA-Z0-9_-][a-zA-Z0-9\s_-]{0,254}$/,
590590
regexExpressionForSecondaryName:
591591
/^([A-Za-z0-9_]|[\u00C0-\u017F])([a-zA-Z0-9\s_. -@]|[\u00C0-\u017F])+$/i,
592592
regexforServiceNameValidation: /^[a-zA-Z0-9_-][a-zA-Z0-9_-]{0,254}$/,
@@ -601,7 +601,7 @@ export const RegexValidation = {
601601
3. Name length should be greater than one."
602602
</>
603603
),
604-
regexforNameValidationMessage:
604+
regexForNameValidationMessage:
605605
"Name should not start with space, it should be less than 256 characters and special characters are not allowed(except _ - and space).",
606606
secondaryNameValidationMessage: (
607607
<>

security-admin/src/main/webapp/react-webapp/src/utils/XAMessages.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,9 @@ export const RegexMessage = {
3636
</p>
3737
</>
3838
),
39-
passwordvalidationinfomessage:
40-
"Password should be minimum 8 characters ,atleast one uppercase letter, one lowercase letter and one numeric. For FIPS environment password should be minimum 14 characters with atleast one uppercase letter, one special characters, one lowercase letter and one numeric.",
41-
emailvalidationinfomessage: (
39+
passwordValidationInfoMessage:
40+
"Password should be minimum 8 characters ,at least one uppercase letter, one lowercase letter and one numeric. For FIPS environment password should be minimum 14 characters with atleast one uppercase letter, one special characters, one lowercase letter and one numeric.",
41+
emailValidationInfoMessage: (
4242
<>
4343
<p className="pd-10 mb-0" style={{ fontSize: "small" }}>
4444
1. Email address should be start with alphabet / numeric / underscore

security-admin/src/main/webapp/react-webapp/src/views/Encryption/KeyCreate.jsx

Lines changed: 31 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,12 @@ import { toast } from "react-toastify";
2424
import { FieldArray } from "react-final-form-arrays";
2525
import arrayMutators from "final-form-arrays";
2626
import { fetchApi } from "Utils/fetchAPI";
27-
import { BlockUi, Loader, scrollToError } from "Components/CommonComponents";
27+
import {
28+
BlockUi,
29+
Loader,
30+
scrollToError,
31+
trimInputValue
32+
} from "Components/CommonComponents";
2833
import { commonBreadcrumb, serverError } from "Utils/XAUtils";
2934
import { cloneDeep, find, isEmpty, values } from "lodash";
3035
import withRouter from "Hooks/withRouter";
@@ -69,7 +74,7 @@ const reducer = (state, action) => {
6974
}
7075
};
7176

72-
const PromtDialog = (props) => {
77+
const PromptDialog = (props) => {
7378
const { isDirtyField, isUnblock } = props;
7479
usePrompt("Are you sure you want to leave", isDirtyField && !isUnblock);
7580
return null;
@@ -120,16 +125,16 @@ function KeyCreate(props) {
120125
serviceJson.name = values.name;
121126
serviceJson.cipher = values.cipher;
122127
serviceJson.length = values.length;
123-
serviceJson.description = values.description;
128+
serviceJson.description = values?.description?.trim();
124129
serviceJson.attributes = {};
125130

126131
for (let key of Object.keys(values.attributes)) {
127132
if (
128133
!isEmpty(values?.attributes[key]?.name) &&
129134
!isEmpty(values?.attributes[key]?.value)
130135
) {
131-
serviceJson.attributes[values.attributes[key].name] =
132-
values.attributes[key].value;
136+
serviceJson.attributes[values.attributes[key].name.trim()] =
137+
values.attributes[key].value.trim();
133138
}
134139
}
135140

@@ -251,7 +256,7 @@ function KeyCreate(props) {
251256
}
252257
}) => (
253258
<div className="wrap">
254-
<PromtDialog isDirtyField={dirty} isUnblock={preventUnBlock} />
259+
<PromptDialog isDirtyField={dirty} isUnblock={preventUnBlock} />
255260
<form
256261
onSubmit={(event) => {
257262
handleSubmit(event);
@@ -268,6 +273,7 @@ function KeyCreate(props) {
268273
{...input}
269274
name="name"
270275
type="text"
276+
onBlur={(e) => trimInputValue(e, input)}
271277
id={meta.error && meta.touched ? "isError" : "name"}
272278
className={
273279
meta.error && meta.touched
@@ -335,6 +341,7 @@ function KeyCreate(props) {
335341
{...input}
336342
className="form-control"
337343
data-cy="description"
344+
onBlur={(e) => trimInputValue(e, input)}
338345
/>
339346
</Col>
340347
</Row>
@@ -361,18 +368,26 @@ function KeyCreate(props) {
361368
fields.map((name, index) => (
362369
<tr key={name}>
363370
<td className="text-center">
364-
<Field
365-
name={`${name}.name`}
366-
component="input"
367-
className="form-control"
368-
/>
371+
<Field name={`${name}.name`}>
372+
{({ input }) => (
373+
<input
374+
{...input}
375+
className="form-control"
376+
onBlur={(e) => trimInputValue(e, input)}
377+
/>
378+
)}
379+
</Field>
369380
</td>
370381
<td className="text-center">
371-
<Field
372-
name={`${name}.value`}
373-
component="input"
374-
className="form-control"
375-
/>
382+
<Field name={`${name}.value`}>
383+
{({ input }) => (
384+
<input
385+
{...input}
386+
className="form-control"
387+
onBlur={(e) => trimInputValue(e, input)}
388+
/>
389+
)}
390+
</Field>
376391
</td>
377392
<td className="text-center">
378393
<Button

security-admin/src/main/webapp/react-webapp/src/views/PolicyListing/AddUpdatePolicyForm.jsx

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,8 @@ import {
5353
BlockUi,
5454
Loader,
5555
scrollToError,
56-
selectInputCustomStyles
56+
selectInputCustomStyles,
57+
trimInputValue
5758
} from "Components/CommonComponents";
5859
import { fetchApi } from "Utils/fetchAPI";
5960
import { RangerPolicyType, getEnumElementByValue } from "Utils/XAEnums";
@@ -291,16 +292,16 @@ export default function AddUpdatePolicyForm() {
291292
const fetchPolicyLabel = async (inputValue) => {
292293
let params = {};
293294
if (inputValue) {
294-
params["policyLabel"] = inputValue || "";
295+
params["policyLabel"] = inputValue.trim() || "";
295296
}
296297
const policyLabelResp = await fetchApi({
297298
url: "plugins/policyLabels",
298299
params: params
299300
});
300301

301302
return policyLabelResp.data.map((name) => ({
302-
label: name,
303-
value: name
303+
label: name.trim(),
304+
value: name.trim()
304305
}));
305306
};
306307

@@ -391,12 +392,12 @@ export default function AddUpdatePolicyForm() {
391392
data.policyName = policyData?.name;
392393
data.isEnabled = policyData?.isEnabled;
393394
data.policyPriority = policyData?.policyPriority == 0 ? false : true;
394-
data.description = policyData?.description;
395+
data.description = policyData?.description?.trim();
395396
data.isAuditEnabled = policyData?.isAuditEnabled;
396397
data.policyLabel =
397398
policyData &&
398399
policyData?.policyLabels?.map((val) => {
399-
return { label: val, value: val };
400+
return { label: val?.trim(), value: val?.trim() };
400401
});
401402
if (policyData?.resources) {
402403
if (!isMultiResources) {
@@ -405,7 +406,7 @@ export default function AddUpdatePolicyForm() {
405406
let setResources = find(serviceCompResourcesDetails, ["name", key]);
406407
data[`resourceName-${setResources?.level}`] = setResources;
407408
data[`value-${setResources?.level}`] = value.values.map((m) => {
408-
return { label: m, value: m };
409+
return { label: m?.trim(), value: m?.trim() };
409410
});
410411
if (setResources?.excludesSupported) {
411412
data[`isExcludesSupport-${setResources?.level}`] =
@@ -450,7 +451,7 @@ export default function AddUpdatePolicyForm() {
450451
setResources;
451452
additionalResourcesObj[`value-${setResources?.level}`] =
452453
value.values.map((m) => {
453-
return { label: m, value: m };
454+
return { label: m?.trim(), value: m?.trim() };
454455
});
455456
if (setResources?.excludesSupported) {
456457
additionalResourcesObj[
@@ -521,7 +522,7 @@ export default function AddUpdatePolicyForm() {
521522
data.conditions[val?.type] = JSON.parse(conditionObj.uiHint)
522523
.isMultiValue
523524
? val?.values
524-
: val?.values.toString();
525+
: val?.values.toString().trim();
525526
}
526527
}
527528
}
@@ -711,9 +712,9 @@ export default function AddUpdatePolicyForm() {
711712
obj.conditions[data?.type] = JSON.parse(conditionObj.uiHint)
712713
.isMultiValue
713714
? data?.values.map((m) => {
714-
return { value: m, label: m };
715+
return { value: m.trim(), label: m.trim() };
715716
})
716-
: data?.values.toString();
717+
: data?.values.toString().trim();
717718
}
718719
}
719720
}
@@ -889,7 +890,7 @@ export default function AddUpdatePolicyForm() {
889890
data["conditions"] = [];
890891
}
891892

892-
/* For create zoen policy*/
893+
/* For create zone policy*/
893894
if (localStorage.getItem("zoneDetails") != null) {
894895
data["zoneName"] = JSON.parse(localStorage.getItem("zoneDetails")).label;
895896
}
@@ -1303,6 +1304,7 @@ export default function AddUpdatePolicyForm() {
13031304
: "form-control"
13041305
}
13051306
data-cy="policyName"
1307+
onBlur={(e) => trimInputValue(e, input)}
13061308
/>
13071309
<InfoIcon
13081310
css="input-box-info-icon"
@@ -1444,6 +1446,7 @@ export default function AddUpdatePolicyForm() {
14441446
as="textarea"
14451447
rows={3}
14461448
data-cy="description"
1449+
onBlur={(e) => trimInputValue(e, input)}
14471450
/>
14481451
</Col>
14491452
</FormB.Group>

security-admin/src/main/webapp/react-webapp/src/views/PolicyListing/PolicyConditionsComp.jsx

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,10 @@ import CreatableSelect from "react-select/creatable";
2525
import { find, isEmpty } from "lodash";
2626
import { InfoIcon } from "Utils/XAUtils";
2727
import { RegexMessage } from "Utils/XAMessages";
28-
import { selectInputCustomStyles } from "Components/CommonComponents";
28+
import {
29+
selectInputCustomStyles,
30+
trimInputValue
31+
} from "Components/CommonComponents";
2932
const esprima = require("esprima");
3033

3134
export default function PolicyConditionsComp(props) {
@@ -90,7 +93,11 @@ export default function PolicyConditionsComp(props) {
9093
const ipRangeVal = (val) => {
9194
let value = [];
9295
if (!isEmpty(val)) {
93-
value = val.map((m) => ({ label: m, value: m }));
96+
// Trim existing values when displaying
97+
value = val.map((m) => ({
98+
label: m.trim(),
99+
value: m.trim()
100+
}));
94101
}
95102
return value;
96103
};
@@ -193,6 +200,9 @@ export default function PolicyConditionsComp(props) {
193200
}
194201
as="textarea"
195202
rows={3}
203+
onBlur={(e) =>
204+
trimInputValue(e, input)
205+
}
196206
/>
197207
{meta.error && (
198208
<span className="invalid-field">
@@ -227,6 +237,24 @@ export default function PolicyConditionsComp(props) {
227237
value={ipRangeVal(input.value)}
228238
onChange={(e) => handleChange(e, input)}
229239
styles={selectInputCustomStyles}
240+
formatCreateLabel={(inputValue) =>
241+
`Create "${inputValue.trim()}"`
242+
}
243+
onCreateOption={(inputValue) => {
244+
const trimmedValue = inputValue.trim();
245+
if (trimmedValue) {
246+
const newOption = {
247+
label: trimmedValue,
248+
value: trimmedValue
249+
};
250+
const currentValues = input.value || [];
251+
const newValues = [
252+
...currentValues,
253+
trimmedValue
254+
];
255+
input.onChange(newValues);
256+
}
257+
}}
230258
/>
231259
)}
232260
/>

0 commit comments

Comments
 (0)