Skip to content

Commit

Permalink
Merge pull request #280 from eclipse-passage/564819
Browse files Browse the repository at this point in the history
Bug 564819 - API revision | conditions | stream codecs review
  • Loading branch information
eparovyshnaya authored Jul 3, 2020
2 parents 2872f84 + 5d45960 commit 6b54e60
Show file tree
Hide file tree
Showing 5 changed files with 263 additions and 64 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,6 @@ void produce(InputStream publicKeyRing, DigestExpectation digest) throws Licensi
signature.init(new JcaPGPContentVerifierBuilderProvider(), decodeKey);
writeVerifiedDecodedOutput(literal, signature, factory);
}

} catch (Exception e) {
throw new LicensingException( //
String.format(BcMessages.getString("BcStreamCodec_deconde_error"), product), //$NON-NLS-1$ ,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
/*******************************************************************************
* Copyright (c) 2020 ArSysOp
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* https://www.eclipse.org/legal/epl-2.0/.
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* ArSysOp - initial API and implementation
*******************************************************************************/
package org.eclipse.passage.lic.internal.bc.tests;

import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.Path;

import org.eclipse.passage.lic.internal.api.LicensedProduct;
import org.eclipse.passage.lic.internal.api.LicensingException;
import org.eclipse.passage.lic.internal.base.BaseLicensedProduct;
import org.eclipse.passage.lic.internal.base.io.PassageFileExtension;
import org.eclipse.passage.lic.internal.bc.BcStreamCodec;
import org.junit.Rule;
import org.junit.rules.TemporaryFolder;

@SuppressWarnings("restriction")
abstract class BcStreamCodecTest {

@Rule
public final TemporaryFolder root = new TemporaryFolder();

protected final void assertFileExists(Path file) {
assertTrue(Files.exists(file));
assertTrue(Files.isRegularFile(file));
}

protected final PairInfo<Path> pair(String user, String pass) throws IOException {
return pair((pub, secret) -> new PairKeys(pub, secret), user, pass);
}

protected final <I> PairInfo<I> pair(ThrowingCtor<I> ctor, String user, String pass) throws IOException {
Path pub = new TmpFile(root).keyFile(new PassageFileExtension.PublicKey());
Path secret = new TmpFile(root).keyFile(new PassageFileExtension.PrivateKey());
BcStreamCodec codec = new BcStreamCodec(this::product);
try {
codec.createKeyPair(pub, secret, user, pass);
} catch (LicensingException e) {
fail("PGP key pair generation on valid data is not supposed to fail"); //$NON-NLS-1$
}
return ctor.create(pub, secret);
}

protected final InputStream anInput() {
return new ByteArrayInputStream(new byte[0]);
}

protected final OutputStream anOutput() {
return new ByteArrayOutputStream();
}

protected final LicensedProduct product() {
return new BaseLicensedProduct("bc-stream-codec-test-product", "2.4.21"); //$NON-NLS-1$//$NON-NLS-2$
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,26 +21,18 @@
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Objects;

import org.eclipse.passage.lic.internal.api.LicensedProduct;
import org.eclipse.passage.lic.internal.api.LicensingException;
import org.eclipse.passage.lic.internal.api.io.DigestExpectation;
import org.eclipse.passage.lic.internal.base.BaseLicensedProduct;
import org.eclipse.passage.lic.internal.base.io.FileContent;
import org.eclipse.passage.lic.internal.base.io.PassageFileExtension;
import org.eclipse.passage.lic.internal.bc.BcStreamCodec;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;

@SuppressWarnings("restriction")
public final class KeyPairGenerationTest {

@Rule
public TemporaryFolder root = new TemporaryFolder();
public final class KeyPairGenerationTest extends BcStreamCodecTest {

@Test
public void generationSucceeds() throws IOException {
Expand Down Expand Up @@ -78,16 +70,16 @@ public void subsequentPairDiffer() throws IOException {
@Test
public void generatedPairIsFunctional() throws IOException {
// given
Path victim = new TmpFile(root).fileWithContent();
Path origin = new TmpFile(root).fileWithContent();
Path encoded = new TmpFile(root).file(".txt"); //$NON-NLS-1$
Path decoded = new TmpFile(root).file(".txt"); //$NON-NLS-1$
String user = "fake.user"; //$NON-NLS-1$
String pass = "some$pass#val&1"; //$NON-NLS-1$

// when: first: encode
PairInfo<Path> pair = pair((pub, secret) -> new PairKeys(pub, secret), user, pass);
// when: first: create pair
PairInfo<Path> pair = pair(user, pass);
try (//
InputStream target = new FileInputStream(victim.toFile()); //
InputStream target = new FileInputStream(origin.toFile()); //
OutputStream destination = new FileOutputStream(encoded.toFile()); //
InputStream key = new FileInputStream(pair.secondInfo().toFile())) {
new BcStreamCodec(this::product).encode(target, destination, key, user, pass);
Expand All @@ -108,7 +100,7 @@ public void generatedPairIsFunctional() throws IOException {

// then
assertTrue(Objects.deepEquals(//
new FileContent(victim).get(), //
new FileContent(origin).get(), //
new FileContent(decoded).get()));

}
Expand Down Expand Up @@ -181,28 +173,4 @@ private <I> PairInfo<I> pair(ThrowingCtor<I> ctor) throws IOException {
return pair(ctor, "test-user", "test-pass-word");//$NON-NLS-1$//$NON-NLS-2$
}

private <I> PairInfo<I> pair(ThrowingCtor<I> ctor, String user, String pass) throws IOException {
// given:
Path pub = new TmpFile(root).keyFile(new PassageFileExtension.PublicKey());
Path secret = new TmpFile(root).keyFile(new PassageFileExtension.PrivateKey());
BcStreamCodec codec = new BcStreamCodec(this::product);
try {
// when
codec.createKeyPair(pub, secret, user, pass);
} catch (LicensingException e) {
// then
fail("PGP key pair generation on valid data is not supposed to fail"); //$NON-NLS-1$
}
return ctor.create(pub, secret);
}

private void assertFileExists(Path file) {
assertTrue(Files.exists(file));
assertTrue(Files.isRegularFile(file));
}

private LicensedProduct product() {
return new BaseLicensedProduct("keygen-test-product", "1.0.18"); //$NON-NLS-1$//$NON-NLS-2$
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
/*******************************************************************************
* Copyright (c) 2020 ArSysOp
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* https://www.eclipse.org/legal/epl-2.0/.
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* ArSysOp - initial API and implementation
*******************************************************************************/
package org.eclipse.passage.lic.internal.bc.tests;

import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.junit.Assume.assumeTrue;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Objects;
import java.util.function.Function;

import org.eclipse.passage.lic.internal.api.LicensingException;
import org.eclipse.passage.lic.internal.api.io.DigestExpectation;
import org.eclipse.passage.lic.internal.base.io.BaseDigestExpectation;
import org.eclipse.passage.lic.internal.base.io.FileContent;
import org.eclipse.passage.lic.internal.bc.BcDigest;
import org.eclipse.passage.lic.internal.bc.BcStreamCodec;
import org.junit.Test;

@SuppressWarnings("restriction")
public final class StreamDecodingTest extends BcStreamCodecTest {

@Test
public void decodingIsFunctional() throws IOException {
Path[] actors;
try {
actors = decode();
} catch (LicensingException e) {
fail("Decoding for valid data is not supposed to fail"); //$NON-NLS-1$
throw new RuntimeException();// unreachable
}
Path origin = actors[0];
Path encoded = actors[1];
Path decoded = actors[2];
assertTrue(Files.size(decoded) > 0);
assertFalse(Objects.deepEquals(//
new FileContent(encoded).get(), //
new FileContent(decoded).get()));
assertTrue(Objects.deepEquals(//
new FileContent(origin).get(), //
new FileContent(decoded).get()));
}

/**
* Decoding with a foreign key must fail even if it is not demanded to be
* assessed by digest expectation.
*/
@Test
public void properKeyIsRequired() throws IOException {
try {
decodeWithKey(PairInfo::secondInfo);
} catch (LicensingException e) {
return;
}
fail("Decoding with incorrect key must fail"); //$NON-NLS-1$
}

@Test
public void validDigestDoesNotFailDecoding() throws IOException {
try {
decodeWithDigest(key -> new BaseDigestExpectation(new BcDigest(key).get()));
} catch (LicensingException e) {
fail("Decoding for valid data is not supposed to fail"); //$NON-NLS-1$
}
}

@Test
public void invalidDigestFailsDecoding() throws IOException {
try {
decodeWithDigest(key -> new BaseDigestExpectation(new byte[0]));
} catch (LicensingException e) {
assertTrue(e.getMessage().contains("digest")); //$NON-NLS-1$
return;
}
fail("Unsatisfiable digest expectation must stop decoding"); //$NON-NLS-1$
}

private Path encoded(Path origin, Path privateKey, String user, String pass) throws IOException {
Path encoded = new TmpFile(root).file(".txt"); //$NON-NLS-1$
try (//
InputStream source = new FileInputStream(origin.toFile());
OutputStream destination = new FileOutputStream(encoded.toFile());
InputStream key = new FileInputStream(privateKey.toFile())) {
new BcStreamCodec(this::product).encode(source, destination, key, user, pass);
} catch (LicensingException e) {
fail("Failed to encode a file: check corresponding tests set"); //$NON-NLS-1$
}
return encoded;
}

@Test(expected = NullPointerException.class)
public void sourceIsMandatory() throws IOException {
try (OutputStream output = anOutput(); InputStream key = anInput()) {
decodeNull(null, output, key, new DigestExpectation.None());
}
}

@Test(expected = NullPointerException.class)
public void targetIsMandatory() throws IOException {
try (InputStream input = anInput(); InputStream key = anInput()) {
decodeNull(input, null, key, new DigestExpectation.None());
}
}

@Test(expected = NullPointerException.class)
public void keyIsMandatory() throws IOException {
try (InputStream input = anInput(); OutputStream output = anOutput()) {
decodeNull(input, output, null, new DigestExpectation.None());
}
}

@Test(expected = NullPointerException.class)
public void digestIsMandatory() throws IOException {
try (InputStream input = anInput(); OutputStream output = anOutput(); InputStream key = anInput()) {
decodeNull(input, output, key, null);
}
}

private void decodeNull(InputStream input, OutputStream output, InputStream key, DigestExpectation digest) {
try {
new BcStreamCodec(this::product).decode(input, output, key, digest);
} catch (LicensingException e) {
fail("Incorrect incoming data are not intended to cause any decoding activity"); //$NON-NLS-1$
}
}

private Path[] decode() throws IOException, LicensingException {
return decode(pair -> pair.firstInfo(), key -> new DigestExpectation.None());
}

private Path[] decodeWithDigest(ThrowingDigestSupplier digest) throws IOException, LicensingException {
return decode(pair -> pair.firstInfo(), digest);
}

private Path[] decodeWithKey(Function<PairInfo<Path>, Path> publicKey) throws IOException, LicensingException {
return decode(publicKey, key -> new DigestExpectation.None());
}

private Path[] decode(Function<PairInfo<Path>, Path> publicKey, ThrowingDigestSupplier digest)
throws IOException, LicensingException {
// given
String user = "Suer"; //$NON-NLS-1$
String pass = "Vyer"; //$NON-NLS-1$
PairInfo<Path> pair = pair(user, pass);
Path origin = new TmpFile(root).fileWithContent();
Path encoded = encoded(origin, pair.secondInfo(), user, pass);
Path decoded = new TmpFile(root).file(".txt"); //$NON-NLS-1$
assumeTrue(Files.size(decoded) == 0);

// when
try (//
InputStream source = new FileInputStream(encoded.toFile());
OutputStream destination = new FileOutputStream(decoded.toFile());
InputStream key = new FileInputStream(publicKey.apply(pair).toFile())) {
new BcStreamCodec(this::product).decode(source, destination, key, digest.forKey(pair.firstInfo()));
}
return new Path[] { origin, encoded, decoded };
}

private interface ThrowingDigestSupplier {
DigestExpectation forKey(Path key) throws IOException;
}

}
Loading

0 comments on commit 6b54e60

Please sign in to comment.