Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bug 564819 - API revision | conditions | stream codecs review #280

Merged
merged 2 commits into from
Jul 3, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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