001/*
002 * jPOS Project [http://jpos.org]
003 * Copyright (C) 2000-2026 jPOS Software SRL
004 *
005 * This program is free software: you can redistribute it and/or modify
006 * it under the terms of the GNU Affero General Public License as
007 * published by the Free Software Foundation, either version 3 of the
008 * License, or (at your option) any later version.
009 *
010 * This program is distributed in the hope that it will be useful,
011 * but WITHOUT ANY WARRANTY; without even the implied warranty of
012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
013 * GNU Affero General Public License for more details.
014 *
015 * You should have received a copy of the GNU Affero General Public License
016 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
017 */
018
019package org.jpos.transaction;
020
021import org.jpos.core.Configurable;
022import org.jpos.core.Configuration;
023import org.jpos.core.ConfigurationException;
024import org.jpos.iso.ISOException;
025import org.jpos.iso.ISOMsg;
026import org.jpos.iso.ISOUtil;
027import org.jpos.tlv.TLVList;
028import org.jpos.util.FSDMsg;
029import org.jpos.util.ProtectedLogListener;
030
031import java.io.Serializable;
032
033/**
034 * @author Alejandro Revilla
035 * @author David Bergert
036 * @author Barspi
037 */
038
039/**
040 *Sample Usage:
041 *<pre>
042 *    &lt;participant class="org.jpos.transaction.ProtectDebugInfo" logger="Q2" realm="debug"&gt;
043 *
044 *        &lt;property name="protect-entry" value="REQUEST" /&gt;
045 *        &lt;property name="protect-entry" value="RESPONSE" /&gt;
046 *        &lt;property name="protect-entry" value="PAN" /&gt;
047 *        &lt;property name="protect-entry" value="REQUEST_ICC_DATA" /&gt;
048 *
049 *        &lt;property name="wipe-entry" value="EXPDATE" /&gt;
050 *
051 *        &lt;property name="protect-ISOMsg" value="2" /&gt;
052 *        &lt;property name="protect-ISOMsg" value="35" /&gt;
053 *        &lt;property name="protect-ISOMsg" value="45" /&gt;
054 *        &lt;property name="wipe-ISOMsg" value="52" /&gt;
055 *        &lt;property name="wipe-ISOMsg" value="55" /&gt;
056 *
057 *        &lt;property name="wipe-TLVList" value="0x56" /&gt;
058 *        &lt;property name="wipe-TLVList" value="0x57" /&gt;
059 *        &lt;property name="wipe-TLVList" value="0x5a" /&gt;
060 *        &lt;property name="wipe-TLVList" value="0x5f20" /&gt;
061 *
062 *        &lt;property name="protect-FSDMsg" value="account-number" /&gt;
063 *        &lt;property name="protect-FSDMsg" value="track2-data" /&gt;
064 *
065 *        &lt;/participant&gt;
066 *</pre>
067 **/
068
069 public class ProtectDebugInfo implements AbortParticipant, Configurable {
070     private String[] protectedEntries;
071     private String[] wipedEntries;
072     private String[] protectFSD;
073     private String[] protectISO;
074     private String[] wipeISO;
075     private String[] wipeTLV;
076
077     public int prepare (long id, Serializable o) {
078         return PREPARED | READONLY;
079     }
080     public int prepareForAbort (long id, Serializable o) {
081         return PREPARED | READONLY;
082     }
083     public void commit (long id, Serializable o) {
084         protect ((Context) o);
085     }
086     public void abort  (long id, Serializable o) {
087         protect ((Context) o);
088     }
089     private void protect (Context ctx) {
090         /* wipe by removing entries from the context  */
091         for (String s: wipedEntries)
092             ctx.remove(s);
093         /* Protect entry items */
094         for (String s: protectedEntries) {
095             Object o = ctx.get (s);
096             if (o instanceof ISOMsg){
097                 ISOMsg m = ctx.get (s);
098                 if (m != null) {
099                     m = (ISOMsg) m.clone();
100                     ctx.put (s, m);   // place a clone in the context
101                     for (String p: protectISO)
102                         protectField(m,p);
103                     for (String p: wipeISO)
104                         wipeField(m,p);
105                 }
106             }
107             if (o instanceof FSDMsg){
108                 FSDMsg m = ctx.get (s);
109                 if (m != null) {
110                     for (String p: protectFSD)
111                         protectField(m,p);
112                 }
113             }
114             if (o instanceof String){
115                 String p = ctx.get(s);
116                 if (p != null){
117                     ctx.put(s, protect (p));
118                 }
119             }
120             if (o instanceof TLVList) {
121                 TLVList tlv = ctx.get(s);
122                 if (tlv != null) {
123                     for (String t: wipeTLV)
124                        wipeTag(tlv, t);
125                 }
126             }
127         }
128     }
129     private void protectField (ISOMsg m, String f) {
130         if (m != null) {
131             m.set (f, protect (m.getString (f)));
132         }
133     }
134    private void wipeField (ISOMsg m, String f) {
135        if (m != null) {
136            Object v = null;
137            try {
138                v = m.getValue(f);
139                if (v != null) {
140                    if (v instanceof String)
141                        m.set(f, ProtectedLogListener.WIPED);
142                    else
143                        m.set(f, ProtectedLogListener.BINARY_WIPED);
144                }
145            } catch (ISOException ignored) {
146                //ignore, valid routes for some messages in the context may not be vaild for others
147                //e.g. in transaction switches with protocol conversion
148            }
149        }
150    }
151
152    static void wipeTag(TLVList tlv, String tag) {
153        if (tlv == null)
154            return;
155        try {
156            int tagName = Integer.decode(tag);
157            if (tlv.hasTag(tagName)) {
158                tlv.deleteByTag(tagName);
159                tlv.append(tagName, ProtectedLogListener.BINARY_WIPED);
160            }
161        }
162        catch (Throwable ignored) { }
163    }
164
165    private void protectField (FSDMsg m, String f) {
166         if (f != null) {
167             String s = m.get (f);
168             if (s != null)
169                 m.set (f, ISOUtil.protect (s));
170         }
171     }
172     private void wipeField (FSDMsg m, String f) {
173         if (m != null && m.get(f) != null) {
174             m.set (f, "*");
175         }
176     }
177     private String protect (String s) {
178         return s != null ? ISOUtil.protect (s) : s;
179     }
180     public void setConfiguration (Configuration cfg) throws ConfigurationException {
181         this.protectedEntries = cfg.getAll("protect-entry");
182         this.wipedEntries = cfg.getAll("wipe-entry");
183         this.protectFSD = cfg.getAll("protect-FSDMsg");
184         this.protectISO = cfg.getAll("protect-ISOMsg");
185         this.wipeISO = cfg.getAll("wipe-ISOMsg");
186         this.wipeTLV = cfg.getAll("wipe-TLVList");
187     }
188}