diff --git a/README.md b/README.md index f789b8b..012b23c 100644 --- a/README.md +++ b/README.md @@ -37,8 +37,9 @@ This project provides a collection of useful template renderers. | 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.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.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.Uptime](https://github.com/rife2/rife2-template-renderers/wiki/rife.render.Uptime) | Renders the server uptime in various customizable formats | diff --git a/lib/src/main/java/rife/render/Mask.java b/lib/src/main/java/rife/render/Mask.java new file mode 100644 index 0000000..8697425 --- /dev/null +++ b/lib/src/main/java/rife/render/Mask.java @@ -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; + +/** + *

Masks characters of a template value. + * + *

Usage:

+ * + *
+ *   <!--v render:rife.render.Mask:valueId/-->
+ *   {{v render:rife.render.Mask:valueId/}}
+ * 
+ * + * @author Erik C. Thauvin + * @see rife.render.Mask + * @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); + } +} diff --git a/lib/src/main/java/rife/render/Normalize.java b/lib/src/main/java/rife/render/Normalize.java index 2f1097d..636c8cb 100644 --- a/lib/src/main/java/rife/render/Normalize.java +++ b/lib/src/main/java/rife/render/Normalize.java @@ -21,7 +21,7 @@ import rife.template.Template; import rife.template.ValueRenderer; /** - *

Normalizes a template value for inclusion in URL path.

+ *

Normalizes a template value for inclusion in a URL path.

* *

Usage:

* diff --git a/lib/src/main/java/rife/render/RenderUtils.java b/lib/src/main/java/rife/render/RenderUtils.java index 1022e0f..3783d03 100644 --- a/lib/src/main/java/rife/render/RenderUtils.java +++ b/lib/src/main/java/rife/render/RenderUtils.java @@ -84,7 +84,6 @@ public final class RenderUtils { /** * Returns the last 4 digits a credit card number. The number must satisfy the Luhn algorithm. * Non-digits are stripped from the number. - * Th * * @param src the credit card number * @return the last 4 digits of the credit card number or empty @@ -124,6 +123,32 @@ public final class RenderUtils { 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. * diff --git a/lib/src/test/java/rife/render/TestFormat.java b/lib/src/test/java/rife/render/TestFormat.java index 8ebdd8f..e7fa330 100644 --- a/lib/src/test/java/rife/render/TestFormat.java +++ b/lib/src/test/java/rife/render/TestFormat.java @@ -36,6 +36,24 @@ class TestFormat { 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 void testNormalize() { var t = TemplateFactory.HTML.get("normalize"); diff --git a/lib/src/test/resources/templates/mask.html b/lib/src/test/resources/templates/mask.html new file mode 100644 index 0000000..2c301fd --- /dev/null +++ b/lib/src/test/resources/templates/mask.html @@ -0,0 +1,5 @@ + +mask=• +unmasked=4 +fromStart=true + \ No newline at end of file diff --git a/lib/src/test/resources/templates/mask.txt b/lib/src/test/resources/templates/mask.txt new file mode 100644 index 0000000..5bcd13a --- /dev/null +++ b/lib/src/test/resources/templates/mask.txt @@ -0,0 +1 @@ +{{v render:rife.render.Mask:foo/}} \ No newline at end of file