From b49b6734f1d61f6fb09157dd72ce514ab350b21b Mon Sep 17 00:00:00 2001 From: Arturo Volpe Date: Wed, 17 Aug 2022 17:46:47 -0400 Subject: [PATCH] feat: Support for 8 length bines on ISOUtil Configured with the environment property ${jpos.util.bin.length}, it should be a comma separated list of bines. For example, if there are two 8 length bines "4000000" and "2000000", then this property should be: jpos.util.bin.length = 4000000,2000000 fixes #475 Signed-off-by: Arturo Volpe --- jpos/src/main/java/org/jpos/iso/ISOUtil.java | 54 ++++++++++++++++++- .../test/java/org/jpos/iso/ISOUtilTest.java | 16 ++++++ 2 files changed, 69 insertions(+), 1 deletion(-) diff --git a/jpos/src/main/java/org/jpos/iso/ISOUtil.java b/jpos/src/main/java/org/jpos/iso/ISOUtil.java index 5f73cb4722..f5ee1e30e7 100644 --- a/jpos/src/main/java/org/jpos/iso/ISOUtil.java +++ b/jpos/src/main/java/org/jpos/iso/ISOUtil.java @@ -18,6 +18,7 @@ package org.jpos.iso; +import org.jpos.core.Environment; import java.math.BigDecimal; import java.nio.ByteBuffer; import java.nio.charset.Charset; @@ -26,13 +27,18 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.BitSet; +import java.util.Collections; +import java.util.HashSet; import java.util.List; import java.util.Random; +import java.util.Set; import java.util.StringJoiner; import java.util.StringTokenizer; +import java.util.concurrent.atomic.AtomicReference; import java.util.regex.Pattern; import java.util.stream.Collectors; + /** * various functions needed to pack/unpack ISO-8583 fields * @@ -87,6 +93,25 @@ public ISOUtil() { public static final byte GS = 0x1E; public static final byte ETX = 0x03; + /** + * BIN configuration, used to support 8 length bines + * + * Configured with the enviornment property ${jpos.util.bin.length}, it + * should be a comma separated list of bines. + * + * For example, if there are two 8 length bines "4000000" and "2000000", + * then this property should be: + * + * + * jpos.util.bin.length = 4000000,2000000 + * + * + * @see {@link org.jpos.core.Environment} + * @see #cleanBinCache() + * @see #protect(String, char) + **/ + private static final AtomicReference> BIN_CONFIG = new AtomicReference<>(); + public static String ebcdicToAscii(byte[] e) { return EBCDIC.decode(ByteBuffer.wrap(e)).toString(); } @@ -887,6 +912,26 @@ private static boolean isInternalUnicodeSequence(String s) { public static String normalize (String s) { return normalize(s, true); } + private static Set initBinConfig() { + String config = Environment.get("${jpos.util.bin.length}", ""); + if (config == null || config.isEmpty()) { + BIN_CONFIG.set(Collections.emptySet()); + } + String[] binArray = config.split(","); + Set bines = new HashSet(); + Collections.addAll(bines, binArray); + BIN_CONFIG.set(bines); + return bines; + } + /** + * Clean the bin cache, see {@link #BIN_CONFIG} + * + * Call this method after changing the {@link Environment} so future calls to + * {@link #protect(String)} will re-calculate the bin list + **/ + public static void cleanBinCache() { + BIN_CONFIG.set(null); + } /** * Protects PAN, Track2, CVC (suitable for logs). * @@ -903,7 +948,14 @@ public static String normalize (String s) { public static String protect (String s, char mask) { StringBuilder sb = new StringBuilder(); int len = s.length(); - int clear = len > 6 ? 6 : 0; + Set bines = BIN_CONFIG.get(); + + if (bines == null) bines = initBinConfig(); + + int binLength = 6; + if (len >= 8 && bines.contains(s.substring(0, 8))) binLength = 8; + + int clear = len > binLength ? binLength : 0; int lastFourIndex = -1; if (clear > 0) { lastFourIndex = s.indexOf ('=') - 4; diff --git a/jpos/src/test/java/org/jpos/iso/ISOUtilTest.java b/jpos/src/test/java/org/jpos/iso/ISOUtilTest.java index 258d40c8cb..caf945ce4c 100644 --- a/jpos/src/test/java/org/jpos/iso/ISOUtilTest.java +++ b/jpos/src/test/java/org/jpos/iso/ISOUtilTest.java @@ -45,11 +45,18 @@ import java.util.TimeZone; import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; public class ISOUtilTest { final String lineSep = System.getProperty("line.separator"); + @BeforeAll + static void cleanCache() { + ISOUtil.cleanBinCache(); + System.setProperty("jpos.util.bin.length", "40000100"); + } + @Test public void testAsciiToEbcdic() throws Throwable { byte[] a = new byte[0]; @@ -4386,6 +4393,15 @@ public void testProtectThrowsNullPointerException() throws Throwable { }); } + @Test + void testProtectWithBin8() throws Exception { + ISOUtil.cleanBinCache(); + System.setProperty("jpos.util.bin.length", "40000100"); + + assertEquals("410001______0101", ISOUtil.protect("4100010000000101", '_'), "Should mask a PAN with a bin of 6 digits"); + assertEquals("40000100____0101", ISOUtil.protect("4000010000000101", '_'), "Should mask a PAN with a bin of 8 digits"); + } + @Test public void testSleep() throws Throwable { ISOUtil.sleep(100L);