diff --git a/src/main/java/org/simplejavamail/outlookmessageparser/OutlookMessageParser.java b/src/main/java/org/simplejavamail/outlookmessageparser/OutlookMessageParser.java index d2a116c..0159466 100644 --- a/src/main/java/org/simplejavamail/outlookmessageparser/OutlookMessageParser.java +++ b/src/main/java/org/simplejavamail/outlookmessageparser/OutlookMessageParser.java @@ -17,6 +17,8 @@ import org.simplejavamail.outlookmessageparser.model.OutlookMsgAttachment; import org.simplejavamail.outlookmessageparser.model.OutlookRecipient; import org.simplejavamail.outlookmessageparser.model.OutlookSmime.OutlookSmimeApplicationSmime; +import org.simplejavamail.outlookmessageparser.model.OutlookSmime.OutlookSmimeMultipartSigned; +import org.simplejavamail.outlookmessageparser.model.OutlookSmime.OutlookSmimeApplicationOctetStream; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -70,11 +72,10 @@ public class OutlookMessageParser { private static final String PROPS_KEY = "__properties_version1.0"; private static final String PROPERTY_STREAM_PREFIX = "__substg1.0_"; - - private static final Pattern SMIME_CONTENT_TYPE_PATTERN = compile(format("^Content-Type: (?%s)(?:; name=\"(?smime.p7m)\")?(?:; smime-type=(?enveloped-data))?$", - "application\\/pkcs7-mime|multipart\\/signed|application\\/octet-stream|application\\/pkcs7-signature"), - Pattern.MULTILINE); - + private static final Pattern SMIME_APPLICATION_PCKS_TYPE_PATTERN = compile("^Content-Type: (?application\\/pkcs7-mime.*?)(?:; name=(\")?(?.*?)(\")?)?(?:; smime-type=(?enveloped-data))?$",Pattern.MULTILINE); + private static final Pattern SMIME_MULTIPART_SIGNED_TYPE_PATTERN = compile("^Content-Type: (?multipart\\/signed.*?)(?:; protocol=(\")?(?application\\/(x-)?pkcs7-signature.*?)(\")?)(?:; micalg=(?.*?))?(?:;(?.*?))?$",Pattern.MULTILINE); + private static final Pattern SMIME_APPLICATION_OCTET_TYPE_PATTERN = compile("^Content-Type: (?application\\/octet-stream.*?)(?:; protocol=(?.*?))?(?:; name=(?(.*p7z|.*p7c|.*p7s|.*p7m).*?))(?:;(?.*?))?$",Pattern.MULTILINE); + private static final Pattern XML_CHARSET_PATTERN = compile("charset=(\"|)(?[\\w\\-]+)\\1", CASE_INSENSITIVE); private RTF2HTMLConverter rtf2htmlConverter = RTF2HTMLConverterRFCCompliant.INSTANCE; @@ -177,12 +178,38 @@ static void extractReplyToHeader(@NotNull final OutlookMessage msg, @NotNull fin } } - static void extractSMimeHeader(@NotNull final OutlookMessage msg, @NotNull final String allHeaders) { + static void extractSMimeHeader(@NotNull final OutlookMessage msg, @NotNull String allHeaders) { if (msg.getSmime() == null) { - // https://regex101.com/r/AE0Uys/1 - final Matcher m = SMIME_CONTENT_TYPE_PATTERN.matcher(allHeaders); - if (m.find()) { - msg.setSmime(new OutlookSmimeApplicationSmime(m.group("contenttype"), m.group("smimetype"), m.group("name"))); + // https://regex101.com/r/pbMYd2/1 + final Matcher applicationPkcs = SMIME_APPLICATION_PCKS_TYPE_PATTERN.matcher(allHeaders); + // https://regex101.com/r/5iAxbs/1 + final Matcher multipartSigned = SMIME_MULTIPART_SIGNED_TYPE_PATTERN.matcher(allHeaders); + // https://regex101.com/r/sa4Rp2/1 + final Matcher octetType = SMIME_APPLICATION_OCTET_TYPE_PATTERN.matcher(allHeaders); + if (applicationPkcs.find()) { + msg.setSmime(new OutlookSmimeApplicationSmime(applicationPkcs.group("contenttype"), applicationPkcs.group("smimetype"), applicationPkcs.group("name"))); + } + if(multipartSigned.find()){ + msg.setSmime(new OutlookSmimeMultipartSigned(multipartSigned.group("contenttype"), multipartSigned.group("protocol").replace("\"", ""), multipartSigned.group("micalg"))); + } + if(octetType.find()){ + msg.setSmime(new OutlookSmimeApplicationOctetStream(octetType.group("contenttype"), octetType.group("protocol"), octetType.group("name"))); + } + if (msg.getSmime() == null && (msg.getMessageClass().equals("IPM.Note.SMIME") || msg.getMessageClass().equals("IPM.Note.SMIME.MultipartSigned"))) { + for (OutlookFileAttachment att : msg.fetchTrueAttachments()) { + if(att.getMimeTag().equals("application/pkcs-mime")){ + msg.setSmime(new OutlookSmimeApplicationSmime(att.getMimeTag(), null, att.getFilename())); + return; + } + if(att.getMimeTag().matches("multipart/signed|application/(x-)?pkcs7-signature") && att.getExtension().matches(".*p7z|.*p7c|.*p7s|.*p7m")){ + msg.setSmime(new OutlookSmimeMultipartSigned(att.getMimeTag(), null, att.getFilename())); + return; + } + if(att.getMimeTag().equals("application/octet-stream") && att.getExtension().matches(".*p7z|.*p7c|.*p7s|.*p7m")){ + msg.setSmime(new OutlookSmimeMultipartSigned(att.getMimeTag(), null, att.getFilename())); + return; + } + } } } } diff --git a/src/main/java/org/simplejavamail/outlookmessageparser/model/OutlookSmime.java b/src/main/java/org/simplejavamail/outlookmessageparser/model/OutlookSmime.java index fa3023d..9b88f24 100644 --- a/src/main/java/org/simplejavamail/outlookmessageparser/model/OutlookSmime.java +++ b/src/main/java/org/simplejavamail/outlookmessageparser/model/OutlookSmime.java @@ -1,5 +1,6 @@ package org.simplejavamail.outlookmessageparser.model; +import javax.annotation.Nullable; import java.util.Objects; // https://tools.ietf.org/html/rfc5751#page-32 (Identifying an S/MIME Message) @@ -10,7 +11,7 @@ public static class OutlookSmimeApplicationSmime extends OutlookSmime { private final String smimeType; private final String smimeName; - public OutlookSmimeApplicationSmime(String smimeMime, String smimeType, String smimeName) { + public OutlookSmimeApplicationSmime(String smimeMime, @Nullable String smimeType, @Nullable String smimeName) { this.smimeMime = smimeMime; this.smimeType = smimeType; this.smimeName = smimeName; @@ -88,6 +89,43 @@ public String toString() { } public static class OutlookSmimeApplicationOctetStream extends OutlookSmime { - + private final String smimeMime; + private final String smimeProtocol; + private final String smimeName; + + public OutlookSmimeApplicationOctetStream(String smimeMime, @Nullable String smimeProtocol, @Nullable String smimeName) { + this.smimeMime = smimeMime; + this.smimeProtocol = smimeProtocol; + this.smimeName = smimeName; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + OutlookSmimeApplicationOctetStream that = (OutlookSmimeApplicationOctetStream) o; + return Objects.equals(smimeMime, that.smimeMime) && + Objects.equals(smimeProtocol, that.smimeProtocol) && + Objects.equals(smimeName, that.smimeName); + } + + @Override + public int hashCode() { + return Objects.hash(smimeMime, smimeProtocol, smimeName); + } + + @Override + public String toString() { + final StringBuilder sb = new StringBuilder("OutlookSmimeApplicationOctetStream{"); + sb.append("smimeMime='").append(smimeMime).append('\''); + sb.append(", smimeProtocol='").append(smimeProtocol).append('\''); + sb.append(", smimeName='").append(smimeName).append('\''); + sb.append('}'); + return sb.toString(); + } + + public String getSmimeMime() { return smimeMime; } + public String getSmimeProtocol() { return smimeProtocol; } + public String getSmimeMicalg() { return smimeName; } } } diff --git a/src/test/java/org/simplejavamail/outlookmessageparser/OutlookMessageParserTest.java b/src/test/java/org/simplejavamail/outlookmessageparser/OutlookMessageParserTest.java index 32c9f70..9eb107c 100644 --- a/src/test/java/org/simplejavamail/outlookmessageparser/OutlookMessageParserTest.java +++ b/src/test/java/org/simplejavamail/outlookmessageparser/OutlookMessageParserTest.java @@ -59,4 +59,71 @@ public void extractReplyToHeaderMalformed2() { assertThat(msg.getReplyToName()).isEqualTo("lo.pop.r"); assertThat(msg.getReplyToEmail()).isEqualTo("eplyto@somemail.com>tg"); } -} \ No newline at end of file + + @Test + public void extractSmimePropertiesOctetStream() { + + /* application/octet-stream and file-suffix p7m, p7s, p7c, p7z */ + String header = "Content-Type: application/octet-stream; name=\"smime.p7m\""; + OutlookMessage msg = new OutlookMessage(); + OutlookMessageParser.extractSMimeHeader(msg, header); + assertThat(msg.getSmime()).isNotNull(); + + header = "Content-Type: application/octet-stream; name=\"smime.p7s\""; + msg = new OutlookMessage(); + OutlookMessageParser.extractSMimeHeader(msg, header); + assertThat(msg.getSmime()).isNotNull(); + + header = "Content-Type: application/octet-stream; name=\"smime.p7c\""; + msg = new OutlookMessage(); + OutlookMessageParser.extractSMimeHeader(msg, header); + assertThat(msg.getSmime()).isNotNull(); + + header = "Content-Type: application/octet-stream; name=\"smime.p7z\""; + msg = new OutlookMessage(); + OutlookMessageParser.extractSMimeHeader(msg, header); + assertThat(msg.getSmime()).isNotNull(); + + /* application/octet-stream and file-suffix NOT p7m, p7s, p7c, p7z */ + header = "Content-Type: application/octet-stream; name=\"smime.zip\""; + msg = new OutlookMessage(); + OutlookMessageParser.extractSMimeHeader(msg, header); + assertThat(msg.getSmime()).isNull(); + + } + + @Test + public void extractSmimePropertiesMultipartSigned() { + /*multipart/signed and protocol=pkcs7-signature*/ + String header = "Content-Type: multipart/signed; protocol=\"application/pkcs7-signature\"; micalg=sha-512; boundary=\"------------ms060207010804070005060507\""; + OutlookMessage msg = new OutlookMessage(); + OutlookMessageParser.extractSMimeHeader(msg, header); + assertThat(msg.getSmime()).isNotNull(); + + /*multipart/signed and protocol=x-pkcs7-signature*/ + header = "Content-Type: multipart/signed; protocol=\"application/x-pkcs7-signature\"; micalg=sha-256; boundary=\"------------ms060207010804070005060507\""; + msg = new OutlookMessage(); + OutlookMessageParser.extractSMimeHeader(msg, header); + assertThat(msg.getSmime()).isNotNull(); + + /*multipart/signed and some other protocol*/ + header = "Content-Type: multipart/signed; protocol=\"application/plain\"; micalg=sha-512"; + msg = new OutlookMessage(); + OutlookMessageParser.extractSMimeHeader(msg, header); + assertThat(msg.getSmime()).isNull(); + } + + @Test + public void extractSmimePropertiesPkcsMime() { + /* application/pkcs7-mime name and smime-type is optional */ + String header = "Content-Type: application/pkcs7-mime; name=\"smime.p7m\"; smime-type=enveloped-data"; + OutlookMessage msg = new OutlookMessage(); + OutlookMessageParser.extractSMimeHeader(msg, header); + assertThat(msg.getSmime()).isNotNull(); + + header = "Content-Type: application/pkcs7-mime"; + msg = new OutlookMessage(); + OutlookMessageParser.extractSMimeHeader(msg, header); + assertThat(msg.getSmime()).isNotNull(); + } +}