Simplify the RyDE API

Second step of RDE encoding refactoring.

Creates a single OutputStream encode RyDE files.
This replaces the 5 OutputStreams that were needed before.

Also removes all the factories that were injected. It's an encoding, there's no point in injecting it.

Finally, removed the buffer-size configuration and replaced with a static final
const value in each individual OutputStream.

This doesn't yet include a decoder (InputStream). And there's still a lot of overlap between the Ryde and the Ghostryde code. Both of those are left for the next CLs.

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=204898369
This commit is contained in:
guyben 2018-07-17 05:50:04 -07:00 committed by jianglai
parent c4a2b5fa8d
commit 8ec2eaf39c
15 changed files with 215 additions and 345 deletions

View file

@ -672,20 +672,6 @@ public final class RegistryConfig {
return config.rde.reportUrlPrefix;
}
/**
* Size of RYDE generator buffer in bytes for each of the five layers.
*
* @see google.registry.rde.RydePgpCompressionOutputStream
* @see google.registry.rde.RydePgpFileOutputStream
* @see google.registry.rde.RydePgpSigningOutputStream
* @see google.registry.rde.RydeTarOutputStream
*/
@Provides
@Config("rdeRydeBufferSize")
public static Integer provideRdeRydeBufferSize() {
return 64 * 1024;
}
/**
* Maximum amount of time generating an escrow deposit for a TLD could take, before killing.
*

View file

@ -64,11 +64,6 @@ public final class BrdaCopyAction implements Runnable {
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
@Inject GcsUtils gcsUtils;
@Inject RydePgpCompressionOutputStreamFactory pgpCompressionFactory;
@Inject RydePgpFileOutputStreamFactory pgpFileFactory;
@Inject RydePgpEncryptionOutputStreamFactory pgpEncryptionFactory;
@Inject RydePgpSigningOutputStreamFactory pgpSigningFactory;
@Inject RydeTarOutputStreamFactory tarFactory;
@Inject @Config("brdaBucket") String brdaBucket;
@Inject @Config("rdeBucket") String stagingBucket;
@Inject @Parameter(RequestParameters.PARAM_TLD) String tld;
@ -96,25 +91,17 @@ public final class BrdaCopyAction implements Runnable {
long xmlLength = readXmlLength(xmlLengthFilename);
logger.atInfo().log("Writing %s", rydeFile);
byte[] signature;
logger.atInfo().log("Writing %s and %s", rydeFile, sigFile);
try (InputStream gcsInput = gcsUtils.openInputStream(xmlFilename);
InputStream ghostrydeDecoder = Ghostryde.decoder(gcsInput, stagingDecryptionKey);
OutputStream gcsOutput = gcsUtils.openOutputStream(rydeFile);
RydePgpSigningOutputStream signLayer = pgpSigningFactory.create(gcsOutput, signingKey)) {
try (OutputStream encryptLayer = pgpEncryptionFactory.create(signLayer, receiverKey);
OutputStream compressLayer = pgpCompressionFactory.create(encryptLayer);
OutputStream fileLayer = pgpFileFactory.create(compressLayer, watermark, prefix + ".tar");
OutputStream tarLayer =
tarFactory.create(fileLayer, xmlLength, watermark, prefix + ".xml")) {
ByteStreams.copy(ghostrydeDecoder, tarLayer);
}
signature = signLayer.getSignature();
}
logger.atInfo().log("Writing %s", sigFile);
try (OutputStream gcsOutput = gcsUtils.openOutputStream(sigFile)) {
gcsOutput.write(signature);
OutputStream rydeOut = gcsUtils.openOutputStream(rydeFile);
OutputStream sigOut = gcsUtils.openOutputStream(sigFile);
RydeEncoder rydeEncoder = new RydeEncoder.Builder()
.setRydeOutput(rydeOut, receiverKey)
.setSignatureOutput(sigOut, signingKey)
.setFileMetadata(prefix, xmlLength, watermark)
.build()) {
ByteStreams.copy(ghostrydeDecoder, rydeEncoder);
}
}

View file

@ -56,6 +56,7 @@ import google.registry.util.Retrier;
import google.registry.util.TaskQueueUtils;
import google.registry.util.TeeOutputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
@ -103,11 +104,6 @@ public final class RdeUploadAction implements Runnable, EscrowTask {
@Inject JSchSshSessionFactory jschSshSessionFactory;
@Inject Response response;
@Inject RydePgpCompressionOutputStreamFactory pgpCompressionFactory;
@Inject RydePgpEncryptionOutputStreamFactory pgpEncryptionFactory;
@Inject RydePgpFileOutputStreamFactory pgpFileFactory;
@Inject RydePgpSigningOutputStreamFactory pgpSigningFactory;
@Inject RydeTarOutputStreamFactory tarFactory;
@Inject SftpProgressMonitor sftpProgressMonitor;
@Inject TaskQueueUtils taskQueueUtils;
@Inject Retrier retrier;
@ -214,28 +210,27 @@ public final class RdeUploadAction implements Runnable, EscrowTask {
InputStream ghostrydeDecoder = Ghostryde.decoder(gcsInput, stagingDecryptionKey)) {
try (JSchSshSession session = jschSshSessionFactory.create(lazyJsch.get(), uploadUrl);
JSchSftpChannel ftpChan = session.openSftpChannel()) {
byte[] signature;
ByteArrayOutputStream sigOut = new ByteArrayOutputStream();
String rydeFilename = name + ".ryde";
GcsFilename rydeGcsFilename = new GcsFilename(bucket, rydeFilename);
try (OutputStream ftpOutput =
ftpChan.get().put(rydeFilename, sftpProgressMonitor, OVERWRITE);
OutputStream gcsOutput = gcsUtils.openOutputStream(rydeGcsFilename);
TeeOutputStream teeOutput = new TeeOutputStream(asList(ftpOutput, gcsOutput));
RydePgpSigningOutputStream signer = pgpSigningFactory.create(teeOutput, signingKey)) {
try (OutputStream encryptLayer = pgpEncryptionFactory.create(signer, receiverKey);
OutputStream kompressor = pgpCompressionFactory.create(encryptLayer);
OutputStream fileLayer = pgpFileFactory.create(kompressor, watermark, name + ".tar");
OutputStream tarLayer =
tarFactory.create(fileLayer, xmlLength, watermark, name + ".xml")) {
ByteStreams.copy(ghostrydeDecoder, tarLayer);
}
signature = signer.getSignature();
logger.atInfo().log("uploaded %,d bytes: %s.ryde", signer.getBytesWritten(), name);
RydeEncoder rydeEncoder =
new RydeEncoder.Builder()
.setRydeOutput(teeOutput, receiverKey)
.setSignatureOutput(sigOut, signingKey)
.setFileMetadata(name, xmlLength, watermark)
.build()) {
long bytesCopied = ByteStreams.copy(ghostrydeDecoder, rydeEncoder);
logger.atInfo().log("uploaded %,d bytes: %s", bytesCopied, rydeFilename);
}
String sigFilename = name + ".sig";
byte[] signature = sigOut.toByteArray();
gcsUtils.createFromBytes(new GcsFilename(bucket, sigFilename), signature);
ftpChan.get().put(new ByteArrayInputStream(signature), sigFilename);
logger.atInfo().log("uploaded %,d bytes: %s.sig", signature.length, name);
logger.atInfo().log("uploaded %,d bytes: %s", signature.length, sigFilename);
}
}
}

View file

@ -0,0 +1,153 @@
// Copyright 2018 The Nomulus Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package google.registry.rde;
import static com.google.common.base.Preconditions.checkNotNull;
import com.google.common.collect.ImmutableList;
import com.google.common.io.Closer;
import java.io.FilterOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Collection;
import javax.annotation.concurrent.NotThreadSafe;
import org.bouncycastle.openpgp.PGPException;
import org.bouncycastle.openpgp.PGPKeyPair;
import org.bouncycastle.openpgp.PGPPublicKey;
import org.joda.time.DateTime;
/**
* Stream that performs the full RyDE encryption.
*
* <p>The RyDE format has 2 files:
*
* <ul>
* <li>the "data" file, encoded in data -&gt; tar -&gt; PgpFile -&gt; compression -&gt; encryption
* <li>the signature of the resulting file
* </ul>
*
* <p>Hence, the encoder needs to receive 2 OutputStreams - one for the data and one for the
* signature.
*
* <p>Because of the external tar file encoding - the encoder must know the total length of the data
* from the start. This is a bit annoying, but necessary.
*/
@NotThreadSafe
public final class RydeEncoder extends FilterOutputStream {
private final OutputStream sigOutput;
private final RydePgpSigningOutputStream signer;
private final OutputStream encryptLayer;
private final OutputStream kompressor;
private final OutputStream fileLayer;
private final OutputStream tarLayer;
// We use a Closer to handle the stream .close, to make sure it's done correctly.
private final Closer closer = Closer.create();
private boolean isClosed = false;
private RydeEncoder(
OutputStream rydeOutput,
OutputStream sigOutput,
long dataLength,
String filenamePrefix,
DateTime modified,
PGPKeyPair signingKey,
Collection<PGPPublicKey> receiverKeys) {
super(null);
this.sigOutput = sigOutput;
signer = closer.register(new RydePgpSigningOutputStream(checkNotNull(rydeOutput), signingKey));
encryptLayer = closer.register(new RydePgpEncryptionOutputStream(signer, receiverKeys));
kompressor = closer.register(new RydePgpCompressionOutputStream(encryptLayer));
fileLayer =
closer.register(new RydePgpFileOutputStream(kompressor, modified, filenamePrefix + ".tar"));
tarLayer =
closer.register(
new RydeTarOutputStream(fileLayer, dataLength, modified, filenamePrefix + ".xml"));
this.out = tarLayer;
}
/**
* Call the underlying 3 input write.
*
* <p>FilterInputStream implements the 3 input write using a for loop over the single-byte write.
* For efficiency reasons, we want it to use the 3 input write instead.
*/
@Override
public void write(byte[] b, int off, int len) throws IOException {
out.write(b, off, len);
}
@Override
public void close() throws IOException {
if (isClosed) {
return;
}
// Close all the streams we opened
closer.close();
isClosed = true;
try {
sigOutput.write(signer.getSignature());
} catch (PGPException e) {
throw new RuntimeException("Failed to generate signature", e);
}
}
/** Builder for {@link RydeEncoder}. */
public static class Builder {
OutputStream rydeOutput;
OutputStream sigOutput;
Long dataLength;
String filenamePrefix;
DateTime modified;
PGPKeyPair signingKey;
ImmutableList<PGPPublicKey> receiverKeys;
/** Sets the OutputStream for the Ryde-encoded data, and the keys used for the encryption. */
public Builder setRydeOutput(
OutputStream rydeOutput, PGPPublicKey receiverKey, PGPPublicKey... moreReceiverKeys) {
this.rydeOutput = rydeOutput;
this.receiverKeys =
new ImmutableList.Builder<PGPPublicKey>().add(receiverKey).add(moreReceiverKeys).build();
return this;
}
/** Sets the OutputStream for the signature, and the key used to sign. */
public Builder setSignatureOutput(OutputStream sigOutput, PGPKeyPair signingKey) {
this.sigOutput = sigOutput;
this.signingKey = signingKey;
return this;
}
/** Sets the information about the unencoded data that will follow. */
public Builder setFileMetadata(String filenamePrefix, long dataLength, DateTime modified) {
this.filenamePrefix = filenamePrefix;
this.dataLength = dataLength;
this.modified = modified;
return this;
}
/** Returns the built {@link RydeEncoder}. */
public RydeEncoder build() {
return new RydeEncoder(
checkNotNull(rydeOutput, "Must call 'setRydeOutput'"),
checkNotNull(sigOutput, "Must call 'setSignatureOutput'"),
checkNotNull(dataLength, "Must call 'setFileMetadata'"),
checkNotNull(filenamePrefix, "Must call 'setFileMetadata'"),
checkNotNull(modified, "Must call 'setFileMetadata'"),
checkNotNull(signingKey, "Must call 'setSignatureOutput'"),
checkNotNull(receiverKeys, "Must call 'setRydeOutput'"));
}
}
}

View file

@ -16,9 +16,6 @@ package google.registry.rde;
import static org.bouncycastle.bcpg.CompressionAlgorithmTags.ZIP;
import com.google.auto.factory.AutoFactory;
import com.google.auto.factory.Provided;
import google.registry.config.RegistryConfig.Config;
import google.registry.util.ImprovedOutputStream;
import java.io.IOException;
import java.io.OutputStream;
@ -31,9 +28,10 @@ import org.bouncycastle.openpgp.PGPException;
*
* <p>This uses the ZIP compression algorithm per the ICANN escrow specification.
*/
@AutoFactory(allowSubclasses = true)
public class RydePgpCompressionOutputStream extends ImprovedOutputStream {
private static final int BUFFER_SIZE = 64 * 1024;
/**
* Creates a new instance that compresses data.
*
@ -41,9 +39,8 @@ public class RydePgpCompressionOutputStream extends ImprovedOutputStream {
* @throws RuntimeException to rethrow {@link PGPException} and {@link IOException}
*/
public RydePgpCompressionOutputStream(
@Provided @Config("rdeRydeBufferSize") Integer bufferSize,
@WillNotClose OutputStream os) {
super("RydePgpCompressionOutputStream", createDelegate(bufferSize, os));
super("RydePgpCompressionOutputStream", createDelegate(BUFFER_SIZE, os));
}
private static OutputStream createDelegate(int bufferSize, OutputStream os) {

View file

@ -14,18 +14,17 @@
package google.registry.rde;
import static com.google.common.base.Preconditions.checkArgument;
import static org.bouncycastle.bcpg.SymmetricKeyAlgorithmTags.AES_128;
import static org.bouncycastle.jce.provider.BouncyCastleProvider.PROVIDER_NAME;
import com.google.auto.factory.AutoFactory;
import com.google.auto.factory.Provided;
import google.registry.config.RegistryConfig.Config;
import google.registry.util.ImprovedOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.security.NoSuchAlgorithmException;
import java.security.ProviderException;
import java.security.SecureRandom;
import java.util.Collection;
import javax.annotation.WillNotClose;
import org.bouncycastle.openpgp.PGPEncryptedDataGenerator;
import org.bouncycastle.openpgp.PGPException;
@ -53,9 +52,10 @@ import org.bouncycastle.openpgp.operator.jcajce.JcePublicKeyKeyEncryptionMethodG
* @see <a href="http://tools.ietf.org/html/rfc4880">RFC 4880 (OpenPGP Message Format)</a>
* @see <a href="http://en.wikipedia.org/wiki/Advanced_Encryption_Standard">AES (Wikipedia)</a>
*/
@AutoFactory(allowSubclasses = true)
public class RydePgpEncryptionOutputStream extends ImprovedOutputStream {
private static final int BUFFER_SIZE = 64 * 1024;
/**
* The symmetric encryption algorithm to use. Do not change this value without checking the
* RFCs to make sure the encryption algorithm and strength combination is allowed.
@ -92,22 +92,23 @@ public class RydePgpEncryptionOutputStream extends ImprovedOutputStream {
* @throws RuntimeException to rethrow {@link PGPException} and {@link IOException}
*/
public RydePgpEncryptionOutputStream(
@Provided @Config("rdeRydeBufferSize") Integer bufferSize,
@WillNotClose OutputStream os,
PGPPublicKey receiverKey) {
super("RydePgpEncryptionOutputStream", createDelegate(bufferSize, os, receiverKey));
Collection<PGPPublicKey> receiverKeys) {
super("RydePgpEncryptionOutputStream", createDelegate(os, receiverKeys));
}
private static
OutputStream createDelegate(int bufferSize, OutputStream os, PGPPublicKey receiverKey) {
private static OutputStream createDelegate(
OutputStream os, Collection<PGPPublicKey> receiverKeys) {
try {
PGPEncryptedDataGenerator encryptor = new PGPEncryptedDataGenerator(
new JcePGPDataEncryptorBuilder(CIPHER)
.setWithIntegrityPacket(USE_INTEGRITY_PACKET)
.setSecureRandom(SecureRandom.getInstance(RANDOM_SOURCE))
.setProvider(PROVIDER_NAME));
encryptor.addMethod(new JcePublicKeyKeyEncryptionMethodGenerator(receiverKey));
return encryptor.open(os, new byte[bufferSize]);
checkArgument(!receiverKeys.isEmpty(), "Must give at least one receiver key");
receiverKeys.forEach(
key -> encryptor.addMethod(new JcePublicKeyKeyEncryptionMethodGenerator(key)));
return encryptor.open(os, new byte[BUFFER_SIZE]);
} catch (NoSuchAlgorithmException e) {
throw new ProviderException(e);
} catch (IOException | PGPException e) {

View file

@ -17,9 +17,6 @@ package google.registry.rde;
import static com.google.common.base.Preconditions.checkArgument;
import static org.bouncycastle.openpgp.PGPLiteralData.BINARY;
import com.google.auto.factory.AutoFactory;
import com.google.auto.factory.Provided;
import google.registry.config.RegistryConfig.Config;
import google.registry.util.ImprovedOutputStream;
import java.io.IOException;
import java.io.OutputStream;
@ -36,9 +33,10 @@ import org.joda.time.DateTime;
*
* <p>According to escrow spec, the PGP message should contain a single tar file.
*/
@AutoFactory(allowSubclasses = true)
public class RydePgpFileOutputStream extends ImprovedOutputStream {
private static final int BUFFER_SIZE = 64 * 1024;
/**
* Creates a new instance for a particular file.
*
@ -47,20 +45,19 @@ public class RydePgpFileOutputStream extends ImprovedOutputStream {
* @throws RuntimeException to rethrow {@link IOException}
*/
public RydePgpFileOutputStream(
@Provided @Config("rdeRydeBufferSize") Integer bufferSize,
@WillNotClose OutputStream os,
DateTime modified,
String filename) {
super("RydePgpFileOutputStream", createDelegate(bufferSize, os, modified, filename));
super("RydePgpFileOutputStream", createDelegate(os, modified, filename));
}
private static OutputStream
createDelegate(int bufferSize, OutputStream os, DateTime modified, String filename) {
createDelegate(OutputStream os, DateTime modified, String filename) {
try {
checkArgument(filename.endsWith(".tar"),
"Ryde PGP message should contain a tar file.");
return new PGPLiteralDataGenerator().open(
os, BINARY, filename, modified.toDate(), new byte[bufferSize]);
os, BINARY, filename, modified.toDate(), new byte[BUFFER_SIZE]);
} catch (IOException e) {
throw new RuntimeException(e);
}

View file

@ -18,7 +18,6 @@ import static org.bouncycastle.bcpg.HashAlgorithmTags.SHA256;
import static org.bouncycastle.bcpg.PublicKeyAlgorithmTags.RSA_GENERAL;
import static org.bouncycastle.openpgp.PGPSignature.BINARY_DOCUMENT;
import com.google.auto.factory.AutoFactory;
import google.registry.util.ImprovedOutputStream;
import java.io.IOException;
import java.io.OutputStream;
@ -40,7 +39,6 @@ import org.bouncycastle.openpgp.operator.bc.BcPGPContentSignerBuilder;
* who receive a deposit to check the signature against our public key so they can know the
* data hasn't been forged.
*/
@AutoFactory(allowSubclasses = true)
public class RydePgpSigningOutputStream extends ImprovedOutputStream {
private final PGPSignatureGenerator signer;

View file

@ -16,7 +16,6 @@ package google.registry.rde;
import static com.google.common.base.Preconditions.checkArgument;
import com.google.auto.factory.AutoFactory;
import google.registry.util.ImprovedOutputStream;
import google.registry.util.PosixTarHeader;
import java.io.IOException;
@ -27,7 +26,6 @@ import org.joda.time.DateTime;
/**
* Single-file POSIX tar archive creator that wraps an {@link OutputStream}.
*/
@AutoFactory(allowSubclasses = true)
public class RydeTarOutputStream extends ImprovedOutputStream {
private final long expectedSize;

View file

@ -20,16 +20,7 @@ import com.google.common.io.ByteStreams;
import google.registry.keyring.api.KeyModule.Key;
import google.registry.model.rde.RdeNamingUtils;
import google.registry.rde.RdeUtil;
import google.registry.rde.RydePgpCompressionOutputStream;
import google.registry.rde.RydePgpCompressionOutputStreamFactory;
import google.registry.rde.RydePgpEncryptionOutputStream;
import google.registry.rde.RydePgpEncryptionOutputStreamFactory;
import google.registry.rde.RydePgpFileOutputStream;
import google.registry.rde.RydePgpFileOutputStreamFactory;
import google.registry.rde.RydePgpSigningOutputStream;
import google.registry.rde.RydePgpSigningOutputStreamFactory;
import google.registry.rde.RydeTarOutputStream;
import google.registry.rde.RydeTarOutputStreamFactory;
import google.registry.rde.RydeEncoder;
import google.registry.xml.XmlException;
import java.io.BufferedInputStream;
import java.io.IOException;
@ -40,7 +31,6 @@ import java.nio.file.Path;
import javax.inject.Inject;
import javax.inject.Provider;
import org.bouncycastle.bcpg.ArmoredOutputStream;
import org.bouncycastle.openpgp.PGPException;
import org.bouncycastle.openpgp.PGPKeyPair;
import org.bouncycastle.openpgp.PGPPublicKey;
import org.joda.time.DateTime;
@ -50,18 +40,13 @@ final class EscrowDepositEncryptor {
private static final int PEEK_BUFFER_SIZE = 64 * 1024;
@Inject RydePgpCompressionOutputStreamFactory pgpCompressionFactory;
@Inject RydePgpEncryptionOutputStreamFactory pgpEncryptionFactory;
@Inject RydePgpFileOutputStreamFactory pgpFileFactory;
@Inject RydePgpSigningOutputStreamFactory pgpSigningFactory;
@Inject RydeTarOutputStreamFactory tarFactory;
@Inject @Key("rdeSigningKey") Provider<PGPKeyPair> rdeSigningKey;
@Inject @Key("rdeReceiverKey") Provider<PGPPublicKey> rdeReceiverKey;
@Inject EscrowDepositEncryptor() {}
/** Creates a {@code .ryde} and {@code .sig} file, provided an XML deposit file. */
void encrypt(String tld, Path xmlFile, Path outdir)
throws IOException, PGPException, XmlException {
throws IOException, XmlException {
try (InputStream xmlFileInput = Files.newInputStream(xmlFile);
BufferedInputStream xmlInput = new BufferedInputStream(xmlFileInput, PEEK_BUFFER_SIZE)) {
DateTime watermark = RdeUtil.peekWatermark(xmlInput);
@ -71,19 +56,14 @@ final class EscrowDepositEncryptor {
Path pubPath = outdir.resolve(tld + ".pub");
PGPKeyPair signingKey = rdeSigningKey.get();
try (OutputStream rydeOutput = Files.newOutputStream(rydePath);
RydePgpSigningOutputStream signLayer =
pgpSigningFactory.create(rydeOutput, signingKey)) {
try (RydePgpEncryptionOutputStream encryptLayer =
pgpEncryptionFactory.create(signLayer, rdeReceiverKey.get());
RydePgpCompressionOutputStream compressLayer =
pgpCompressionFactory.create(encryptLayer);
RydePgpFileOutputStream fileLayer =
pgpFileFactory.create(compressLayer, watermark, name + ".tar");
RydeTarOutputStream tarLayer =
tarFactory.create(fileLayer, Files.size(xmlFile), watermark, name + ".xml")) {
ByteStreams.copy(xmlInput, tarLayer);
OutputStream sigOutput = Files.newOutputStream(sigPath);
RydeEncoder rydeEncoder = new RydeEncoder.Builder()
.setRydeOutput(rydeOutput, rdeReceiverKey.get())
.setSignatureOutput(sigOutput, signingKey)
.setFileMetadata(name, Files.size(xmlFile), watermark)
.build()) {
ByteStreams.copy(xmlInput, rydeEncoder);
}
Files.write(sigPath, signLayer.getSignature());
try (OutputStream pubOutput = Files.newOutputStream(pubPath);
ArmoredOutputStream ascOutput = new ArmoredOutputStream(pubOutput)) {
signingKey.getPublicKey().encode(ascOutput);
@ -91,4 +71,3 @@ final class EscrowDepositEncryptor {
}
}
}
}

View file

@ -100,11 +100,6 @@ public class BrdaCopyActionTest extends ShardableTestCase {
@Before
public void before() throws Exception {
action.gcsUtils = gcsUtils;
action.pgpCompressionFactory = new RydePgpCompressionOutputStreamFactory(() -> 1024);
action.pgpEncryptionFactory = new RydePgpEncryptionOutputStreamFactory(() -> 1024);
action.pgpFileFactory = new RydePgpFileOutputStreamFactory(() -> 1024);
action.pgpSigningFactory = new RydePgpSigningOutputStreamFactory();
action.tarFactory = new RydeTarOutputStreamFactory();
action.tld = "lol";
action.watermark = DateTime.parse("2010-10-17TZ");
action.brdaBucket = "tub";

View file

@ -70,7 +70,6 @@ import google.registry.testing.FakeKeyringModule;
import google.registry.testing.FakeResponse;
import google.registry.testing.FakeSleeper;
import google.registry.testing.GpgSystemCommandRule;
import google.registry.testing.IoSpyRule;
import google.registry.testing.Lazies;
import google.registry.testing.TaskQueueHelper.TaskMatcher;
import google.registry.testing.sftp.SftpServerRule;
@ -81,10 +80,8 @@ import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.Socket;
import java.net.URI;
import org.bouncycastle.openpgp.PGPKeyPair;
import org.bouncycastle.openpgp.PGPPublicKey;
import org.joda.time.DateTime;
import org.junit.Before;
@ -131,11 +128,6 @@ public class RdeUploadActionTest {
RdeTestData.loadBytes("pgp-public-keyring.asc"),
RdeTestData.loadBytes("pgp-private-keyring-escrow.asc"));
@Rule
public final IoSpyRule ioSpy = new IoSpyRule()
.checkClosedOnlyOnce()
.checkCharIoMaxCalls(10);
@Rule
public final AppEngineRule appEngine = AppEngineRule.builder()
.withDatastore()
@ -146,42 +138,6 @@ public class RdeUploadActionTest {
private final EscrowTaskRunner runner = mock(EscrowTaskRunner.class);
private final FakeClock clock = new FakeClock(DateTime.parse("2010-10-17TZ"));
private final RydeTarOutputStreamFactory tarFactory =
new RydeTarOutputStreamFactory() {
@Override
public RydeTarOutputStream create(
OutputStream os, long size, DateTime modified, String filename) {
return ioSpy.register(super.create(os, size, modified, filename));
}};
private final RydePgpFileOutputStreamFactory literalFactory =
new RydePgpFileOutputStreamFactory(() -> BUFFER_SIZE) {
@Override
public RydePgpFileOutputStream create(OutputStream os, DateTime modified, String filename) {
return ioSpy.register(super.create(os, modified, filename));
}};
private final RydePgpEncryptionOutputStreamFactory encryptFactory =
new RydePgpEncryptionOutputStreamFactory(() -> BUFFER_SIZE) {
@Override
public RydePgpEncryptionOutputStream create(OutputStream os, PGPPublicKey publicKey) {
return ioSpy.register(super.create(os, publicKey));
}};
private final RydePgpCompressionOutputStreamFactory compressFactory =
new RydePgpCompressionOutputStreamFactory(() -> BUFFER_SIZE) {
@Override
public RydePgpCompressionOutputStream create(OutputStream os) {
return ioSpy.register(super.create(os));
}};
private final RydePgpSigningOutputStreamFactory signFactory =
new RydePgpSigningOutputStreamFactory() {
@Override
public RydePgpSigningOutputStream create(OutputStream os, PGPKeyPair signingKey) {
return ioSpy.register(super.create(os, signingKey));
}};
private RdeUploadAction createAction(URI uploadUrl) {
try (Keyring keyring = new FakeKeyringModule().get()) {
RdeUploadAction action = new RdeUploadAction();
@ -195,11 +151,6 @@ public class RdeUploadActionTest {
keyring.getRdeSshClientPublicKey());
action.jschSshSessionFactory = new JSchSshSessionFactory(standardSeconds(3));
action.response = response;
action.pgpCompressionFactory = compressFactory;
action.pgpEncryptionFactory = encryptFactory;
action.pgpFileFactory = literalFactory;
action.pgpSigningFactory = signFactory;
action.tarFactory = tarFactory;
action.bucket = "bucket";
action.interval = standardDays(1);
action.timeout = standardSeconds(23);

View file

@ -68,12 +68,6 @@ public class RydeGpgIntegrationTest extends ShardableTestCase {
new GpgCommand("gpg2"),
};
@DataPoints
public static BufferSize[] bufferSizes = new BufferSize[] {
new BufferSize(1),
new BufferSize(7),
};
@DataPoints
public static Filename[] filenames = new Filename[] {
new Filename("sloth"),
@ -88,22 +82,11 @@ public class RydeGpgIntegrationTest extends ShardableTestCase {
};
@Theory
public void test(GpgCommand cmd, BufferSize bufSize, Filename name, Content content)
public void test(GpgCommand cmd, Filename name, Content content)
throws Exception {
assumeTrue(hasCommand("tar"));
assumeTrue(hasCommand(cmd.get() + " --version"));
RydeTarOutputStreamFactory tarFactory =
new RydeTarOutputStreamFactory();
RydePgpFileOutputStreamFactory pgpFileFactory =
new RydePgpFileOutputStreamFactory(bufSize::get);
RydePgpEncryptionOutputStreamFactory pgpEncryptionFactory =
new RydePgpEncryptionOutputStreamFactory(bufSize::get);
RydePgpCompressionOutputStreamFactory pgpCompressionFactory =
new RydePgpCompressionOutputStreamFactory(bufSize::get);
RydePgpSigningOutputStreamFactory pgpSigningFactory =
new RydePgpSigningOutputStreamFactory();
Keyring keyring = keyringFactory.get();
PGPKeyPair signingKey = keyring.getRdeSigningKey();
PGPPublicKey receiverKey = keyring.getRdeReceiverKey();
@ -116,20 +99,13 @@ public class RydeGpgIntegrationTest extends ShardableTestCase {
byte[] data = content.get().getBytes(UTF_8);
try (OutputStream rydeOut = new FileOutputStream(rydeFile);
RydePgpSigningOutputStream signLayer = pgpSigningFactory.create(rydeOut, signingKey)) {
try (RydePgpEncryptionOutputStream encryptLayer =
pgpEncryptionFactory.create(signLayer, receiverKey);
RydePgpCompressionOutputStream compressLayer =
pgpCompressionFactory.create(encryptLayer);
RydePgpFileOutputStream fileLayer =
pgpFileFactory.create(compressLayer, modified, name.get() + ".tar");
RydeTarOutputStream tarLayer =
tarFactory.create(fileLayer, data.length, modified, name.get() + ".xml")) {
tarLayer.write(data);
}
try (OutputStream sigOut = new FileOutputStream(sigFile)) {
sigOut.write(signLayer.getSignature());
}
OutputStream sigOut = new FileOutputStream(sigFile);
RydeEncoder rydeEncoder = new RydeEncoder.Builder()
.setRydeOutput(rydeOut, receiverKey)
.setSignatureOutput(sigOut, signingKey)
.setFileMetadata(name.get(), data.length, modified)
.build()) {
rydeEncoder.write(data);
}
// Iron Mountain examines the ryde file to see what sort of OpenPGP layers it contains.
@ -252,18 +228,6 @@ public class RydeGpgIntegrationTest extends ShardableTestCase {
}
}
private static class BufferSize {
private final int value;
BufferSize(int value) {
this.value = value;
}
int get() {
return value;
}
}
private static class Filename {
private final String value;

View file

@ -1,121 +0,0 @@
// Copyright 2017 The Nomulus Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package google.registry.testing;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkState;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.atMost;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import java.io.Closeable;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
import javax.annotation.CheckReturnValue;
import org.junit.rules.ExternalResource;
/** JUnit Rule that uses Mockito to spy on I/O streams to make sure they're healthy. */
public final class IoSpyRule extends ExternalResource {
private boolean checkClosedOnlyOnce;
private boolean checkClosedAtLeastOnce;
private int checkCharIoMaxCalls = -1;
private final List<Closeable> spiedCloseables = new ArrayList<>();
private final List<InputStream> spiedInputStreams = new ArrayList<>();
private final List<OutputStream> spiedOutputStreams = new ArrayList<>();
public IoSpyRule() {}
/**
* Enables check where {@link Closeable#close() close} must be called EXACTLY once.
*
* <p>This is sort of pedantic, since Java's contract for close specifies that it must permit
* multiple calls.
*/
public IoSpyRule checkClosedOnlyOnce() {
checkState(!checkClosedAtLeastOnce, "you're already using checkClosedAtLeastOnce()");
checkClosedOnlyOnce = true;
return this;
}
/** Enables check where {@link Closeable#close() close} must be called at least once. */
public IoSpyRule checkClosedAtLeastOnce() {
checkState(!checkClosedOnlyOnce, "you're already using checkClosedOnlyOnce()");
checkClosedAtLeastOnce = true;
return this;
}
/** Enables check to make sure your streams aren't going too slow with char-based I/O. */
public IoSpyRule checkCharIoMaxCalls(int value) {
checkArgument(value >= 0, "value >= 0");
checkCharIoMaxCalls = value;
return this;
}
/** Adds your {@link Closeable} to the list of streams to check, and returns its mocked self. */
@CheckReturnValue
public <T extends Closeable> T register(T stream) {
T res = spy(stream);
spiedCloseables.add(res);
if (stream instanceof InputStream) {
spiedInputStreams.add((InputStream) res);
}
if (stream instanceof OutputStream) {
spiedOutputStreams.add((OutputStream) res);
}
return res;
}
@Override
protected void after() {
checkState(checkClosedOnlyOnce
|| checkClosedAtLeastOnce
|| checkCharIoMaxCalls != -1,
"At least one check must be enabled.");
try {
check();
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
spiedCloseables.clear();
spiedInputStreams.clear();
spiedOutputStreams.clear();
}
}
private void check() throws IOException {
for (Closeable stream : spiedCloseables) {
if (checkClosedAtLeastOnce) {
verify(stream, atLeastOnce()).close();
} else if (checkClosedOnlyOnce) {
verify(stream, times(1)).close();
}
}
if (checkCharIoMaxCalls != -1) {
for (InputStream stream : spiedInputStreams) {
verify(stream, atMost(checkCharIoMaxCalls)).read();
}
for (OutputStream stream : spiedOutputStreams) {
verify(stream, atMost(checkCharIoMaxCalls)).write(anyInt());
}
}
}
}

View file

@ -20,11 +20,6 @@ import static google.registry.testing.TestDataHelper.loadBytes;
import com.google.common.io.ByteSource;
import com.google.common.io.Files;
import google.registry.rde.RdeTestData;
import google.registry.rde.RydePgpCompressionOutputStreamFactory;
import google.registry.rde.RydePgpEncryptionOutputStreamFactory;
import google.registry.rde.RydePgpFileOutputStreamFactory;
import google.registry.rde.RydePgpSigningOutputStreamFactory;
import google.registry.rde.RydeTarOutputStreamFactory;
import google.registry.testing.BouncyCastleProviderRule;
import google.registry.testing.FakeKeyringModule;
import java.io.File;
@ -43,11 +38,6 @@ public class EncryptEscrowDepositCommandTest
static EscrowDepositEncryptor createEncryptor() {
EscrowDepositEncryptor res = new EscrowDepositEncryptor();
res.pgpCompressionFactory = new RydePgpCompressionOutputStreamFactory(() -> 1024);
res.pgpEncryptionFactory = new RydePgpEncryptionOutputStreamFactory(() -> 1024);
res.pgpFileFactory = new RydePgpFileOutputStreamFactory(() -> 1024);
res.pgpSigningFactory = new RydePgpSigningOutputStreamFactory();
res.tarFactory = new RydeTarOutputStreamFactory();
res.rdeReceiverKey = () -> new FakeKeyringModule().get().getRdeReceiverKey();
res.rdeSigningKey = () -> new FakeKeyringModule().get().getRdeSigningKey();
return res;