package foundation.pEp.jniadapter.test.speedtest; import java.nio.charset.StandardCharsets; import java.text.ParseException; import java.util.ArrayList; import java.util.Properties; import java.util.Vector; import java.util.regex.Matcher; import java.util.regex.Pattern; import foundation.pEp.jniadapter.Blob; import foundation.pEp.jniadapter.Engine; import foundation.pEp.jniadapter.Identity; import foundation.pEp.jniadapter.Message; import foundation.pEp.jniadapter.Pair; /** * MTMsgCodec is the Codec class for encoding/decoding p≡p for SWIFT messages. * *
* See SWIFT message structure, MT message format, MT999 *
** Copyright 2019, p≡p * Security. *
* * @author Volker Birk * @version %I% %G% */ // FIXME: rework to stringbuffer public class MTMsgCodec { public Engine pEp; /** * Constructs a MessageCodec using p≡p engine. * * @param pEp_engine p≡p engine to use */ public MTMsgCodec(Engine pEp_engine) { pEp = pEp_engine; } private final static String magicKeys = "pEpKeys"; private final static String magicEnc = "pEpMessage"; private final static String pgp_regex = "(?ms)" + "-----BEGIN PGP (?pgp_text
without PGP header
*/
protected static String stripFromPGP(String pgp_text) throws ParseException {
Matcher m = pgp_pattern.matcher(pgp_text);
if (!m.matches())
throw new ParseException("not a PGP block", 0);
return m.group("block");
}
/**
* Adds PGP header and footer.
*
* @param payload text to decorate
* @param pgp_type PGP data type
* @return payload
with added header and footer
*/
protected static String addPGPHeader(String payload, String pgp_type) {
// FIXME: rework to stringbuffer
return "-----BEGIN PGP " + pgp_type + "-----\n\n" + payload + "\n-----END PGP " + pgp_type + "-----\n";
}
/**
* Decodes a BIC from an URI.
*
* @param uri the URI to decode from
* @throws ParseException if URI has not the correct form
* @return decoded BIC
*/
public static String decodeBIC(String uri) throws ParseException {
Matcher m = uri_pattern.matcher(uri);
if (!m.matches())
throw new ParseException("not a valid URI", 0);
return m.group("bic");
}
/**
* Encodes a BIC into an URI.
*
* @param bic BIC to encode
* @return encoded URI
*/
public static String encodeBIC(String bic) {
// return "payto://swift/" + bic
return bic + "@BIC";
}
/**
* Generates a list of transporting MT999 messages for a payload.
*
* @param from source address
* @param to destination address
* @param ii message direction
* @param trn message id
* @param payload payload to split
* @param magic magic string to mark as p≡p message
*
* @return array of String with MT999 messages
*/
protected String[] transportMT999(String from, String to, String ii, String trn, String rr, String payload,
String magic) {
Vectorlongmsg
; in this case
* message direction is being taken from there, too
* @param config properties with configuration
* @return String with encoded p≡p for SWIFT message
* @throws UnsupportedOperationException if EncFormat
is other than
* None
, Inline
* or PEP
*/
public String encode(Message msg, Properties config) {
if (msg.getLongmsg() == null || msg.getLongmsg().length() < 1)
throw new IllegalArgumentException("longmsg must contain the message");
String result = "";
String msgid = msg.getId() != null && msg.getId().length() > 0 ? msg.getId() : "23";
String dir = msg.getDir() == Message.Direction.Incoming ? "I" : "O";
if (msgid.length() > 12) {
if (msgid.substring(0, 3).compareTo("pEp.") == 0 && msgid.length() >= 15)
msgid = msgid.substring(4, 15);
else
msgid = msgid.substring(0, 11);
}
String from = msg.getFrom() != null && msg.getFrom().address.length() > 0 ? msg.getFrom().address : null;
String to = msg.getTo() != null && msg.getTo().size() > 0 && msg.getTo().elementAt(0).address.length() > 0
? msg.getTo().elementAt(0).address
: null;
if (from != null) {
try {
from = decodeBIC(from);
if (from.length() != 12)
throw new IllegalArgumentException("from address must be URI with BIC12");
} catch (ParseException ex) {
throw new IllegalArgumentException("from address must be URI with BIC12");
}
}
if (to != null) {
try {
to = decodeBIC(to);
if (to.length() != 12)
throw new IllegalArgumentException("to address must be URI with BIC12");
} catch (ParseException ex) {
throw new IllegalArgumentException("to address must be URI with BIC12");
}
}
switch (msg.getEncFormat()) {
case None:
result = msg.getLongmsg(); // we send the message unmodified
if (result.substring(0, 3).compareTo("{1:") == 0) {
// probably SWIFT MTFIN
if (from == null || to == null || msgid == null) {
// parse SWIFT header
SWIFTMsg mh = new SWIFTMsg();
try {
mh.parseHeader(result);
} catch (ParseException ex) {
throw new UnsupportedOperationException("unsupported message format");
}
if (from == null)
from = mh.logicalTerminalAddress;
if (to == null)
to = mh.destinationAddress;
dir = mh.inputIdentifier;
}
} else if (result.substring(0, 1).compareTo("<") == 0) {
// probably XML
// FIXME: let's do the job for MTXML, too
return result;
} else { // we don't know this format, so let it be
return result;
}
if(msg.getAttachments() != null)
for (int i = 0; i < msg.getAttachments().size(); ++i) { // FIXME: can attachments become null?
Blob attach = msg.getAttachments().elementAt(i);
String magic;
if (attach.mime_type.compareToIgnoreCase("application/pgp-keys") == 0)
magic = magicKeys;
else
break; // don't know this MIME type
// we send an MT999 with the keys
String payload;
try {
payload = stripFromPGP(new String(attach.data, StandardCharsets.UTF_8));
} catch (ParseException ex) {
// cannot parse this
break;
}
String[] msgs = transportMT999(from, to, dir, msgid, "", payload, magic);
for (int j = 0; j < msgs.length; ++j) {
if (j > 0)
result += "\n";
result += msgs[j].toString();
}
}
break;
case PEP:
case PGPMIME:
case Inline:
if (from == null || to == null)
throw new IllegalArgumentException("from and to must be set to URIs with BIC12");
String pgp_txt;
Vector