Skip to content

Commit a483c80

Browse files
committed
#268: Resolve all input streams immediately, don't keep references or reuse anymore.
1 parent b5cd6ef commit a483c80

File tree

12 files changed

+122
-198
lines changed

12 files changed

+122
-198
lines changed

modules/core-module/src/main/java/org/simplejavamail/api/email/Email.java

Lines changed: 7 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -144,14 +144,10 @@ public class Email implements Serializable {
144144

145145
/**
146146
* @see EmailPopulatingBuilder#signWithDomainKey(InputStream, String, String)
147-
*/
148-
// mime message is not serializable, so transient
149-
private final transient InputStream dkimPrivateKeyInputStream;
150-
151-
/**
147+
* @see EmailPopulatingBuilder#signWithDomainKey(byte[], String, String)
152148
* @see EmailPopulatingBuilder#signWithDomainKey(File, String, String)
153149
*/
154-
private final File dkimPrivateKeyFile; // supported separately, so we don't have to do resource management ourselves for the InputStream
150+
private final byte[] dkimPrivateKeyData;
155151

156152
/**
157153
* @see EmailPopulatingBuilder#signWithDomainKey(InputStream, String, String)
@@ -271,19 +267,12 @@ public Email(@NotNull final EmailPopulatingBuilder builder) {
271267
returnReceiptTo = builder.getReturnReceiptTo();
272268
}
273269

274-
if (builder.getDkimPrivateKeyFile() != null) {
275-
this.dkimPrivateKeyInputStream = null;
276-
this.dkimPrivateKeyFile = builder.getDkimPrivateKeyFile();
277-
this.dkimSigningDomain = builder.getDkimSigningDomain();
278-
this.dkimSelector = builder.getDkimSelector();
279-
} else if (builder.getDkimPrivateKeyInputStream() != null) {
280-
this.dkimPrivateKeyFile = null;
281-
this.dkimPrivateKeyInputStream = builder.getDkimPrivateKeyInputStream();
270+
if (builder.getDkimPrivateKeyData() != null) {
271+
this.dkimPrivateKeyData = builder.getDkimPrivateKeyData();
282272
this.dkimSigningDomain = builder.getDkimSigningDomain();
283273
this.dkimSelector = builder.getDkimSelector();
284274
} else {
285-
this.dkimPrivateKeyFile = null;
286-
this.dkimPrivateKeyInputStream = null;
275+
this.dkimPrivateKeyData = null;
287276
this.dkimSigningDomain = null;
288277
this.dkimSelector = null;
289278
}
@@ -552,16 +541,8 @@ public Map<String, String> getHeaders() {
552541
* @see EmailPopulatingBuilder#signWithDomainKey(InputStream, String, String)
553542
*/
554543
@Nullable
555-
public InputStream getDkimPrivateKeyInputStream() {
556-
return dkimPrivateKeyInputStream;
557-
}
558-
559-
/**
560-
* @see EmailPopulatingBuilder#signWithDomainKey(File, String, String)
561-
*/
562-
@Nullable
563-
public File getDkimPrivateKeyFile() {
564-
return dkimPrivateKeyFile;
544+
public byte[] getDkimPrivateKeyData() {
545+
return dkimPrivateKeyData;
565546
}
566547

567548
/**

modules/core-module/src/main/java/org/simplejavamail/api/email/EmailPopulatingBuilder.java

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1113,8 +1113,7 @@ public interface EmailPopulatingBuilder {
11131113
* @see #signWithDomainKey(String, String, String)
11141114
* @see #signWithDomainKey(File, String, String)
11151115
*/
1116-
EmailPopulatingBuilder signWithDomainKey(@NotNull InputStream dkimPrivateKeyInputStream, @NotNull String signingDomain,
1117-
@NotNull String dkimSelector);
1116+
EmailPopulatingBuilder signWithDomainKey(@NotNull InputStream dkimPrivateKeyInputStream, @NotNull String signingDomain, @NotNull String dkimSelector);
11181117

11191118
/**
11201119
* As {@link #signWithDomainKey(InputStream, String, String)}, but with a File reference that is later read as {@code InputStream}.
@@ -1148,18 +1147,26 @@ EmailPopulatingBuilder signWithDomainKey(@NotNull InputStream dkimPrivateKeyInpu
11481147
*/
11491148
EmailPopulatingBuilder signWithSmime(@NotNull File pkcs12StoreFile, @NotNull String storePassword, @NotNull String keyAlias, @NotNull String keyPassword);
11501149

1150+
/**
1151+
* Delegates to {@link #signWithSmime(byte[], String, String, String)}.
1152+
* <p>
1153+
* <strong>Note:</strong> this only works in combination with the {@value org.simplejavamail.internal.modules.SMIMEModule#NAME}.
1154+
*/
1155+
@Cli.ExcludeApi(reason = "Is duplicate API from CLI point of view")
1156+
EmailPopulatingBuilder signWithSmime(@NotNull InputStream pkcs12StoreStream, @NotNull String storePassword, @NotNull String keyAlias, @NotNull String keyPassword);
1157+
11511158
/**
11521159
* Delegates to {@link #signWithSmime(Pkcs12Config)}.
11531160
* <p>
11541161
* <strong>Note:</strong> this only works in combination with the {@value org.simplejavamail.internal.modules.SMIMEModule#NAME}.
11551162
*
1156-
* @param pkcs12StoreStream The key store file to use to find the indicated key
1163+
* @param pkcs12StoreData The key store file to use to find the indicated key
11571164
* @param storePassword The store's password
11581165
* @param keyAlias The name of the certificate in the key store to use
11591166
* @param keyPassword The password of the certificate
11601167
*/
11611168
@Cli.ExcludeApi(reason = "Is duplicate API from CLI point of view")
1162-
EmailPopulatingBuilder signWithSmime(@NotNull InputStream pkcs12StoreStream, @NotNull String storePassword, @NotNull String keyAlias, @NotNull String keyPassword);
1169+
EmailPopulatingBuilder signWithSmime(@NotNull byte[] pkcs12StoreData, @NotNull String storePassword, @NotNull String keyAlias, @NotNull String keyPassword);
11631170

11641171
/**
11651172
* Delegates to {@link #encryptWithSmime(X509Certificate)} using the provided PEM file.
@@ -1541,17 +1548,13 @@ EmailPopulatingBuilder signWithDomainKey(@NotNull InputStream dkimPrivateKeyInpu
15411548
@NotNull
15421549
Map<String, String> getHeaders();
15431550

1544-
/**
1545-
* @see #signWithDomainKey(File, String, String)
1546-
*/
1547-
@Nullable
1548-
File getDkimPrivateKeyFile();
1549-
15501551
/**
15511552
* @see #signWithDomainKey(InputStream, String, String)
1553+
* @see #signWithDomainKey(byte[], String, String)
1554+
* @see #signWithDomainKey(File, String, String)
15521555
*/
15531556
@Nullable
1554-
InputStream getDkimPrivateKeyInputStream();
1557+
byte[] getDkimPrivateKeyData();
15551558

15561559
/**
15571560
* @see #signWithDomainKey(InputStream, String, String)

modules/core-module/src/main/java/org/simplejavamail/api/mailer/config/Pkcs12Config.java

Lines changed: 32 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -3,44 +3,49 @@
33
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
44
import org.jetbrains.annotations.NotNull;
55
import org.jetbrains.annotations.Nullable;
6+
import org.simplejavamail.internal.util.MiscUtil;
67

78
import java.io.File;
89
import java.io.FileInputStream;
9-
import java.io.FileNotFoundException;
10+
import java.io.IOException;
1011
import java.io.InputStream;
1112
import java.util.Arrays;
1213
import java.util.Objects;
1314

1415
import static java.lang.String.format;
15-
import static org.simplejavamail.internal.util.MiscUtil.inputStreamEqual;
16+
import static org.simplejavamail.internal.util.MiscUtil.readInputStreamToBytes;
1617

1718
/**
1819
* Config holder for PKCS12 store+key info used for S/MIME encrypting / decrypting.
1920
*/
2021
// FIXME LOMBOK!!
2122
public final class Pkcs12Config {
2223

23-
private static final long serialVersionUID = 1234567L;
24-
25-
@NotNull private final InputStream pkcs12StoreStream;
24+
@NotNull private final byte[] pkcs12StoreData;
2625
@NotNull private final char[] storePassword;
2726
@NotNull private final String keyAlias;
2827
@NotNull private final char[] keyPassword;
2928

30-
private Pkcs12Config(@NotNull InputStream pkcs12StoreStream, @NotNull char[] storePassword, @NotNull String keyAlias, @NotNull char[] keyPassword) {
31-
this.pkcs12StoreStream = pkcs12StoreStream;
29+
private Pkcs12Config(@NotNull InputStream pkcs12StoreStream, @NotNull char[] storePassword, @NotNull String keyAlias, @NotNull char[] keyPassword)
30+
throws IOException {
31+
this(readInputStreamToBytes(pkcs12StoreStream), storePassword, keyAlias, keyPassword);
32+
}
33+
34+
private Pkcs12Config(@NotNull byte[] pkcs12StoreData, @NotNull char[] storePassword, @NotNull String keyAlias, @NotNull char[] keyPassword) {
35+
this.pkcs12StoreData = pkcs12StoreData;
3236
this.storePassword = storePassword;
3337
this.keyAlias = keyAlias;
3438
this.keyPassword = keyPassword;
3539
}
3640

41+
@NotNull
3742
public static Pkcs12ConfigBuilder builder() {
3843
return new Pkcs12ConfigBuilder();
3944
}
4045

4146
@NotNull
42-
public InputStream getPkcs12StoreStream() {
43-
return this.pkcs12StoreStream;
47+
public byte[] getPkcs12StoreData() {
48+
return this.pkcs12StoreData;
4449
}
4550

4651
@NotNull
@@ -61,12 +66,11 @@ public char[] getKeyPassword() {
6166
@Override
6267
public String toString() {
6368
@SuppressWarnings("StringBufferReplaceableByString")
64-
final StringBuilder sb = new StringBuilder("Pkcs12Config{");
65-
sb.append("pkcs12StoreStream=").append(pkcs12StoreStream);
66-
sb.append(", storePassword=***");
67-
sb.append(", keyAlias='").append(keyAlias).append('\'');
68-
sb.append(", keyPassword=***");
69-
sb.append('}');
69+
final StringBuilder sb = new StringBuilder("Pkcs12Config{")
70+
.append(" storePassword=***")
71+
.append(", keyAlias='").append(keyAlias).append('\'')
72+
.append(", keyPassword=***")
73+
.append('}');
7074
return sb.toString();
7175
}
7276

@@ -79,22 +83,22 @@ public boolean equals(@Nullable final Object o) {
7983
return false;
8084
}
8185
final Pkcs12Config that = (Pkcs12Config) o;
82-
return inputStreamEqual(pkcs12StoreStream, that.pkcs12StoreStream) &&
86+
return Arrays.equals(pkcs12StoreData, that.pkcs12StoreData) &&
8387
Arrays.equals(storePassword, that.storePassword) &&
8488
keyAlias.equals(that.keyAlias) &&
8589
Arrays.equals(keyPassword, that.keyPassword);
8690
}
8791

8892
@Override
8993
public int hashCode() {
90-
int result = Objects.hash(pkcs12StoreStream, keyAlias);
94+
int result = Objects.hash(pkcs12StoreData, keyAlias);
9195
result = 31 * result + Arrays.hashCode(storePassword);
9296
result = 31 * result + Arrays.hashCode(keyPassword);
9397
return result;
9498
}
9599

96100
public static class Pkcs12ConfigBuilder {
97-
private InputStream pkcs12StoreStream;
101+
private byte[] pkcs12StoreData;
98102
private char[] storePassword;
99103
private String keyAlias;
100104
private char[] keyPassword;
@@ -113,13 +117,19 @@ public Pkcs12ConfigBuilder pkcs12Store(String pkcs12StorePath) {
113117
public Pkcs12ConfigBuilder pkcs12Store(File pkcs12StorePath) {
114118
try {
115119
return pkcs12Store(new FileInputStream(pkcs12StorePath));
116-
} catch (FileNotFoundException e) {
120+
} catch (IOException e) {
117121
throw new IllegalStateException(format("error reading PKCS12 store from File [%s]", pkcs12StorePath), e);
118122
}
119123
}
120124

121-
public Pkcs12ConfigBuilder pkcs12Store(InputStream pkcs12StoreStream) {
122-
this.pkcs12StoreStream = pkcs12StoreStream;
125+
public Pkcs12ConfigBuilder pkcs12Store(InputStream pkcs12StoreStream)
126+
throws IOException {
127+
this.pkcs12StoreData = MiscUtil.readInputStreamToBytes(pkcs12StoreStream);
128+
return this;
129+
}
130+
131+
public Pkcs12ConfigBuilder pkcs12Store(byte[] pkcs12StoreData) {
132+
this.pkcs12StoreData = pkcs12StoreData;
123133
return this;
124134
}
125135

@@ -149,7 +159,7 @@ public Pkcs12ConfigBuilder keyPassword(String keyPassword) {
149159
}
150160

151161
public Pkcs12Config build() {
152-
return new Pkcs12Config(pkcs12StoreStream, storePassword, keyAlias, keyPassword);
162+
return new Pkcs12Config(pkcs12StoreData, storePassword, keyAlias, keyPassword);
153163
}
154164
}
155165
}

modules/core-module/src/main/java/org/simplejavamail/internal/util/MiscUtil.java

Lines changed: 0 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,8 @@
1414
import javax.mail.internet.MimeUtility;
1515
import javax.mail.util.ByteArrayDataSource;
1616
import java.io.BufferedInputStream;
17-
import java.io.ByteArrayInputStream;
1817
import java.io.ByteArrayOutputStream;
1918
import java.io.File;
20-
import java.io.FileInputStream;
2119
import java.io.IOException;
2220
import java.io.InputStream;
2321
import java.io.UnsupportedEncodingException;
@@ -231,47 +229,6 @@ public static String readFileContent(@NotNull final File file) throws IOExceptio
231229
return new String(Files.readAllBytes(file.toPath()), UTF_8);
232230
}
233231

234-
public static boolean inputStreamEqual(InputStream inputOrg1, InputStream inputOrg2) {
235-
ByteArrayInputStream input1 = copyInputstream(inputOrg1);
236-
ByteArrayInputStream input2 = copyInputstream(inputOrg2);
237-
238-
int ch;
239-
ch = input1.read();
240-
while (ch != -1) {
241-
int ch2 = input2.read();
242-
if (ch != ch2) {
243-
return false;
244-
}
245-
ch = input1.read();
246-
}
247-
248-
int ch2 = input2.read();
249-
return (ch2 == -1);
250-
}
251-
252-
public static ByteArrayInputStream copyInputstream(InputStream input) {
253-
ByteArrayOutputStream baos = new ByteArrayOutputStream();
254-
255-
byte[] buffer = new byte[1024];
256-
int len;
257-
try {
258-
while ((len = input.read(buffer)) > -1 ) {
259-
baos.write(buffer, 0, len);
260-
}
261-
baos.flush();
262-
263-
if (input instanceof FileInputStream) {
264-
((FileInputStream) input).getChannel().position(0);
265-
} else {
266-
input.reset();
267-
}
268-
} catch (IOException e) {
269-
throw new RuntimeException(e);
270-
}
271-
272-
return new ByteArrayInputStream(baos.toByteArray());
273-
}
274-
275232
@Nullable
276233
public static DataSource tryResolveImageFileDataSourceFromDisk(final @Nullable String baseDir, final boolean allowOutsideBaseDir, final @NotNull String srcLocation) {
277234
DataSource dataSource;

modules/dkim-module/src/main/java/org/simplejavamail/internal/dkimsupport/DKIMSigner.java

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
import javax.mail.MessagingException;
1313
import javax.mail.internet.MimeMessage;
14+
import java.io.ByteArrayInputStream;
1415
import java.io.IOException;
1516
import java.security.NoSuchAlgorithmException;
1617
import java.security.spec.InvalidKeySpecException;
@@ -32,11 +33,9 @@ public MimeMessage signMessageWithDKIM(final MimeMessage messageToSign, final Em
3233
LOGGER.debug("signing MimeMessage with DKIM...");
3334
try {
3435
final String dkimSelector = checkNonEmptyArgument(signingDetails.getDkimSelector(), "dkimSelector");
35-
final DkimSigner dkimSigner = signingDetails.getDkimPrivateKeyFile() != null
36-
// InputStream is managed by Dkim library
37-
? new DkimSigner(signingDetails.getDkimSigningDomain(), dkimSelector, signingDetails.getDkimPrivateKeyFile())
38-
// InputStream is managed by SimpleJavaMail user
39-
: new DkimSigner(signingDetails.getDkimSigningDomain(), dkimSelector, signingDetails.getDkimPrivateKeyInputStream());
36+
// InputStream is managed by Dkim library
37+
// InputStream is managed by SimpleJavaMail user
38+
final DkimSigner dkimSigner = new DkimSigner(signingDetails.getDkimSigningDomain(), dkimSelector, new ByteArrayInputStream(signingDetails.getDkimPrivateKeyData()));
4039
dkimSigner.setIdentity(checkNonEmptyArgument(signingDetails.getFromRecipient(), "fromRecipient").getAddress());
4140
dkimSigner.setHeaderCanonicalization(Canonicalization.RELAXED);
4241
dkimSigner.setBodyCanonicalization(Canonicalization.RELAXED);

modules/simple-java-mail/src/main/java/org/simplejavamail/email/internal/EmailException.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ class EmailException extends MailException {
1010

1111
static final String NAME_MISSING_FOR_EMBEDDED_IMAGE = "No name given for embedded image nor passed inside the data source";
1212
static final String ERROR_READING_FROM_FILE = "Error reading from file: %s";
13+
static final String ERROR_READING_DKIM_FROM_INPUTSTREAM = "Was unable to read DKIM data from input stream";
14+
static final String ERROR_READING_SMIME_FROM_INPUTSTREAM = "Was unable to read S/MIME data from input stream";
1315
static final String ERROR_READING_FROM_PEM_INPUTSTREAM = "Was unable to convert PEM data to X509 certificate";
1416
static final String ERROR_LOADING_PROVIDER_FOR_SMIME_SUPPORT = "Unable to load certificate (missing bouncy castle), is the S/MIME module on the class path?";
1517
static final String ERROR_RESOLVING_IMAGE_DATASOURCE = "Unable to dynamically resolve data source for the following image src: %s";

0 commit comments

Comments
 (0)