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);