mirror of
https://github.com/cryptomator/cryptomator.git
synced 2026-08-02 11:39:48 -04:00
Refactor event handling
AppLauchEvent became a sealed interface with implemented Events RevealRunningApp-, OpenFile- and ValtCreateEvent. Signed-off-by: Armin Schrenk <armin.schrenk@skymatic.de>
This commit is contained in:
@@ -1,28 +1,16 @@
|
||||
package org.cryptomator.launcher;
|
||||
|
||||
import java.net.URI;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
public record AppLaunchEvent(AppLaunchEvent.EventType type, Collection<Path> pathsToOpen, URI uri) {
|
||||
|
||||
public enum EventType {
|
||||
REVEAL_APP,
|
||||
OPEN_FILE,
|
||||
OPEN_URI
|
||||
}
|
||||
|
||||
static AppLaunchEvent revealApp() {
|
||||
return new AppLaunchEvent(EventType.REVEAL_APP, List.of(), null);
|
||||
}
|
||||
|
||||
static AppLaunchEvent openFiles(Collection<Path> pathsToOpen) {
|
||||
return new AppLaunchEvent(EventType.OPEN_FILE, pathsToOpen, null);
|
||||
}
|
||||
|
||||
static AppLaunchEvent openUri(URI uri) {
|
||||
return new AppLaunchEvent(EventType.OPEN_URI, List.of(), uri);
|
||||
}
|
||||
/**
|
||||
* An event triggering an action in the running application instance.
|
||||
* <p>
|
||||
* Produced by the launch-argument handling (see {@link LaunchArgsParser} and the {@code *RequestHandler}s) and consumed
|
||||
* by the UI's {@code AppLaunchEventHandler}. Each permitted subtype represents one supported action:
|
||||
* <ul>
|
||||
* <li>{@link RevealRunningEvent} - reveal the already-running app,</li>
|
||||
* <li>{@link OpenFileEvent} - open one or more paths,</li>
|
||||
* <li>{@link VaultCreationEvent} - create a vault from a deeplink.</li>
|
||||
* </ul>
|
||||
*/
|
||||
public sealed interface AppLaunchEvent permits RevealRunningEvent, OpenFileEvent, VaultCreationEvent {
|
||||
|
||||
}
|
||||
|
||||
@@ -1,38 +0,0 @@
|
||||
package org.cryptomator.launcher;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.Arrays;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* Enumerates the supported deeplink actions and maps an incoming {@link URI} to one of them.
|
||||
* <p>
|
||||
* A deeplink action is identified by the URI's host and path, e.g. {@code cryptomator://vault/create} maps to
|
||||
* {@link #VAULT_CREATE}. Unknown host/path combinations yield an empty {@link Optional} and should be treated as
|
||||
* unsupported. New actions are added by extending this enum.
|
||||
*/
|
||||
public enum DeeplinkAction {
|
||||
|
||||
VAULT_CREATE("vault", "/create");
|
||||
|
||||
private final String host;
|
||||
private final String path;
|
||||
|
||||
DeeplinkAction(String host, String path) {
|
||||
this.host = host;
|
||||
this.path = path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Matches the given URI against the known deeplink actions.
|
||||
*
|
||||
* @param uri the deeplink URI
|
||||
* @return the matching action, or an empty optional if the host/path is not recognized
|
||||
*/
|
||||
public static Optional<DeeplinkAction> match(URI uri) {
|
||||
return Arrays.stream(values()) //
|
||||
.filter(action -> action.host.equalsIgnoreCase(uri.getHost()) && action.path.equals(uri.getPath())) //
|
||||
.findFirst();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -41,7 +41,7 @@ class FileOpenRequestHandler {
|
||||
|
||||
private void openFiles(OpenFilesEvent evt) {
|
||||
Collection<Path> pathsToOpen = evt.getFiles().stream().map(File::toPath).toList();
|
||||
AppLaunchEvent launchEvent = AppLaunchEvent.openFiles(pathsToOpen);
|
||||
AppLaunchEvent launchEvent = new OpenFileEvent(pathsToOpen);
|
||||
tryToEnqueueFileOpenRequest(launchEvent);
|
||||
}
|
||||
|
||||
@@ -60,7 +60,7 @@ class FileOpenRequestHandler {
|
||||
}
|
||||
}).filter(Objects::nonNull).toList();
|
||||
if (!pathsToOpen.isEmpty()) {
|
||||
AppLaunchEvent launchEvent = AppLaunchEvent.openFiles(pathsToOpen);
|
||||
AppLaunchEvent launchEvent = new OpenFileEvent(pathsToOpen);
|
||||
tryToEnqueueFileOpenRequest(launchEvent);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ class IpcMessageHandler implements IpcMessageListener {
|
||||
|
||||
@Override
|
||||
public void revealRunningApp() {
|
||||
launchEventQueue.add(AppLaunchEvent.revealApp());
|
||||
launchEventQueue.add(new RevealRunningEvent());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -21,7 +21,7 @@ public class NoopRequestHandler {
|
||||
}
|
||||
|
||||
public void revealApp() {
|
||||
AppLaunchEvent launchEvent = AppLaunchEvent.revealApp();
|
||||
AppLaunchEvent launchEvent = new RevealRunningEvent();
|
||||
if (!launchEventQueue.offer(launchEvent)) {
|
||||
LOG.warn("Could not enqueue application launch event {}.", launchEvent);
|
||||
}
|
||||
|
||||
13
src/main/java/org/cryptomator/launcher/OpenFileEvent.java
Normal file
13
src/main/java/org/cryptomator/launcher/OpenFileEvent.java
Normal file
@@ -0,0 +1,13 @@
|
||||
package org.cryptomator.launcher;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* Requests that the given paths (e.g. {@code .cryptomator} vault files) are opened.
|
||||
*
|
||||
* @param pathsToOpen the paths to open
|
||||
*/
|
||||
public record OpenFileEvent(Collection<Path> pathsToOpen) implements AppLaunchEvent {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package org.cryptomator.launcher;
|
||||
|
||||
/**
|
||||
* Requests that the already-running application instance reveals itself (brings its main window to the front).
|
||||
*/
|
||||
public record RevealRunningEvent() implements AppLaunchEvent {
|
||||
|
||||
}
|
||||
@@ -7,13 +7,24 @@ import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
import javax.inject.Singleton;
|
||||
import java.net.URI;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
import java.util.function.Function;
|
||||
|
||||
@Singleton
|
||||
public class URIOpenRequestHandler {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(URIOpenRequestHandler.class);
|
||||
|
||||
/**
|
||||
* The registered deeplink parsers, tried in order. Each returns a matching event, an empty optional if the URI is
|
||||
* not its concern, or throws {@link IllegalArgumentException} if the URI is its concern but malformed.
|
||||
*/
|
||||
private static final List<Function<URI, Optional<? extends AppLaunchEvent>>> DEEPLINK_PARSERS = List.of( //
|
||||
VaultCreationEvent::tryParse //
|
||||
);
|
||||
|
||||
private final BlockingQueue<AppLaunchEvent> launchEventQueue;
|
||||
|
||||
@Inject
|
||||
@@ -22,10 +33,26 @@ public class URIOpenRequestHandler {
|
||||
}
|
||||
|
||||
public void handleLaunchArgs(URI uri) {
|
||||
AppLaunchEvent launchEvent = AppLaunchEvent.openUri(uri);
|
||||
AppLaunchEvent launchEvent = toLaunchEvent(uri);
|
||||
if (!launchEventQueue.offer(launchEvent)) {
|
||||
LOG.warn("Could not enqueue application launch event {}.", launchEvent);
|
||||
}
|
||||
}
|
||||
|
||||
private AppLaunchEvent toLaunchEvent(URI uri) {
|
||||
try {
|
||||
for (var parser : DEEPLINK_PARSERS) {
|
||||
var event = parser.apply(uri);
|
||||
if (event.isPresent()) {
|
||||
return event.get();
|
||||
}
|
||||
}
|
||||
} catch (IllegalArgumentException e) {
|
||||
LOG.warn("Received malformed deeplink {}: {}. Revealing running app instead.", uri, e.getMessage());
|
||||
return new RevealRunningEvent();
|
||||
}
|
||||
LOG.warn("Received unsupported deeplink {}, revealing running app instead.", uri);
|
||||
return new RevealRunningEvent();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,17 +1,18 @@
|
||||
package org.cryptomator.launcher;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.net.URI;
|
||||
import java.net.URLDecoder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Base64;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* Parsed representation of a {@code cryptomator://vault/create?name=…&template=…} deeplink.
|
||||
* Requests creation of a new vault from a {@code cryptomator://vault/create?name=…&template=…} deeplink.
|
||||
* <p>
|
||||
* The {@code template} is a Base64URL-encoded ZIP archive holding a ready-made (signed) vault. The {@code name} fixes
|
||||
* the vault's directory name and is restricted to a single, safe path segment so that resolving it against a
|
||||
@@ -20,19 +21,27 @@ import org.slf4j.LoggerFactory;
|
||||
* @param name the fixed vault name (a single, safe path segment)
|
||||
* @param template the Base64URL-decoded vault template
|
||||
*/
|
||||
public record VaultCreateDeeplink(String name, byte[] template) {
|
||||
public record VaultCreationEvent(String name, byte[] template) implements AppLaunchEvent {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(VaultCreateDeeplink.class);
|
||||
private static final Logger LOG = LoggerFactory.getLogger(VaultCreationEvent.class);
|
||||
private static final String SCHEME = "cryptomator";
|
||||
private static final String HOST = "vault";
|
||||
private static final String PATH = "/create";
|
||||
|
||||
/**
|
||||
* Parses the query parameters of a {@code vault/create} deeplink.
|
||||
* Attempts to interpret the given URI as a {@code cryptomator://vault/create?name=…&template=…} deeplink.
|
||||
*
|
||||
* @param uri the deeplink URI
|
||||
* @return the parsed deeplink
|
||||
* @throws IllegalArgumentException if a required parameter is missing, the template is not valid Base64URL, or the
|
||||
* name is not a single safe path segment
|
||||
* @return the parsed event, or an empty optional if the URI's scheme, host or path do not identify a
|
||||
* vault-creation deeplink
|
||||
* @throws IllegalArgumentException if the URI identifies a vault-creation deeplink, but a required parameter is
|
||||
* missing, the template is not valid Base64URL, or the name is not a single safe
|
||||
* path segment
|
||||
*/
|
||||
public static VaultCreateDeeplink parse(URI uri) {
|
||||
public static Optional<VaultCreationEvent> tryParse(URI uri) {
|
||||
if (!SCHEME.equalsIgnoreCase(uri.getScheme()) || !HOST.equalsIgnoreCase(uri.getHost()) || !PATH.equals(uri.getPath())) {
|
||||
return Optional.empty();
|
||||
}
|
||||
var params = parseQuery(uri.getRawQuery());
|
||||
var name = params.get("name");
|
||||
var templateParam = params.get("template");
|
||||
@@ -49,11 +58,11 @@ public record VaultCreateDeeplink(String name, byte[] template) {
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new IllegalArgumentException("Query parameter 'template' is not valid Base64URL.", e);
|
||||
}
|
||||
var leftoverParams = params.keySet().stream().filter(k -> ! (k.equals("template") || k.equals("name"))).toList();
|
||||
if(!leftoverParams.isEmpty()) {
|
||||
LOG.debug("Ignoring unknow parameters {}", leftoverParams);
|
||||
var leftoverParams = params.keySet().stream().filter(k -> !(k.equals("template") || k.equals("name"))).toList();
|
||||
if (!leftoverParams.isEmpty()) {
|
||||
LOG.debug("Ignoring unknown parameters {}", leftoverParams);
|
||||
}
|
||||
return new VaultCreateDeeplink(name, template);
|
||||
return Optional.of(new VaultCreationEvent(name, template));
|
||||
}
|
||||
|
||||
private static void validateName(String name) {
|
||||
@@ -4,6 +4,9 @@ import org.cryptomator.common.vaults.NotAVaultDirectoryException;
|
||||
import org.cryptomator.common.vaults.Vault;
|
||||
import org.cryptomator.common.vaults.VaultListManager;
|
||||
import org.cryptomator.launcher.AppLaunchEvent;
|
||||
import org.cryptomator.launcher.OpenFileEvent;
|
||||
import org.cryptomator.launcher.RevealRunningEvent;
|
||||
import org.cryptomator.launcher.VaultCreationEvent;
|
||||
import org.cryptomator.ui.common.VaultService;
|
||||
import org.cryptomator.ui.dialogs.Dialogs;
|
||||
import org.slf4j.Logger;
|
||||
@@ -14,7 +17,6 @@ import javax.inject.Named;
|
||||
import javafx.application.Platform;
|
||||
import javafx.stage.Stage;
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
@@ -64,17 +66,16 @@ class AppLaunchEventHandler {
|
||||
}
|
||||
|
||||
private void handleLaunchEvent(AppLaunchEvent event) {
|
||||
switch (event.type()) {
|
||||
case REVEAL_APP -> appWindows.showMainWindow();
|
||||
case OPEN_FILE -> event.pathsToOpen().forEach(this::openPotentialVault);
|
||||
case OPEN_URI -> handleUri(event.uri());
|
||||
default -> LOG.warn("Unsupported event type: {}", event.type());
|
||||
switch (event) {
|
||||
case RevealRunningEvent _ -> appWindows.showMainWindow();
|
||||
case OpenFileEvent openFileEvent -> openFileEvent.pathsToOpen().forEach(this::openPotentialVault);
|
||||
case VaultCreationEvent vaultCreationEvent -> handleVaultCreation(vaultCreationEvent);
|
||||
}
|
||||
}
|
||||
|
||||
private void handleUri(URI uri) {
|
||||
// TODO: dispatch to a handler depending on the URI (e.g. host/path) once deeplink actions are defined
|
||||
LOG.warn("Received deeplink {}, but handling of this scheme is not yet implemented.", uri);
|
||||
private void handleVaultCreation(VaultCreationEvent event) {
|
||||
// TODO (deeplink step 5): open the dedicated vault-creation dialog via appWindows
|
||||
LOG.warn("Received vault-creation deeplink for '{}', but handling is not yet implemented.", event.name());
|
||||
appWindows.showMainWindow();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
package org.cryptomator.launcher;
|
||||
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.Optional;
|
||||
|
||||
public class DeeplinkActionTest {
|
||||
|
||||
@Test
|
||||
@DisplayName("cryptomator://vault/create maps to VAULT_CREATE")
|
||||
public void testVaultCreateMatches() {
|
||||
var result = DeeplinkAction.match(URI.create("cryptomator://vault/create?name=foo&template=bar"));
|
||||
|
||||
Assertions.assertEquals(Optional.of(DeeplinkAction.VAULT_CREATE), result);
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("host matching is case-insensitive")
|
||||
public void testHostCaseInsensitive() {
|
||||
var result = DeeplinkAction.match(URI.create("cryptomator://VAULT/create"));
|
||||
|
||||
Assertions.assertEquals(Optional.of(DeeplinkAction.VAULT_CREATE), result);
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("an unknown host yields empty")
|
||||
public void testUnknownHost() {
|
||||
Assertions.assertEquals(Optional.empty(), DeeplinkAction.match(URI.create("cryptomator://foo/create")));
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("an unknown path yields empty")
|
||||
public void testUnknownPath() {
|
||||
Assertions.assertEquals(Optional.empty(), DeeplinkAction.match(URI.create("cryptomator://vault/bar")));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -40,8 +40,7 @@ public class FileOpenRequestHandlerTest {
|
||||
public void testOpenArgsWithCorrectPaths() {
|
||||
inTest.handleLaunchArgs(List.of("foo", "bar"));
|
||||
|
||||
AppLaunchEvent evt = queue.poll();
|
||||
Assertions.assertNotNull(evt);
|
||||
OpenFileEvent evt = Assertions.assertInstanceOf(OpenFileEvent.class, queue.poll());
|
||||
Collection<Path> paths = evt.pathsToOpen();
|
||||
MatcherAssert.assertThat(paths, CoreMatchers.hasItems(Paths.get("foo"), Paths.get("bar")));
|
||||
}
|
||||
@@ -60,7 +59,7 @@ public class FileOpenRequestHandlerTest {
|
||||
@Test
|
||||
@DisplayName("./cryptomator.exe foo (with full event queue)")
|
||||
public void testOpenArgsWithFullQueue() {
|
||||
queue.add(AppLaunchEvent.openFiles(Collections.emptyList()));
|
||||
queue.add(new OpenFileEvent(Collections.emptyList()));
|
||||
Assumptions.assumeTrue(queue.remainingCapacity() == 0);
|
||||
|
||||
inTest.handleLaunchArgs(List.of("foo"));
|
||||
|
||||
@@ -1,69 +0,0 @@
|
||||
package org.cryptomator.launcher;
|
||||
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.net.URI;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Base64;
|
||||
|
||||
public class VaultCreateDeeplinkTest {
|
||||
|
||||
private static final byte[] TEMPLATE_BYTES = "a-ready-made-vault-zip".getBytes(StandardCharsets.UTF_8);
|
||||
private static final String TEMPLATE_B64 = Base64.getUrlEncoder().withoutPadding().encodeToString(TEMPLATE_BYTES);
|
||||
|
||||
@Test
|
||||
@DisplayName("a valid vault/create deeplink is parsed")
|
||||
public void testValid() {
|
||||
var inTest = VaultCreateDeeplink.parse(URI.create("cryptomator://vault/create?name=MyVault&template=" + TEMPLATE_B64));
|
||||
|
||||
Assertions.assertEquals("MyVault", inTest.name());
|
||||
Assertions.assertArrayEquals(TEMPLATE_BYTES, inTest.template());
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("a URL-encoded name is decoded")
|
||||
public void testUrlEncodedName() {
|
||||
var inTest = VaultCreateDeeplink.parse(URI.create("cryptomator://vault/create?name=My%20Vault&template=" + TEMPLATE_B64));
|
||||
|
||||
Assertions.assertEquals("My Vault", inTest.name());
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("a missing name fails")
|
||||
public void testMissingName() {
|
||||
Assertions.assertThrows(IllegalArgumentException.class, () -> VaultCreateDeeplink.parse(URI.create("cryptomator://vault/create?template=" + TEMPLATE_B64)));
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("a blank name fails")
|
||||
public void testBlankName() {
|
||||
Assertions.assertThrows(IllegalArgumentException.class, () -> VaultCreateDeeplink.parse(URI.create("cryptomator://vault/create?name=&template=" + TEMPLATE_B64)));
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("a missing template fails")
|
||||
public void testMissingTemplate() {
|
||||
Assertions.assertThrows(IllegalArgumentException.class, () -> VaultCreateDeeplink.parse(URI.create("cryptomator://vault/create?name=MyVault")));
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("an invalid Base64URL template fails")
|
||||
public void testInvalidTemplate() {
|
||||
Assertions.assertThrows(IllegalArgumentException.class, () -> VaultCreateDeeplink.parse(URI.create("cryptomator://vault/create?name=MyVault&template=@@@")));
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("a name containing a path separator fails")
|
||||
public void testNameWithSlash() {
|
||||
Assertions.assertThrows(IllegalArgumentException.class, () -> VaultCreateDeeplink.parse(URI.create("cryptomator://vault/create?name=foo%2Fbar&template=" + TEMPLATE_B64)));
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("a name with parent-dir traversal fails")
|
||||
public void testNameWithTraversal() {
|
||||
Assertions.assertThrows(IllegalArgumentException.class, () -> VaultCreateDeeplink.parse(URI.create("cryptomator://vault/create?name=..&template=" + TEMPLATE_B64)));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
package org.cryptomator.launcher;
|
||||
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.net.URI;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Base64;
|
||||
import java.util.Optional;
|
||||
|
||||
public class VaultCreationEventTest {
|
||||
|
||||
private static final byte[] TEMPLATE_BYTES = "a-ready-made-vault-zip".getBytes(StandardCharsets.UTF_8);
|
||||
private static final String TEMPLATE_B64 = Base64.getUrlEncoder().withoutPadding().encodeToString(TEMPLATE_BYTES);
|
||||
|
||||
@Test
|
||||
@DisplayName("a valid vault/create deeplink is parsed")
|
||||
public void testValid() {
|
||||
var inTest = VaultCreationEvent.tryParse(URI.create("cryptomator://vault/create?name=MyVault&template=" + TEMPLATE_B64)).orElseThrow();
|
||||
|
||||
Assertions.assertEquals("MyVault", inTest.name());
|
||||
Assertions.assertArrayEquals(TEMPLATE_BYTES, inTest.template());
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("a URL-encoded name is decoded")
|
||||
public void testUrlEncodedName() {
|
||||
var inTest = VaultCreationEvent.tryParse(URI.create("cryptomator://vault/create?name=My%20Vault&template=" + TEMPLATE_B64)).orElseThrow();
|
||||
|
||||
Assertions.assertEquals("My Vault", inTest.name());
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("a non-cryptomator scheme yields empty")
|
||||
public void testWrongScheme() {
|
||||
Assertions.assertEquals(Optional.empty(), VaultCreationEvent.tryParse(URI.create("foobar://vault/create?name=MyVault&template=" + TEMPLATE_B64)));
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("an unknown host yields empty")
|
||||
public void testWrongHost() {
|
||||
Assertions.assertEquals(Optional.empty(), VaultCreationEvent.tryParse(URI.create("cryptomator://foo/create?name=MyVault&template=" + TEMPLATE_B64)));
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("an unknown path yields empty")
|
||||
public void testWrongPath() {
|
||||
Assertions.assertEquals(Optional.empty(), VaultCreationEvent.tryParse(URI.create("cryptomator://vault/bar?name=MyVault&template=" + TEMPLATE_B64)));
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("a matching host is recognized case-insensitively")
|
||||
public void testHostCaseInsensitive() {
|
||||
Assertions.assertTrue(VaultCreationEvent.tryParse(URI.create("cryptomator://VAULT/create?name=MyVault&template=" + TEMPLATE_B64)).isPresent());
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("a missing name fails")
|
||||
public void testMissingName() {
|
||||
Assertions.assertThrows(IllegalArgumentException.class, () -> VaultCreationEvent.tryParse(URI.create("cryptomator://vault/create?template=" + TEMPLATE_B64)));
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("a blank name fails")
|
||||
public void testBlankName() {
|
||||
Assertions.assertThrows(IllegalArgumentException.class, () -> VaultCreationEvent.tryParse(URI.create("cryptomator://vault/create?name=&template=" + TEMPLATE_B64)));
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("a missing template fails")
|
||||
public void testMissingTemplate() {
|
||||
Assertions.assertThrows(IllegalArgumentException.class, () -> VaultCreationEvent.tryParse(URI.create("cryptomator://vault/create?name=MyVault")));
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("an invalid Base64URL template fails")
|
||||
public void testInvalidTemplate() {
|
||||
Assertions.assertThrows(IllegalArgumentException.class, () -> VaultCreationEvent.tryParse(URI.create("cryptomator://vault/create?name=MyVault&template=@@@")));
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("a name containing a path separator fails")
|
||||
public void testNameWithSlash() {
|
||||
Assertions.assertThrows(IllegalArgumentException.class, () -> VaultCreationEvent.tryParse(URI.create("cryptomator://vault/create?name=foo%2Fbar&template=" + TEMPLATE_B64)));
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("a name with parent-dir traversal fails")
|
||||
public void testNameWithTraversal() {
|
||||
Assertions.assertThrows(IllegalArgumentException.class, () -> VaultCreationEvent.tryParse(URI.create("cryptomator://vault/create?name=..&template=" + TEMPLATE_B64)));
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user