diff --git a/bundles/org.eclipse.passage.lic.bc/src/org/eclipse/passage/lic/internal/bc/BcDecodedStream.java b/bundles/org.eclipse.passage.lic.bc/src/org/eclipse/passage/lic/internal/bc/BcDecodedStream.java index b1461a8c8..536255e2c 100644 --- a/bundles/org.eclipse.passage.lic.bc/src/org/eclipse/passage/lic/internal/bc/BcDecodedStream.java +++ b/bundles/org.eclipse.passage.lic.bc/src/org/eclipse/passage/lic/internal/bc/BcDecodedStream.java @@ -52,7 +52,9 @@ final class BcDecodedStream { void produce(InputStream publicKeyRing, DigestExpectation digest) throws LicensingException { byte[] ring = ring(publicKeyRing, digest); - try (InputStream compressed = compressedData().getDataStream()) { + try (// + InputStream decodedInput = PGPUtil.getDecoderStream(input); + InputStream compressed = compressedData(decodedInput).getDataStream()) { PGPObjectFactory factory = new JcaPGPObjectFactory(compressed); PGPOnePassSignature signature = signature(factory); try (InputStream literal = literalDataStream(factory); @@ -61,6 +63,7 @@ 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$ , @@ -102,16 +105,14 @@ private InputStream literalDataStream(PGPObjectFactory factory) throws IOExcepti return ((PGPLiteralData) factory.nextObject()).getInputStream(); } - private PGPCompressedData compressedData() throws LicensingException, IOException { - try (InputStream decoder = PGPUtil.getDecoderStream(input)) { - PGPObjectFactory factory = new JcaPGPObjectFactory(decoder); - Optional compressed = Optional.ofNullable((PGPCompressedData) factory.nextObject()); - if (!compressed.isPresent()) { - throw new LicensingException(// - String.format(BcMessages.getString("BcStreamCodec_encode_error_data"), product)); //$NON-NLS-1$ - } - return compressed.get(); + private PGPCompressedData compressedData(InputStream decoder) throws LicensingException, IOException { + PGPObjectFactory factory = new JcaPGPObjectFactory(decoder); + Optional compressed = Optional.ofNullable((PGPCompressedData) factory.nextObject()); + if (!compressed.isPresent()) { + throw new LicensingException(// + String.format(BcMessages.getString("BcStreamCodec_encode_error_data"), product)); //$NON-NLS-1$ } + return compressed.get(); } private byte[] ring(InputStream publicKeyRing, DigestExpectation digest) throws LicensingException { diff --git a/bundles/org.eclipse.passage.lic.bc/src/org/eclipse/passage/lic/internal/bc/BcDigest.java b/bundles/org.eclipse.passage.lic.bc/src/org/eclipse/passage/lic/internal/bc/BcDigest.java index db803e623..dd52024fc 100644 --- a/bundles/org.eclipse.passage.lic.bc/src/org/eclipse/passage/lic/internal/bc/BcDigest.java +++ b/bundles/org.eclipse.passage.lic.bc/src/org/eclipse/passage/lic/internal/bc/BcDigest.java @@ -12,15 +12,17 @@ *******************************************************************************/ package org.eclipse.passage.lic.internal.bc; +import java.util.Objects; import java.util.function.Supplier; import org.bouncycastle.crypto.digests.SHA512Digest; -public final class BcDigest implements Supplier { +final class BcDigest implements Supplier { private final byte[] source; - public BcDigest(byte[] source) { + BcDigest(byte[] source) { + Objects.requireNonNull(source, "BcDigest::source"); //$NON-NLS-1$ this.source = source; } diff --git a/bundles/org.eclipse.passage.lic.bc/src/org/eclipse/passage/lic/internal/bc/BcKeyPair.java b/bundles/org.eclipse.passage.lic.bc/src/org/eclipse/passage/lic/internal/bc/BcKeyPair.java index cd48e384c..92f42e34d 100644 --- a/bundles/org.eclipse.passage.lic.bc/src/org/eclipse/passage/lic/internal/bc/BcKeyPair.java +++ b/bundles/org.eclipse.passage.lic.bc/src/org/eclipse/passage/lic/internal/bc/BcKeyPair.java @@ -30,6 +30,7 @@ import org.bouncycastle.openpgp.PGPKeyRing; import org.bouncycastle.openpgp.PGPKeyRingGenerator; import org.bouncycastle.openpgp.PGPPublicKey; +import org.bouncycastle.openpgp.PGPSecretKey; import org.bouncycastle.openpgp.PGPSignature; import org.bouncycastle.openpgp.PGPSignatureSubpacketGenerator; import org.bouncycastle.openpgp.PGPSignatureSubpacketVector; @@ -44,6 +45,21 @@ import org.eclipse.passage.lic.internal.api.io.EncryptionKeySize; import org.eclipse.passage.lic.internal.bc.i18n.BcMessages; +/** + *

+ * Generated a couple of PGP keys ({@linkplain PGPPublicKey} and pairing + * {@linkplain PGPSecretKey}) + *

+ *
    + *
  • into the files pointed in the given {@linkplain Targets}
  • + *
  • according to the configured {@linkplain EncryptionParameters}
  • + *
  • for an owner with the passed credentials
  • + *
+ *

+ * Empowers + * {@linkplain BcStreamCodec#createKeyPair(Path, Path, String, String)}. + *

+ */ @SuppressWarnings("restriction") final class BcKeyPair { diff --git a/bundles/org.eclipse.passage.lic.bc/src/org/eclipse/passage/lic/internal/bc/BcResidentSecretKey.java b/bundles/org.eclipse.passage.lic.bc/src/org/eclipse/passage/lic/internal/bc/BcResidentSecretKey.java index 8b0397620..051c3a5bf 100644 --- a/bundles/org.eclipse.passage.lic.bc/src/org/eclipse/passage/lic/internal/bc/BcResidentSecretKey.java +++ b/bundles/org.eclipse.passage.lic.bc/src/org/eclipse/passage/lic/internal/bc/BcResidentSecretKey.java @@ -30,6 +30,10 @@ import org.eclipse.passage.lic.internal.api.LicensingException; import org.eclipse.passage.lic.internal.bc.i18n.BcMessages; +/** + * Look for a {@code secret key} in the given {@code residence} input stream, + * which is supposed to be begotten by a key ring file. + */ @SuppressWarnings("restriction") final class BcResidentSecretKey { diff --git a/bundles/org.eclipse.passage.lic.bc/src/org/eclipse/passage/lic/internal/bc/BcStreamCodec.java b/bundles/org.eclipse.passage.lic.bc/src/org/eclipse/passage/lic/internal/bc/BcStreamCodec.java index 48cc4966e..2166da6e4 100644 --- a/bundles/org.eclipse.passage.lic.bc/src/org/eclipse/passage/lic/internal/bc/BcStreamCodec.java +++ b/bundles/org.eclipse.passage.lic.bc/src/org/eclipse/passage/lic/internal/bc/BcStreamCodec.java @@ -15,8 +15,11 @@ import java.io.InputStream; import java.io.OutputStream; import java.nio.file.Path; +import java.security.Security; +import java.util.Objects; import java.util.function.Supplier; +import org.bouncycastle.jce.provider.BouncyCastleProvider; 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; @@ -27,6 +30,10 @@ @SuppressWarnings("restriction") public final class BcStreamCodec implements StreamCodec { + static { + Security.addProvider(new BouncyCastleProvider()); + } + private final Supplier product; private final EncryptionAlgorithm algorithm; private final EncryptionKeySize keySize; @@ -59,24 +66,38 @@ public EncryptionKeySize keySize() { @Override public void createKeyPair(Path publicKey, Path privateKey, String username, String password) throws LicensingException { + Objects.requireNonNull(publicKey, "BcStreamCodec::createKeyPair::publicKey"); //$NON-NLS-1$ + Objects.requireNonNull(privateKey, "BcStreamCodec::createKeyPair::privateKey"); //$NON-NLS-1$ + Objects.requireNonNull(username, "BcStreamCodec::createKeyPair::username"); //$NON-NLS-1$ + Objects.requireNonNull(password, "BcStreamCodec::createKeyPair::password"); //$NON-NLS-1$ new BcKeyPair( // new BcKeyPair.Targets(publicKey, privateKey), // new BcKeyPair.EncryptionParameters(algorithm, keySize) // ).generate(username, password); } + @SuppressWarnings("resource") @Override public void encode(InputStream input, OutputStream output, InputStream key, String username, String password) throws LicensingException { + Objects.requireNonNull(input, "BcStreamCodec::encode::input"); //$NON-NLS-1$ + Objects.requireNonNull(output, "BcStreamCodec::encode::output"); //$NON-NLS-1$ + Objects.requireNonNull(key, "BcStreamCodec::encode::key"); //$NON-NLS-1$ ; + Objects.requireNonNull(username, "BcStreamCodec::encode::username"); //$NON-NLS-1$ + Objects.requireNonNull(password, "BcStreamCodec::encode::password"); //$NON-NLS-1$ new BcEncodedStream(product.get(), input, output)// .produce(new BcResidentSecretKey(key, username).get(), password); } + @SuppressWarnings("resource") @Override public void decode(InputStream input, OutputStream output, InputStream key, DigestExpectation digest) throws LicensingException { - // TODO Auto-generated method stub - + Objects.requireNonNull(input, "BcStreamCodec::decode::input"); //$NON-NLS-1$ + Objects.requireNonNull(output, "BcStreamCodec::decode::output"); //$NON-NLS-1$ + Objects.requireNonNull(key, "BcStreamCodec::decode::key"); //$NON-NLS-1$ ; + Objects.requireNonNull(digest, "BcStreamCodec::decode::digest"); //$NON-NLS-1$ + new BcDecodedStream(product.get(), input, output).produce(key, digest); } } diff --git a/tests/org.eclipse.passage.lic.bc.tests/src/org/eclipse/passage/lic/internal/bc/tests/FileContent.java b/tests/org.eclipse.passage.lic.bc.tests/src/org/eclipse/passage/lic/internal/bc/tests/FileContent.java new file mode 100644 index 000000000..22a4810df --- /dev/null +++ b/tests/org.eclipse.passage.lic.bc.tests/src/org/eclipse/passage/lic/internal/bc/tests/FileContent.java @@ -0,0 +1,36 @@ +/******************************************************************************* + * 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 java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Files; +import java.nio.file.Path; + +final class FileContent { + + private final Path file; + + FileContent(Path file) { + this.file = file; + } + + byte[] get() throws IOException { + byte[] content = new byte[(int) Files.size(file)]; + try (InputStream stream = new FileInputStream(file.toFile())) { + stream.read(content); + } + return content; + } +} diff --git a/tests/org.eclipse.passage.lic.bc.tests/src/org/eclipse/passage/lic/internal/bc/tests/KeyPairGenerationTest.java b/tests/org.eclipse.passage.lic.bc.tests/src/org/eclipse/passage/lic/internal/bc/tests/KeyPairGenerationTest.java new file mode 100644 index 000000000..7aa31e124 --- /dev/null +++ b/tests/org.eclipse.passage.lic.bc.tests/src/org/eclipse/passage/lic/internal/bc/tests/KeyPairGenerationTest.java @@ -0,0 +1,233 @@ +/******************************************************************************* + * 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 java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.PrintWriter; +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.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 folder = new TemporaryFolder(); + + @Test + public void generationSucceeds() throws IOException { + PairInfo pair = pair((pub, secret) -> new PairSize(pub, secret)); + assertTrue(pair.secondInfo() > 0); + assertTrue(pair.firstInfo() > 0); + } + + @Test + public void subsequentPairDiffer() throws IOException { + PairInfo first = pair((pub, secret) -> new PairContent(pub, secret)); + PairInfo second = pair((pub, secret) -> new PairContent(pub, secret)); + assertFalse(first.equals(second)); + } + + /** + *
    + *
  • generate pair of keys
  • + *
  • encode random text file with {@code private} key
  • + *
  • decode the result with the pairing {@code public} key
  • + *
  • compare original and decoded files: they re expected to have equal + * content
  • + *
+ * + *

+ * NB: It is not symmetric: you can encrypt only with {@code private} key + * and then decipher only with the pairing {@code public}. + *

+ * + * @throws IOException in case of file system denials + */ + @Test + public void generatedPairIsFunctional() throws IOException { + // given + Path victim = fileWithContent(); + Path encoded = file(".txt"); //$NON-NLS-1$ + Path decoded = 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 pair = pair((pub, secret) -> new PairKeys(pub, secret), user, pass); + try (// + InputStream target = new FileInputStream(victim.toFile()); // + OutputStream destination = new FileOutputStream(encoded.toFile()); // + InputStream key = new FileInputStream(pair.secondInfo().toFile())) { + new BcStreamCodec(this::product).encode(target, destination, key, user, pass); + } catch (LicensingException e) { + fail("Encoding is not supposed to fail on valid data"); //$NON-NLS-1$ + } + + // when: second: decode + try (// + InputStream target = new FileInputStream(encoded.toFile()); // + OutputStream destination = new FileOutputStream(decoded.toFile()); // + InputStream key = new FileInputStream(pair.firstInfo().toFile())) { + new BcStreamCodec(this::product).decode(target, destination, key, new DigestExpectation.None()); + } catch (LicensingException e) { + e.printStackTrace(); + fail("Decoding is not supposed to fail on valid data"); //$NON-NLS-1$ + } + + // then + assertTrue(Objects.deepEquals(// + new FileContent(victim).get(), // + new FileContent(decoded).get())); + + } + + @Test(expected = NullPointerException.class) + public void publicKeyPathIsMandatory() throws LicensingException, IOException { + new BcStreamCodec(this::product).createKeyPair(// + null, // + keyFile(new PassageFileExtension.PrivateKey()), // + "u", //$NON-NLS-1$ + "p"); //$NON-NLS-1$ + } + + @Test(expected = NullPointerException.class) + public void privateKeyPathIsMandatory() throws LicensingException, IOException { + new BcStreamCodec(this::product).createKeyPair(// + keyFile(new PassageFileExtension.PublicKey()), // + null, // + "u", //$NON-NLS-1$ + "p"); //$NON-NLS-1$ + } + + @Test(expected = NullPointerException.class) + public void usernameIsMandatory() throws LicensingException, IOException { + new BcStreamCodec(this::product).createKeyPair(// + keyFile(new PassageFileExtension.PublicKey()), // + keyFile(new PassageFileExtension.PrivateKey()), // + null, // + "p"); //$NON-NLS-1$ + } + + @Test(expected = NullPointerException.class) + public void passwordIsMandatory() throws LicensingException, IOException { + new BcStreamCodec(this::product).createKeyPair(// + keyFile(new PassageFileExtension.PublicKey()), // + keyFile(new PassageFileExtension.PrivateKey()), // + "u", //$NON-NLS-1$ + null); + } + + @Test + public void absentPrivateKeyFileIsCreated() throws LicensingException, IOException { + // given + Path privatePath = keyPath(new PassageFileExtension.PrivateKey()); + // when + new BcStreamCodec(this::product).createKeyPair(// + keyFile(new PassageFileExtension.PublicKey()), // + privatePath, // + "u", //$NON-NLS-1$ + "p"); //$NON-NLS-1$ + // then + assertFileExists(privatePath); + } + + @Test + public void absentPublicKeyFileIsCreated() throws LicensingException, IOException { + // given + Path publicPath = keyPath(new PassageFileExtension.PublicKey()); + // when + new BcStreamCodec(this::product).createKeyPair(// + publicPath, // + keyFile(new PassageFileExtension.PrivateKey()), // + "u", //$NON-NLS-1$ + "p"); //$NON-NLS-1$ + // then + assertFileExists(publicPath); + } + + private PairInfo pair(ThrowingCtor ctor) throws IOException { + return pair(ctor, "test-user", "test-pass-word");//$NON-NLS-1$//$NON-NLS-2$ + } + + private PairInfo pair(ThrowingCtor ctor, String user, String pass) throws IOException { + // given: + Path pub = keyFile(new PassageFileExtension.PublicKey()); + Path secret = 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("test-product", "1.0.18"); //$NON-NLS-1$//$NON-NLS-2$ + } + + /** + * Physically creates an empty file with demanded extension + */ + private Path keyFile(PassageFileExtension extension) throws IOException { + return file(extension.get()); + } + + private Path file(String extension) throws IOException { + return folder.newFile(Long.toHexString(System.nanoTime()) + extension).toPath(); + } + + /** + * Creates a reference for not yet existing file + */ + private Path keyPath(PassageFileExtension extension) throws IOException { + return folder.getRoot().toPath().resolve(Long.toHexString(System.nanoTime()) + extension.get()); + } + + private Path fileWithContent() throws IOException { + Path path = folder.newFile(Long.toHexString(System.nanoTime()) + ".txt").toPath(); //$NON-NLS-1$ + try (PrintWriter writer = new PrintWriter(path.toFile())) { + writer.println("content row 1"); //$NON-NLS-1$ + writer.println("content row 2"); //$NON-NLS-1$ + writer.println("content row 3"); //$NON-NLS-1$ + } + return path; + } + +} diff --git a/tests/org.eclipse.passage.lic.bc.tests/src/org/eclipse/passage/lic/internal/bc/tests/PairContent.java b/tests/org.eclipse.passage.lic.bc.tests/src/org/eclipse/passage/lic/internal/bc/tests/PairContent.java new file mode 100644 index 000000000..25ba046de --- /dev/null +++ b/tests/org.eclipse.passage.lic.bc.tests/src/org/eclipse/passage/lic/internal/bc/tests/PairContent.java @@ -0,0 +1,29 @@ +/******************************************************************************* + * 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 java.io.IOException; +import java.nio.file.Path; + +final class PairContent extends PairInfo { + + PairContent(Path first, Path second) throws IOException { + super(first, second); + } + + @Override + protected byte[] info(Path file) throws IOException { + return new FileContent(file).get(); + } + +} diff --git a/tests/org.eclipse.passage.lic.bc.tests/src/org/eclipse/passage/lic/internal/bc/tests/PairInfo.java b/tests/org.eclipse.passage.lic.bc.tests/src/org/eclipse/passage/lic/internal/bc/tests/PairInfo.java new file mode 100644 index 000000000..cdea5f5f6 --- /dev/null +++ b/tests/org.eclipse.passage.lic.bc.tests/src/org/eclipse/passage/lic/internal/bc/tests/PairInfo.java @@ -0,0 +1,55 @@ +/******************************************************************************* + * 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 java.io.IOException; +import java.nio.file.Path; +import java.util.Objects; + +abstract class PairInfo { + + private final I first; + private final I second; + + PairInfo(Path first, Path second) throws IOException { + this.first = info(first); + this.second = info(second); + } + + I firstInfo() { + return first; + } + + I secondInfo() { + return second; + } + + protected abstract I info(Path file) throws IOException; + + @Override + public boolean equals(Object object) { + if (!getClass().isInstance(object)) { + return false; + } + @SuppressWarnings("unchecked") + PairInfo another = (PairInfo) object; + return Objects.deepEquals(first, another.first) // + && Objects.deepEquals(second, another.second); + } + + @Override + public int hashCode() { + return Objects.hash(first, second); + } + +} diff --git a/tests/org.eclipse.passage.lic.bc.tests/src/org/eclipse/passage/lic/internal/bc/tests/PairKeys.java b/tests/org.eclipse.passage.lic.bc.tests/src/org/eclipse/passage/lic/internal/bc/tests/PairKeys.java new file mode 100644 index 000000000..c609ab147 --- /dev/null +++ b/tests/org.eclipse.passage.lic.bc.tests/src/org/eclipse/passage/lic/internal/bc/tests/PairKeys.java @@ -0,0 +1,29 @@ +/******************************************************************************* + * 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 java.io.IOException; +import java.nio.file.Path; + +final class PairKeys extends PairInfo { + + PairKeys(Path first, Path second) throws IOException { + super(first, second); + } + + @Override + protected Path info(Path file) throws IOException { + return file; + } + +} diff --git a/tests/org.eclipse.passage.lic.bc.tests/src/org/eclipse/passage/lic/internal/bc/tests/PairSize.java b/tests/org.eclipse.passage.lic.bc.tests/src/org/eclipse/passage/lic/internal/bc/tests/PairSize.java new file mode 100644 index 000000000..72df17175 --- /dev/null +++ b/tests/org.eclipse.passage.lic.bc.tests/src/org/eclipse/passage/lic/internal/bc/tests/PairSize.java @@ -0,0 +1,30 @@ +/******************************************************************************* + * 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 java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; + +final class PairSize extends PairInfo { + + PairSize(Path first, Path second) throws IOException { + super(first, second); + } + + @Override + protected Integer info(Path file) throws IOException { + return (int) Files.size(file); + } + +} diff --git a/tests/org.eclipse.passage.lic.bc.tests/src/org/eclipse/passage/lic/internal/bc/tests/ThrowingCtor.java b/tests/org.eclipse.passage.lic.bc.tests/src/org/eclipse/passage/lic/internal/bc/tests/ThrowingCtor.java new file mode 100644 index 000000000..cd7dc5017 --- /dev/null +++ b/tests/org.eclipse.passage.lic.bc.tests/src/org/eclipse/passage/lic/internal/bc/tests/ThrowingCtor.java @@ -0,0 +1,23 @@ +/******************************************************************************* + * 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 java.io.IOException; +import java.nio.file.Path; + +@FunctionalInterface +interface ThrowingCtor { + + PairInfo create(Path pub, Path secret) throws IOException; + +}