diff options
| -rw-r--r-- | .github/workflows/test.yml | 4 | ||||
| -rw-r--r-- | Makefile | 24 | ||||
| -rw-r--r-- | wrappers/EduVpnCommon/src/eduvpncommon/VerifyException.java | 5 | ||||
| -rw-r--r-- | wrappers/EduVpnCommon/tests/eduvpncommon/VerifyTests.java | 31 | ||||
| -rw-r--r-- | wrappers/java/.gitignore | 1 | ||||
| -rw-r--r-- | wrappers/java/Makefile | 14 | ||||
| -rw-r--r-- | wrappers/java/README.md | 31 | ||||
| -rw-r--r-- | wrappers/java/pom.xml | 102 | ||||
| -rw-r--r-- | wrappers/java/src/main/java/nl/eduvpn/common/Discovery.java (renamed from wrappers/EduVpnCommon/src/eduvpncommon/Discovery.java) | 20 | ||||
| -rw-r--r-- | wrappers/java/src/main/java/nl/eduvpn/common/VerifyException.java | 9 | ||||
| -rw-r--r-- | wrappers/java/src/test/java/nl/eduvpn/common/VerifyTests.java | 78 | ||||
| -rw-r--r-- | wrappers/python/Makefile | 3 |
12 files changed, 267 insertions, 55 deletions
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index b96901f..ab46a47 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -26,4 +26,8 @@ jobs: - uses: actions/setup-dotnet@v1 with: dotnet-version: 5.0.x + - uses: actions/setup-java@v2 + with: + distribution: temurin + java-version: 9 - run: make test-wrappers @@ -8,16 +8,24 @@ test: test-go test-wrappers test-go: go test +wrappers = $(wildcard wrappers/*/) + # Enable parallelism if -j is specified test-wrappers: build - $(MAKE) .test-csharp .test-python - -.test-csharp: - $(MAKE) -C wrappers/csharp test - -.test-python: - $(MAKE) -C wrappers/python test + $(MAKE) $(foreach wrapper,$(wrappers),.test_$(wrapper)) clean: $(MAKE) -C exports clean - $(MAKE) -C wrappers/csharp clean + $(MAKE) .clean_libs $(foreach wrapper,$(wrappers),.clean_$(wrapper) ) + +.clean_libs: + $(MAKE) -C exports clean + +define wrapper_targets +.test_$(1): + $(MAKE) -C $(1) test +.clean_$(1): + $(MAKE) -C $(1) clean +endef + +$(foreach wrapper,$(wrappers),$(eval $(call wrapper_targets,$(wrapper)))) diff --git a/wrappers/EduVpnCommon/src/eduvpncommon/VerifyException.java b/wrappers/EduVpnCommon/src/eduvpncommon/VerifyException.java deleted file mode 100644 index a81aceb..0000000 --- a/wrappers/EduVpnCommon/src/eduvpncommon/VerifyException.java +++ /dev/null @@ -1,5 +0,0 @@ -package eduvpncommon; - -public class VerifyException extends Exception { - //TODO -}
\ No newline at end of file diff --git a/wrappers/EduVpnCommon/tests/eduvpncommon/VerifyTests.java b/wrappers/EduVpnCommon/tests/eduvpncommon/VerifyTests.java deleted file mode 100644 index 117f5ef..0000000 --- a/wrappers/EduVpnCommon/tests/eduvpncommon/VerifyTests.java +++ /dev/null @@ -1,31 +0,0 @@ -package eduvpncommon; - -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; - -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.time.Instant; - -class VerifyTests { - private static final Path testDataDir = Paths.get("../../test_data"); - - @BeforeAll - static void oneTimeSetup() throws IOException { - Discovery.insecureTestingSetExtraKey(Files.lines(testDataDir.resolve("dummy/public.key")).reduce((a, b) -> b).get()); - } - - @Test - void testValid() throws IOException, VerifyException { - Discovery.verify( - Files.readAllBytes(Paths.get("../../test_data/dummy/server_list.json.minisig")), - Files.readAllBytes(Paths.get("../../test_data/dummy/server_list.json")), - "server_list.json", - Instant.EPOCH - ); - } - - //TODO -}
\ No newline at end of file diff --git a/wrappers/java/.gitignore b/wrappers/java/.gitignore new file mode 100644 index 0000000..b83d222 --- /dev/null +++ b/wrappers/java/.gitignore @@ -0,0 +1 @@ +/target/ diff --git a/wrappers/java/Makefile b/wrappers/java/Makefile new file mode 100644 index 0000000..03e7d88 --- /dev/null +++ b/wrappers/java/Makefile @@ -0,0 +1,14 @@ +.PHONY: build pack test clean + +build: + mvn compile + +pack: + mvn package + +test: + $(MAKE) -C ../../exports + mvn test + +clean: + mvn clean diff --git a/wrappers/java/README.md b/wrappers/java/README.md new file mode 100644 index 0000000..87cdd49 --- /dev/null +++ b/wrappers/java/README.md @@ -0,0 +1,31 @@ +# Java wrapper + +## Requirements + +You will need to install JDK 8 or later ([Adoptium](https://adoptium.net/) +or [Oracle](https://www.oracle.com/java/technologies/downloads/)). To easily compile the project, you should +download [Maven](https://maven.apache.org/). + +## Build & test + +First build the shared Go library. Next: + +Build `EduVpnCommon`: + +```shell +make +``` + +Build as JAR, including eduvpn_verify library: + +```shell +make pack +``` + +The JAR will include all versions of the library that are built in the `exports` folder. + +Test: + +```shell +make test +``` diff --git a/wrappers/java/pom.xml b/wrappers/java/pom.xml new file mode 100644 index 0000000..bd9f721 --- /dev/null +++ b/wrappers/java/pom.xml @@ -0,0 +1,102 @@ +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + + <groupId>nl.eduvpn.common</groupId> + <version>0.1.0</version> + <packaging>jar</packaging> + + <artifactId>eduvpncommon</artifactId> + <name>eduVPN common library</name> + + <properties> + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> + <maven.compiler.source>1.8</maven.compiler.source> + <maven.compiler.target>1.8</maven.compiler.target> + </properties> + + <dependencies> + <dependency> + <groupId>net.java.dev.jna</groupId> + <artifactId>jna</artifactId> + <version>5.10.0</version> + </dependency> + <dependency> + <groupId>org.junit.jupiter</groupId> + <artifactId>junit-jupiter-api</artifactId> + <version>5.8.1</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.junit.jupiter</groupId> + <artifactId>junit-jupiter-engine</artifactId> + <version>5.8.1</version> + <scope>test</scope> + </dependency> + </dependencies> + + <build> + <resources> + <!-- See com.sun.jna.Platform#getNativeLibraryResourcePrefix --> + + <resource> + <directory>../../exports/linux/amd64</directory> + <includes> + <include>*.so</include> + </includes> + <targetPath>linux-x86-64</targetPath> + </resource> + <resource> + <directory>../../exports/linux/arm</directory> + <includes> + <include>*.so</include> + </includes> + <targetPath>linux-arm</targetPath> + </resource> + <resource> + <directory>../../exports/linux/arm64</directory> + <includes> + <include>*.so</include> + </includes> + <targetPath>linux-arm64</targetPath> + </resource> + + <resource> + <directory>../../exports/windows/amd64</directory> + <includes> + <include>*.dll</include> + </includes> + <targetPath>win32-x86-64</targetPath> + </resource> + <resource> + <directory>../../exports/windows/386</directory> + <includes> + <include>*.dll</include> + </includes> + <targetPath>win32-x86</targetPath> + </resource> + <resource> + <directory>../../exports/windows/arm</directory> + <includes> + <include>*.dll</include> + </includes> + <targetPath>win32-arm</targetPath> + </resource> + <resource> + <directory>../../exports/windows/arm64</directory> + <includes> + <include>*.dll</include> + </includes> + <targetPath>win32-arm64</targetPath> + </resource> + </resources> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-surefire-plugin</artifactId> + <version>2.22.1</version> + </plugin> + </plugins> + </build> +</project> + diff --git a/wrappers/EduVpnCommon/src/eduvpncommon/Discovery.java b/wrappers/java/src/main/java/nl/eduvpn/common/Discovery.java index 6c27eee..d73a3d2 100644 --- a/wrappers/EduVpnCommon/src/eduvpncommon/Discovery.java +++ b/wrappers/java/src/main/java/nl/eduvpn/common/Discovery.java @@ -1,14 +1,12 @@ -package eduvpncommon; +package nl.eduvpn.common; import com.sun.jna.*; import java.nio.charset.StandardCharsets; import java.time.Instant; -import java.util.*; public class Discovery { - private static final String libName = "eduvpn_verify"; - private static final NativeApi discovery = Native.load(libName, NativeApi.class); + private static final NativeApi discovery = Native.load("eduvpn_verify", NativeApi.class); /** * Verifies the signature on the JSON server_list.json/organization_list.json file. @@ -18,14 +16,17 @@ public class Discovery { * @param signedJson Signed .json file contents. * @param expectedFileName The file type to be verified, one of {@code "server_list.json"} or {@code "organization_list.json"}. * @param minSignTime Minimum time for signature. Should be set to at least the time in a previously retrieved file. - * @throws VerifyException If signature verification fails. + * @throws IllegalArgumentException If {@code expectedFileName} is not one of the allowed values or one of the parameters is empty. + * @throws VerifyException If signature verification fails. */ public static void verify(byte[] signature, byte[] signedJson, String expectedFileName, Instant minSignTime) throws VerifyException { long err = discovery.Verify(NativeApi.GoSlice.make(signature), NativeApi.GoSlice.make(signedJson), NativeApi.GoSlice.make(expectedFileName.getBytes(StandardCharsets.UTF_8)), minSignTime.getEpochSecond()); - if (err != 0) throw new VerifyException(); - //TODO throw new IllegalArgumentException() + if (err != 0) { + if (err == 1) throw new IllegalArgumentException("Unknown excpectedFileName"); + throw new VerifyException(err); + } } /** @@ -37,6 +38,7 @@ public class Discovery { } private interface NativeApi extends Library { + @Structure.FieldOrder({"data", "len", "cap"}) class GoSlice extends Structure implements Structure.ByValue { public Pointer data; public long len, cap; @@ -52,10 +54,6 @@ public class Discovery { memory.write(0, bytes, 0, bytes.length); return new GoSlice(memory, bytes.length, bytes.length); } - - protected List<String> getFieldOrder() { - return Arrays.asList("data", "len", "cap"); - } } long Verify(GoSlice signatureFileContent, GoSlice signedJson, GoSlice expectedFileName, long minSignTime); diff --git a/wrappers/java/src/main/java/nl/eduvpn/common/VerifyException.java b/wrappers/java/src/main/java/nl/eduvpn/common/VerifyException.java new file mode 100644 index 0000000..83dffb1 --- /dev/null +++ b/wrappers/java/src/main/java/nl/eduvpn/common/VerifyException.java @@ -0,0 +1,9 @@ +package nl.eduvpn.common; + +public class VerifyException extends Exception { + public final long code; //TODO not use plain long + + public VerifyException(long code) { + this.code = code; + } +}
\ No newline at end of file diff --git a/wrappers/java/src/test/java/nl/eduvpn/common/VerifyTests.java b/wrappers/java/src/test/java/nl/eduvpn/common/VerifyTests.java new file mode 100644 index 0000000..b4767a5 --- /dev/null +++ b/wrappers/java/src/test/java/nl/eduvpn/common/VerifyTests.java @@ -0,0 +1,78 @@ +package nl.eduvpn.common; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.time.Instant; + +import static org.junit.jupiter.api.Assertions.*; + +class VerifyTests { + private static final Path testDataDir = Paths.get("../../test_data"); + + @SuppressWarnings("OptionalGetWithoutIsPresent") + @BeforeAll + static void oneTimeSetup() throws IOException { + Discovery.insecureTestingSetExtraKey(Files.lines(testDataDir.resolve("dummy/public.key")).reduce((a, b) -> b).get()); + } + + @Test + void testValid() { + assertDoesNotThrow(() -> + Discovery.verify( + Files.readAllBytes(testDataDir.resolve("dummy/server_list.json.minisig")), + Files.readAllBytes(testDataDir.resolve("dummy/server_list.json")), + "server_list.json", + Instant.EPOCH + )); + } + + @Test + void testInvalidSignature() { + Assertions.assertEquals(2, assertThrows(VerifyException.class, () -> + Discovery.verify( + Files.readAllBytes(testDataDir.resolve("dummy/random.txt")), + Files.readAllBytes(testDataDir.resolve("dummy/server_list.json")), + "server_list.json", + Instant.EPOCH + )).code); + } + + @Test + void testWrongKey() { + assertEquals(3, assertThrows(VerifyException.class, () -> + Discovery.verify( + Files.readAllBytes(testDataDir.resolve("dummy/server_list.json.wrong_key.minisig")), + Files.readAllBytes(testDataDir.resolve("dummy/server_list.json")), + "server_list.json", + Instant.EPOCH + )).code); + } + + @Test + void testOldSignature() { + assertEquals(4, assertThrows(VerifyException.class, () -> + Discovery.verify( + Files.readAllBytes(testDataDir.resolve("dummy/server_list.json.minisig")), + Files.readAllBytes(testDataDir.resolve("dummy/server_list.json")), + "server_list.json", + Instant.MAX + )).code); + } + + @Test + void testUnknownExpectedFile() { + assertThrows(IllegalArgumentException.class, () -> + Discovery.verify( + Files.readAllBytes(testDataDir.resolve("dummy/other_list.json.minisig")), + Files.readAllBytes(testDataDir.resolve("dummy/other_list.json")), + "other_list.json", + Instant.EPOCH + )); + } +}
\ No newline at end of file diff --git a/wrappers/python/Makefile b/wrappers/python/Makefile index 77c620e..690901f 100644 --- a/wrappers/python/Makefile +++ b/wrappers/python/Makefile @@ -6,3 +6,6 @@ compile: test: $(MAKE) -C ../../exports python3 -m unittest test_discovery + +clean: + # Nothing to do |
