Added Mask renderer

This commit is contained in:
Erik C. Thauvin 2023-03-19 12:04:47 -07:00
parent b34363fccf
commit 4dd5df1d61
7 changed files with 116 additions and 3 deletions

View file

@ -37,8 +37,9 @@ This project provides a collection of useful template renderers.
| Renderer | Description | | Renderer | Description |
|:--------------------------------------------------------------------------------------------------------------------|:-----------------------------------------------------------------| |:--------------------------------------------------------------------------------------------------------------------|:-----------------------------------------------------------------|
| [rife.render.formatCreditcard](https://github.com/rife2/rife2-template-renderers/wiki/rife.render.FormatCreditCard) | Formats a template credit card number value to the last 4 digits | | [rife.render.formatCreditcard](https://github.com/rife2/rife2-template-renderers/wiki/rife.render.FormatCreditCard) | Formats a template credit card number value to the last 4 digits |
| [rife.render.Mask](https://github.com/rife2/rife2-template-renderers/wiki/rife.render.Mask) | Masks characters of a template value |
| [rife.render.Normalize](https://github.com/rife2/rife2-template-renderers/wiki/rife.render.Normalize) | Normalizes a template value for inclusion in a URL path | | [rife.render.Normalize](https://github.com/rife2/rife2-template-renderers/wiki/rife.render.Normalize) | Normalizes a template value for inclusion in a URL path |
| [rife.render.QrCode](https://github.com/rife2/rife2-template-renderers/wiki/rife.render.QrCode) | Generates an SVG QR Code from a template value | | [rife.render.QrCode](https://github.com/rife2/rife2-template-renderers/wiki/rife.render.QrCode) | Generates an SVG QR Code from a template value |
| [rife.render.ShortenUrl](https://github.com/rife2/rife2-template-renderers/wiki/rife.render.ShortenUrl) | Shortens a template value URL | | [rife.render.ShortenUrl](https://github.com/rife2/rife2-template-renderers/wiki/rife.render.ShortenUrl) | Shortens a template value URL |
| [rife.render.Uptime](https://github.com/rife2/rife2-template-renderers/wiki/rife.render.Uptime) | Renders the server uptime in various customizable formats | | [rife.render.Uptime](https://github.com/rife2/rife2-template-renderers/wiki/rife.render.Uptime) | Renders the server uptime in various customizable formats |

View file

@ -0,0 +1,63 @@
/*
* Copyright 2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package rife.render;
import rife.template.Template;
import rife.template.ValueRenderer;
import java.io.IOException;
import java.io.StringReader;
import java.util.Properties;
/**
* <p>Masks characters of a template value.
*
* <p>Usage:</p>
*
* <pre>
* &lt;!--v render:rife.render.Mask:valueId/--&gt;
* {{v render:rife.render.Mask:valueId/}}
* </pre>
*
* @author <a href="https://erik.thauvin.net/">Erik C. Thauvin</a>
* @see <a href="https://github.com/rife2/rife2-template-renderers/wiki/rife.render.Mask">rife.render.Mask</a>
* @since 1.0
*/
public class Mask implements ValueRenderer {
/**
* {@inheritDoc}
*/
@Override
public String render(Template template, String valueId, String differentiator) {
var mask = "*";
var unmasked = 0;
var fromStart = false;
if (template.hasDefaultValue(valueId)) {
var properties = new Properties();
try {
properties.load(new StringReader(template.getDefaultValue(valueId)));
mask = properties.getProperty("mask", mask);
unmasked = Integer.parseInt(properties.getProperty("unmasked", "0"));
fromStart = "true".equalsIgnoreCase(properties.getProperty("fromStart", "false"));
} catch (IOException | NumberFormatException ignore) {
// do nothing
}
}
return RenderUtils.mask(template.getValueOrAttribute(differentiator), mask, unmasked, fromStart);
}
}

View file

@ -21,7 +21,7 @@ import rife.template.Template;
import rife.template.ValueRenderer; import rife.template.ValueRenderer;
/** /**
* <p>Normalizes a template value for inclusion in URL path.</p> * <p>Normalizes a template value for inclusion in a URL path.</p>
* *
* <p>Usage:</p> * <p>Usage:</p>
* *

View file

@ -84,7 +84,6 @@ public final class RenderUtils {
/** /**
* Returns the last 4 digits a credit card number. The number must satisfy the Luhn algorithm. * Returns the last 4 digits a credit card number. The number must satisfy the Luhn algorithm.
* Non-digits are stripped from the number. * Non-digits are stripped from the number.
* Th
* *
* @param src the credit card number * @param src the credit card number
* @return the last 4 digits of the credit card number or empty * @return the last 4 digits of the credit card number or empty
@ -124,6 +123,32 @@ public final class RenderUtils {
return ""; return "";
} }
/**
* Masks characters in a String.
*
* @param src the source String.
* @param mask the String to mask characters with
* @param unmasked the number of characters to leave unmasked
* @param fromStart to unmask characters from the start of the String
* @return the masked String
*/
public static String mask(String src, String mask, int unmasked, boolean fromStart) {
var len = src.length();
var buff = new StringBuilder(len);
if (unmasked > 0 && unmasked < len) {
if (fromStart) {
buff.append(src, 0, unmasked);
}
buff.append(mask.repeat(len - unmasked));
if (!fromStart) {
buff.append(src.substring(len - unmasked));
}
} else {
buff.append(mask.repeat(len));
}
return buff.toString();
}
/** /**
* Normalizes a String for inclusion in a URL path. * Normalizes a String for inclusion in a URL path.
* *

View file

@ -36,6 +36,24 @@ class TestFormat {
assertThat(t.getContent()).isEmpty(); assertThat(t.getContent()).isEmpty();
} }
@Test
void testMask() {
var t = TemplateFactory.HTML.get("mask");
var foo = "374380141731053";
t.setAttribute(TestCase.FOO, foo);
assertThat(t.getContent()).as("mask.html").isEqualTo("3743•••••••••••");
t = TemplateFactory.TXT.get("mask");
t.setAttribute(TestCase.FOO, foo);
assertThat(t.getContent()).as("mask.txt").isEqualTo("***************");
assertThat(RenderUtils.mask(foo, "?", 4, false)).as("mask=?")
.isEqualTo("???????????1053");
assertThat(RenderUtils.mask(foo, "-", 22, false)).as("unmasked=22")
.isEqualTo("---------------");
}
@Test @Test
void testNormalize() { void testNormalize() {
var t = TemplateFactory.HTML.get("normalize"); var t = TemplateFactory.HTML.get("normalize");

View file

@ -0,0 +1,5 @@
<!--v render:rife.render.Mask:foo-->
mask=•
unmasked=4
fromStart=true
<!--/v-->

View file

@ -0,0 +1 @@
{{v render:rife.render.Mask:foo/}}