Skip to content

Commit

Permalink
Add support for CMF DE 027 - POS Capability
Browse files Browse the repository at this point in the history
  • Loading branch information
ar committed Jun 4, 2022
1 parent 1099453 commit 8eea34d
Show file tree
Hide file tree
Showing 5 changed files with 397 additions and 31 deletions.
205 changes: 205 additions & 0 deletions jpos/src/main/java/org/jpos/iso/PosCapability.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,205 @@
/*
* jPOS Project [http://jpos.org]
* Copyright (C) 2000-2022 jPOS Software SRL
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

package org.jpos.iso;

import java.io.PrintStream;

import org.jpos.util.Loggeable;

@SuppressWarnings("unused")
public class PosCapability extends PosFlags implements Loggeable {
public enum ReadingCapability implements Flag {
UNKNOWN (1, "Unknown"),
CONTACTLESS (1 << 1, "Information not taken from card"), // i.e.: RFID
PHYSICAL (1 << 2, "Physical entry"), // i.e.: Manual Entry or OCR
BARCODE (1 << 3, "Bar code"),
MAGNETIC_STRIPE (1 << 4, "Magnetic Stripe"),
ICC (1 << 5, "ICC"),
DATA_ON_FILE (1 << 6, "Data on file"),
ICC_FAILED (1 << 11, "ICC read but failed"),
MAGNETIC_STRIPE_FAILED (1 << 12, "Magnetic Stripe read but failed"),
FALLBACK (1 << 13, "Fallback"),
TRACK1_PRESENT (1 << 27, "Track1 data present"), // jCard private field
TRACK2_PRESENT (1 << 28, "Track2 data present"); // jCard private field

private int val;
private String description;
ReadingCapability (int val, String description) {
this.val = val;
this.description = description;
}
public int intValue() {
return val;
}
public String toString () {
return description;
}

public static int OFFSET = 0;
@Override
public int getOffset() {
return OFFSET;
}
}

public enum VerificationCapability implements Flag {
UNKNOWN (1, "Unknown"),
NONE (1 << 1, "None"),
MANUAL_SIGNATURE (1 << 2, "Manual signature"),
ONLINE_PIN (1 << 3, "Online PIN"),
OFFLINE_PIN_IN_CLEAR (1 << 4, "Offline PIN in clear"),
OFFLINE_PIN_ENCRYPTED (1 << 5, "Offline PIN encrypted"),
OFFLINE_DIGITIZED_SIGNATURE_ANALYSIS (1 << 6, "Offline digitized signature analysis"),
OFFLINE_BIOMETRICS (1 << 7, "Offline biometrics"),
OFFLINE_MANUAL_VERIFICATION (1 << 8, "Offline manual verification"),
OFFLINE_BIOGRAPHICS (1 << 9, "Offline biographics"),
ACCOUNT_BASED_DIGITAL_SIGNATURE (1 << 10, "Account based digital signature"),
PUBLIC_KEY_BASED_DIGITAL_SIGNATURE (1 << 11, "Public key based digital signature");

private int val;
private String description;
VerificationCapability (int val, String description) {
this.val = val;
this.description = description;
}
public int intValue() {
return val;
}
public String toString () {
return description;
}

public static int OFFSET = 0;
@Override
public int getOffset() {
return OFFSET;
}
}

private byte[] b = new byte[8];

public PosCapability() {}

public PosCapability (
int readingCapability,
int verificationCapability)
{
super();

b[0] = (byte) readingCapability;
b[1] = (byte) (readingCapability >>> 8);
b[2] = (byte) (readingCapability >>> 16);
b[3] = (byte) (readingCapability >>> 24);

b[4] = (byte) verificationCapability;
b[5] = (byte) (verificationCapability >>> 8);
b[6] = (byte) (verificationCapability >>> 16);
b[7] = (byte) (verificationCapability >>> 24);
}

private PosCapability (byte[] b) {
if (b != null) {
// will always use our own internal copy of array
int copyLen= Math.min(b.length, 16);
System.arraycopy(b, 0, this.b, 0, copyLen);
}
}

public boolean hasReadingCapability (int readingMethods) {
int i = b[3] << 24 | b[2] << 16 & 0xFF0000 | b[1] << 8 & 0xFF00 | b[0] & 0xFF ;
return (i & readingMethods) == readingMethods;
}
public boolean hasReadingCapability (ReadingCapability method) {
return hasReadingCapability (method.intValue());
}
public boolean hasVerificationCapability (int verificationMethods) {
int i = b[7] << 24 | b[6] << 16 & 0xFF0000 | b[5] << 8 & 0xFF00 | b[4] & 0xFF;
return (i & verificationMethods) == verificationMethods;
}
public boolean hasVerificationCapability (VerificationCapability method) {
return hasVerificationCapability(method.intValue());
}
public byte[] getBytes() {
return b;
}
public boolean canEMV() {
return hasReadingCapability(ReadingCapability.ICC) || hasReadingCapability(ReadingCapability.CONTACTLESS);
}
public boolean canManualEntry() {
return hasReadingCapability(ReadingCapability.PHYSICAL);
}
public boolean isSwiped() {
return hasReadingCapability(ReadingCapability.MAGNETIC_STRIPE);
}
public String toString() {
return super.toString() + "[" + ISOUtil.hexString (getBytes())+ "]";
}

public static PosCapability valueOf (byte[] b) {
return new PosCapability(b); // we create new objects for now, but may return cached instances in the future
}

public void dump(PrintStream p, String indent) {
String inner = indent + " ";
StringBuilder sb = new StringBuilder();
p.printf("%s<pvc value='%s'>%n", indent, ISOUtil.hexString(getBytes()));
for (ReadingCapability m : ReadingCapability.values()) {
if (hasReadingCapability(m)) {
if (sb.length() > 0)
sb.append(',');
sb.append(m.name());
}
}
p.printf ("%src: %s%n", inner, sb);
sb = new StringBuilder();
for (VerificationCapability m : VerificationCapability.values()) {
if (hasVerificationCapability(m)) {
if (sb.length() > 0)
sb.append(',');
sb.append(m.name());
}
}
p.printf ("%svc: %s%n", inner, sb);
p.println("</pvc>");
}

public void setReadingCapabilities(boolean value, ReadingCapability ... capabilities ){
setFlags(value, capabilities);
}

public void unsetReadingCapabilities(ReadingCapability ... capabilities) {
setReadingCapabilities(false, capabilities);
}

public void setReadingCapabilities(ReadingCapability ... capabilities) {
setReadingCapabilities(true, capabilities);
}

public void setVerificationCapabilities(boolean value, VerificationCapability ... capabilities){
setFlags(value, capabilities);
}

public void unsetVerificationCapabilities(VerificationCapability ... capabilities) {
setVerificationCapabilities(false, capabilities);
}

public void setVerificationCapabilities(VerificationCapability ... capabilities) {
setVerificationCapabilities(true, capabilities);
}
}
32 changes: 2 additions & 30 deletions jpos/src/main/java/org/jpos/iso/PosDataCode.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,7 @@
import org.jpos.util.Loggeable;

@SuppressWarnings("unused")
public class PosDataCode implements Loggeable {

public interface Flag {
int getOffset();
int intValue();
}
public class PosDataCode extends PosFlags implements Loggeable {
public enum ReadingMethod implements Flag {
UNKNOWN (1, "Unknown"),
CONTACTLESS (1 << 1, "Information not taken from card"), // i.e.: RFID
Expand Down Expand Up @@ -310,30 +305,7 @@ public void dump(PrintStream p, String indent) {
p.printf ("%ssc: %s%n", inner, sb.toString());
p.println("</pdc>");
}


/**
* Sets or unsets a set of flags according to value
* @param value if true flags are set, else unset
* @param flags flag set to set or unset
*/
public void setFlags(boolean value, Flag... flags) {
if (value) {
for (Flag flag : flags) {
for (int v = flag.intValue(), offset = flag.getOffset(); v != 0; v >>>= 8, offset++) {
b[offset] |= (byte) v;
}
}
} else {
for (Flag flag : flags) {
for (int v = flag.intValue(), offset = flag.getOffset(); v != 0; v >>>= 8, offset++) {
b[offset] &= (byte) ~v;
}
}
}

}


public void setReadingMethods(boolean value, ReadingMethod ... methods ){
setFlags(value, methods);
}
Expand Down
57 changes: 57 additions & 0 deletions jpos/src/main/java/org/jpos/iso/PosFlags.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/*
* jPOS Project [http://jpos.org]
* Copyright (C) 2000-2022 jPOS Software SRL
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

package org.jpos.iso;

@SuppressWarnings("unused")
public abstract class PosFlags {

public interface Flag {
int getOffset();
int intValue();
}

/**
* Sets or unsets a set of flags according to value
* @param value if true flags are set, else unset
* @param flags flag set to set or unset
*/
protected void setFlags(boolean value, Flag... flags) {
byte[] b = getBytes();
if (value) {
for (Flag flag : flags) {
for (int v = flag.intValue(), offset = flag.getOffset(); v != 0; v >>>= 8, offset++) {
if (offset < b.length)
b[offset] |= (byte) v;
}
}
} else {
for (Flag flag : flags) {
for (int v = flag.intValue(), offset = flag.getOffset(); v != 0; v >>>= 8, offset++) {
if (offset < b.length)
b[offset] &= (byte) ~v;
}
}
}
}
public abstract byte[] getBytes();

public String toString() {
return super.toString() + "[" + ISOUtil.hexString (getBytes())+ "]";
}
}
57 changes: 56 additions & 1 deletion jpos/src/main/resources/packager/cmf.xml
Original file line number Diff line number Diff line change
Expand Up @@ -190,12 +190,67 @@
name="Merchant category code"
pad="false"
class="org.jpos.iso.IFB_NUMERIC"/>
<isofield
<isofieldpackager
id="27"
length="27"
name="POS capability"
pad="false"
class="org.jpos.iso.IFB_BINARY"
emitBitmap="false"
firstField="0"
packager="org.jpos.iso.packager.GenericSubFieldPackager">
<isofield
id="0"
length="8"
name="Card Reading and Verification Capabilities"
pad="false"
class="org.jpos.iso.IFB_BINARY"/>
<isofield
id="1"
length="1"
name="Approval code length"
class="org.jpos.iso.IFA_NUMERIC"/>
<isofield
id="2"
length="3"
name="Cardholder receipt data length"
class="org.jpos.iso.IFA_NUMERIC"/>
<isofield
id="3"
length="3"
name="Card acceptor receipt data length"
class="org.jpos.iso.IFA_NUMERIC"/>
<isofield
id="4"
length="3"
name="Cardholder display data length"
class="org.jpos.iso.IFA_NUMERIC"/>
<isofield
id="5"
length="3"
name="Card acceptor display data length"
class="org.jpos.iso.IFA_NUMERIC"/>
<isofield
id="6"
length="3"
name="ICC script data length"
class="org.jpos.iso.IFA_NUMERIC"/>
<isofield
id="7"
length="1"
name="Track3 rewrite capability"
class="org.jpos.iso.IF_CHAR"/>
<isofield
id="8"
length="1"
name="Card capture capability"
class="org.jpos.iso.IF_CHAR"/>
<isofield
id="9"
length="1"
name="PIN Input length"
class="org.jpos.iso.IFB_BINARY"/>
</isofieldpackager>
<isofield
id="28"
length="8"
Expand Down
Loading

0 comments on commit 8eea34d

Please sign in to comment.