summaryrefslogtreecommitdiff
path: root/wrappers
diff options
context:
space:
mode:
authorStevenWdV <stevenwdv@gmail.com>2022-01-24 14:59:25 +0100
committerStevenWdV <stevenwdv@gmail.com>2022-01-24 16:24:57 +0100
commite544c6fa9e15e7277da79e2464243e90b2706b8c (patch)
treede6613747e0e34a799089d4677f9833a85748712 /wrappers
parentaab2e4b966c82b67eb0e204060e5ea6cd4ea15cf (diff)
Cleanup
Added variables to Makefiles to specify custom exports/ directory; Split exception classes in Java & C#; Added more comments; Renamed library and Go package; Removed real (pure) tests; Added generate_lib.ps1 to generate import .lib for Windows (Swift); Moved built Go libraries to exports/lib/; Switch to hopefully faster Swift GitHub Action.
Diffstat (limited to 'wrappers')
-rw-r--r--wrappers/csharp/Discovery.cs86
-rw-r--r--wrappers/csharp/EduVpnCommon.csproj57
-rw-r--r--wrappers/csharp/EduVpnCommon.props7
-rw-r--r--wrappers/csharp/EduVpnCommonTests/VerifyTests.cs27
-rw-r--r--wrappers/csharp/Makefile10
-rw-r--r--wrappers/csharp/README.md15
-rw-r--r--wrappers/java/Makefile15
-rw-r--r--wrappers/java/README.md2
-rw-r--r--wrappers/java/pom.xml24
-rw-r--r--wrappers/java/src/main/java/nl/eduvpn/common/Discovery.java47
-rw-r--r--wrappers/java/src/main/java/nl/eduvpn/common/InvalidSignatureException.java8
-rw-r--r--wrappers/java/src/main/java/nl/eduvpn/common/InvalidSignatureUnknownKeyException.java8
-rw-r--r--wrappers/java/src/main/java/nl/eduvpn/common/SignatureTooOldException.java8
-rw-r--r--wrappers/java/src/main/java/nl/eduvpn/common/UnknownVerifyException.java9
-rw-r--r--wrappers/java/src/main/java/nl/eduvpn/common/VerifyException.java11
-rw-r--r--wrappers/java/src/test/java/nl/eduvpn/common/VerifyTests.java37
-rw-r--r--wrappers/php/.gitignore1
-rw-r--r--wrappers/php/Makefile38
-rw-r--r--wrappers/php/README.md6
-rw-r--r--wrappers/php/src/Discovery.php10
-rw-r--r--wrappers/php/src/SignatureTooOldException.php2
-rw-r--r--wrappers/php/tests/DiscoveryTest.php22
-rw-r--r--wrappers/python/Makefile16
-rw-r--r--wrappers/python/README.md15
-rw-r--r--wrappers/python/eduvpncommon/discovery.py31
-rwxr-xr-xwrappers/python/setup.py25
-rwxr-xr-xwrappers/python/test_discovery.py26
-rw-r--r--wrappers/swift/CEduVpnCommon/Sources/CEduVpnCommon/module.modulemap4
-rw-r--r--wrappers/swift/Makefile33
-rw-r--r--wrappers/swift/README.md20
-rw-r--r--wrappers/swift/Sources/EduVpnCommon/EduVpnCommon.swift8
-rw-r--r--wrappers/swift/Tests/EduVpnCommonTests/EduVpnCommonTests.swift22
-rwxr-xr-xwrappers/swift/swift.cmd2
33 files changed, 421 insertions, 231 deletions
diff --git a/wrappers/csharp/Discovery.cs b/wrappers/csharp/Discovery.cs
index 183d94f..da4a6ea 100644
--- a/wrappers/csharp/Discovery.cs
+++ b/wrappers/csharp/Discovery.cs
@@ -1,8 +1,10 @@
using System;
+using System.Diagnostics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Text;
+// Make InsecureTestingSetExtraKey visible to tests
[assembly: InternalsVisibleTo("EduVpnCommonTests")]
namespace EduVpnCommon
@@ -11,12 +13,12 @@ namespace EduVpnCommon
{
/// <summary>
/// Verifies the signature on the JSON server_list.json/organization_list.json file.
- /// If the function returns the signature is valid for the given file type.
+ /// If the function returns, the signature is valid for the given file type.
/// </summary>
/// <param name="signatureFileContent">.minisig signature file contents.</param>
/// <param name="signedJson">Signed .json file contents.</param>
/// <param name="expectedFileName">The file type to be verified, one of <c>"server_list.json"</c> or <c>"organization_list.json"</c>.</param>
- /// <param name="minSignTime">Minimum time for signature. Should be set to at least the time in a previously retrieved file.</param>
+ /// <param name="minSignTime">Minimum time for signature. Should be set to at least the time of the previous signature.</param>
/// <exception cref="ArgumentException">If <c>expectedFileName</c> is not one of the allowed values.</exception>
/// <exception cref="VerifyException">If signature verification fails.</exception>
public static void Verify(
@@ -35,11 +37,20 @@ namespace EduVpnCommon
(ulong) minSignTime.ToUnixTimeSeconds());
}
- if (result != VerifyReturnCode.Ok)
+ switch (result)
{
- if (result == VerifyReturnCode.ErrUnknownExpectedFileName)
- throw new ArgumentException("unknown name", nameof(expectedFileName));
- throw new VerifyException((VerifyErrorCode) result);
+ case VerifyReturnCode.Ok:
+ return;
+ case VerifyReturnCode.ErrUnknownExpectedFileName:
+ throw new ArgumentException("unknown expected file name", nameof(expectedFileName));
+ case VerifyReturnCode.ErrInvalidSignature:
+ throw new InvalidSignatureException();
+ case VerifyReturnCode.ErrInvalidSignatureUnknownKey:
+ throw new InvalidSignatureUnknownKeyException();
+ case VerifyReturnCode.ErrTooOld:
+ throw new SignatureTooOldException();
+ default:
+ throw new UnknownVerifyException((sbyte) result);
}
}
@@ -50,13 +61,17 @@ namespace EduVpnCommon
InsecureTestingSetExtraKey(keyHandle.Slice);
}
- const string VerifyLibName = "eduvpn_verify";
+ const string LibName = "eduvpn_common";
- [DllImport(VerifyLibName)]
+ [DllImport(LibName)]
static extern VerifyReturnCode Verify(GoSlice signatureFileContent, GoSlice signedJson, GoSlice expectedFileName, ulong minSignTime);
- [DllImport(VerifyLibName)] static extern void InsecureTestingSetExtraKey(GoSlice keyStr);
+ [DllImport(LibName)] static extern void InsecureTestingSetExtraKey(GoSlice keyStr);
+ /// <summary>
+ /// Safe auto-disposing Go slice handle.
+ /// Non-copying alternative to `Marshal.AllocHGlobal` etc.
+ /// </summary>
class GoSliceHandle : IDisposable
{
GCHandle gcHandle_;
@@ -68,6 +83,7 @@ namespace EduVpnCommon
GoSliceHandle(Array array, int offset, int count)
{
+ Debug.Assert(offset <= array.Length && /*prevent overflow:*/ count <= array.Length && offset <= array.Length - count);
gcHandle_ = GCHandle.Alloc(array, GCHandleType.Pinned);
var elemSize = Marshal.SizeOf(array.GetType().GetElementType()!);
slice_ = new GoSlice(gcHandle_.AddrOfPinnedObject() + offset * elemSize, count * elemSize);
@@ -76,12 +92,14 @@ namespace EduVpnCommon
public static GoSliceHandle FromArray<T>(ArraySegment<T> segment) where T : struct =>
new GoSliceHandle(segment.Array!, segment.Offset, segment.Count);
+ /// <summary>From string as UTF-8.</summary>
public static GoSliceHandle FromString(string str) =>
FromArray(new ArraySegment<byte>(Encoding.UTF8.GetBytes(str)));
public void Dispose() => gcHandle_.Free();
}
+ // C-compatible structure
readonly struct GoSlice
{
readonly IntPtr data_;
@@ -98,38 +116,42 @@ namespace EduVpnCommon
}
}
- public class VerifyException : Exception
+ /// <summary>Verification failed, do not trust the file.</summary>
+ public abstract class VerifyException : Exception
{
- public VerifyErrorCode Code { get; }
-
- internal VerifyException(VerifyErrorCode code) : base(GetMessage(code)) => Code = code;
+ protected VerifyException(string message) : base(message) { }
+ }
- static string GetMessage(VerifyErrorCode code) => code switch
- {
- VerifyErrorCode.ErrInvalidSignature => "invalid signature",
- VerifyErrorCode.ErrInvalidSignatureUnknownKey => "invalid signature (unknown key)",
- VerifyErrorCode.ErrTooOld => "replay of previous signature (rollback)",
- _ => $"unknown verify error ({code})"
- };
+ /// <summary>Signature is invalid (for the expected file type).</summary>
+ public sealed class InvalidSignatureException : VerifyException
+ {
+ public InvalidSignatureException() : base("invalid signature") { }
}
- public enum VerifyErrorCode
+ /// <summary>Signature was created with an unknown key and has not been verified.</summary>
+ public sealed class InvalidSignatureUnknownKeyException : VerifyException
{
- /// <summary>Signature is invalid (for the expected file type).</summary>
- ErrInvalidSignature = VerifyReturnCode.ErrUnknownExpectedFileName + 1,
+ public InvalidSignatureUnknownKeyException() : base("invalid signature (unknown key)") { }
+ }
- /// <summary>Signature was created with an unknown key and has not been verified.</summary>
- ErrInvalidSignatureUnknownKey,
+ /// <summary>Signature timestamp smaller than specified minimum signing time (rollback).</summary>
+ public sealed class SignatureTooOldException : VerifyException
+ {
+ public SignatureTooOldException() : base("replay of previous signature (rollback)") { }
+ }
- /// <summary>Signature has a timestamp lower than the specified minimum signing time.</summary>
- ErrTooOld
+ /// <summary>Other unknown error.</summary>
+ public sealed class UnknownVerifyException : VerifyException
+ {
+ public UnknownVerifyException(sbyte code) : base($"unknown verify error ({code})") => Debug.Assert(code != 0);
}
- enum VerifyReturnCode
+ enum VerifyReturnCode : sbyte
{
Ok,
- ErrUnknownExpectedFileName
-
- //...
+ ErrUnknownExpectedFileName,
+ ErrInvalidSignature,
+ ErrInvalidSignatureUnknownKey,
+ ErrTooOld
}
-} \ No newline at end of file
+}
diff --git a/wrappers/csharp/EduVpnCommon.csproj b/wrappers/csharp/EduVpnCommon.csproj
index 4643da2..587601c 100644
--- a/wrappers/csharp/EduVpnCommon.csproj
+++ b/wrappers/csharp/EduVpnCommon.csproj
@@ -1,4 +1,4 @@
-<Project Sdk="Microsoft.NET.Sdk">
+<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
@@ -13,58 +13,59 @@
<ItemGroup>
<Compile Remove="EduVpnCommonTests/**" />
- </ItemGroup>
-
- <ItemGroup>
<EmbeddedResource Remove="EduVpnCommonTests/**" />
+ <None Remove="EduVpnCommonTests/**" />
</ItemGroup>
+ <!-- Include EXPORTS_LIB_PATH, LIB_NAME definitions -->
+ <ImportGroup Label="PropertySheets">
+ <Import Project="EduVpnCommon.props" />
+ </ImportGroup>
+
<Target Name="Build library for current OS" BeforeTargets="PrepareForBuild"
- Condition="!(Exists('../../exports/windows/amd64/eduvpn_verify.dll')
- Or Exists('../../exports/windows/386/eduvpn_verify.dll')
- Or Exists('../../exports/windows/arm/eduvpn_verify.dll')
- Or Exists('../../exports/windows/arm64/eduvpn_verify.dll')
- Or Exists('../../exports/linux/amd64/libeduvpn_verify.so')
- Or Exists('../../exports/linux/arm/libeduvpn_verify.so')
- Or Exists('../../exports/linux/arm64/libeduvpn_verify.so'))">
- <Message Text="Shared eduvpn_verify library not found, you should build that one first" Importance="high" />
+ Condition="!(Exists('$(EXPORTS_LIB_PATH)/windows/amd64/$(LIB_NAME).dll')
+ Or Exists('$(EXPORTS_LIB_PATH)/windows/386/$(LIB_NAME).dll')
+ Or Exists('$(EXPORTS_LIB_PATH)/windows/arm/$(LIB_NAME).dll')
+ Or Exists('$(EXPORTS_LIB_PATH)/windows/arm64/$(LIB_NAME).dll')
+ Or Exists('$(EXPORTS_LIB_PATH)/linux/amd64/lib$(LIB_NAME).so')
+ Or Exists('$(EXPORTS_LIB_PATH)/linux/arm/lib$(LIB_NAME).so')
+ Or Exists('$(EXPORTS_LIB_PATH)/linux/arm64/lib$(LIB_NAME).so'))">
+ <Message Text="!! Shared $(LIB_NAME) library not found, you should build that one first" Importance="high" />
</Target>
<ItemGroup>
- <None Remove="EduVpnCommonTests/**" />
-
<!--
See https://docs.microsoft.com/en-us/nuget/create-packages/supporting-multiple-target-frameworks#architecture-specific-folders
and https://docs.microsoft.com/en-us/dotnet/core/rid-catalog
-->
- <None Condition="Exists('../../exports/windows/amd64/eduvpn_verify.dll')"
- Include="../../exports/windows/amd64/eduvpn_verify.dll" Pack="true" PackagePath="runtimes/win-x64/native/">
+ <None Condition="Exists('$(EXPORTS_LIB_PATH)/windows/amd64/$(LIB_NAME).dll')"
+ Include="$(EXPORTS_LIB_PATH)/windows/amd64/$(LIB_NAME).dll" Pack="true" PackagePath="runtimes/win-x64/native/">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
- <None Condition="Exists('../../exports/windows/386/eduvpn_verify.dll')"
- Include="../../exports/windows/386/eduvpn_verify.dll" Pack="true" PackagePath="runtimes/win-x86/native/">
+ <None Condition="Exists('$(EXPORTS_LIB_PATH)/windows/386/$(LIB_NAME).dll')"
+ Include="$(EXPORTS_LIB_PATH)/windows/386/$(LIB_NAME).dll" Pack="true" PackagePath="runtimes/win-x86/native/">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
- <None Condition="Exists('../../exports/windows/arm/eduvpn_verify.dll')"
- Include="../../exports/windows/arm/eduvpn_verify.dll" Pack="true" PackagePath="runtimes/win-arm/native/">
+ <None Condition="Exists('$(EXPORTS_LIB_PATH)/windows/arm/$(LIB_NAME).dll')"
+ Include="$(EXPORTS_LIB_PATH)/windows/arm/$(LIB_NAME).dll" Pack="true" PackagePath="runtimes/win-arm/native/">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
- <None Condition="Exists('../../exports/windows/arm64/eduvpn_verify.dll')"
- Include="../../exports/windows/arm64/eduvpn_verify.dll" Pack="true" PackagePath="runtimes/win-arm64/native/">
+ <None Condition="Exists('$(EXPORTS_LIB_PATH)/windows/arm64/$(LIB_NAME).dll')"
+ Include="$(EXPORTS_LIB_PATH)/windows/arm64/$(LIB_NAME).dll" Pack="true" PackagePath="runtimes/win-arm64/native/">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
- <None Condition="Exists('../../exports/linux/amd64/libeduvpn_verify.so')"
- Include="../../exports/linux/amd64/libeduvpn_verify.so" Pack="true" PackagePath="runtimes/linux-x64/native/">
+ <None Condition="Exists('$(EXPORTS_LIB_PATH)/linux/amd64/lib$(LIB_NAME).so')"
+ Include="$(EXPORTS_LIB_PATH)/linux/amd64/lib$(LIB_NAME).so" Pack="true" PackagePath="runtimes/linux-x64/native/">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
- <None Condition="Exists('../../exports/linux/arm/libeduvpn_verify.so')"
- Include="../../exports/linux/arm/libeduvpn_verify.so" Pack="true" PackagePath="runtimes/linux-arm/native/">
+ <None Condition="Exists('$(EXPORTS_LIB_PATH)/linux/arm/lib$(LIB_NAME).so')"
+ Include="$(EXPORTS_LIB_PATH)/linux/arm/lib$(LIB_NAME).so" Pack="true" PackagePath="runtimes/linux-arm/native/">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
- <None Condition="Exists('../../exports/linux/arm64/libeduvpn_verify.so')"
- Include="../../exports/linux/arm64/libeduvpn_verify.so" Pack="true" PackagePath="runtimes/linux-arm64/native/">
+ <None Condition="Exists('$(EXPORTS_LIB_PATH)/linux/arm64/lib$(LIB_NAME).so')"
+ Include="$(EXPORTS_LIB_PATH)/linux/arm64/lib$(LIB_NAME).so" Pack="true" PackagePath="runtimes/linux-arm64/native/">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup>
diff --git a/wrappers/csharp/EduVpnCommon.props b/wrappers/csharp/EduVpnCommon.props
new file mode 100644
index 0000000..97c2289
--- /dev/null
+++ b/wrappers/csharp/EduVpnCommon.props
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <EXPORTS_LIB_PATH Condition="'$(EXPORTS_LIB_PATH)' == ''">$(SolutionDir)../../exports/lib</EXPORTS_LIB_PATH>
+ <LIB_NAME Condition="'$(LIB_NAME)' == ''">eduvpn_common</LIB_NAME>
+ </PropertyGroup>
+</Project>
diff --git a/wrappers/csharp/EduVpnCommonTests/VerifyTests.cs b/wrappers/csharp/EduVpnCommonTests/VerifyTests.cs
index 41faf87..2d4a565 100644
--- a/wrappers/csharp/EduVpnCommonTests/VerifyTests.cs
+++ b/wrappers/csharp/EduVpnCommonTests/VerifyTests.cs
@@ -14,11 +14,11 @@ namespace EduVpnCommonTests
[OneTimeSetUp]
public void OneTimeSetUp() =>
- Discovery.InsecureTestingSetExtraKey(File.ReadLines($"{testDataDir_}/dummy/public.key").Last());
+ Discovery.InsecureTestingSetExtraKey(File.ReadLines($"{testDataDir_}/public.key").Last());
[Test]
- [TestCase("dummy/server_list.json.minisig", "dummy/server_list.json", "server_list.json")]
- [TestCase("dummy/organization_list.json.minisig", "dummy/organization_list.json", "organization_list.json")]
+ [TestCase("server_list.json.minisig", "server_list.json", "server_list.json")]
+ [TestCase("organization_list.json.minisig", "organization_list.json", "organization_list.json")]
public void TestValid(string sigFile, string jsonFile, string expectedFileName) =>
Discovery.Verify(
File.ReadAllBytes($"{testDataDir_}/{sigFile}"),
@@ -27,7 +27,7 @@ namespace EduVpnCommonTests
DateTimeOffset.UnixEpoch);
[Test]
- [TestCase("dummy/server_list.json.minisig", "dummy/server_list.json", "server_list.json")]
+ [TestCase("server_list.json.minisig", "server_list.json", "server_list.json")]
public void TestValidSegment(string sigFile, string jsonFile, string expectedFileName)
{
var bytes = new byte[] { 1, 2, 3 }.Concat(File.ReadAllBytes($"{testDataDir_}/{jsonFile}"))
@@ -40,10 +40,9 @@ namespace EduVpnCommonTests
}
[Test]
- [TestCase("dummy/random.txt", "dummy/server_list.json", "server_list.json")]
+ [TestCase("random.txt", "server_list.json", "server_list.json")]
public void TestInvalidSignature(string sigFile, string jsonFile, string expectedFileName) =>
- Assert.Throws(Is.TypeOf<VerifyException>()
- .And.Property(nameof(VerifyException.Code)).EqualTo(VerifyErrorCode.ErrInvalidSignature),
+ Assert.Throws<InvalidSignatureException>(
() => Discovery.Verify(
File.ReadAllBytes($"{testDataDir_}/{sigFile}"),
File.ReadAllBytes($"{testDataDir_}/{jsonFile}"),
@@ -51,10 +50,9 @@ namespace EduVpnCommonTests
DateTimeOffset.UnixEpoch));
[Test]
- [TestCase("dummy/server_list.json.wrong_key.minisig", "dummy/server_list.json", "server_list.json")]
+ [TestCase("server_list.json.wrong_key.minisig", "server_list.json", "server_list.json")]
public void TestWrongKey(string sigFile, string jsonFile, string expectedFileName) =>
- Assert.Throws(Is.TypeOf<VerifyException>()
- .And.Property(nameof(VerifyException.Code)).EqualTo(VerifyErrorCode.ErrInvalidSignatureUnknownKey),
+ Assert.Throws<InvalidSignatureUnknownKeyException>(
() => Discovery.Verify(
File.ReadAllBytes($"{testDataDir_}/{sigFile}"),
File.ReadAllBytes($"{testDataDir_}/{jsonFile}"),
@@ -62,10 +60,9 @@ namespace EduVpnCommonTests
DateTimeOffset.UnixEpoch));
[Test]
- [TestCase("dummy/server_list.json.minisig", "dummy/server_list.json", "server_list.json")]
+ [TestCase("server_list.json.minisig", "server_list.json", "server_list.json")]
public void TestOldSignature(string sigFile, string jsonFile, string expectedFileName) =>
- Assert.Throws(Is.TypeOf<VerifyException>()
- .And.Property(nameof(VerifyException.Code)).EqualTo(VerifyErrorCode.ErrTooOld),
+ Assert.Throws<SignatureTooOldException>(
() => Discovery.Verify(
File.ReadAllBytes($"{testDataDir_}/{sigFile}"),
File.ReadAllBytes($"{testDataDir_}/{jsonFile}"),
@@ -73,7 +70,7 @@ namespace EduVpnCommonTests
DateTimeOffset.MaxValue));
[Test]
- [TestCase("dummy/other_list.json.minisig", "dummy/other_list.json", "other_list.json")]
+ [TestCase("other_list.json.minisig", "other_list.json", "other_list.json")]
public void TestUnknownExpectedFile(string sigFile, string jsonFile, string expectedFileName) =>
Assert.Throws<ArgumentException>(
() => Discovery.Verify(
@@ -82,4 +79,4 @@ namespace EduVpnCommonTests
expectedFileName,
DateTimeOffset.UnixEpoch));
}
-} \ No newline at end of file
+}
diff --git a/wrappers/csharp/Makefile b/wrappers/csharp/Makefile
index 1761edc..29f9682 100644
--- a/wrappers/csharp/Makefile
+++ b/wrappers/csharp/Makefile
@@ -1,5 +1,9 @@
.PHONY: build pack test clean
+EXPORTS_PATH ?= ../../exports
+# Export, see EduVpnCommon.props
+export EXPORTS_LIB_PATH ?= $(EXPORTS_PATH)/lib
+
build:
dotnet publish EduVpnCommon.csproj --configuration Release
@@ -7,7 +11,11 @@ pack:
dotnet pack EduVpnCommon.csproj --configuration Release
test:
- $(MAKE) -C ../../exports
+ifneq ($(EXPORTS_PATH),)
+ifneq ($(wildcard $(EXPORTS_PATH)/Makefile),)
+ $(MAKE) -C "$(EXPORTS_PATH)"
+endif
+endif
dotnet test
clean:
diff --git a/wrappers/csharp/README.md b/wrappers/csharp/README.md
index d4d1d97..32d2330 100644
--- a/wrappers/csharp/README.md
+++ b/wrappers/csharp/README.md
@@ -3,33 +3,38 @@
## Requirements
You will need to install the [.NET SDK](https://dotnet.microsoft.com/download), which includes the `dotnet` tool. The
-wrapper targets .NET Standard 2.0, so which means that at least .NET Core 2.0 is required (.NET 5+ is also fine). For
-the tests, .NET 5 or newer is required.
+wrapper targets .NET Standard 2.0, which means that at least .NET Core 2.0 is required (.NET 5+ is also fine). For the
+tests, .NET 5 is required.
## Build & test
First build the shared Go library. Next:
-Build `EduVpnCommon`:
+Build `EduVpnCommon` (Release):
```shell
make
```
-Build as nupkg, including eduvpn_verify library:
+Build as nupkg, including shared Go library for all platforms built in `exports/lib/`:
```shell
make pack
```
+If you do not build this as part of the full repository, specify `EXPORTS_PATH="" EXPORTS_LIB_PATH="path/to/lib-folder"`
+when calling make.
+
The wrapper targets .NET Standard 2.0, which means that it can be referenced by projects using either .NET Framework
4.6.1+, .NET Core 2.0+, or .NET 5+.
Currently, directly referencing the project may not work (with `System.BadImageFormatException`) if you have multiple
-dynamic libraries compiled in the `exports` folder. If you instead add the `.nupkg`, e.g. with one of the
+dynamic libraries compiled in the `exports/lib/` folder. If you instead add the `.nupkg`, e.g. with one of the
methods [here](https://stackoverflow.com/q/43400069) or [here](https://stackoverflow.com/q/10240029), it automatically
copies the correct library.
+This also means that tests may fail if you have multiple dynamic libraries compiled!
+
Test:
```shell
diff --git a/wrappers/java/Makefile b/wrappers/java/Makefile
index 4b7b602..a63aef7 100644
--- a/wrappers/java/Makefile
+++ b/wrappers/java/Makefile
@@ -1,14 +1,21 @@
.PHONY: build pack test clean
+EXPORTS_PATH ?= ../../exports
+EXPORTS_LIB_PATH ?= $(EXPORTS_PATH)/lib
+
build:
- mvn --no-transfer-progress compile
+ mvn --no-transfer-progress compile -DEXPORTS_LIB_PATH="$(EXPORTS_LIB_PATH)"
pack:
- mvn --no-transfer-progress package
+ mvn --no-transfer-progress package -DEXPORTS_LIB_PATH="$(EXPORTS_LIB_PATH)"
test:
- $(MAKE) -C ../../exports
- mvn --no-transfer-progress test
+ifneq ($(EXPORTS_PATH),)
+ifneq ($(wildcard $(EXPORTS_PATH)/Makefile),)
+ $(MAKE) -C "$(EXPORTS_PATH)"
+endif
+endif
+ mvn --no-transfer-progress test -DEXPORTS_LIB_PATH="$(EXPORTS_LIB_PATH)"
clean:
rm -rf target/
diff --git a/wrappers/java/README.md b/wrappers/java/README.md
index 87cdd49..b72d90e 100644
--- a/wrappers/java/README.md
+++ b/wrappers/java/README.md
@@ -16,7 +16,7 @@ Build `EduVpnCommon`:
make
```
-Build as JAR, including eduvpn_verify library:
+Build as JAR, including shared Go library:
```shell
make pack
diff --git a/wrappers/java/pom.xml b/wrappers/java/pom.xml
index bd9f721..520bd34 100644
--- a/wrappers/java/pom.xml
+++ b/wrappers/java/pom.xml
@@ -10,9 +10,11 @@
<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>
+ <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+ <maven.compiler.source>1.8</maven.compiler.source>
+ <maven.compiler.target>1.8</maven.compiler.target>
+
+ <EXPORTS_LIB_PATH>../../exports/lib</EXPORTS_LIB_PATH>
</properties>
<dependencies>
@@ -40,21 +42,21 @@
<!-- See com.sun.jna.Platform#getNativeLibraryResourcePrefix -->
<resource>
- <directory>../../exports/linux/amd64</directory>
+ <directory>${EXPORTS_LIB_PATH}/linux/amd64</directory>
<includes>
<include>*.so</include>
</includes>
<targetPath>linux-x86-64</targetPath>
</resource>
<resource>
- <directory>../../exports/linux/arm</directory>
+ <directory>${EXPORTS_LIB_PATH}/linux/arm</directory>
<includes>
<include>*.so</include>
</includes>
<targetPath>linux-arm</targetPath>
</resource>
<resource>
- <directory>../../exports/linux/arm64</directory>
+ <directory>${EXPORTS_LIB_PATH}/linux/arm64</directory>
<includes>
<include>*.so</include>
</includes>
@@ -62,36 +64,38 @@
</resource>
<resource>
- <directory>../../exports/windows/amd64</directory>
+ <directory>${EXPORTS_LIB_PATH}/windows/amd64</directory>
<includes>
<include>*.dll</include>
</includes>
<targetPath>win32-x86-64</targetPath>
</resource>
<resource>
- <directory>../../exports/windows/386</directory>
+ <directory>${EXPORTS_LIB_PATH}/windows/386</directory>
<includes>
<include>*.dll</include>
</includes>
<targetPath>win32-x86</targetPath>
</resource>
<resource>
- <directory>../../exports/windows/arm</directory>
+ <directory>${EXPORTS_LIB_PATH}/windows/arm</directory>
<includes>
<include>*.dll</include>
</includes>
<targetPath>win32-arm</targetPath>
</resource>
<resource>
- <directory>../../exports/windows/arm64</directory>
+ <directory>${EXPORTS_LIB_PATH}/windows/arm64</directory>
<includes>
<include>*.dll</include>
</includes>
<targetPath>win32-arm64</targetPath>
</resource>
</resources>
+
<plugins>
<plugin>
+ <!-- Test adapter -->
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.1</version>
diff --git a/wrappers/java/src/main/java/nl/eduvpn/common/Discovery.java b/wrappers/java/src/main/java/nl/eduvpn/common/Discovery.java
index 40d5300..69308c8 100644
--- a/wrappers/java/src/main/java/nl/eduvpn/common/Discovery.java
+++ b/wrappers/java/src/main/java/nl/eduvpn/common/Discovery.java
@@ -6,38 +6,48 @@ import java.nio.charset.StandardCharsets;
import java.time.Instant;
public final class Discovery {
- private static final NativeApi discovery = Native.load("eduvpn_verify", NativeApi.class);
+ private static final String LIB_NAME = "eduvpn_common";
+ private static final NativeApi discovery = Native.load(LIB_NAME, NativeApi.class);
/**
* Verifies the signature on the JSON server_list.json/organization_list.json file.
- * If the function returns the signature is valid for the given file type.
+ * If the function returns, the signature is valid for the given file type.
*
* @param signature .minisig signature file contents.
* @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.
+ * @param minSignTime Minimum time for signature. Should be set to at least the time of the previous signature.
* @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) {
- if (err == 1) throw new IllegalArgumentException("Unknown excpectedFileName");
- throw new VerifyException(err);
+ byte err = discovery.Verify(NativeApi.GoSlice.fromArray(signature), NativeApi.GoSlice.fromArray(signedJson),
+ NativeApi.GoSlice.fromString(expectedFileName), minSignTime.getEpochSecond());
+
+ switch (err) {
+ case 0:
+ return;
+ case 1:
+ throw new IllegalArgumentException("unknown expected file name");
+ case 2:
+ throw new InvalidSignatureException();
+ case 3:
+ throw new InvalidSignatureUnknownKeyException();
+ case 4:
+ throw new SignatureTooOldException();
+ default:
+ throw new UnknownVerifyException(err);
}
}
- /**
- * Use for testing only, see Go documentation.
- */
- // package-private
+ /** Use for testing only, see Go documentation. */
+ /*package-private*/
static void insecureTestingSetExtraKey(String keyString) {
- discovery.InsecureTestingSetExtraKey(NativeApi.GoSlice.make(keyString.getBytes(StandardCharsets.UTF_8)));
+ discovery.InsecureTestingSetExtraKey(NativeApi.GoSlice.fromArray(keyString.getBytes(StandardCharsets.UTF_8)));
}
private interface NativeApi extends Library {
+ // C-compatible structure
@Structure.FieldOrder({"data", "len", "cap"})
class GoSlice extends Structure implements Structure.ByValue {
public Pointer data;
@@ -49,14 +59,19 @@ public final class Discovery {
this.cap = cap;
}
- public static GoSlice make(byte[] bytes) {
+ public static GoSlice fromArray(byte[] bytes) {
Memory memory = new Memory(bytes.length);
memory.write(0, bytes, 0, bytes.length);
return new GoSlice(memory, bytes.length, bytes.length);
}
+
+ /** From string as UTF-8. */
+ public static GoSlice fromString(String str) {
+ return fromArray(str.getBytes(StandardCharsets.UTF_8));
+ }
}
- long Verify(GoSlice signatureFileContent, GoSlice signedJson, GoSlice expectedFileName, long minSignTime);
+ byte Verify(GoSlice signatureFileContent, GoSlice signedJson, GoSlice expectedFileName, long minSignTime);
void InsecureTestingSetExtraKey(GoSlice keyString);
}
diff --git a/wrappers/java/src/main/java/nl/eduvpn/common/InvalidSignatureException.java b/wrappers/java/src/main/java/nl/eduvpn/common/InvalidSignatureException.java
new file mode 100644
index 0000000..e531206
--- /dev/null
+++ b/wrappers/java/src/main/java/nl/eduvpn/common/InvalidSignatureException.java
@@ -0,0 +1,8 @@
+package nl.eduvpn.common;
+
+/** Signature is invalid (for the expected file type). */
+public final class InvalidSignatureException extends VerifyException {
+ public InvalidSignatureException() {
+ super("invalid signature");
+ }
+}
diff --git a/wrappers/java/src/main/java/nl/eduvpn/common/InvalidSignatureUnknownKeyException.java b/wrappers/java/src/main/java/nl/eduvpn/common/InvalidSignatureUnknownKeyException.java
new file mode 100644
index 0000000..8eaf661
--- /dev/null
+++ b/wrappers/java/src/main/java/nl/eduvpn/common/InvalidSignatureUnknownKeyException.java
@@ -0,0 +1,8 @@
+package nl.eduvpn.common;
+
+/** Signature was created with an unknown key and has not been verified. */
+public final class InvalidSignatureUnknownKeyException extends VerifyException {
+ public InvalidSignatureUnknownKeyException() {
+ super("invalid signature (unknown key)");
+ }
+}
diff --git a/wrappers/java/src/main/java/nl/eduvpn/common/SignatureTooOldException.java b/wrappers/java/src/main/java/nl/eduvpn/common/SignatureTooOldException.java
new file mode 100644
index 0000000..c40c718
--- /dev/null
+++ b/wrappers/java/src/main/java/nl/eduvpn/common/SignatureTooOldException.java
@@ -0,0 +1,8 @@
+package nl.eduvpn.common;
+
+/** Signature timestamp smaller than specified minimum signing time (rollback). */
+public final class SignatureTooOldException extends VerifyException {
+ public SignatureTooOldException() {
+ super("replay of previous signature (rollback)");
+ }
+}
diff --git a/wrappers/java/src/main/java/nl/eduvpn/common/UnknownVerifyException.java b/wrappers/java/src/main/java/nl/eduvpn/common/UnknownVerifyException.java
new file mode 100644
index 0000000..fa76a44
--- /dev/null
+++ b/wrappers/java/src/main/java/nl/eduvpn/common/UnknownVerifyException.java
@@ -0,0 +1,9 @@
+package nl.eduvpn.common;
+
+/** Other unknown error. */
+public final class UnknownVerifyException extends VerifyException {
+ public UnknownVerifyException(byte code) {
+ super(String.format("unknown verify error (%d)", code));
+ assert code != 0;
+ }
+}
diff --git a/wrappers/java/src/main/java/nl/eduvpn/common/VerifyException.java b/wrappers/java/src/main/java/nl/eduvpn/common/VerifyException.java
index 83dffb1..71ea290 100644
--- a/wrappers/java/src/main/java/nl/eduvpn/common/VerifyException.java
+++ b/wrappers/java/src/main/java/nl/eduvpn/common/VerifyException.java
@@ -1,9 +1,8 @@
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;
+/** Verification failed, do not trust the file. */
+public abstract class VerifyException extends Exception {
+ protected VerifyException(String message) {
+ super(message);
}
-} \ 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
index b4767a5..a82c019 100644
--- a/wrappers/java/src/test/java/nl/eduvpn/common/VerifyTests.java
+++ b/wrappers/java/src/test/java/nl/eduvpn/common/VerifyTests.java
@@ -1,6 +1,5 @@
package nl.eduvpn.common;
-import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
@@ -18,15 +17,15 @@ class VerifyTests {
@SuppressWarnings("OptionalGetWithoutIsPresent")
@BeforeAll
static void oneTimeSetup() throws IOException {
- Discovery.insecureTestingSetExtraKey(Files.lines(testDataDir.resolve("dummy/public.key")).reduce((a, b) -> b).get());
+ Discovery.insecureTestingSetExtraKey(Files.lines(testDataDir.resolve("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")),
+ Files.readAllBytes(testDataDir.resolve("server_list.json.minisig")),
+ Files.readAllBytes(testDataDir.resolve("server_list.json")),
"server_list.json",
Instant.EPOCH
));
@@ -34,45 +33,45 @@ class VerifyTests {
@Test
void testInvalidSignature() {
- Assertions.assertEquals(2, assertThrows(VerifyException.class, () ->
+ assertThrows(InvalidSignatureException.class, () ->
Discovery.verify(
- Files.readAllBytes(testDataDir.resolve("dummy/random.txt")),
- Files.readAllBytes(testDataDir.resolve("dummy/server_list.json")),
+ Files.readAllBytes(testDataDir.resolve("random.txt")),
+ Files.readAllBytes(testDataDir.resolve("server_list.json")),
"server_list.json",
Instant.EPOCH
- )).code);
+ ));
}
@Test
void testWrongKey() {
- assertEquals(3, assertThrows(VerifyException.class, () ->
+ assertThrows(InvalidSignatureUnknownKeyException.class, () ->
Discovery.verify(
- Files.readAllBytes(testDataDir.resolve("dummy/server_list.json.wrong_key.minisig")),
- Files.readAllBytes(testDataDir.resolve("dummy/server_list.json")),
+ Files.readAllBytes(testDataDir.resolve("server_list.json.wrong_key.minisig")),
+ Files.readAllBytes(testDataDir.resolve("server_list.json")),
"server_list.json",
Instant.EPOCH
- )).code);
+ ));
}
@Test
void testOldSignature() {
- assertEquals(4, assertThrows(VerifyException.class, () ->
+ assertThrows(SignatureTooOldException.class, () ->
Discovery.verify(
- Files.readAllBytes(testDataDir.resolve("dummy/server_list.json.minisig")),
- Files.readAllBytes(testDataDir.resolve("dummy/server_list.json")),
+ Files.readAllBytes(testDataDir.resolve("server_list.json.minisig")),
+ Files.readAllBytes(testDataDir.resolve("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")),
+ Files.readAllBytes(testDataDir.resolve("other_list.json.minisig")),
+ Files.readAllBytes(testDataDir.resolve("other_list.json")),
"other_list.json",
Instant.EPOCH
));
}
-} \ No newline at end of file
+}
diff --git a/wrappers/php/.gitignore b/wrappers/php/.gitignore
index 4a56e6c..bdaa6e3 100644
--- a/wrappers/php/.gitignore
+++ b/wrappers/php/.gitignore
@@ -1,4 +1,5 @@
/vendor/
+/lib/*
composer.phar
.phpunit*
*.h
diff --git a/wrappers/php/Makefile b/wrappers/php/Makefile
index 06c49f1..e0262e9 100644
--- a/wrappers/php/Makefile
+++ b/wrappers/php/Makefile
@@ -1,25 +1,51 @@
.PHONY: install-header test install-dev-dependencies clean
-ifneq (clean,$(MAKECMDGOALS))
-include ../../exports/platform.mk
+EXPORTS_PATH ?= ../../exports
+EXPORTS_LIB_PATH ?= $(EXPORTS_PATH)/lib
+ifneq ($(MAKECMDGOALS),clean)
+include $(EXPORTS_PATH)/platform.mk
+
+# Add phpunit to PATH
export PATH := $(abspath vendor/bin):$(PATH)
endif
+ifeq ($(COPY_LIB),1)
+COPY_LIB_DIR = lib
+endif
+
+ifneq ($(COPY_LIB_DIR),)
+COPY_LIB_DIR := $(COPY_LIB_DIR)/
+endif
+
+# Strip / replace elements confusing PHP's limited C parser: __SIZE_TYPE__, _Complex, extern "C"
+# Also add FFI_LIB library name, see https://www.php.net/manual/en/ffi.load
install-header:
- $(MAKE) -C ../../exports
+ifneq ($(EXPORTS_PATH),)
+ifneq ($(wildcard $(EXPORTS_PATH)/Makefile),)
+ $(MAKE) -C "$(EXPORTS_PATH)"
+endif
+endif
mkdir -p src/headers
sed --null-data \
-e 's/DO NOT EDIT/Modified for PHP/' \
+ \
-e 's/__SIZE_TYPE__/size_t/g' \
-e 's/[^\n]*_Complex[^\n]*//g' \
-e 's/#ifdef __cplusplus[^#]*#endif//g' \
- -e 's/^/#define FFI_LIB "$(LIB_PREFIX)eduvpn_verify$(LIB_SUFFIX)"\n\n/' \
- "../../exports/$(GOOS)/$(GOARCH)/eduvpn_verify.h" > src/headers/eduvpn_verify_php.h
+ \
+ -e 's/^/#define FFI_LIB "$(subst /,\/,$(COPY_LIB_DIR))$(LIB_FILE)"\n\n/' \
+ \
+ "$(EXPORTS_LIB_PATH)/$(GOOS)/$(GOARCH)/$(LIB_NAME).h" > src/headers/$(LIB_NAME)_php.h
+ifeq ($(COPY_LIB),1)
+ install "$(EXPORTS_LIB_PATH)/$(GOOS)/$(GOARCH)/$(LIB_FILE)" -Dt "$(COPY_LIB_DIR)"
+endif
test: install-header install-dev-dependencies
phpunit
+# Try: composer, composer.phar, ./composer.phar, ./composer
+# check-platform-reqs is needed because of config.platform in composer.json, see https://getcomposer.org/doc/06-config.md#platform
install-dev-dependencies:
if command -v composer; then \
composer install && composer check-platform-reqs; \
@@ -31,4 +57,4 @@ install-dev-dependencies:
fi
clean:
- rm -rf vendor/ .phpunit* src/headers/*.h
+ rm -rf vendor/ .phpunit* src/headers/*.h lib/*
diff --git a/wrappers/php/README.md b/wrappers/php/README.md
index 776c0ac..b5cafa2 100644
--- a/wrappers/php/README.md
+++ b/wrappers/php/README.md
@@ -27,3 +27,9 @@ Or for the specified platform:
```shell
make install-header GOOS=windows GOARCH=amd64
```
+
+When using this library, you will need to make sure that the linker can find the shared Go library. Alternatively,
+pass `COPY_LIB=1` to `make install-header` to copy the library over to this folder and load it via this relative path.
+
+If you do not build this as part of the full repository, specify `EXPORTS_PATH="path/to/exports-folder"` when calling
+make. This folder must contain `platform.mk` and the `lib/` folder with built libraries and headers.
diff --git a/wrappers/php/src/Discovery.php b/wrappers/php/src/Discovery.php
index 3ae7010..322d621 100644
--- a/wrappers/php/src/Discovery.php
+++ b/wrappers/php/src/Discovery.php
@@ -11,13 +11,15 @@ final class Discovery
{
public function __construct() { }
+ const LIB_NAME = "eduvpn_common";
+
private static ?FFI $ffi = null;
private static function ffi(): FFI
{
if (!self::$ffi) {
- if (!(self::$ffi = FFI::load(__DIR__ . '/headers/eduvpn_verify_php.h')))
- throw new Error('failed to load eduvpn_verify');
+ if (!(self::$ffi = FFI::load(__DIR__ . '/headers/' . self::LIB_NAME . '_php.h')))
+ throw new Error('failed to load ' . self::LIB_NAME);
}
return self::$ffi;
}
@@ -30,8 +32,8 @@ final class Discovery
* @param string $signedJson Signed .json file contents.
* @param string $expectedFileName The file type to be verified, one of "server_list.json" or
* "organization_list.json".
- * @param int $minSignTime Minimum time for signature. Should be set to at least the time in a previously
- * retrieved file.
+ * @param int $minSignTime Minimum time for signature. Should be set to at least the time of the previous
+ * signature.
* @return void
* @throws InvalidArgumentException If expectedFileName is not one of the allowed values.
* @throws VerifyException If signature verification fails.
diff --git a/wrappers/php/src/SignatureTooOldException.php b/wrappers/php/src/SignatureTooOldException.php
index bbae949..4b7e341 100644
--- a/wrappers/php/src/SignatureTooOldException.php
+++ b/wrappers/php/src/SignatureTooOldException.php
@@ -2,7 +2,7 @@
namespace EduVpn\Common;
-/** Signature has a timestamp lower than the specified minimum signing time. */
+/** Signature timestamp smaller than specified minimum signing time (rollback). */
final class SignatureTooOldException extends VerifyException
{
public function __construct()
diff --git a/wrappers/php/tests/DiscoveryTest.php b/wrappers/php/tests/DiscoveryTest.php
index 25ac187..fdce505 100644
--- a/wrappers/php/tests/DiscoveryTest.php
+++ b/wrappers/php/tests/DiscoveryTest.php
@@ -13,31 +13,31 @@ class DiscoveryTest extends TestCase
public static function setUpBeforeClass(): void
{
- preg_match('/[\r\n](\S+)\s*/', file_get_contents(self::TEST_DATA_DIR . '/dummy/public.key'), $matches);
+ preg_match('/[\r\n](\S+)\s*/', file_get_contents(self::TEST_DATA_DIR . '/public.key'), $matches);
Discovery::insecureTestingSetExtraKey($matches[1]);
}
public function testValid(): void
{
$this->expectNotToPerformAssertions();
- Discovery::verify(file_get_contents(self::TEST_DATA_DIR . '/dummy/server_list.json.minisig'),
- file_get_contents(self::TEST_DATA_DIR . '/dummy/server_list.json'),
+ Discovery::verify(file_get_contents(self::TEST_DATA_DIR . '/server_list.json.minisig'),
+ file_get_contents(self::TEST_DATA_DIR . '/server_list.json'),
'server_list.json', 0);
}
public function testInvalidSignature(): void
{
$this->expectException(InvalidSignatureException::class);
- Discovery::verify(file_get_contents(self::TEST_DATA_DIR . '/dummy/random.txt'),
- file_get_contents(self::TEST_DATA_DIR . '/dummy/server_list.json'),
+ Discovery::verify(file_get_contents(self::TEST_DATA_DIR . '/random.txt'),
+ file_get_contents(self::TEST_DATA_DIR . '/server_list.json'),
'server_list.json', 0);
}
public function testWrongKey(): void
{
$this->expectException(InvalidSignatureUnknownKeyException::class);
- Discovery::verify(file_get_contents(self::TEST_DATA_DIR . '/dummy/server_list.json.wrong_key.minisig'),
- file_get_contents(self::TEST_DATA_DIR . '/dummy/server_list.json'),
+ Discovery::verify(file_get_contents(self::TEST_DATA_DIR . '/server_list.json.wrong_key.minisig'),
+ file_get_contents(self::TEST_DATA_DIR . '/server_list.json'),
'server_list.json', 0);
}
@@ -45,16 +45,16 @@ class DiscoveryTest extends TestCase
public function testOldSignature(): void
{
$this->expectException(SignatureTooOldException::class);
- Discovery::verify(file_get_contents(self::TEST_DATA_DIR . '/dummy/server_list.json.minisig'),
- file_get_contents(self::TEST_DATA_DIR . '/dummy/server_list.json'),
+ Discovery::verify(file_get_contents(self::TEST_DATA_DIR . '/server_list.json.minisig'),
+ file_get_contents(self::TEST_DATA_DIR . '/server_list.json'),
'server_list.json', 1 << 31);
}
public function testUnknownExpectedFileName(): void
{
$this->expectException(InvalidArgumentException::class);
- Discovery::verify(file_get_contents(self::TEST_DATA_DIR . '/dummy/other_list.json.minisig'),
- file_get_contents(self::TEST_DATA_DIR . '/dummy/other_list.json'),
+ Discovery::verify(file_get_contents(self::TEST_DATA_DIR . '/other_list.json.minisig'),
+ file_get_contents(self::TEST_DATA_DIR . '/other_list.json'),
'other_list.json', 0);
}
}
diff --git a/wrappers/python/Makefile b/wrappers/python/Makefile
index be4beaa..ba4cf5f 100644
--- a/wrappers/python/Makefile
+++ b/wrappers/python/Makefile
@@ -1,15 +1,27 @@
.PHONY: pack test clean
+EXPORTS_PATH ?= ../../exports
+EXPORTS_LIB_PATH ?= $(EXPORTS_PATH)/lib
+
+ifneq ($(MAKECMDGOALS),clean)
+include $(EXPORTS_PATH)/platform.mk
+endif
+
ifdef PLAT_NAME
SETUP_ARGS += --plat-name=$(PLAT_NAME)
endif
# Build for current platform only
pack:
- ./setup.py bdist_wheel $(SETUP_ARGS)
+ ./setup.py bdist_wheel $(SETUP_ARGS) --exports-lib-path="$(EXPORTS_LIB_PATH)"
test:
- $(MAKE) -C ../../exports copy-to COPY_TARGET=../wrappers/python/eduvpncommon/lib
+ifneq ($(EXPORTS_PATH),)
+ifneq ($(wildcard $(EXPORTS_PATH)/Makefile),)
+ $(MAKE) -C "$(EXPORTS_PATH)"
+endif
+endif
+ install "$(EXPORTS_LIB_PATH)/$(GOOS)/$(GOARCH)/$(LIB_FILE)" -Dt "eduvpncommon/lib"
python3 -m unittest test_discovery
rm eduvpncommon/lib/*
diff --git a/wrappers/python/README.md b/wrappers/python/README.md
index 6175910..bce492e 100644
--- a/wrappers/python/README.md
+++ b/wrappers/python/README.md
@@ -2,9 +2,7 @@
## Requirements
-Python 3.6+ is assumed, but it may work with older versions.
-
-TODO Build
+Python 3.6+ is assumed, but it may work with older versions. To build, `setuptools` and `wheel` are required.
## Build & test
@@ -16,7 +14,11 @@ Build wheel using library for current platform:
make pack
```
-Build wheel using library for specified platform (passed to setuptools `--plat-name`):
+(This does not build the shared Go library.)
+
+Build wheel using library for specified platform (passed to setuptools `--plat-name`,
+see [`get_build_platform`](https://setuptools.pypa.io/en/latest/pkg_resources.html?highlight=get_build_platform#platform-utilities)
+for more):
```shell
make pack PLAT_NAME=win32
@@ -28,9 +30,12 @@ To install the wheel, run:
pip install dist/eduvpncommon-[version]-py3-none-[platform].whl
```
-You could also reference the discovery module directly and copy the library for the platform to the `eduvpncommon/lib`
+You could also reference the discovery module directly and copy the library for the platform to the `eduvpncommon/lib/`
folder.
+If you do not build this as part of the full repository, specify `EXPORTS_PATH="path/to/exports-folder"` when calling
+make. This folder must contain `platform.mk` and the `lib/` folder with built libraries.
+
Test:
```shell
diff --git a/wrappers/python/eduvpncommon/discovery.py b/wrappers/python/eduvpncommon/discovery.py
index f7a312e..f22df58 100644
--- a/wrappers/python/eduvpncommon/discovery.py
+++ b/wrappers/python/eduvpncommon/discovery.py
@@ -15,28 +15,30 @@ _lib_suffixes = defaultdict(lambda: ".so", {
_os = platform.system().lower()
-_libname = f"{_lib_prefixes[_os]}eduvpn_verify{_lib_suffixes[_os]}"
-_lib = cdll.LoadLibrary(str(pathlib.Path(__file__).parent / "lib" / _libname))
+_libname = "eduvpn_common"
+_libfile = f"{_lib_prefixes[_os]}{_libname}{_lib_suffixes[_os]}"
+# Library should have been copied to the lib/ folder
+_lib = cdll.LoadLibrary(str(pathlib.Path(__file__).parent / "lib" / _libfile))
-class GoSlice(Structure):
+class _GoSlice(Structure):
_fields_ = [("data", POINTER(c_char)), ("len", c_int64), ("cap", c_int64)]
@staticmethod
- def make(bs: bytes) -> "GoSlice":
- return GoSlice((c_char * len(bs))(*bs), len(bs), len(bs))
+ def make(bs: bytes) -> "_GoSlice":
+ return _GoSlice((c_char * len(bs))(*bs), len(bs), len(bs))
-_lib.Verify.argtypes, _lib.Verify.restype = [GoSlice, GoSlice, GoSlice, c_uint64], c_int64
-_lib.InsecureTestingSetExtraKey.argtypes, _lib.InsecureTestingSetExtraKey.restype = [GoSlice], None
+_lib.Verify.argtypes, _lib.Verify.restype = [_GoSlice, _GoSlice, _GoSlice, c_uint64], c_int64
+_lib.InsecureTestingSetExtraKey.argtypes, _lib.InsecureTestingSetExtraKey.restype = [_GoSlice], None
class VerifyErrorCode(Enum):
- ErrUnknownExpectedFileName = 1 # Expected file name is not one of the recognized values.
+ ErrUnknownExpectedFileName = 1 # Unknown expected file name specified. The signature has not been verified.
ErrInvalidSignature = 2 # Signature is invalid (for the expected file type).
ErrInvalidSignatureUnknownKey = 3 # Signature was created with an unknown key and has not been verified.
- ErrTooOld = 4 # Signature has a timestamp lower than the specified minimum signing time.
- Unknown = -1 # Other unknown error
+ ErrTooOld = 4 # Signature timestamp smaller than specified minimum signing time (rollback).
+ Unknown = -1 # Other unknown error.
class VerifyError(Exception):
@@ -44,6 +46,7 @@ class VerifyError(Exception):
code_int: int # Original error code also for VerifyErrorCode.Unknown
def __init__(self, err: int):
+ assert err
try:
self.code = VerifyErrorCode(err)
except ValueError:
@@ -68,13 +71,13 @@ def verify(signature: bytes, signed_json: bytes, expected_file_name: str, min_si
:param signature: .minisig signature file contents.
:param signed_json: Signed .json file contents.
:param expected_file_name: The file type to be verified, one of "server_list.json" or "organization_list.json".
- :param min_sign_time: Minimum time for signature. Should be set to at least the time in a previously retrieved file.
+ :param min_sign_time: Minimum time for signature. Should be set to at least the time of the previous signature.
:raises VerifyException: If signature verification fails or expectedFileName is not one of the allowed values.
"""
- err = _lib.Verify(GoSlice.make(signature), GoSlice.make(signed_json),
- GoSlice.make(expected_file_name.encode()), min_sign_time)
+ err = _lib.Verify(_GoSlice.make(signature), _GoSlice.make(signed_json),
+ _GoSlice.make(expected_file_name.encode()), min_sign_time)
if err:
raise VerifyError(err)
@@ -82,4 +85,4 @@ def verify(signature: bytes, signed_json: bytes, expected_file_name: str, min_si
def _insecure_testing_set_extra_key(key_string: str) -> None:
"""Use for testing only, see Go documentation."""
- _lib.InsecureTestingSetExtraKey(GoSlice.make(key_string.encode()))
+ _lib.InsecureTestingSetExtraKey(_GoSlice.make(key_string.encode()))
diff --git a/wrappers/python/setup.py b/wrappers/python/setup.py
index db254aa..9e7bde4 100755
--- a/wrappers/python/setup.py
+++ b/wrappers/python/setup.py
@@ -1,17 +1,20 @@
#!/usr/bin/env python3
import os
-import pathlib
import shutil
+import sys
import typing
from collections import defaultdict
-import sys
from setuptools import setup
from wheel.bdist_wheel import bdist_wheel as _bdist_wheel
+_libname = "eduvpn_common"
+
def getlibpath(plat_name: str) -> typing.Union[str, None]:
+ """Get library path for plat_name relative to exports/lib/ folder."""
+
_plat_map = defaultdict(lambda: plat_name, {
"win32": "win-x86",
})
@@ -47,12 +50,21 @@ def getlibpath(plat_name: str) -> typing.Union[str, None]:
processed_os = _os_map[plat_os]
return f"{processed_os}/{_arch_map[plat_arch]}/" \
- f"{_lib_prefixes[processed_os]}eduvpn_verify{_lib_suffixes[processed_os]}"
+ f"{_lib_prefixes[processed_os]}{_libname}{_lib_suffixes[processed_os]}"
+# Adapted from https://stackoverflow.com/a/51794740
# You would say there would be a better way to do all of this, but I couldn't find it
class bdist_wheel(_bdist_wheel):
+ user_options = _bdist_wheel.user_options + [
+ ("exports-lib-path=", None, "path to exports/lib directory"),
+ ]
+
+ def initialize_options(self):
+ super().initialize_options()
+ self.exports_lib_path = "../../exports/lib" # default
+
def run(self):
self.plat_name_supplied = True # Force use platform
@@ -63,9 +75,10 @@ class bdist_wheel(_bdist_wheel):
print(f"Building wheel for platform {self.plat_name}")
- shutil.copy2(f"../../exports/{libpath}", "eduvpncommon/lib/")
+ # setuptools will only use paths inside the package for package_data, so we copy the library
+ tmp_lib = shutil.copy2(f"{self.exports_lib_path}/{libpath}", "eduvpncommon/lib/")
_bdist_wheel.run(self)
- os.remove(f"eduvpncommon/lib/{pathlib.Path(libpath).name}")
+ os.remove(tmp_lib)
setup(
@@ -73,6 +86,6 @@ setup(
version="0.1.0",
packages=["eduvpncommon"],
python_requires=">=3.6",
- package_data={"eduvpncommon": ["lib/*eduvpn_verify*"]},
+ package_data={"eduvpncommon": [f"lib/*{_libname}*"]},
cmdclass={"bdist_wheel": bdist_wheel},
)
diff --git a/wrappers/python/test_discovery.py b/wrappers/python/test_discovery.py
index 1282a3e..73c51c4 100755
--- a/wrappers/python/test_discovery.py
+++ b/wrappers/python/test_discovery.py
@@ -14,21 +14,21 @@ def read_bytes(path: str) -> bytes:
class VerifyTests(unittest.TestCase):
@classmethod
def setUpClass(cls) -> None:
- with open(f"{test_data_dir}/dummy/public.key") as f:
+ with open(f"{test_data_dir}/public.key") as f:
discovery._insecure_testing_set_extra_key(f.readlines()[-1][:-1])
def testValid(self):
discovery.verify(
- read_bytes(f"{test_data_dir}/dummy/server_list.json.minisig"),
- read_bytes(f"{test_data_dir}/dummy/server_list.json"),
+ read_bytes(f"{test_data_dir}/server_list.json.minisig"),
+ read_bytes(f"{test_data_dir}/server_list.json"),
"server_list.json",
0
)
def testValidMemoryView(self):
discovery.verify(
- read_bytes(f"{test_data_dir}/dummy/server_list.json.minisig"),
- memoryview(b"abc" + read_bytes(f"{test_data_dir}/dummy/server_list.json") + b"abc")[3:-3],
+ read_bytes(f"{test_data_dir}/server_list.json.minisig"),
+ memoryview(b"abc" + read_bytes(f"{test_data_dir}/server_list.json") + b"abc")[3:-3],
"server_list.json",
0
)
@@ -36,8 +36,8 @@ class VerifyTests(unittest.TestCase):
def testInvalidSignature(self):
with self.assertRaises(discovery.VerifyError) as ctx:
discovery.verify(
- read_bytes(f"{test_data_dir}/dummy/random.txt"),
- read_bytes(f"{test_data_dir}/dummy/server_list.json"),
+ read_bytes(f"{test_data_dir}/random.txt"),
+ read_bytes(f"{test_data_dir}/server_list.json"),
"server_list.json",
0
)
@@ -46,8 +46,8 @@ class VerifyTests(unittest.TestCase):
def testWrongKey(self):
with self.assertRaises(discovery.VerifyError) as ctx:
discovery.verify(
- read_bytes(f"{test_data_dir}/dummy/server_list.json.wrong_key.minisig"),
- read_bytes(f"{test_data_dir}/dummy/server_list.json"),
+ read_bytes(f"{test_data_dir}/server_list.json.wrong_key.minisig"),
+ read_bytes(f"{test_data_dir}/server_list.json"),
"server_list.json",
0
)
@@ -56,8 +56,8 @@ class VerifyTests(unittest.TestCase):
def testOldSignature(self):
with self.assertRaises(discovery.VerifyError) as ctx:
discovery.verify(
- read_bytes(f"{test_data_dir}/dummy/server_list.json.minisig"),
- read_bytes(f"{test_data_dir}/dummy/server_list.json"),
+ read_bytes(f"{test_data_dir}/server_list.json.minisig"),
+ read_bytes(f"{test_data_dir}/server_list.json"),
"server_list.json",
1 << 31
)
@@ -66,8 +66,8 @@ class VerifyTests(unittest.TestCase):
def TestUnknownExpectedFile(self):
with self.assertRaises(discovery.VerifyError) as ctx:
discovery.verify(
- read_bytes(f"{test_data_dir}/dummy/other_list.json.minisig"),
- read_bytes(f"{test_data_dir}/dummy/other_list.json"),
+ read_bytes(f"{test_data_dir}/other_list.json.minisig"),
+ read_bytes(f"{test_data_dir}/other_list.json"),
"other_list.json",
0
)
diff --git a/wrappers/swift/CEduVpnCommon/Sources/CEduVpnCommon/module.modulemap b/wrappers/swift/CEduVpnCommon/Sources/CEduVpnCommon/module.modulemap
index c85e48f..2c50cfd 100644
--- a/wrappers/swift/CEduVpnCommon/Sources/CEduVpnCommon/module.modulemap
+++ b/wrappers/swift/CEduVpnCommon/Sources/CEduVpnCommon/module.modulemap
@@ -1,5 +1,5 @@
module CEduVpnCommon {
- header "Headers/eduvpn_verify.h"
- link "eduvpn_verify"
+ header "Headers/eduvpn_common.h"
+ link "eduvpn_common"
export *
}
diff --git a/wrappers/swift/Makefile b/wrappers/swift/Makefile
index 84b3cc1..b46a177 100644
--- a/wrappers/swift/Makefile
+++ b/wrappers/swift/Makefile
@@ -1,24 +1,33 @@
-.PHONY: build test clean
+.PHONY: build test install-header clean
-ifneq (clean,$(MAKECMDGOALS))
-include ../../exports/platform.mk
+EXPORTS_PATH ?= ../../exports
+EXPORTS_LIB_PATH ?= $(EXPORTS_PATH)/lib
-ifeq (Windows_NT,$(OS))
+ifneq ($(MAKECMDGOALS),clean)
+include $(EXPORTS_PATH)/platform.mk
+
+LIB_DIR = $(EXPORTS_LIB_PATH)/$(GOOS)/$(GOARCH)
+
+ifeq ($(OS),Windows_NT)
SWIFT = ./swift.cmd
else
SWIFT = swift
endif
endif
-build: .build_lib
- $(SWIFT) build --configuration release -Xlinker -L"../../exports/$(GOOS)/$(GOARCH)"
+build: install-header
+ $(SWIFT) build --configuration release -Xlinker -L"$(LIB_DIR)"
+
+test: install-header
+ $(SWIFT) test --parallel -Xlinker -L"$(LIB_DIR)"
-test: .build_lib
- $(SWIFT) test --parallel -Xlinker -L"../../exports/$(GOOS)/$(GOARCH)"
+install-header:
+ifneq ($(EXPORTS_PATH),)
+ifneq ($(wildcard $(EXPORTS_PATH)/Makefile),)
+ $(MAKE) -C "$(EXPORTS_PATH)"
+endif
+endif
+ install "$(LIB_DIR)/$(LIB_NAME).h" -Dt CEduVpnCommon/Sources/CEduVpnCommon/Headers # Copy header for modulemap
clean:
rm -rf .build/ CEduVpnCommon/Sources/CEduVpnCommon/Headers/*.h
-
-.build_lib:
- $(MAKE) -C ../../exports
- install "../../exports/$(GOOS)/$(GOARCH)/eduvpn_verify.h" -Dt CEduVpnCommon/Sources/CEduVpnCommon/Headers
diff --git a/wrappers/swift/README.md b/wrappers/swift/README.md
index 8259592..f28b028 100644
--- a/wrappers/swift/README.md
+++ b/wrappers/swift/README.md
@@ -2,7 +2,8 @@
## Requirements
-You will need to install the [Swift SDK](https://www.swift.org/getting-started), which includes the `swift` tool.
+You will need to install the [Swift SDK](https://www.swift.org/getting-started), which includes the `swift` tool. This
+project does not require Xcode as it uses the Swift Package Manager.
## Build & test
@@ -18,7 +19,22 @@ Build `EduVpnCommon` using shared Go library for specified platform, e.g.:
make GOOS=linux GOARCH=amd64
```
-On Windows, you will also need to generate a .lib for the .dll.
+When using this library, you will need to make sure that the linker can find the shared Go library.
+
+<small>On Windows, you will also need to generate a .lib import library for the .dll. You can
+use `exports/generate_lib.ps1`
+for this, passing in the path to the DLL file. Execute this from a Visual Studio Developer shell before building the
+Swift project. Alternatively, you could use `objdump` and `llvm-dlltool`. You only need to update this if the list of
+exported symbols changes.</small>
+
+If you just want to copy over the C header file to the right directory for the modulemap in `CEduVpnCommon`, run:
+
+```shell
+make install-header
+```
+
+If you do not build this as part of the full repository, specify `EXPORTS_PATH="path/to/exports-folder"` when calling
+make. This folder must contain `platform.mk` and the `lib/` folder with built libraries and headers.
Test:
diff --git a/wrappers/swift/Sources/EduVpnCommon/EduVpnCommon.swift b/wrappers/swift/Sources/EduVpnCommon/EduVpnCommon.swift
index 340e94a..b849626 100644
--- a/wrappers/swift/Sources/EduVpnCommon/EduVpnCommon.swift
+++ b/wrappers/swift/Sources/EduVpnCommon/EduVpnCommon.swift
@@ -9,7 +9,7 @@ private extension Data {
// This closure method guarantees this
try withUnsafeBytes { (pointer: UnsafeRawBufferPointer) -> ResultType in
// Note: UnsafeRawBufferPointer.startIndex will always be 0, see docs
- // Cast to UnsafeMutableRawPointer, assumes it will not be written to
+ // Cast to UnsafeMutableRawPointer, assumes it will not actually be written to
try body(GoSlice(data: UnsafeMutableRawPointer(mutating: pointer.baseAddress),
len: GoInt(pointer.count), cap: GoInt(pointer.count)))
}
@@ -33,9 +33,9 @@ public enum VerifyErr: Error, Equatable {
/// Signature has a timestamp lower than the specified minimum signing time.
case ErrTooOld
/// Other unknown error
- case Unknown(code: GoInt)
+ case Unknown(code: GoInt8)
- static func fromCode(_ code: GoInt) -> VerifyErr {
+ static func fromCode(_ code: GoInt8) -> VerifyErr {
precondition(code != 0)
switch code {
case 1: return ErrUnknownExpectedFileName
@@ -54,7 +54,7 @@ public enum VerifyErr: Error, Equatable {
/// - signature: .minisig signature file contents.
/// - signedJson: Signed .json file contents.
/// - expectedFileName: The file type to be verified, one of "server_list.json" or "organization_list.json".
-/// - minSignTime: Minimum time for signature. Should be set to at least the time in a previously retrieved file.
+/// - minSignTime: Minimum time for signature. Should be set to at least the time of the previous signature.
/// - Throws: VerifyErr: If signature verification fails or `expectedFileName` is not one of the allowed values.
public func Verify(signature: Data, signedJson: Data, expectedFileName: String, minSignTime: Date) throws {
let result = signature.withSlice { signatureData in
diff --git a/wrappers/swift/Tests/EduVpnCommonTests/EduVpnCommonTests.swift b/wrappers/swift/Tests/EduVpnCommonTests/EduVpnCommonTests.swift
index a508023..21186a9 100644
--- a/wrappers/swift/Tests/EduVpnCommonTests/EduVpnCommonTests.swift
+++ b/wrappers/swift/Tests/EduVpnCommonTests/EduVpnCommonTests.swift
@@ -6,14 +6,14 @@ final class EduVpnCommonTests: XCTestCase {
override class func setUp() {
// Swift is confused by CRLF, so on some systems we cannot just take the second-to-last element
- InsecureTestingSetExtraKey(keyString: try! String(contentsOfFile: "\(testDataDir)/dummy/public.key")
+ InsecureTestingSetExtraKey(keyString: try! String(contentsOfFile: "\(testDataDir)/public.key")
.components(separatedBy: .newlines).last(where: { !$0.isEmpty })!)
}
func testValid() throws {
try Verify(
- signature: try! Data(contentsOf: URL(fileURLWithPath: "\(EduVpnCommonTests.testDataDir)/dummy/server_list.json.minisig")),
- signedJson: try! Data(contentsOf: URL(fileURLWithPath: "\(EduVpnCommonTests.testDataDir)/dummy/server_list.json")),
+ signature: try! Data(contentsOf: URL(fileURLWithPath: "\(EduVpnCommonTests.testDataDir)/server_list.json.minisig")),
+ signedJson: try! Data(contentsOf: URL(fileURLWithPath: "\(EduVpnCommonTests.testDataDir)/server_list.json")),
expectedFileName: "server_list.json",
minSignTime: Date(timeIntervalSince1970: 0))
}
@@ -21,8 +21,8 @@ final class EduVpnCommonTests: XCTestCase {
func testInvalidSignature() throws {
XCTAssertThrowsError(
try Verify(
- signature: try! Data(contentsOf: URL(fileURLWithPath: "\(EduVpnCommonTests.testDataDir)/dummy/random.txt")),
- signedJson: try! Data(contentsOf: URL(fileURLWithPath: "\(EduVpnCommonTests.testDataDir)/dummy/server_list.json")),
+ signature: try! Data(contentsOf: URL(fileURLWithPath: "\(EduVpnCommonTests.testDataDir)/random.txt")),
+ signedJson: try! Data(contentsOf: URL(fileURLWithPath: "\(EduVpnCommonTests.testDataDir)/server_list.json")),
expectedFileName: "server_list.json",
minSignTime: Date(timeIntervalSince1970: 0)),
"", {err in XCTAssertEqual(err as? VerifyErr, VerifyErr.ErrInvalidSignature)});
@@ -31,8 +31,8 @@ final class EduVpnCommonTests: XCTestCase {
func testWrongKey() throws {
XCTAssertThrowsError(
try Verify(
- signature: try! Data(contentsOf: URL(fileURLWithPath: "\(EduVpnCommonTests.testDataDir)/dummy/server_list.json.wrong_key.minisig")),
- signedJson: try! Data(contentsOf: URL(fileURLWithPath: "\(EduVpnCommonTests.testDataDir)/dummy/server_list.json")),
+ signature: try! Data(contentsOf: URL(fileURLWithPath: "\(EduVpnCommonTests.testDataDir)/server_list.json.wrong_key.minisig")),
+ signedJson: try! Data(contentsOf: URL(fileURLWithPath: "\(EduVpnCommonTests.testDataDir)/server_list.json")),
expectedFileName: "server_list.json",
minSignTime: Date(timeIntervalSince1970: 0)),
"", {err in XCTAssertEqual(err as? VerifyErr, VerifyErr.ErrInvalidSignatureUnknownKey)});
@@ -41,8 +41,8 @@ final class EduVpnCommonTests: XCTestCase {
func testOldSignature() throws {
XCTAssertThrowsError(
try Verify(
- signature: try! Data(contentsOf: URL(fileURLWithPath: "\(EduVpnCommonTests.testDataDir)/dummy/server_list.json.minisig")),
- signedJson: try! Data(contentsOf: URL(fileURLWithPath: "\(EduVpnCommonTests.testDataDir)/dummy/server_list.json")),
+ signature: try! Data(contentsOf: URL(fileURLWithPath: "\(EduVpnCommonTests.testDataDir)/server_list.json.minisig")),
+ signedJson: try! Data(contentsOf: URL(fileURLWithPath: "\(EduVpnCommonTests.testDataDir)/server_list.json")),
expectedFileName: "server_list.json",
minSignTime: Date(timeIntervalSince1970: TimeInterval(1 << 31))),
"", {err in XCTAssertEqual(err as? VerifyErr, VerifyErr.ErrTooOld)});
@@ -51,8 +51,8 @@ final class EduVpnCommonTests: XCTestCase {
func testUnknownExpectedFile() throws {
XCTAssertThrowsError(
try Verify(
- signature: try! Data(contentsOf: URL(fileURLWithPath: "\(EduVpnCommonTests.testDataDir)/dummy/other_list.json.minisig")),
- signedJson: try! Data(contentsOf: URL(fileURLWithPath: "\(EduVpnCommonTests.testDataDir)/dummy/other_list.json")),
+ signature: try! Data(contentsOf: URL(fileURLWithPath: "\(EduVpnCommonTests.testDataDir)/other_list.json.minisig")),
+ signedJson: try! Data(contentsOf: URL(fileURLWithPath: "\(EduVpnCommonTests.testDataDir)/other_list.json")),
expectedFileName: "other_list.json",
minSignTime: Date(timeIntervalSince1970: 0)),
"", {err in XCTAssertEqual(err as? VerifyErr, VerifyErr.ErrUnknownExpectedFileName)});
diff --git a/wrappers/swift/swift.cmd b/wrappers/swift/swift.cmd
index 87fba4b..57040bd 100755
--- a/wrappers/swift/swift.cmd
+++ b/wrappers/swift/swift.cmd
@@ -1,6 +1,6 @@
@echo off
-:: Rename PATH -> Path
+:: Rename PATH -> Path because of swift issue https://github.com/compnerd/swift-build/issues/413
set _p=%PATH%
set PATH=
set Path=%_p%