StringInput masking
- Add a feature to define a mask character for StringInput which help when there's a need to as something sensitive. - This masks both input and result value.
This commit is contained in:
@@ -40,6 +40,7 @@ public class StringInput extends AbstractTextComponent<String, StringInputContex
|
||||
|
||||
private final String defaultValue;
|
||||
private StringInputContext currentContext;
|
||||
private Character maskCharacter;
|
||||
|
||||
public StringInput(Terminal terminal) {
|
||||
this(terminal, null, null, null);
|
||||
@@ -57,12 +58,21 @@ public class StringInput extends AbstractTextComponent<String, StringInputContex
|
||||
this.defaultValue = defaultValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a mask character for input and result value.
|
||||
*
|
||||
* @param maskCharacter a mask character
|
||||
*/
|
||||
public void setMaskCharater(Character maskCharacter) {
|
||||
this.maskCharacter = maskCharacter;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected StringInputContext getThisContext(ComponentContext<?> context) {
|
||||
if (context != null && currentContext == context) {
|
||||
return currentContext;
|
||||
}
|
||||
currentContext = StringInputContext.of(defaultValue);
|
||||
currentContext = StringInputContext.of(defaultValue, maskCharacter);
|
||||
currentContext.setName(getName());
|
||||
context.stream().forEach(e -> {
|
||||
currentContext.put(e.getKey(), e.getValue());
|
||||
@@ -123,13 +133,48 @@ public class StringInput extends AbstractTextComponent<String, StringInputContex
|
||||
*/
|
||||
void setDefaultValue(String defaultValue);
|
||||
|
||||
/**
|
||||
* Sets a mask character.
|
||||
*
|
||||
* @param maskCharacter the mask character
|
||||
*/
|
||||
void setMaskCharacter(Character maskCharacter);
|
||||
|
||||
/**
|
||||
* Gets a masked input.
|
||||
*
|
||||
* @return a masked input
|
||||
*/
|
||||
String getMaskedInput();
|
||||
|
||||
/**
|
||||
* Gets a masked result value.
|
||||
*
|
||||
* @return masked result value
|
||||
*/
|
||||
String getMaskedResultValue();
|
||||
|
||||
/**
|
||||
* Returns flag if there is a mask character defined.
|
||||
*
|
||||
* @return true if mask character defined, false otherwise
|
||||
*/
|
||||
boolean hasMaskCharacter();
|
||||
|
||||
/**
|
||||
* Gets a mask character.
|
||||
*
|
||||
* @return a mask character.
|
||||
*/
|
||||
Character getMaskCharacter();
|
||||
|
||||
/**
|
||||
* Gets an empty {@link StringInputContext}.
|
||||
*
|
||||
* @return empty path input context
|
||||
*/
|
||||
public static StringInputContext empty() {
|
||||
return of(null);
|
||||
return of(null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -137,8 +182,8 @@ public class StringInput extends AbstractTextComponent<String, StringInputContex
|
||||
*
|
||||
* @return path input context
|
||||
*/
|
||||
public static StringInputContext of(String defaultValue) {
|
||||
return new DefaultStringInputContext(defaultValue);
|
||||
public static StringInputContext of(String defaultValue, Character maskCharacter) {
|
||||
return new DefaultStringInputContext(defaultValue, maskCharacter);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -146,9 +191,11 @@ public class StringInput extends AbstractTextComponent<String, StringInputContex
|
||||
implements StringInputContext {
|
||||
|
||||
private String defaultValue;
|
||||
private Character maskCharacter;
|
||||
|
||||
public DefaultStringInputContext(String defaultValue) {
|
||||
public DefaultStringInputContext(String defaultValue, Character maskCharacter) {
|
||||
this.defaultValue = defaultValue;
|
||||
this.maskCharacter = maskCharacter;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -161,14 +208,52 @@ public class StringInput extends AbstractTextComponent<String, StringInputContex
|
||||
this.defaultValue = defaultValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMaskCharacter(Character maskCharacter) {
|
||||
this.maskCharacter = maskCharacter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMaskedInput() {
|
||||
return maybeMask(getInput());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMaskedResultValue() {
|
||||
return maybeMask(getResultValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasMaskCharacter() {
|
||||
return maskCharacter != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Character getMaskCharacter() {
|
||||
return maskCharacter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> toTemplateModel() {
|
||||
Map<String, Object> attributes = super.toTemplateModel();
|
||||
attributes.put("defaultValue", getDefaultValue() != null ? getDefaultValue() : null);
|
||||
attributes.put("maskedInput", getMaskedInput());
|
||||
attributes.put("maskedResultValue", getMaskedResultValue());
|
||||
attributes.put("maskCharacter", getMaskCharacter());
|
||||
attributes.put("hasMaskCharacter", hasMaskCharacter());
|
||||
Map<String, Object> model = new HashMap<>();
|
||||
model.put("model", attributes);
|
||||
return model;
|
||||
}
|
||||
|
||||
private String maybeMask(String str) {
|
||||
if (StringUtils.hasLength(str) && maskCharacter != null) {
|
||||
return new String(new char[str.length()]).replace('\0', maskCharacter);
|
||||
}
|
||||
else {
|
||||
return str;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class DefaultRenderer implements Function<StringInputContext, List<AttributedString>> {
|
||||
|
||||
@@ -1,9 +1,17 @@
|
||||
// info section after '? xxx'
|
||||
info(model) ::= <%
|
||||
<if(model.input)>
|
||||
<model.input>
|
||||
<if(model.hasMaskCharacter)>
|
||||
<if(model.maskedInput)>
|
||||
<model.maskedInput>
|
||||
<else>
|
||||
<("[Default "); format="value"><model.defaultValue; format="value"><("]"); format="value">
|
||||
<endif>
|
||||
<else>
|
||||
<("[Default "); format="value"><model.defaultValue; format="value"><("]"); format="value">
|
||||
<if(model.input)>
|
||||
<model.input>
|
||||
<else>
|
||||
<("[Default "); format="value"><model.defaultValue; format="value"><("]"); format="value">
|
||||
<endif>
|
||||
<endif>
|
||||
%>
|
||||
|
||||
@@ -14,7 +22,7 @@ question_name(model) ::= <<
|
||||
|
||||
// component result
|
||||
result(model) ::= <<
|
||||
<question_name(model)> <model.resultValue; format="value">
|
||||
<question_name(model)> <model.maskedResultValue; format="value">
|
||||
>>
|
||||
|
||||
// component is running
|
||||
|
||||
Reference in New Issue
Block a user