Merge pull request #18094 from iterate-ch/feature/preflight-argument-optionals

Review preflight parameters
This commit is contained in:
Yves Langisch
2026-05-09 14:36:50 +02:00
committed by GitHub
71 changed files with 310 additions and 241 deletions
@@ -32,6 +32,7 @@ import org.apache.commons.lang3.StringUtils;
import java.text.MessageFormat; import java.text.MessageFormat;
import java.util.EnumSet; import java.util.EnumSet;
import java.util.Optional;
import com.azure.core.exception.HttpResponseException; import com.azure.core.exception.HttpResponseException;
@@ -69,17 +70,18 @@ public class AzureDirectoryFeature implements Directory<Void> {
} }
@Override @Override
public void preflight(final Path workdir, final String filename) throws BackgroundException { public void preflight(final Path workdir, final Optional<String> filename) throws BackgroundException {
if(workdir.isRoot()) { if(workdir.isRoot()) {
if(!validate(filename)) { if(filename.isPresent()) {
if(!validate(filename.get())) {
throw new InvalidFilenameException(MessageFormat.format(LocaleFactory.localizedString("Cannot create folder {0}", "Error"), filename)); throw new InvalidFilenameException(MessageFormat.format(LocaleFactory.localizedString("Cannot create folder {0}", "Error"), filename));
} }
} }
// Empty argument if not known in validation
}
} }
public static boolean validate(final String filename) { public static boolean validate(final String filename) {
// Empty argument if not known in validation
if(StringUtils.isNotBlank(filename)) {
// Container names must be lowercase, between 3-63 characters long and must start with a letter or // Container names must be lowercase, between 3-63 characters long and must start with a letter or
// number. Container names may contain only letters, numbers, and the dash (-) character. // number. Container names may contain only letters, numbers, and the dash (-) character.
if(StringUtils.length(filename) > 63) { if(StringUtils.length(filename) > 63) {
@@ -91,7 +93,6 @@ public class AzureDirectoryFeature implements Directory<Void> {
if(!StringUtils.isAlphanumeric(RegExUtils.removeAll(filename, "-"))) { if(!StringUtils.isAlphanumeric(RegExUtils.removeAll(filename, "-"))) {
return false; return false;
} }
}
return true; return true;
} }
} }
@@ -26,6 +26,7 @@ import ch.cyberduck.core.transfer.TransferStatus;
import org.apache.commons.io.input.NullInputStream; import org.apache.commons.io.input.NullInputStream;
import java.text.MessageFormat; import java.text.MessageFormat;
import java.util.Optional;
public class AzureTouchFeature extends DefaultTouchFeature<Void> { public class AzureTouchFeature extends DefaultTouchFeature<Void> {
@@ -34,7 +35,7 @@ public class AzureTouchFeature extends DefaultTouchFeature<Void> {
} }
@Override @Override
public void preflight(final Path workdir, final String filename) throws BackgroundException { public void preflight(final Path workdir, final Optional<String> filename) throws BackgroundException {
if(workdir.isRoot()) { if(workdir.isRoot()) {
throw new AccessDeniedException(MessageFormat.format(LocaleFactory.localizedString("Cannot create {0}", "Error"), filename)).withFile(workdir); throw new AccessDeniedException(MessageFormat.format(LocaleFactory.localizedString("Cannot create {0}", "Error"), filename)).withFile(workdir);
} }
@@ -16,6 +16,7 @@ import org.junit.experimental.categories.Category;
import java.util.Collections; import java.util.Collections;
import java.util.EnumSet; import java.util.EnumSet;
import java.util.Optional;
import static org.junit.Assert.*; import static org.junit.Assert.*;
@@ -38,8 +39,8 @@ public class AzureDirectoryFeatureTest extends AbstractAzureTest {
public void testCreateContainerInvalidName() throws Exception { public void testCreateContainerInvalidName() throws Exception {
final Path container = new Path("untitled folder", EnumSet.of(Path.Type.directory)); final Path container = new Path("untitled folder", EnumSet.of(Path.Type.directory));
final AzureDirectoryFeature feature = new AzureDirectoryFeature(session); final AzureDirectoryFeature feature = new AzureDirectoryFeature(session);
assertFalse(feature.isSupported(container.getParent(), container.getName())); assertFalse(feature.isSupported(container.getParent(), Optional.of(container.getName())));
assertThrows(InvalidFilenameException.class, () -> feature.preflight(container.getParent(), container.getName())); assertThrows(InvalidFilenameException.class, () -> feature.preflight(container.getParent(), Optional.of(container.getName())));
feature.mkdir(new AzureWriteFeature(session), container, new TransferStatus()); feature.mkdir(new AzureWriteFeature(session), container, new TransferStatus());
assertTrue(new AzureFindFeature(session).find(container)); assertTrue(new AzureFindFeature(session).find(container));
new AzureDeleteFeature(session).delete(Collections.singletonList(container), LoginCallback.noop, new Delete.DisabledCallback()); new AzureDeleteFeature(session).delete(Collections.singletonList(container), LoginCallback.noop, new Delete.DisabledCallback());
@@ -28,6 +28,7 @@ import org.junit.experimental.categories.Category;
import java.util.Collections; import java.util.Collections;
import java.util.EnumSet; import java.util.EnumSet;
import java.util.Optional;
@Category(IntegrationTest.class) @Category(IntegrationTest.class)
public class AzureTouchFeatureTest extends AbstractAzureTest { public class AzureTouchFeatureTest extends AbstractAzureTest {
@@ -44,9 +45,9 @@ public class AzureTouchFeatureTest extends AbstractAzureTest {
public void testPreflightFilename() throws Exception { public void testPreflightFilename() throws Exception {
final Path container = new Path("cyberduck", EnumSet.of(Path.Type.directory, Path.Type.volume)); final Path container = new Path("cyberduck", EnumSet.of(Path.Type.directory, Path.Type.volume));
final AzureTouchFeature feature = new AzureTouchFeature(session); final AzureTouchFeature feature = new AzureTouchFeature(session);
feature.preflight(container, new AsciiRandomStringService().random()); feature.preflight(container, Optional.of(new AsciiRandomStringService().random()));
feature.preflight(container, new AlphanumericRandomStringService().random()); feature.preflight(container, Optional.of(new AlphanumericRandomStringService().random()));
feature.preflight(container, String.format("%s.suffix", new AlphanumericRandomStringService().random())); feature.preflight(container, Optional.of(String.format("%s.suffix", new AlphanumericRandomStringService().random())));
feature.preflight(container, "?"); feature.preflight(container, Optional.of("?"));
} }
} }
@@ -33,6 +33,7 @@ import org.apache.commons.lang3.StringUtils;
import java.io.IOException; import java.io.IOException;
import java.text.MessageFormat; import java.text.MessageFormat;
import java.util.EnumSet; import java.util.EnumSet;
import java.util.Optional;
import synapticloop.b2.BucketType; import synapticloop.b2.BucketType;
import synapticloop.b2.exception.B2ApiException; import synapticloop.b2.exception.B2ApiException;
@@ -79,23 +80,23 @@ public class B2DirectoryFeature implements Directory<BaseB2Response> {
} }
@Override @Override
public void preflight(final Path workdir, final String filename) throws BackgroundException { public void preflight(final Path workdir, final Optional<String> filename) throws BackgroundException {
if(workdir.isRoot()) { if(workdir.isRoot()) {
// Empty argument if not known in validation // Empty argument if not known in validation
if(StringUtils.isNotBlank(filename)) { if(filename.isPresent()) {
// Bucket names must be a minimum of 6 and a maximum of 50 characters long, and must be globally unique; // Bucket names must be a minimum of 6 and a maximum of 50 characters long, and must be globally unique;
// two different B2 accounts cannot have buckets with the name name. Bucket names can consist of: letters, // two different B2 accounts cannot have buckets with the name name. Bucket names can consist of: letters,
// digits, and "-". Bucket names cannot start with "b2-"; these are reserved for internal Backblaze use. // digits, and "-". Bucket names cannot start with "b2-"; these are reserved for internal Backblaze use.
if(StringUtils.startsWith(filename, "b2-")) { if(StringUtils.startsWith(filename.get(), "b2-")) {
throw new InvalidFilenameException(MessageFormat.format(LocaleFactory.localizedString("Cannot create folder {0}", "Error"), filename)); throw new InvalidFilenameException(MessageFormat.format(LocaleFactory.localizedString("Cannot create folder {0}", "Error"), filename));
} }
if(StringUtils.length(filename) > 50) { if(StringUtils.length(filename.get()) > 50) {
throw new InvalidFilenameException(MessageFormat.format(LocaleFactory.localizedString("Cannot create folder {0}", "Error"), filename)); throw new InvalidFilenameException(MessageFormat.format(LocaleFactory.localizedString("Cannot create folder {0}", "Error"), filename));
} }
if(StringUtils.length(filename) < 6) { if(StringUtils.length(filename.get()) < 6) {
throw new InvalidFilenameException(MessageFormat.format(LocaleFactory.localizedString("Cannot create folder {0}", "Error"), filename)); throw new InvalidFilenameException(MessageFormat.format(LocaleFactory.localizedString("Cannot create folder {0}", "Error"), filename));
} }
if(!StringUtils.isAlphanumeric(RegExUtils.removeAll(filename, "-"))) { if(!StringUtils.isAlphanumeric(RegExUtils.removeAll(filename.get(), "-"))) {
throw new InvalidFilenameException(MessageFormat.format(LocaleFactory.localizedString("Cannot create folder {0}", "Error"), filename)); throw new InvalidFilenameException(MessageFormat.format(LocaleFactory.localizedString("Cannot create folder {0}", "Error"), filename));
} }
} }
@@ -26,6 +26,7 @@ import ch.cyberduck.core.transfer.TransferStatus;
import org.apache.commons.io.input.NullInputStream; import org.apache.commons.io.input.NullInputStream;
import java.text.MessageFormat; import java.text.MessageFormat;
import java.util.Optional;
import synapticloop.b2.response.BaseB2Response; import synapticloop.b2.response.BaseB2Response;
@@ -41,7 +42,7 @@ public class B2TouchFeature extends DefaultTouchFeature<BaseB2Response> {
} }
@Override @Override
public void preflight(final Path workdir, final String filename) throws BackgroundException { public void preflight(final Path workdir, final Optional<String> filename) throws BackgroundException {
// Creating files is only possible inside a bucket. // Creating files is only possible inside a bucket.
if(workdir.isRoot()) { if(workdir.isRoot()) {
throw new AccessDeniedException(MessageFormat.format(LocaleFactory.localizedString("Cannot create {0}", "Error"), filename)).withFile(workdir); throw new AccessDeniedException(MessageFormat.format(LocaleFactory.localizedString("Cannot create {0}", "Error"), filename)).withFile(workdir);
@@ -31,6 +31,7 @@ import org.junit.experimental.categories.Category;
import java.util.Collections; import java.util.Collections;
import java.util.EnumSet; import java.util.EnumSet;
import java.util.Optional;
import static org.junit.Assert.*; import static org.junit.Assert.*;
@@ -42,7 +43,7 @@ public class B2DirectoryFeatureTest extends AbstractB2Test {
final Path bucket = new Path(new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory, Path.Type.volume)); final Path bucket = new Path(new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory, Path.Type.volume));
final B2VersionIdProvider fileid = new B2VersionIdProvider(session); final B2VersionIdProvider fileid = new B2VersionIdProvider(session);
final B2DirectoryFeature feature = new B2DirectoryFeature(session, fileid); final B2DirectoryFeature feature = new B2DirectoryFeature(session, fileid);
assertTrue(feature.isSupported(bucket.getParent(), bucket.getName())); assertTrue(feature.isSupported(bucket.getParent(), Optional.of(bucket.getName())));
feature.mkdir(new B2WriteFeature(session, fileid), bucket, new TransferStatus()); feature.mkdir(new B2WriteFeature(session, fileid), bucket, new TransferStatus());
assertThrows(ConflictException.class, () -> feature.mkdir(new B2WriteFeature(session, fileid), bucket, new TransferStatus())); assertThrows(ConflictException.class, () -> feature.mkdir(new B2WriteFeature(session, fileid), bucket, new TransferStatus()));
new B2DeleteFeature(session, fileid).delete(Collections.singletonList(bucket), LoginCallback.noop, new Delete.DisabledCallback()); new B2DeleteFeature(session, fileid).delete(Collections.singletonList(bucket), LoginCallback.noop, new Delete.DisabledCallback());
@@ -65,7 +66,7 @@ public class B2DirectoryFeatureTest extends AbstractB2Test {
public void testBucketInvalidCharacter() throws Exception { public void testBucketInvalidCharacter() throws Exception {
final Path bucket = new Path("untitled folder", EnumSet.of(Path.Type.directory, Path.Type.volume)); final Path bucket = new Path("untitled folder", EnumSet.of(Path.Type.directory, Path.Type.volume));
final B2VersionIdProvider fileid = new B2VersionIdProvider(session); final B2VersionIdProvider fileid = new B2VersionIdProvider(session);
assertFalse(new B2DirectoryFeature(session, fileid).isSupported(bucket.getParent(), bucket.getName())); assertFalse(new B2DirectoryFeature(session, fileid).isSupported(bucket.getParent(), Optional.of(bucket.getName())));
try { try {
new B2DirectoryFeature(session, fileid).mkdir(new B2WriteFeature(session, fileid), bucket, new TransferStatus()); new B2DirectoryFeature(session, fileid).mkdir(new B2WriteFeature(session, fileid), bucket, new TransferStatus());
} }
@@ -30,6 +30,7 @@ import ch.cyberduck.core.transfer.TransferStatus;
import java.text.MessageFormat; import java.text.MessageFormat;
import java.util.Collections; import java.util.Collections;
import java.util.Optional;
public class BoxDirectoryFeature implements Directory<File> { public class BoxDirectoryFeature implements Directory<File> {
@@ -55,9 +56,11 @@ public class BoxDirectoryFeature implements Directory<File> {
} }
@Override @Override
public void preflight(final Path workdir, final String filename) throws BackgroundException { public void preflight(final Path workdir, final Optional<String> filename) throws BackgroundException {
if(!BoxTouchFeature.validate(filename)) { if(filename.isPresent()) {
if(!BoxTouchFeature.validate(filename.get())) {
throw new InvalidFilenameException(MessageFormat.format(LocaleFactory.localizedString("Cannot create folder {0}", "Error"), filename)); throw new InvalidFilenameException(MessageFormat.format(LocaleFactory.localizedString("Cannot create folder {0}", "Error"), filename));
} }
} }
} }
}
@@ -25,6 +25,7 @@ import ch.cyberduck.core.shared.DefaultTouchFeature;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import java.text.MessageFormat; import java.text.MessageFormat;
import java.util.Optional;
public class BoxTouchFeature extends DefaultTouchFeature<File> { public class BoxTouchFeature extends DefaultTouchFeature<File> {
@@ -33,11 +34,13 @@ public class BoxTouchFeature extends DefaultTouchFeature<File> {
} }
@Override @Override
public void preflight(final Path workdir, final String filename) throws BackgroundException { public void preflight(final Path workdir, final Optional<String> filename) throws BackgroundException {
if(!validate(filename)) { if(filename.isPresent()) {
if(!validate(filename.get())) {
throw new InvalidFilenameException(MessageFormat.format(LocaleFactory.localizedString("Cannot create {0}", "Error"), filename)); throw new InvalidFilenameException(MessageFormat.format(LocaleFactory.localizedString("Cannot create {0}", "Error"), filename));
} }
} }
}
public static boolean validate(final String filename) { public static boolean validate(final String filename) {
// Max Length 255 // Max Length 255
@@ -30,6 +30,7 @@ import org.junit.experimental.categories.Category;
import java.util.Collections; import java.util.Collections;
import java.util.EnumSet; import java.util.EnumSet;
import java.util.Optional;
import static org.junit.Assert.*; import static org.junit.Assert.*;
@@ -53,11 +54,11 @@ public class BoxDirectoryFeatureTest extends AbstractBoxTest {
@Test @Test
public void isSupported() { public void isSupported() {
final BoxFileidProvider fileid = new BoxFileidProvider(session); final BoxFileidProvider fileid = new BoxFileidProvider(session);
assertTrue(new BoxDirectoryFeature(session, fileid).isSupported(Home.root(), new AlphanumericRandomStringService().random())); assertTrue(new BoxDirectoryFeature(session, fileid).isSupported(Home.root(), Optional.of(new AlphanumericRandomStringService().random())));
assertFalse(new BoxDirectoryFeature(session, fileid).isSupported(Home.root(), String.format("%s ", new AlphanumericRandomStringService().random()))); assertFalse(new BoxDirectoryFeature(session, fileid).isSupported(Home.root(), Optional.of(String.format("%s ", new AlphanumericRandomStringService().random()))));
assertFalse(new BoxDirectoryFeature(session, fileid).isSupported(Home.root(), String.format("%s\\", new AlphanumericRandomStringService().random()))); assertFalse(new BoxDirectoryFeature(session, fileid).isSupported(Home.root(), Optional.of(String.format("%s\\", new AlphanumericRandomStringService().random()))));
assertFalse(new BoxDirectoryFeature(session, fileid).isSupported(Home.root(), String.format("%s/", new AlphanumericRandomStringService().random()))); assertFalse(new BoxDirectoryFeature(session, fileid).isSupported(Home.root(), Optional.of(String.format("%s/", new AlphanumericRandomStringService().random()))));
assertFalse(new BoxDirectoryFeature(session, fileid).isSupported(Home.root(), ".")); assertFalse(new BoxDirectoryFeature(session, fileid).isSupported(Home.root(), Optional.of(".")));
assertFalse(new BoxDirectoryFeature(session, fileid).isSupported(Home.root(), "..")); assertFalse(new BoxDirectoryFeature(session, fileid).isSupported(Home.root(), Optional.of("..")));
} }
} }
@@ -21,6 +21,8 @@ import ch.cyberduck.test.IntegrationTest;
import org.junit.Test; import org.junit.Test;
import org.junit.experimental.categories.Category; import org.junit.experimental.categories.Category;
import java.util.Optional;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
@Category(IntegrationTest.class) @Category(IntegrationTest.class)
@@ -29,6 +31,6 @@ public class BoxTouchFeatureTest extends AbstractBoxTest {
@Test @Test
public void testSupported() { public void testSupported() {
final BoxFileidProvider fileid = new BoxFileidProvider(session); final BoxFileidProvider fileid = new BoxFileidProvider(session);
assertTrue(new BoxTouchFeature(session, fileid).isSupported(Home.root(), "xacjivli-éf")); assertTrue(new BoxTouchFeature(session, fileid).isSupported(Home.root(), Optional.of("xacjivli-éf")));
} }
} }
@@ -22,6 +22,7 @@ import ch.cyberduck.core.exception.BackgroundException;
import ch.cyberduck.core.transfer.TransferStatus; import ch.cyberduck.core.transfer.TransferStatus;
import java.text.MessageFormat; import java.text.MessageFormat;
import java.util.Optional;
/** /**
* Create new folder on server * Create new folder on server
@@ -43,10 +44,10 @@ public interface Directory<Reply> {
/** /**
* @param workdir Working directory in browser * @param workdir Working directory in browser
* @param filename Folder name or null if unknown * @param filename Folder name if known
* @return True if creating directory is supported in the working directory * @return True if creating directory is supported in the working directory
*/ */
default boolean isSupported(final Path workdir, final String filename) { default boolean isSupported(final Path workdir, final Optional<String> filename) {
try { try {
this.preflight(workdir, filename); this.preflight(workdir, filename);
return true; return true;
@@ -59,7 +60,7 @@ public interface Directory<Reply> {
/** /**
* @throws AccessDeniedException Permission failure for target directory * @throws AccessDeniedException Permission failure for target directory
*/ */
default void preflight(final Path workdir, final String filename) throws BackgroundException { default void preflight(final Path workdir, final Optional<String> filename) throws BackgroundException {
if(!workdir.attributes().getPermission().isWritable()) { if(!workdir.attributes().getPermission().isWritable()) {
throw new AccessDeniedException(MessageFormat.format(LocaleFactory.localizedString( throw new AccessDeniedException(MessageFormat.format(LocaleFactory.localizedString(
"Cannot create folder {0}", "Error"), filename)).withFile(workdir); "Cannot create folder {0}", "Error"), filename)).withFile(workdir);
@@ -40,7 +40,7 @@ public interface Touch<Reply> {
* @param filename Relative filename * @param filename Relative filename
* @return True if creating an empty file is possible. * @return True if creating an empty file is possible.
*/ */
default boolean isSupported(final Path workdir, final String filename) { default boolean isSupported(final Path workdir, final java.util.Optional<String> filename) {
try { try {
this.preflight(workdir, filename); this.preflight(workdir, filename);
return true; return true;
@@ -53,7 +53,7 @@ public interface Touch<Reply> {
/** /**
* @throws AccessDeniedException Permission failure for target directory * @throws AccessDeniedException Permission failure for target directory
*/ */
default void preflight(final Path workdir, final String filename) throws BackgroundException { default void preflight(final Path workdir, final java.util.Optional<String> filename) throws BackgroundException {
if(!workdir.attributes().getPermission().isWritable()) { if(!workdir.attributes().getPermission().isWritable()) {
throw new AccessDeniedException(MessageFormat.format(LocaleFactory.localizedString( throw new AccessDeniedException(MessageFormat.format(LocaleFactory.localizedString(
"Cannot create {0}", "Error"), filename)).withFile(workdir); "Cannot create {0}", "Error"), filename)).withFile(workdir);
@@ -97,9 +97,14 @@ public class VaultRegistryCopyFeature implements Copy {
} }
} }
else { else {
try {
registry.find(session, source, false).getFeature(session, Copy.class, proxy).preflight(source, optional);
}
catch(VaultUnlockCancelException e) {
proxy.preflight(source, optional); proxy.preflight(source, optional);
} }
} }
}
@Override @Override
public Copy withTarget(final Session<?> session) { public Copy withTarget(final Session<?> session) {
@@ -24,6 +24,8 @@ import ch.cyberduck.core.transfer.TransferStatus;
import ch.cyberduck.core.vault.VaultRegistry; import ch.cyberduck.core.vault.VaultRegistry;
import ch.cyberduck.core.vault.VaultUnlockCancelException; import ch.cyberduck.core.vault.VaultUnlockCancelException;
import java.util.Optional;
public class VaultRegistryDirectoryFeature<Reply> implements Directory<Reply> { public class VaultRegistryDirectoryFeature<Reply> implements Directory<Reply> {
private final Session<?> session; private final Session<?> session;
@@ -42,7 +44,7 @@ public class VaultRegistryDirectoryFeature<Reply> implements Directory<Reply> {
} }
@Override @Override
public void preflight(final Path workdir, final String filename) throws BackgroundException { public void preflight(final Path workdir, final Optional<String> filename) throws BackgroundException {
try { try {
registry.find(session, workdir, false).getFeature(session, Directory.class, proxy).preflight(workdir, filename); registry.find(session, workdir, false).getFeature(session, Directory.class, proxy).preflight(workdir, filename);
} }
@@ -111,9 +111,14 @@ public class VaultRegistryMoveFeature implements Move {
} }
} }
else { else {
try {
registry.find(session, source, false).getFeature(session, Move.class, proxy).preflight(source, optional);
}
catch(VaultUnlockCancelException e) {
proxy.preflight(source, optional); proxy.preflight(source, optional);
} }
} }
}
@Override @Override
public Move withTarget(final Session<?> session) { public Move withTarget(final Session<?> session) {
@@ -24,6 +24,8 @@ import ch.cyberduck.core.transfer.TransferStatus;
import ch.cyberduck.core.vault.VaultRegistry; import ch.cyberduck.core.vault.VaultRegistry;
import ch.cyberduck.core.vault.VaultUnlockCancelException; import ch.cyberduck.core.vault.VaultUnlockCancelException;
import java.util.Optional;
public class VaultRegistryTouchFeature<R> implements Touch<R> { public class VaultRegistryTouchFeature<R> implements Touch<R> {
private final Session<?> session; private final Session<?> session;
@@ -42,7 +44,7 @@ public class VaultRegistryTouchFeature<R> implements Touch<R> {
} }
@Override @Override
public void preflight(final Path workdir, final String filename) throws BackgroundException { public void preflight(final Path workdir, final Optional<String> filename) throws BackgroundException {
try { try {
registry.find(session, workdir, false).getFeature(session, Touch.class, proxy).preflight(workdir, filename); registry.find(session, workdir, false).getFeature(session, Touch.class, proxy).preflight(workdir, filename);
} }
@@ -28,6 +28,8 @@ import ch.cyberduck.core.transfer.TransferStatus;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import java.util.Optional;
public class CryptoDirectoryV6Feature<Reply> implements Directory<Reply> { public class CryptoDirectoryV6Feature<Reply> implements Directory<Reply> {
private static final Logger log = LogManager.getLogger(CryptoDirectoryV6Feature.class); private static final Logger log = LogManager.getLogger(CryptoDirectoryV6Feature.class);
@@ -65,12 +67,12 @@ public class CryptoDirectoryV6Feature<Reply> implements Directory<Reply> {
} }
@Override @Override
public boolean isSupported(final Path workdir, final String name) { public boolean isSupported(final Path workdir, final Optional<String> name) {
return delegate.isSupported(workdir, name); return delegate.isSupported(workdir, name);
} }
@Override @Override
public void preflight(final Path workdir, final String filename) throws BackgroundException { public void preflight(final Path workdir, final Optional<String> filename) throws BackgroundException {
delegate.preflight(cryptomator.encrypt(session, workdir), filename); delegate.preflight(cryptomator.encrypt(session, workdir), filename);
} }
@@ -30,6 +30,7 @@ import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import java.util.EnumSet; import java.util.EnumSet;
import java.util.Optional;
public class CryptoDirectoryV7Feature<Reply> implements Directory<Reply> { public class CryptoDirectoryV7Feature<Reply> implements Directory<Reply> {
private static final Logger log = LogManager.getLogger(CryptoDirectoryV7Feature.class); private static final Logger log = LogManager.getLogger(CryptoDirectoryV7Feature.class);
@@ -73,12 +74,12 @@ public class CryptoDirectoryV7Feature<Reply> implements Directory<Reply> {
} }
@Override @Override
public boolean isSupported(final Path workdir, final String name) { public boolean isSupported(final Path workdir, final Optional<String> name) {
return delegate.isSupported(workdir, name); return delegate.isSupported(workdir, name);
} }
@Override @Override
public void preflight(final Path workdir, final String filename) throws BackgroundException { public void preflight(final Path workdir, final Optional<String> filename) throws BackgroundException {
delegate.preflight(cryptomator.encrypt(session, workdir), filename); delegate.preflight(cryptomator.encrypt(session, workdir), filename);
} }
@@ -31,6 +31,7 @@ import ch.cyberduck.core.transfer.TransferStatus;
import org.cryptomator.cryptolib.api.FileHeader; import org.cryptomator.cryptolib.api.FileHeader;
import java.text.MessageFormat; import java.text.MessageFormat;
import java.util.Optional;
public class CryptoTouchFeature<Reply> implements Touch<Reply> { public class CryptoTouchFeature<Reply> implements Touch<Reply> {
@@ -65,10 +66,12 @@ public class CryptoTouchFeature<Reply> implements Touch<Reply> {
} }
@Override @Override
public void preflight(final Path workdir, final String filename) throws BackgroundException { public void preflight(final Path workdir, final Optional<String> filename) throws BackgroundException {
if(!cryptomator.getFilenameProvider().isValid(filename)) { if(filename.isPresent()) {
if(!cryptomator.getFilenameProvider().isValid(filename.get())) {
throw new InvalidFilenameException(MessageFormat.format(LocaleFactory.localizedString("Cannot create {0}", "Error"), filename)); throw new InvalidFilenameException(MessageFormat.format(LocaleFactory.localizedString("Cannot create {0}", "Error"), filename));
} }
}
proxy.preflight(cryptomator.encrypt(session, workdir), filename); proxy.preflight(cryptomator.encrypt(session, workdir), filename);
} }
@@ -401,17 +401,11 @@ public class CryptomatorVaultTest {
public <T> T _getFeature(final Class<T> type) { public <T> T _getFeature(final Class<T> type) {
if(type == Directory.class) { if(type == Directory.class) {
return (T) new Directory() { return (T) new Directory() {
@Override @Override
public Path mkdir(final Write writer, final Path folder, final TransferStatus status) { public Path mkdir(final Write writer, final Path folder, final TransferStatus status) {
assertTrue(folder.equals(home) || folder.isChild(home)); assertTrue(folder.equals(home) || folder.isChild(home));
return folder; return folder;
} }
@Override
public boolean isSupported(final Path workdir, final String name) {
throw new UnsupportedOperationException();
}
}; };
} }
return super._getFeature(type); return super._getFeature(type);
@@ -31,6 +31,7 @@ import org.apache.logging.log4j.Logger;
import org.cryptomator.cryptolib.api.DirectoryMetadata; import org.cryptomator.cryptolib.api.DirectoryMetadata;
import java.util.EnumSet; import java.util.EnumSet;
import java.util.Optional;
public class CryptoDirectoryFeature<Reply> implements Directory<Reply> { public class CryptoDirectoryFeature<Reply> implements Directory<Reply> {
private static final Logger log = LogManager.getLogger(CryptoDirectoryFeature.class); private static final Logger log = LogManager.getLogger(CryptoDirectoryFeature.class);
@@ -87,13 +88,13 @@ public class CryptoDirectoryFeature<Reply> implements Directory<Reply> {
} }
@Override @Override
public boolean isSupported(final Path workdir, final String name) { public boolean isSupported(final Path workdir, final Optional<String> name) {
return delegate.isSupported(workdir, name); return delegate.isSupported(workdir, name);
} }
@Override @Override
public void preflight(final Path workdir, final String filename) throws BackgroundException { public void preflight(final Path workdir, final Optional<String> filename) throws BackgroundException {
vault.getDirectoryProvider().createDirectoryId(new Path(workdir, filename, EnumSet.of(Path.Type.directory))); filename.ifPresent(s -> vault.getDirectoryProvider().createDirectoryId(new Path(workdir, s, EnumSet.of(Path.Type.directory))));
delegate.preflight(vault.encrypt(session, workdir), filename); delegate.preflight(vault.encrypt(session, workdir), filename);
} }
@@ -31,6 +31,7 @@ import ch.cyberduck.core.transfer.TransferStatus;
import org.cryptomator.cryptolib.api.FileHeader; import org.cryptomator.cryptolib.api.FileHeader;
import java.text.MessageFormat; import java.text.MessageFormat;
import java.util.Optional;
public class CryptoTouchFeature<Reply> implements Touch<Reply> { public class CryptoTouchFeature<Reply> implements Touch<Reply> {
@@ -65,10 +66,12 @@ public class CryptoTouchFeature<Reply> implements Touch<Reply> {
} }
@Override @Override
public void preflight(final Path workdir, final String filename) throws BackgroundException { public void preflight(final Path workdir, final Optional<String> filename) throws BackgroundException {
if(!vault.getFilenameProvider().isValid(filename)) { if(filename.isPresent()) {
if(!vault.getFilenameProvider().isValid(filename.get())) {
throw new InvalidFilenameException(MessageFormat.format(LocaleFactory.localizedString("Cannot create {0}", "Error"), filename)); throw new InvalidFilenameException(MessageFormat.format(LocaleFactory.localizedString("Cannot create {0}", "Error"), filename));
} }
}
proxy.preflight(vault.encrypt(session, workdir), filename); proxy.preflight(vault.encrypt(session, workdir), filename);
} }
@@ -354,11 +354,6 @@ public class CryptomatorVaultTest {
assertTrue(folder.equals(home) || folder.isChild(home)); assertTrue(folder.equals(home) || folder.isChild(home));
return folder; return folder;
} }
@Override
public boolean isSupported(final Path workdir, final String name) {
throw new UnsupportedOperationException();
}
}; };
} }
return super._getFeature(type); return super._getFeature(type);
@@ -116,10 +116,6 @@ public class CteraAttributesFinderFeature extends DAVAttributesFinderFeature {
* @throws AccessDeniedException ACLs do not contain role * @throws AccessDeniedException ACLs do not contain role
*/ */
protected static void assumeRole(final Path file, final Acl.Role role) throws BackgroundException { protected static void assumeRole(final Path file, final Acl.Role role) throws BackgroundException {
assumeRole(file, file.getName(), role);
}
protected static void assumeRole(final Path file, final String filename, final Acl.Role role) throws BackgroundException {
final Acl acl = file.attributes().getAcl(); final Acl acl = file.attributes().getAcl();
if(acl == Acl.EMPTY) { if(acl == Acl.EMPTY) {
log.warn("Missing ACL for {}", file); log.warn("Missing ACL for {}", file);
@@ -134,11 +130,11 @@ public class CteraAttributesFinderFeature extends DAVAttributesFinderFeature {
log.warn("ACL {} for {} does not include {}", acl, file, role); log.warn("ACL {} for {} does not include {}", acl, file, role);
if(role == READPERMISSION) { if(role == READPERMISSION) {
throw new AccessDeniedException(MessageFormat.format(LocaleFactory.localizedString("Download {0} failed", "Error"), throw new AccessDeniedException(MessageFormat.format(LocaleFactory.localizedString("Download {0} failed", "Error"),
filename)).withFile(file); file.getName())).withFile(file);
} }
if(role == WRITEPERMISSION) { if(role == WRITEPERMISSION) {
throw new AccessDeniedException(MessageFormat.format(LocaleFactory.localizedString("Upload {0} failed", "Error"), throw new AccessDeniedException(MessageFormat.format(LocaleFactory.localizedString("Upload {0} failed", "Error"),
filename)).withFile(file); file.getName())).withFile(file);
} }
if(role == DELETEPERMISSION) { if(role == DELETEPERMISSION) {
throw new AccessDeniedException(MessageFormat.format( throw new AccessDeniedException(MessageFormat.format(
@@ -146,7 +142,7 @@ public class CteraAttributesFinderFeature extends DAVAttributesFinderFeature {
} }
if(role == CREATEDIRECTORIESPERMISSION) { if(role == CREATEDIRECTORIESPERMISSION) {
throw new AccessDeniedException(MessageFormat.format(LocaleFactory.localizedString("Cannot create folder {0}", "Error"), throw new AccessDeniedException(MessageFormat.format(LocaleFactory.localizedString("Cannot create folder {0}", "Error"),
filename)).withFile(file); file.getName())).withFile(file);
} }
throw new AccessDeniedException(MessageFormat.format( throw new AccessDeniedException(MessageFormat.format(
LocaleFactory.localizedString("Cannot create {0}", "Error"), file.getName())).withFile(file); LocaleFactory.localizedString("Cannot create {0}", "Error"), file.getName())).withFile(file);
@@ -37,7 +37,7 @@ public class CteraCopyFeature extends DAVCopyFeature {
assumeRole(target, WRITEPERMISSION); assumeRole(target, WRITEPERMISSION);
// no createfilespermission required for now // no createfilespermission required for now
if(source.isDirectory()) { if(source.isDirectory()) {
assumeRole(target.getParent(), target.getName(), CREATEDIRECTORIESPERMISSION); assumeRole(target, CREATEDIRECTORIESPERMISSION);
} }
} }
} }
@@ -22,6 +22,7 @@ import ch.cyberduck.core.exception.BackgroundException;
import ch.cyberduck.core.exception.InvalidFilenameException; import ch.cyberduck.core.exception.InvalidFilenameException;
import java.text.MessageFormat; import java.text.MessageFormat;
import java.util.Optional;
import static ch.cyberduck.core.ctera.CteraAttributesFinderFeature.CREATEDIRECTORIESPERMISSION; import static ch.cyberduck.core.ctera.CteraAttributesFinderFeature.CREATEDIRECTORIESPERMISSION;
import static ch.cyberduck.core.ctera.CteraAttributesFinderFeature.assumeRole; import static ch.cyberduck.core.ctera.CteraAttributesFinderFeature.assumeRole;
@@ -34,10 +35,12 @@ public class CteraDirectoryFeature extends DAVDirectoryFeature {
} }
@Override @Override
public void preflight(final Path workdir, final String filename) throws BackgroundException { public void preflight(final Path workdir, final Optional<String> filename) throws BackgroundException {
if(!validate(filename)) { if(filename.isPresent()) {
if(!validate(filename.get())) {
throw new InvalidFilenameException(MessageFormat.format(LocaleFactory.localizedString("Cannot create folder {0}", "Error"), filename)); throw new InvalidFilenameException(MessageFormat.format(LocaleFactory.localizedString("Cannot create folder {0}", "Error"), filename));
} }
assumeRole(workdir, filename, CREATEDIRECTORIESPERMISSION); }
assumeRole(workdir, CREATEDIRECTORIESPERMISSION);
} }
} }
@@ -44,7 +44,7 @@ public class CteraMoveFeature extends DAVMoveFeature {
assumeRole(target, WRITEPERMISSION); assumeRole(target, WRITEPERMISSION);
// no createfilespermission required for now // no createfilespermission required for now
if(source.isDirectory()) { if(source.isDirectory()) {
assumeRole(target.getParent(), target.getName(), CREATEDIRECTORIESPERMISSION); assumeRole(target, CREATEDIRECTORIESPERMISSION);
} }
} }
} }
@@ -27,6 +27,7 @@ import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import java.text.MessageFormat; import java.text.MessageFormat;
import java.util.Optional;
import static ch.cyberduck.core.ctera.CteraAttributesFinderFeature.*; import static ch.cyberduck.core.ctera.CteraAttributesFinderFeature.*;
@@ -39,10 +40,12 @@ public class CteraTouchFeature extends DAVTouchFeature {
} }
@Override @Override
public void preflight(final Path workdir, final String filename) throws BackgroundException { public void preflight(final Path workdir, final Optional<String> filename) throws BackgroundException {
if(!validate(filename)) { if(filename.isPresent()) {
if(!validate(filename.get())) {
throw new InvalidFilenameException(MessageFormat.format(LocaleFactory.localizedString("Cannot create {0}", "Error"), filename)); throw new InvalidFilenameException(MessageFormat.format(LocaleFactory.localizedString("Cannot create {0}", "Error"), filename));
} }
}
// File/directory creation summary: // File/directory creation summary:
// - Directories with ctera:writepermission but no ctera:createdirectoriespermission allow for file creation only. // - Directories with ctera:writepermission but no ctera:createdirectoriespermission allow for file creation only.
@@ -32,6 +32,7 @@ import org.junit.experimental.categories.Category;
import java.util.Collections; import java.util.Collections;
import java.util.EnumSet; import java.util.EnumSet;
import java.util.Optional;
import static ch.cyberduck.core.ctera.CteraAttributesFinderFeature.CREATEDIRECTORIESPERMISSION; import static ch.cyberduck.core.ctera.CteraAttributesFinderFeature.CREATEDIRECTORIESPERMISSION;
import static ch.cyberduck.core.ctera.CteraAttributesFinderFeature.READPERMISSION; import static ch.cyberduck.core.ctera.CteraAttributesFinderFeature.READPERMISSION;
@@ -54,21 +55,21 @@ public class CteraDirectoryFeatureTest extends AbstractCteraTest {
public void testPreflightFileMissingCustomProps() throws Exception { public void testPreflightFileMissingCustomProps() throws Exception {
final Path workdir = new Path(new DefaultHomeFinderService(session).find(), new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path workdir = new Path(new DefaultHomeFinderService(session).find(), new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory));
workdir.setAttributes(workdir.attributes().setAcl(Acl.EMPTY)); workdir.setAttributes(workdir.attributes().setAcl(Acl.EMPTY));
new CteraDirectoryFeature(session).preflight(workdir, new AlphanumericRandomStringService().random()); new CteraDirectoryFeature(session).preflight(workdir, Optional.of(new AlphanumericRandomStringService().random()));
} }
@Test @Test
public void testPreflightFileAccessDeniedCustomProps() throws Exception { public void testPreflightFileAccessDeniedCustomProps() throws Exception {
final Path workdir = new Path(new DefaultHomeFinderService(session).find(), new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path workdir = new Path(new DefaultHomeFinderService(session).find(), new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory));
workdir.setAttributes(workdir.attributes().setAcl(new Acl(new Acl.CanonicalUser(), READPERMISSION))); workdir.setAttributes(workdir.attributes().setAcl(new Acl(new Acl.CanonicalUser(), READPERMISSION)));
assertThrows(AccessDeniedException.class, () -> new CteraDirectoryFeature(session).preflight(workdir, new AlphanumericRandomStringService().random())); assertThrows(AccessDeniedException.class, () -> new CteraDirectoryFeature(session).preflight(workdir, Optional.of(new AlphanumericRandomStringService().random())));
} }
@Test @Test
public void testPreflightFileAccessGrantedCustomProps() throws Exception { public void testPreflightFileAccessGrantedCustomProps() throws Exception {
final Path workdir = new Path(new DefaultHomeFinderService(session).find(), new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path workdir = new Path(new DefaultHomeFinderService(session).find(), new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory));
workdir.setAttributes(workdir.attributes().setAcl(new Acl(new Acl.CanonicalUser(), CREATEDIRECTORIESPERMISSION))); workdir.setAttributes(workdir.attributes().setAcl(new Acl(new Acl.CanonicalUser(), CREATEDIRECTORIESPERMISSION)));
new CteraDirectoryFeature(session).preflight(workdir, new AlphanumericRandomStringService().random()); new CteraDirectoryFeature(session).preflight(workdir, Optional.of(new AlphanumericRandomStringService().random()));
// assert no fail // assert no fail
} }
} }
@@ -26,6 +26,7 @@ import org.junit.Test;
import org.junit.experimental.categories.Category; import org.junit.experimental.categories.Category;
import java.util.EnumSet; import java.util.EnumSet;
import java.util.Optional;
import static ch.cyberduck.core.ctera.CteraAttributesFinderFeature.CREATEDIRECTORIESPERMISSION; import static ch.cyberduck.core.ctera.CteraAttributesFinderFeature.CREATEDIRECTORIESPERMISSION;
import static ch.cyberduck.core.ctera.CteraAttributesFinderFeature.WRITEPERMISSION; import static ch.cyberduck.core.ctera.CteraAttributesFinderFeature.WRITEPERMISSION;
@@ -38,28 +39,28 @@ public class CteraTouchFeatureTest extends AbstractCteraTest {
public void testPreflightFileMissingCustomProps() throws Exception { public void testPreflightFileMissingCustomProps() throws Exception {
final Path file = new Path(new DefaultHomeFinderService(session).find(), new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path file = new Path(new DefaultHomeFinderService(session).find(), new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory));
file.setAttributes(file.attributes().setAcl(Acl.EMPTY)); file.setAttributes(file.attributes().setAcl(Acl.EMPTY));
new CteraTouchFeature(session).preflight(file, new AlphanumericRandomStringService().random()); new CteraTouchFeature(session).preflight(file, Optional.of(new AlphanumericRandomStringService().random()));
} }
@Test @Test
public void testPreflightReadPermission() throws Exception { public void testPreflightReadPermission() throws Exception {
final Path file = new Path(new DefaultHomeFinderService(session).find(), new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path file = new Path(new DefaultHomeFinderService(session).find(), new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory));
file.setAttributes(file.attributes().setAcl(new Acl(new Acl.CanonicalUser(), CteraAttributesFinderFeature.READPERMISSION))); file.setAttributes(file.attributes().setAcl(new Acl(new Acl.CanonicalUser(), CteraAttributesFinderFeature.READPERMISSION)));
assertThrows(AccessDeniedException.class, () -> new CteraTouchFeature(session).preflight(file, new AlphanumericRandomStringService().random())); assertThrows(AccessDeniedException.class, () -> new CteraTouchFeature(session).preflight(file, Optional.of(new AlphanumericRandomStringService().random())));
} }
@Test @Test
public void testPreflightNoPermissions() throws Exception { public void testPreflightNoPermissions() throws Exception {
final Path file = new Path(new DefaultHomeFinderService(session).find(), new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path file = new Path(new DefaultHomeFinderService(session).find(), new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory));
file.setAttributes(file.attributes().setAcl(new Acl(new Acl.CanonicalUser()))); file.setAttributes(file.attributes().setAcl(new Acl(new Acl.CanonicalUser())));
assertThrows(AccessDeniedException.class, () -> new CteraTouchFeature(session).preflight(file, new AlphanumericRandomStringService().random())); assertThrows(AccessDeniedException.class, () -> new CteraTouchFeature(session).preflight(file, Optional.of(new AlphanumericRandomStringService().random())));
} }
@Test @Test
public void testPreflightWritePermission() throws Exception { public void testPreflightWritePermission() throws Exception {
final Path file = new Path(new DefaultHomeFinderService(session).find(), new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path file = new Path(new DefaultHomeFinderService(session).find(), new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory));
file.setAttributes(file.attributes().setAcl(new Acl(new Acl.CanonicalUser(), CteraAttributesFinderFeature.WRITEPERMISSION))); file.setAttributes(file.attributes().setAcl(new Acl(new Acl.CanonicalUser(), CteraAttributesFinderFeature.WRITEPERMISSION)));
new CteraTouchFeature(session).preflight(file, new AlphanumericRandomStringService().random()); new CteraTouchFeature(session).preflight(file, Optional.of(new AlphanumericRandomStringService().random()));
// assert no fail // assert no fail
} }
@@ -67,7 +68,7 @@ public class CteraTouchFeatureTest extends AbstractCteraTest {
public void testPreflightCreateDirectoriesPermission() throws Exception { public void testPreflightCreateDirectoriesPermission() throws Exception {
final Path file = new Path(new DefaultHomeFinderService(session).find(), new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path file = new Path(new DefaultHomeFinderService(session).find(), new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory));
file.setAttributes(file.attributes().setAcl(new Acl(new Acl.CanonicalUser(), CteraAttributesFinderFeature.CREATEDIRECTORIESPERMISSION))); file.setAttributes(file.attributes().setAcl(new Acl(new Acl.CanonicalUser(), CteraAttributesFinderFeature.CREATEDIRECTORIESPERMISSION)));
new CteraTouchFeature(session).preflight(file, new AlphanumericRandomStringService().random()); new CteraTouchFeature(session).preflight(file, Optional.of(new AlphanumericRandomStringService().random()));
// assert no fail // assert no fail
} }
@@ -79,14 +80,14 @@ public class CteraTouchFeatureTest extends AbstractCteraTest {
new Acl.UserAndRole(new Acl.CanonicalUser(), WRITEPERMISSION), new Acl.UserAndRole(new Acl.CanonicalUser(), WRITEPERMISSION),
new Acl.UserAndRole(new Acl.CanonicalUser(), CREATEDIRECTORIESPERMISSION) new Acl.UserAndRole(new Acl.CanonicalUser(), CREATEDIRECTORIESPERMISSION)
))); )));
new CteraTouchFeature(session).preflight(file, new AlphanumericRandomStringService().random()); new CteraTouchFeature(session).preflight(file, Optional.of(new AlphanumericRandomStringService().random()));
// assert no fail // assert no fail
} }
@Test @Test
public void testPreflightFileAccessGrantedCustomProps() throws Exception { public void testPreflightFileAccessGrantedCustomProps() throws Exception {
final Path file = new Path(new DefaultHomeFinderService(session).find(), new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path file = new Path(new DefaultHomeFinderService(session).find(), new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory));
new CteraTouchFeature(session).preflight(file, new AlphanumericRandomStringService().random()); new CteraTouchFeature(session).preflight(file, Optional.of(new AlphanumericRandomStringService().random()));
// assert no fail // assert no fail
} }
} }
@@ -34,6 +34,7 @@ import org.apache.logging.log4j.Logger;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Optional;
public class DeepboxDirectoryFeature implements Directory<Node> { public class DeepboxDirectoryFeature implements Directory<Node> {
private static final Logger log = LogManager.getLogger(DeepboxDirectoryFeature.class); private static final Logger log = LogManager.getLogger(DeepboxDirectoryFeature.class);
@@ -89,7 +90,7 @@ public class DeepboxDirectoryFeature implements Directory<Node> {
} }
@Override @Override
public void preflight(final Path workdir, final String filename) throws BackgroundException { public void preflight(final Path workdir, final Optional<String> filename) throws BackgroundException {
if(containerService.isInbox(workdir)) { if(containerService.isInbox(workdir)) {
throw new AccessDeniedException(LocaleFactory.localizedString("Adding folders is not permitted in the inbox", "Deepbox")).withFile(workdir); throw new AccessDeniedException(LocaleFactory.localizedString("Adding folders is not permitted in the inbox", "Deepbox")).withFile(workdir);
} }
@@ -26,6 +26,8 @@ import ch.cyberduck.core.shared.DefaultTouchFeature;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import java.util.Optional;
import static ch.cyberduck.core.deepbox.DeepboxAttributesFinderFeature.CANADDCHILDREN; import static ch.cyberduck.core.deepbox.DeepboxAttributesFinderFeature.CANADDCHILDREN;
public class DeepboxTouchFeature extends DefaultTouchFeature<Node> { public class DeepboxTouchFeature extends DefaultTouchFeature<Node> {
@@ -39,7 +41,7 @@ public class DeepboxTouchFeature extends DefaultTouchFeature<Node> {
} }
@Override @Override
public void preflight(final Path workdir, final String filename) throws BackgroundException { public void preflight(final Path workdir, final Optional<String> filename) throws BackgroundException {
if(workdir.isRoot()) { if(workdir.isRoot()) {
throw new AccessDeniedException(LocaleFactory.localizedString("Adding files is not permitted at the organisation level", "Deepbox")).withFile(workdir); throw new AccessDeniedException(LocaleFactory.localizedString("Adding files is not permitted at the organisation level", "Deepbox")).withFile(workdir);
} }
@@ -33,6 +33,7 @@ import org.junit.experimental.categories.Category;
import java.util.Collections; import java.util.Collections;
import java.util.EnumSet; import java.util.EnumSet;
import java.util.Optional;
import static org.junit.Assert.*; import static org.junit.Assert.*;
@@ -45,7 +46,7 @@ public class DeepboxDirectoryFeatureTest extends AbstractDeepboxTest {
final DeepboxDirectoryFeature directory = new DeepboxDirectoryFeature(session, nodeid); final DeepboxDirectoryFeature directory = new DeepboxDirectoryFeature(session, nodeid);
final Path parent = new Path("/", EnumSet.of(Path.Type.directory)); final Path parent = new Path("/", EnumSet.of(Path.Type.directory));
final Path folder = new Path(parent, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path folder = new Path(parent, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory));
assertThrows(AccessDeniedException.class, () -> directory.preflight(parent, folder.getName())); assertThrows(AccessDeniedException.class, () -> directory.preflight(parent, Optional.of(folder.getName())));
assertThrows(NotfoundException.class, () -> directory.mkdir(new DeepboxWriteFeature(session, nodeid), folder, new TransferStatus())); assertThrows(NotfoundException.class, () -> directory.mkdir(new DeepboxWriteFeature(session, nodeid), folder, new TransferStatus()));
} }
@@ -55,7 +56,7 @@ public class DeepboxDirectoryFeatureTest extends AbstractDeepboxTest {
final DeepboxDirectoryFeature directory = new DeepboxDirectoryFeature(session, nodeid); final DeepboxDirectoryFeature directory = new DeepboxDirectoryFeature(session, nodeid);
final Path parent = new Path("/ORG 4 - DeepBox Desktop App/", EnumSet.of(Path.Type.directory)); final Path parent = new Path("/ORG 4 - DeepBox Desktop App/", EnumSet.of(Path.Type.directory));
final Path folder = new Path(parent, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path folder = new Path(parent, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory));
assertThrows(AccessDeniedException.class, () -> directory.preflight(parent, folder.getName())); assertThrows(AccessDeniedException.class, () -> directory.preflight(parent, Optional.of(folder.getName())));
assertThrows(NotfoundException.class, () -> directory.mkdir(new DeepboxWriteFeature(session, nodeid), folder, new TransferStatus())); assertThrows(NotfoundException.class, () -> directory.mkdir(new DeepboxWriteFeature(session, nodeid), folder, new TransferStatus()));
} }
@@ -65,7 +66,7 @@ public class DeepboxDirectoryFeatureTest extends AbstractDeepboxTest {
final DeepboxDirectoryFeature directory = new DeepboxDirectoryFeature(session, nodeid); final DeepboxDirectoryFeature directory = new DeepboxDirectoryFeature(session, nodeid);
final Path parent = new Path(String.format("/ORG 1 - DeepBox Desktop App/%s", DeepboxListService.SHARED), EnumSet.of(Path.Type.directory)); final Path parent = new Path(String.format("/ORG 1 - DeepBox Desktop App/%s", DeepboxListService.SHARED), EnumSet.of(Path.Type.directory));
final Path folder = new Path(parent, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path folder = new Path(parent, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory));
assertThrows(AccessDeniedException.class, () -> directory.preflight(parent, folder.getName())); assertThrows(AccessDeniedException.class, () -> directory.preflight(parent, Optional.of(folder.getName())));
assertThrows(NotfoundException.class, () -> directory.mkdir(new DeepboxWriteFeature(session, nodeid), folder, new TransferStatus())); assertThrows(NotfoundException.class, () -> directory.mkdir(new DeepboxWriteFeature(session, nodeid), folder, new TransferStatus()));
} }
@@ -75,7 +76,7 @@ public class DeepboxDirectoryFeatureTest extends AbstractDeepboxTest {
final DeepboxDirectoryFeature directory = new DeepboxDirectoryFeature(session, nodeid); final DeepboxDirectoryFeature directory = new DeepboxDirectoryFeature(session, nodeid);
final Path parent = new Path("/ORG 4 - DeepBox Desktop App/ORG 4 - DeepBox Desktop App/ORG3:Box1", EnumSet.of(Path.Type.directory)); final Path parent = new Path("/ORG 4 - DeepBox Desktop App/ORG 4 - DeepBox Desktop App/ORG3:Box1", EnumSet.of(Path.Type.directory));
final Path folder = new Path(parent, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path folder = new Path(parent, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory));
assertThrows(AccessDeniedException.class, () -> directory.preflight(parent, folder.getName())); assertThrows(AccessDeniedException.class, () -> directory.preflight(parent, Optional.of(folder.getName())));
assertThrows(AccessDeniedException.class, () -> directory.mkdir(new DeepboxWriteFeature(session, nodeid), folder, new TransferStatus())); assertThrows(AccessDeniedException.class, () -> directory.mkdir(new DeepboxWriteFeature(session, nodeid), folder, new TransferStatus()));
} }
@@ -85,7 +86,7 @@ public class DeepboxDirectoryFeatureTest extends AbstractDeepboxTest {
final DeepboxDirectoryFeature directory = new DeepboxDirectoryFeature(session, nodeid); final DeepboxDirectoryFeature directory = new DeepboxDirectoryFeature(session, nodeid);
final Path parent = new Path(String.format("/ORG 1 - DeepBox Desktop App/%s/Demo 1 (1 Christian Gruber)", DeepboxListService.SHARED), EnumSet.of(Path.Type.directory)); final Path parent = new Path(String.format("/ORG 1 - DeepBox Desktop App/%s/Demo 1 (1 Christian Gruber)", DeepboxListService.SHARED), EnumSet.of(Path.Type.directory));
final Path folder = new Path(parent, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path folder = new Path(parent, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory));
assertThrows(AccessDeniedException.class, () -> directory.preflight(parent, folder.getName())); assertThrows(AccessDeniedException.class, () -> directory.preflight(parent, Optional.of(folder.getName())));
assertThrows(AccessDeniedException.class, () -> directory.mkdir(new DeepboxWriteFeature(session, nodeid), folder, new TransferStatus())); assertThrows(AccessDeniedException.class, () -> directory.mkdir(new DeepboxWriteFeature(session, nodeid), folder, new TransferStatus()));
} }
@@ -95,7 +96,7 @@ public class DeepboxDirectoryFeatureTest extends AbstractDeepboxTest {
final DeepboxDirectoryFeature directory = new DeepboxDirectoryFeature(session, nodeid); final DeepboxDirectoryFeature directory = new DeepboxDirectoryFeature(session, nodeid);
final Path parent = new Path("/ORG 4 - DeepBox Desktop App/ORG 4 - DeepBox Desktop App/ORG3:Box1/Inbox", EnumSet.of(Path.Type.directory)); final Path parent = new Path("/ORG 4 - DeepBox Desktop App/ORG 4 - DeepBox Desktop App/ORG3:Box1/Inbox", EnumSet.of(Path.Type.directory));
final Path folder = new Path(parent, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path folder = new Path(parent, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory));
assertThrows(AccessDeniedException.class, () -> directory.preflight(parent, folder.getName())); assertThrows(AccessDeniedException.class, () -> directory.preflight(parent, Optional.of(folder.getName())));
assertThrows(InteroperabilityException.class, () -> directory.mkdir(new DeepboxWriteFeature(session, nodeid), folder, new TransferStatus())); assertThrows(InteroperabilityException.class, () -> directory.mkdir(new DeepboxWriteFeature(session, nodeid), folder, new TransferStatus()));
} }
@@ -105,7 +106,7 @@ public class DeepboxDirectoryFeatureTest extends AbstractDeepboxTest {
final DeepboxDirectoryFeature directory = new DeepboxDirectoryFeature(session, nodeid); final DeepboxDirectoryFeature directory = new DeepboxDirectoryFeature(session, nodeid);
final Path parent = new Path(String.format("/ORG 1 - DeepBox Desktop App/%s/Demo 1 (1 Christian Gruber)/Inbox", DeepboxListService.SHARED), EnumSet.of(Path.Type.directory)); final Path parent = new Path(String.format("/ORG 1 - DeepBox Desktop App/%s/Demo 1 (1 Christian Gruber)/Inbox", DeepboxListService.SHARED), EnumSet.of(Path.Type.directory));
final Path folder = new Path(parent, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path folder = new Path(parent, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory));
assertThrows(AccessDeniedException.class, () -> directory.preflight(parent, folder.getName())); assertThrows(AccessDeniedException.class, () -> directory.preflight(parent, Optional.of(folder.getName())));
assertThrows(InteroperabilityException.class, () -> directory.mkdir(new DeepboxWriteFeature(session, nodeid), folder, new TransferStatus())); assertThrows(InteroperabilityException.class, () -> directory.mkdir(new DeepboxWriteFeature(session, nodeid), folder, new TransferStatus()));
} }
@@ -115,7 +116,7 @@ public class DeepboxDirectoryFeatureTest extends AbstractDeepboxTest {
final DeepboxDirectoryFeature directory = new DeepboxDirectoryFeature(session, nodeid); final DeepboxDirectoryFeature directory = new DeepboxDirectoryFeature(session, nodeid);
final Path parent = new Path("/ORG 4 - DeepBox Desktop App/ORG 4 - DeepBox Desktop App/ORG3:Box1/Trash", EnumSet.of(Path.Type.directory)); final Path parent = new Path("/ORG 4 - DeepBox Desktop App/ORG 4 - DeepBox Desktop App/ORG3:Box1/Trash", EnumSet.of(Path.Type.directory));
final Path folder = new Path(parent, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path folder = new Path(parent, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory));
assertThrows(AccessDeniedException.class, () -> directory.preflight(parent, folder.getName())); assertThrows(AccessDeniedException.class, () -> directory.preflight(parent, Optional.of(folder.getName())));
assertThrows(AccessDeniedException.class, () -> directory.mkdir(new DeepboxWriteFeature(session, nodeid), folder, new TransferStatus())); assertThrows(AccessDeniedException.class, () -> directory.mkdir(new DeepboxWriteFeature(session, nodeid), folder, new TransferStatus()));
} }
@@ -150,7 +151,7 @@ public class DeepboxDirectoryFeatureTest extends AbstractDeepboxTest {
final DeepboxIdProvider nodeid = new DeepboxIdProvider(session); final DeepboxIdProvider nodeid = new DeepboxIdProvider(session);
final Path documents = new Path("/ORG 4 - DeepBox Desktop App/ORG 4 - DeepBox Desktop App/ORG3:Box1/Documents/", EnumSet.of(Path.Type.directory, Path.Type.volume)); final Path documents = new Path("/ORG 4 - DeepBox Desktop App/ORG 4 - DeepBox Desktop App/ORG3:Box1/Documents/", EnumSet.of(Path.Type.directory, Path.Type.volume));
final Path test = new DeepboxDirectoryFeature(session, nodeid).mkdir(new DeepboxWriteFeature(session, nodeid), new Path(documents, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)), new TransferStatus()); final Path test = new DeepboxDirectoryFeature(session, nodeid).mkdir(new DeepboxWriteFeature(session, nodeid), new Path(documents, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)), new TransferStatus());
new DeepboxDirectoryFeature(session, nodeid).preflight(documents.withAttributes(new DeepboxAttributesFinderFeature(session, nodeid).find(documents)), test.getName()); new DeepboxDirectoryFeature(session, nodeid).preflight(documents.withAttributes(new DeepboxAttributesFinderFeature(session, nodeid).find(documents)), Optional.of(test.getName()));
assertTrue(new DeepboxFindFeature(session, nodeid).find(test)); assertTrue(new DeepboxFindFeature(session, nodeid).find(test));
new DeepboxDeleteFeature(session, nodeid).delete(Collections.singletonList(test), LoginCallback.noop, new Delete.DisabledCallback()); new DeepboxDeleteFeature(session, nodeid).delete(Collections.singletonList(test), LoginCallback.noop, new Delete.DisabledCallback());
} }
@@ -34,6 +34,7 @@ import org.junit.experimental.categories.Category;
import java.util.Collections; import java.util.Collections;
import java.util.EnumSet; import java.util.EnumSet;
import java.util.Optional;
import static ch.cyberduck.core.deepbox.DeepboxAttributesFinderFeature.CANADDCHILDREN; import static ch.cyberduck.core.deepbox.DeepboxAttributesFinderFeature.CANADDCHILDREN;
import static org.junit.Assert.*; import static org.junit.Assert.*;
@@ -44,7 +45,7 @@ public class DeepboxTouchFeatureTest extends AbstractDeepboxTest {
@Test @Test
public void testTouchRoot() throws Exception { public void testTouchRoot() throws Exception {
final DeepboxIdProvider fileid = new DeepboxIdProvider(session); final DeepboxIdProvider fileid = new DeepboxIdProvider(session);
assertThrows(AccessDeniedException.class, () -> new DeepboxTouchFeature(session, fileid).preflight(Home.root(), new AlphanumericRandomStringService().random())); assertThrows(AccessDeniedException.class, () -> new DeepboxTouchFeature(session, fileid).preflight(Home.root(), Optional.of(new AlphanumericRandomStringService().random())));
assertThrows(NotfoundException.class, () -> new DeepboxTouchFeature(session, fileid).touch(new DeepboxWriteFeature(session, fileid), new Path(new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)), new TransferStatus())); assertThrows(NotfoundException.class, () -> new DeepboxTouchFeature(session, fileid).touch(new DeepboxWriteFeature(session, fileid), new Path(new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)), new TransferStatus()));
} }
@@ -53,7 +54,7 @@ public class DeepboxTouchFeatureTest extends AbstractDeepboxTest {
final DeepboxIdProvider fileid = new DeepboxIdProvider(session); final DeepboxIdProvider fileid = new DeepboxIdProvider(session);
final Path documents = new Path("/ORG 4 - DeepBox Desktop App/ORG 4 - DeepBox Desktop App/ORG3:Box1/Documents/", EnumSet.of(Path.Type.directory, Path.Type.volume)); final Path documents = new Path("/ORG 4 - DeepBox Desktop App/ORG 4 - DeepBox Desktop App/ORG3:Box1/Documents/", EnumSet.of(Path.Type.directory, Path.Type.volume));
final Path test = new DeepboxTouchFeature(session, fileid).touch(new DeepboxWriteFeature(session, fileid), new Path(documents, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)), new TransferStatus()); final Path test = new DeepboxTouchFeature(session, fileid).touch(new DeepboxWriteFeature(session, fileid), new Path(documents, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)), new TransferStatus());
new DeepboxTouchFeature(session, fileid).preflight(documents.withAttributes(new DeepboxAttributesFinderFeature(session, fileid).find(documents)), test.getName()); new DeepboxTouchFeature(session, fileid).preflight(documents.withAttributes(new DeepboxAttributesFinderFeature(session, fileid).find(documents)), Optional.of(test.getName()));
assertTrue(new DeepboxFindFeature(session, fileid).find(test)); assertTrue(new DeepboxFindFeature(session, fileid).find(test));
new DeepboxDeleteFeature(session, fileid).delete(Collections.singletonList(test), LoginCallback.noop, new Delete.DisabledCallback()); new DeepboxDeleteFeature(session, fileid).delete(Collections.singletonList(test), LoginCallback.noop, new Delete.DisabledCallback());
} }
@@ -73,7 +74,7 @@ public class DeepboxTouchFeatureTest extends AbstractDeepboxTest {
final Path folder = new Path("/ORG 4 - DeepBox Desktop App/", EnumSet.of(Path.Type.directory, Path.Type.volume)); final Path folder = new Path("/ORG 4 - DeepBox Desktop App/", EnumSet.of(Path.Type.directory, Path.Type.volume));
final PathAttributes attributes = new DeepboxAttributesFinderFeature(session, nodeid).find(folder); final PathAttributes attributes = new DeepboxAttributesFinderFeature(session, nodeid).find(folder);
assertEquals(Acl.EMPTY, attributes.getAcl()); assertEquals(Acl.EMPTY, attributes.getAcl());
assertThrows(AccessDeniedException.class, () -> new DeepboxTouchFeature(session, nodeid).preflight(folder.withAttributes(attributes), new AlphanumericRandomStringService().random())); assertThrows(AccessDeniedException.class, () -> new DeepboxTouchFeature(session, nodeid).preflight(folder.withAttributes(attributes), Optional.of(new AlphanumericRandomStringService().random())));
} }
@Test @Test
@@ -82,7 +83,7 @@ public class DeepboxTouchFeatureTest extends AbstractDeepboxTest {
final Path folder = new Path("/ORG 4 - DeepBox Desktop App/ORG 4 - DeepBox Desktop App/", EnumSet.of(Path.Type.directory, Path.Type.volume)); final Path folder = new Path("/ORG 4 - DeepBox Desktop App/ORG 4 - DeepBox Desktop App/", EnumSet.of(Path.Type.directory, Path.Type.volume));
final PathAttributes attributes = new DeepboxAttributesFinderFeature(session, nodeid).find(folder); final PathAttributes attributes = new DeepboxAttributesFinderFeature(session, nodeid).find(folder);
assertEquals(Acl.EMPTY, attributes.getAcl()); assertEquals(Acl.EMPTY, attributes.getAcl());
assertThrows(AccessDeniedException.class, () -> new DeepboxTouchFeature(session, nodeid).preflight(folder.withAttributes(attributes), new AlphanumericRandomStringService().random())); assertThrows(AccessDeniedException.class, () -> new DeepboxTouchFeature(session, nodeid).preflight(folder.withAttributes(attributes), Optional.of(new AlphanumericRandomStringService().random())));
} }
@Test @Test
@@ -91,7 +92,7 @@ public class DeepboxTouchFeatureTest extends AbstractDeepboxTest {
final Path folder = new Path("/ORG 4 - DeepBox Desktop App/ORG 4 - DeepBox Desktop App/ORG3:Box1", EnumSet.of(Path.Type.directory, Path.Type.volume)); final Path folder = new Path("/ORG 4 - DeepBox Desktop App/ORG 4 - DeepBox Desktop App/ORG3:Box1", EnumSet.of(Path.Type.directory, Path.Type.volume));
final PathAttributes attributes = new DeepboxAttributesFinderFeature(session, nodeid).find(folder); final PathAttributes attributes = new DeepboxAttributesFinderFeature(session, nodeid).find(folder);
assertEquals(Acl.EMPTY, attributes.getAcl()); assertEquals(Acl.EMPTY, attributes.getAcl());
assertThrows(AccessDeniedException.class, () -> new DeepboxTouchFeature(session, nodeid).preflight(folder.withAttributes(attributes), new AlphanumericRandomStringService().random())); assertThrows(AccessDeniedException.class, () -> new DeepboxTouchFeature(session, nodeid).preflight(folder.withAttributes(attributes), Optional.of(new AlphanumericRandomStringService().random())));
} }
@Test @Test
@@ -102,9 +103,9 @@ public class DeepboxTouchFeatureTest extends AbstractDeepboxTest {
assertTrue(new BoxRestControllerApi(session.getClient()).getBox(ORG4_DEEPBOX4, ORG4_DEEPBOX4_BOX1).getBoxPolicy().isCanAddQueue()); assertTrue(new BoxRestControllerApi(session.getClient()).getBox(ORG4_DEEPBOX4, ORG4_DEEPBOX4_BOX1).getBoxPolicy().isCanAddQueue());
assertTrue(attributes.getAcl().get(new Acl.CanonicalUser()).contains(CANADDCHILDREN)); assertTrue(attributes.getAcl().get(new Acl.CanonicalUser()).contains(CANADDCHILDREN));
// assert no fail // assert no fail
new DeepboxTouchFeature(session, nodeid).preflight(folder.withAttributes(attributes), new AlphanumericRandomStringService().random()); new DeepboxTouchFeature(session, nodeid).preflight(folder.withAttributes(attributes), Optional.of(new AlphanumericRandomStringService().random()));
// DeepBox inbox is flat // DeepBox inbox is flat
assertThrows(AccessDeniedException.class, () -> new DeepboxDirectoryFeature(session, nodeid).preflight(folder.withAttributes(attributes), new AlphanumericRandomStringService().random())); assertThrows(AccessDeniedException.class, () -> new DeepboxDirectoryFeature(session, nodeid).preflight(folder.withAttributes(attributes), Optional.of(new AlphanumericRandomStringService().random())));
} }
@Test @Test
@@ -114,8 +115,8 @@ public class DeepboxTouchFeatureTest extends AbstractDeepboxTest {
final PathAttributes attributes = new DeepboxAttributesFinderFeature(session, nodeid).find(folder); final PathAttributes attributes = new DeepboxAttributesFinderFeature(session, nodeid).find(folder);
assertFalse(new BoxRestControllerApi(session.getClient()).getBox(ORG1_DEEPBOX1, ORG1_DEEPBOX1_BOX1).getBoxPolicy().isCanAddQueue()); assertFalse(new BoxRestControllerApi(session.getClient()).getBox(ORG1_DEEPBOX1, ORG1_DEEPBOX1_BOX1).getBoxPolicy().isCanAddQueue());
assertFalse(attributes.getAcl().get(new Acl.CanonicalUser()).contains(CANADDCHILDREN)); assertFalse(attributes.getAcl().get(new Acl.CanonicalUser()).contains(CANADDCHILDREN));
assertThrows(AccessDeniedException.class, () -> new DeepboxTouchFeature(session, nodeid).preflight(folder.withAttributes(attributes), new AlphanumericRandomStringService().random())); assertThrows(AccessDeniedException.class, () -> new DeepboxTouchFeature(session, nodeid).preflight(folder.withAttributes(attributes), Optional.of(new AlphanumericRandomStringService().random())));
assertThrows(AccessDeniedException.class, () -> new DeepboxDirectoryFeature(session, nodeid).preflight(folder.withAttributes(attributes), new AlphanumericRandomStringService().random())); assertThrows(AccessDeniedException.class, () -> new DeepboxDirectoryFeature(session, nodeid).preflight(folder.withAttributes(attributes), Optional.of(new AlphanumericRandomStringService().random())));
} }
@Test @Test
@@ -126,9 +127,9 @@ public class DeepboxTouchFeatureTest extends AbstractDeepboxTest {
assertTrue(new BoxRestControllerApi(session.getClient()).getBox(ORG4_DEEPBOX4, ORG4_DEEPBOX4_BOX1).getBoxPolicy().isCanAddFilesRoot()); assertTrue(new BoxRestControllerApi(session.getClient()).getBox(ORG4_DEEPBOX4, ORG4_DEEPBOX4_BOX1).getBoxPolicy().isCanAddFilesRoot());
assertTrue(attributes.getAcl().get(new Acl.CanonicalUser()).contains(CANADDCHILDREN)); assertTrue(attributes.getAcl().get(new Acl.CanonicalUser()).contains(CANADDCHILDREN));
// assert no fail // assert no fail
new DeepboxTouchFeature(session, nodeid).preflight(folder.withAttributes(attributes), new AlphanumericRandomStringService().random()); new DeepboxTouchFeature(session, nodeid).preflight(folder.withAttributes(attributes), Optional.of(new AlphanumericRandomStringService().random()));
// assert no fail // assert no fail
new DeepboxDirectoryFeature(session, nodeid).preflight(folder.withAttributes(attributes), new AlphanumericRandomStringService().random()); new DeepboxDirectoryFeature(session, nodeid).preflight(folder.withAttributes(attributes), Optional.of(new AlphanumericRandomStringService().random()));
} }
@Test @Test
@@ -138,8 +139,8 @@ public class DeepboxTouchFeatureTest extends AbstractDeepboxTest {
final PathAttributes attributes = new DeepboxAttributesFinderFeature(session, nodeid).find(folder); final PathAttributes attributes = new DeepboxAttributesFinderFeature(session, nodeid).find(folder);
assertFalse(new BoxRestControllerApi(session.getClient()).getBox(ORG1_DEEPBOX1, ORG1_DEEPBOX1_BOX1).getBoxPolicy().isCanAddFilesRoot()); assertFalse(new BoxRestControllerApi(session.getClient()).getBox(ORG1_DEEPBOX1, ORG1_DEEPBOX1_BOX1).getBoxPolicy().isCanAddFilesRoot());
assertFalse(attributes.getAcl().get(new Acl.CanonicalUser()).contains(CANADDCHILDREN)); assertFalse(attributes.getAcl().get(new Acl.CanonicalUser()).contains(CANADDCHILDREN));
assertThrows(AccessDeniedException.class, () -> new DeepboxTouchFeature(session, nodeid).preflight(folder.withAttributes(attributes), new AlphanumericRandomStringService().random())); assertThrows(AccessDeniedException.class, () -> new DeepboxTouchFeature(session, nodeid).preflight(folder.withAttributes(attributes), Optional.of(new AlphanumericRandomStringService().random())));
assertThrows(AccessDeniedException.class, () -> new DeepboxDirectoryFeature(session, nodeid).preflight(folder.withAttributes(attributes), new AlphanumericRandomStringService().random())); assertThrows(AccessDeniedException.class, () -> new DeepboxDirectoryFeature(session, nodeid).preflight(folder.withAttributes(attributes), Optional.of(new AlphanumericRandomStringService().random())));
} }
@Test @Test
@@ -148,8 +149,8 @@ public class DeepboxTouchFeatureTest extends AbstractDeepboxTest {
final Path folder = new Path("/ORG 1 - DeepBox Desktop App/ORG 1 - DeepBox Desktop App/ORG1:Box1/Trash/", EnumSet.of(Path.Type.directory, Path.Type.volume)); final Path folder = new Path("/ORG 1 - DeepBox Desktop App/ORG 1 - DeepBox Desktop App/ORG1:Box1/Trash/", EnumSet.of(Path.Type.directory, Path.Type.volume));
final PathAttributes attributes = new DeepboxAttributesFinderFeature(session, nodeid).find(folder); final PathAttributes attributes = new DeepboxAttributesFinderFeature(session, nodeid).find(folder);
assertFalse(attributes.getAcl().get(new Acl.CanonicalUser()).contains(CANADDCHILDREN)); assertFalse(attributes.getAcl().get(new Acl.CanonicalUser()).contains(CANADDCHILDREN));
assertThrows(AccessDeniedException.class, () -> new DeepboxTouchFeature(session, nodeid).preflight(folder.withAttributes(attributes), new AlphanumericRandomStringService().random())); assertThrows(AccessDeniedException.class, () -> new DeepboxTouchFeature(session, nodeid).preflight(folder.withAttributes(attributes), Optional.of(new AlphanumericRandomStringService().random())));
assertThrows(AccessDeniedException.class, () -> new DeepboxDirectoryFeature(session, nodeid).preflight(folder.withAttributes(attributes), new AlphanumericRandomStringService().random())); assertThrows(AccessDeniedException.class, () -> new DeepboxDirectoryFeature(session, nodeid).preflight(folder.withAttributes(attributes), Optional.of(new AlphanumericRandomStringService().random())));
} }
@Test @Test
@@ -160,9 +161,9 @@ public class DeepboxTouchFeatureTest extends AbstractDeepboxTest {
assertTrue(new CoreRestControllerApi(session.getClient()).getNodeInfo(attributes.getFileId(), null, null, null).getNode().getPolicy().isCanAddChildren()); assertTrue(new CoreRestControllerApi(session.getClient()).getNodeInfo(attributes.getFileId(), null, null, null).getNode().getPolicy().isCanAddChildren());
assertTrue(attributes.getAcl().get(new Acl.CanonicalUser()).contains(CANADDCHILDREN)); assertTrue(attributes.getAcl().get(new Acl.CanonicalUser()).contains(CANADDCHILDREN));
// assert no fail // assert no fail
new DeepboxTouchFeature(session, nodeid).preflight(folder.withAttributes(attributes), new AlphanumericRandomStringService().random()); new DeepboxTouchFeature(session, nodeid).preflight(folder.withAttributes(attributes), Optional.of(new AlphanumericRandomStringService().random()));
// assert no fail // assert no fail
new DeepboxDirectoryFeature(session, nodeid).preflight(folder.withAttributes(attributes), new AlphanumericRandomStringService().random()); new DeepboxDirectoryFeature(session, nodeid).preflight(folder.withAttributes(attributes), Optional.of(new AlphanumericRandomStringService().random()));
} }
@Test @Test
@@ -172,8 +173,8 @@ public class DeepboxTouchFeatureTest extends AbstractDeepboxTest {
final PathAttributes attributes = new DeepboxAttributesFinderFeature(session, nodeid).find(folder); final PathAttributes attributes = new DeepboxAttributesFinderFeature(session, nodeid).find(folder);
assertFalse(new CoreRestControllerApi(session.getClient()).getNodeInfo(attributes.getFileId(), null, null, null).getNode().getPolicy().isCanAddChildren()); assertFalse(new CoreRestControllerApi(session.getClient()).getNodeInfo(attributes.getFileId(), null, null, null).getNode().getPolicy().isCanAddChildren());
assertFalse(attributes.getAcl().get(new Acl.CanonicalUser()).contains(CANADDCHILDREN)); assertFalse(attributes.getAcl().get(new Acl.CanonicalUser()).contains(CANADDCHILDREN));
assertThrows(AccessDeniedException.class, () -> new DeepboxTouchFeature(session, nodeid).preflight(folder.withAttributes(attributes), new AlphanumericRandomStringService().random())); assertThrows(AccessDeniedException.class, () -> new DeepboxTouchFeature(session, nodeid).preflight(folder.withAttributes(attributes), Optional.of(new AlphanumericRandomStringService().random())));
assertThrows(AccessDeniedException.class, () -> new DeepboxDirectoryFeature(session, nodeid).preflight(folder.withAttributes(attributes), new AlphanumericRandomStringService().random())); assertThrows(AccessDeniedException.class, () -> new DeepboxDirectoryFeature(session, nodeid).preflight(folder.withAttributes(attributes), Optional.of(new AlphanumericRandomStringService().random())));
} }
@Test @Test
@@ -183,8 +184,8 @@ public class DeepboxTouchFeatureTest extends AbstractDeepboxTest {
final PathAttributes attributes = new DeepboxAttributesFinderFeature(session, nodeid).find(folder); final PathAttributes attributes = new DeepboxAttributesFinderFeature(session, nodeid).find(folder);
assertFalse(new CoreRestControllerApi(session.getClient()).getNodeInfo(attributes.getFileId(), null, null, null).getNode().getPolicy().isCanAddChildren()); assertFalse(new CoreRestControllerApi(session.getClient()).getNodeInfo(attributes.getFileId(), null, null, null).getNode().getPolicy().isCanAddChildren());
assertFalse(attributes.getAcl().get(new Acl.CanonicalUser()).contains(CANADDCHILDREN)); assertFalse(attributes.getAcl().get(new Acl.CanonicalUser()).contains(CANADDCHILDREN));
assertThrows(AccessDeniedException.class, () -> new DeepboxTouchFeature(session, nodeid).preflight(folder.withAttributes(attributes), new AlphanumericRandomStringService().random())); assertThrows(AccessDeniedException.class, () -> new DeepboxTouchFeature(session, nodeid).preflight(folder.withAttributes(attributes), Optional.of(new AlphanumericRandomStringService().random())));
assertThrows(AccessDeniedException.class, () -> new DeepboxDirectoryFeature(session, nodeid).preflight(folder.withAttributes(attributes), new AlphanumericRandomStringService().random())); assertThrows(AccessDeniedException.class, () -> new DeepboxDirectoryFeature(session, nodeid).preflight(folder.withAttributes(attributes), Optional.of(new AlphanumericRandomStringService().random())));
} }
@Test @Test
@@ -192,7 +193,7 @@ public class DeepboxTouchFeatureTest extends AbstractDeepboxTest {
final DeepboxIdProvider nodeid = new DeepboxIdProvider(session); final DeepboxIdProvider nodeid = new DeepboxIdProvider(session);
final Path parent = new Path("/ORG 4 - DeepBox Desktop App/ORG 4 - DeepBox Desktop App/ORG3:Box1/Trash", EnumSet.of(Path.Type.directory)); final Path parent = new Path("/ORG 4 - DeepBox Desktop App/ORG 4 - DeepBox Desktop App/ORG3:Box1/Trash", EnumSet.of(Path.Type.directory));
final Path folder = new Path(parent, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path folder = new Path(parent, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory));
assertThrows(AccessDeniedException.class, () -> new DeepboxTouchFeature(session, nodeid).preflight(parent, folder.getName())); assertThrows(AccessDeniedException.class, () -> new DeepboxTouchFeature(session, nodeid).preflight(parent, Optional.of(folder.getName())));
assertThrows(AccessDeniedException.class, () -> new DeepboxTouchFeature(session, nodeid).touch(new DeepboxWriteFeature(session, nodeid), folder, new TransferStatus())); assertThrows(AccessDeniedException.class, () -> new DeepboxTouchFeature(session, nodeid).touch(new DeepboxWriteFeature(session, nodeid), folder, new TransferStatus()));
} }
@@ -201,7 +202,7 @@ public class DeepboxTouchFeatureTest extends AbstractDeepboxTest {
final DeepboxIdProvider nodeid = new DeepboxIdProvider(session); final DeepboxIdProvider nodeid = new DeepboxIdProvider(session);
final Path parent = new Path(String.format("/ORG 1 - DeepBox Desktop App/%s", DeepboxListService.SHARED), EnumSet.of(Path.Type.directory)); final Path parent = new Path(String.format("/ORG 1 - DeepBox Desktop App/%s", DeepboxListService.SHARED), EnumSet.of(Path.Type.directory));
final Path file = new Path(parent, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path file = new Path(parent, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory));
assertThrows(AccessDeniedException.class, () -> new DeepboxTouchFeature(session, nodeid).preflight(parent, file.getName())); assertThrows(AccessDeniedException.class, () -> new DeepboxTouchFeature(session, nodeid).preflight(parent, Optional.of(file.getName())));
assertThrows(NotfoundException.class, () -> new DeepboxTouchFeature(session, nodeid).touch(new DeepboxWriteFeature(session, nodeid), file, new TransferStatus())); assertThrows(NotfoundException.class, () -> new DeepboxTouchFeature(session, nodeid).touch(new DeepboxWriteFeature(session, nodeid), file, new TransferStatus()));
} }
} }
@@ -31,6 +31,7 @@ import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import java.util.EnumSet; import java.util.EnumSet;
import java.util.Optional;
public class SDSDelegatingWriteFeature implements MultipartWrite<Node> { public class SDSDelegatingWriteFeature implements MultipartWrite<Node> {
private static final Logger log = LogManager.getLogger(SDSDelegatingWriteFeature.class); private static final Logger log = LogManager.getLogger(SDSDelegatingWriteFeature.class);
@@ -68,7 +69,7 @@ public class SDSDelegatingWriteFeature implements MultipartWrite<Node> {
@Override @Override
public void preflight(final Path file) throws BackgroundException { public void preflight(final Path file) throws BackgroundException {
new SDSTouchFeature(session, nodeid).preflight(file.getParent(), file.getName()); new SDSTouchFeature(session, nodeid).preflight(file.getParent(), Optional.of(file.getName()));
} }
@Override @Override
@@ -32,12 +32,12 @@ import ch.cyberduck.core.sds.io.swagger.client.model.EncryptRoomRequest;
import ch.cyberduck.core.sds.io.swagger.client.model.Node; import ch.cyberduck.core.sds.io.swagger.client.model.Node;
import ch.cyberduck.core.transfer.TransferStatus; import ch.cyberduck.core.transfer.TransferStatus;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import java.text.MessageFormat; import java.text.MessageFormat;
import java.util.EnumSet; import java.util.EnumSet;
import java.util.Optional;
public class SDSDirectoryFeature implements Directory<Node> { public class SDSDirectoryFeature implements Directory<Node> {
private static final Logger log = LogManager.getLogger(SDSDirectoryFeature.class); private static final Logger log = LogManager.getLogger(SDSDirectoryFeature.class);
@@ -102,16 +102,18 @@ public class SDSDirectoryFeature implements Directory<Node> {
} }
@Override @Override
public void preflight(final Path workdir, final String filename) throws BackgroundException { public void preflight(final Path workdir, final Optional<String> filename) throws BackgroundException {
if(workdir.isRoot()) { if(workdir.isRoot()) {
if(!HostPreferencesFactory.get(session.getHost()).getBoolean("sds.create.dataroom.enable")) { if(!HostPreferencesFactory.get(session.getHost()).getBoolean("sds.create.dataroom.enable")) {
log.warn("Disallow creating new top level data room {}", filename); log.warn("Disallow creating new top level data room {}", filename);
throw new AccessDeniedException(MessageFormat.format(LocaleFactory.localizedString("Cannot create folder {0}", "Error"), filename)).withFile(workdir); throw new AccessDeniedException(MessageFormat.format(LocaleFactory.localizedString("Cannot create folder {0}", "Error"), filename)).withFile(workdir);
} }
} }
if(!SDSTouchFeature.validate(filename)) { if(filename.isPresent()) {
if(!SDSTouchFeature.validate(filename.get())) {
throw new InvalidFilenameException(MessageFormat.format(LocaleFactory.localizedString("Cannot create folder {0}", "Error"), filename)); throw new InvalidFilenameException(MessageFormat.format(LocaleFactory.localizedString("Cannot create folder {0}", "Error"), filename));
} }
}
final SDSPermissionsFeature permissions = new SDSPermissionsFeature(session, nodeid); final SDSPermissionsFeature permissions = new SDSPermissionsFeature(session, nodeid);
if(!permissions.containsRole(workdir, SDSPermissionsFeature.CREATE_ROLE)) { if(!permissions.containsRole(workdir, SDSPermissionsFeature.CREATE_ROLE)) {
throw new AccessDeniedException(MessageFormat.format(LocaleFactory.localizedString("Cannot create folder {0}", "Error"), filename)).withFile(workdir); throw new AccessDeniedException(MessageFormat.format(LocaleFactory.localizedString("Cannot create folder {0}", "Error"), filename)).withFile(workdir);
@@ -33,6 +33,7 @@ import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import java.text.MessageFormat; import java.text.MessageFormat;
import java.util.Optional;
public class SDSTouchFeature extends DefaultTouchFeature<Node> { public class SDSTouchFeature extends DefaultTouchFeature<Node> {
private static final Logger log = LogManager.getLogger(SDSTouchFeature.class); private static final Logger log = LogManager.getLogger(SDSTouchFeature.class);
@@ -59,13 +60,15 @@ public class SDSTouchFeature extends DefaultTouchFeature<Node> {
} }
@Override @Override
public void preflight(final Path workdir, final String filename) throws BackgroundException { public void preflight(final Path workdir, final Optional<String> filename) throws BackgroundException {
if(workdir.isRoot()) { if(workdir.isRoot()) {
throw new AccessDeniedException(MessageFormat.format(LocaleFactory.localizedString("Cannot create {0}", "Error"), filename)).withFile(workdir); throw new AccessDeniedException(MessageFormat.format(LocaleFactory.localizedString("Cannot create {0}", "Error"), filename)).withFile(workdir);
} }
if(!validate(filename)) { if(filename.isPresent()) {
if(!validate(filename.get())) {
throw new InvalidFilenameException(MessageFormat.format(LocaleFactory.localizedString("Cannot create {0}", "Error"), filename)); throw new InvalidFilenameException(MessageFormat.format(LocaleFactory.localizedString("Cannot create {0}", "Error"), filename));
} }
}
final SDSPermissionsFeature permissions = new SDSPermissionsFeature(session, nodeid); final SDSPermissionsFeature permissions = new SDSPermissionsFeature(session, nodeid);
if(!permissions.containsRole(workdir, SDSPermissionsFeature.CREATE_ROLE) if(!permissions.containsRole(workdir, SDSPermissionsFeature.CREATE_ROLE)
// For existing files the delete role is also required to overwrite // For existing files the delete role is also required to overwrite
@@ -35,7 +35,6 @@ import ch.cyberduck.core.transfer.TransferStatus;
import ch.cyberduck.test.IntegrationTest; import ch.cyberduck.test.IntegrationTest;
import org.apache.commons.lang3.RandomUtils; import org.apache.commons.lang3.RandomUtils;
import org.apache.commons.lang3.StringUtils;
import org.junit.Test; import org.junit.Test;
import org.junit.experimental.categories.Category; import org.junit.experimental.categories.Category;
@@ -44,6 +43,7 @@ import java.time.Duration;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.EnumSet; import java.util.EnumSet;
import java.util.Optional;
import static org.junit.Assert.*; import static org.junit.Assert.*;
@@ -53,9 +53,9 @@ public class SDSTouchFeatureTest extends AbstractSDSTest {
@Test @Test
public void testSupported() { public void testSupported() {
final SDSNodeIdProvider nodeid = new SDSNodeIdProvider(session); final SDSNodeIdProvider nodeid = new SDSNodeIdProvider(session);
assertTrue(new SDSTouchFeature(session, nodeid).isSupported(new Path(new Path(new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)), new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)), StringUtils.EMPTY)); assertTrue(new SDSTouchFeature(session, nodeid).isSupported(new Path(new Path(new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)), new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)), Optional.empty()));
assertTrue(new SDSTouchFeature(session, nodeid).isSupported(new Path(new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)), StringUtils.EMPTY)); assertTrue(new SDSTouchFeature(session, nodeid).isSupported(new Path(new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)), Optional.empty()));
assertFalse(new SDSTouchFeature(session, nodeid).isSupported(new Path("/", EnumSet.of(Path.Type.directory)), StringUtils.EMPTY)); assertFalse(new SDSTouchFeature(session, nodeid).isSupported(new Path("/", EnumSet.of(Path.Type.directory)), Optional.empty()));
} }
@Test(expected = BackgroundException.class) @Test(expected = BackgroundException.class)
@@ -77,8 +77,8 @@ public class SDSTouchFeatureTest extends AbstractSDSTest {
new SDSDirectS3MultipartWriteFeature(session, nodeid), new Path(new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory, Path.Type.volume)), new TransferStatus()); new SDSDirectS3MultipartWriteFeature(session, nodeid), new Path(new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory, Path.Type.volume)), new TransferStatus());
try { try {
final SDSTouchFeature feature = new SDSTouchFeature(session, nodeid); final SDSTouchFeature feature = new SDSTouchFeature(session, nodeid);
assertFalse(feature.isSupported(room, "?")); assertFalse(feature.isSupported(room, Optional.of("?")));
assertThrows(InvalidFilenameException.class, () -> feature.preflight(room, "?")); assertThrows(InvalidFilenameException.class, () -> feature.preflight(room, Optional.of("?")));
feature.touch(new SDSDirectS3MultipartWriteFeature(session, nodeid), new Path(room, "CON", EnumSet.of(Path.Type.file)), new TransferStatus()); feature.touch(new SDSDirectS3MultipartWriteFeature(session, nodeid), new Path(room, "CON", EnumSet.of(Path.Type.file)), new TransferStatus());
} }
catch(InteroperabilityException e) { catch(InteroperabilityException e) {
@@ -97,8 +97,8 @@ public class SDSTouchFeatureTest extends AbstractSDSTest {
new SDSDirectS3MultipartWriteFeature(session, nodeid), new Path(new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory, Path.Type.volume)), new TransferStatus()); new SDSDirectS3MultipartWriteFeature(session, nodeid), new Path(new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory, Path.Type.volume)), new TransferStatus());
try { try {
final SDSTouchFeature feature = new SDSTouchFeature(session, nodeid); final SDSTouchFeature feature = new SDSTouchFeature(session, nodeid);
assertFalse(feature.isSupported(room, "?")); assertFalse(feature.isSupported(room, Optional.of("?")));
assertThrows(InvalidFilenameException.class, () -> feature.preflight(room, "?")); assertThrows(InvalidFilenameException.class, () -> feature.preflight(room, Optional.of("?")));
feature.touch(new SDSDirectS3MultipartWriteFeature(session, nodeid), new Path(room, "?", EnumSet.of(Path.Type.file)), new TransferStatus()); feature.touch(new SDSDirectS3MultipartWriteFeature(session, nodeid), new Path(room, "?", EnumSet.of(Path.Type.file)), new TransferStatus());
} }
catch(InteroperabilityException e) { catch(InteroperabilityException e) {
@@ -132,7 +132,7 @@ public class SDSTouchFeatureTest extends AbstractSDSTest {
final long quota = 1L + PreferencesFactory.get().getInteger("sds.upload.multipart.chunksize"); final long quota = 1L + PreferencesFactory.get().getInteger("sds.upload.multipart.chunksize");
updateRoomRequest.setQuota(quota); updateRoomRequest.setQuota(quota);
assertEquals(quota, new NodesApi(session.getClient()).updateRoom(updateRoomRequest, Long.valueOf(room.attributes().getVersionId()), null).getQuota(), 0L); assertEquals(quota, new NodesApi(session.getClient()).updateRoom(updateRoomRequest, Long.valueOf(room.attributes().getVersionId()), null).getQuota(), 0L);
assertTrue(new SDSTouchFeature(session, nodeid).isSupported(room.withAttributes(new SDSAttributesFinderFeature(session, nodeid).find(room)), StringUtils.EMPTY)); assertTrue(new SDSTouchFeature(session, nodeid).isSupported(room.withAttributes(new SDSAttributesFinderFeature(session, nodeid).find(room)), Optional.empty()));
assertEquals(quota, room.attributes().getQuota().available, 0L); assertEquals(quota, room.attributes().getQuota().available, 0L);
final byte[] content = RandomUtils.nextBytes(2); final byte[] content = RandomUtils.nextBytes(2);
final TransferStatus status = new TransferStatus(); final TransferStatus status = new TransferStatus();
@@ -150,7 +150,7 @@ public class SDSTouchFeatureTest extends AbstractSDSTest {
} }
} }
while(attr.getSize() != 2L); while(attr.getSize() != 2L);
assertFalse(new SDSTouchFeature(session, nodeid).isSupported(room.withAttributes(attr), StringUtils.EMPTY)); assertFalse(new SDSTouchFeature(session, nodeid).isSupported(room.withAttributes(attr), Optional.empty()));
assertEquals(quota, attr.getQuota().available, 0L); assertEquals(quota, attr.getQuota().available, 0L);
assertEquals(2L, attr.getSize()); assertEquals(2L, attr.getSize());
new SDSDeleteFeature(session, nodeid).delete(Arrays.asList(test, room), LoginCallback.noop, new Delete.DisabledCallback()); new SDSDeleteFeature(session, nodeid).delete(Arrays.asList(test, room), LoginCallback.noop, new Delete.DisabledCallback());
@@ -25,6 +25,7 @@ import ch.cyberduck.core.features.Write;
import ch.cyberduck.core.transfer.TransferStatus; import ch.cyberduck.core.transfer.TransferStatus;
import java.text.MessageFormat; import java.text.MessageFormat;
import java.util.Optional;
import com.dropbox.core.DbxException; import com.dropbox.core.DbxException;
import com.dropbox.core.v2.files.CreateFolderResult; import com.dropbox.core.v2.files.CreateFolderResult;
@@ -54,9 +55,11 @@ public class DropboxDirectoryFeature implements Directory<Metadata> {
} }
@Override @Override
public void preflight(final Path workdir, final String filename) throws BackgroundException { public void preflight(final Path workdir, final Optional<String> filename) throws BackgroundException {
if(!DropboxTouchFeature.validate(filename)) { if(filename.isPresent()) {
if(!DropboxTouchFeature.validate(filename.get())) {
throw new InvalidFilenameException(MessageFormat.format(LocaleFactory.localizedString("Cannot create folder {0}", "Error"), filename)); throw new InvalidFilenameException(MessageFormat.format(LocaleFactory.localizedString("Cannot create folder {0}", "Error"), filename));
} }
} }
} }
}
@@ -24,6 +24,7 @@ import ch.cyberduck.core.shared.DefaultTouchFeature;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import java.text.MessageFormat; import java.text.MessageFormat;
import java.util.Optional;
import com.dropbox.core.v2.files.Metadata; import com.dropbox.core.v2.files.Metadata;
@@ -42,11 +43,13 @@ public class DropboxTouchFeature extends DefaultTouchFeature<Metadata> {
* @throws InvalidFilenameException If restricted filename * @throws InvalidFilenameException If restricted filename
*/ */
@Override @Override
public void preflight(final Path workdir, final String filename) throws BackgroundException { public void preflight(final Path workdir, final Optional<String> filename) throws BackgroundException {
if(!validate(filename)) { if(filename.isPresent()) {
if(!validate(filename.get())) {
throw new InvalidFilenameException(MessageFormat.format(LocaleFactory.localizedString("Cannot create {0}", "Error"), filename)); throw new InvalidFilenameException(MessageFormat.format(LocaleFactory.localizedString("Cannot create {0}", "Error"), filename));
} }
} }
}
public static boolean validate(final String filename) { public static boolean validate(final String filename) {
if(StringUtils.startsWith(filename, "~$")) { if(StringUtils.startsWith(filename, "~$")) {
@@ -41,6 +41,7 @@ import org.junit.experimental.categories.Category;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.util.Collections; import java.util.Collections;
import java.util.EnumSet; import java.util.EnumSet;
import java.util.Optional;
import static org.junit.Assert.*; import static org.junit.Assert.*;
@@ -51,7 +52,7 @@ public class DropboxTouchFeatureTest extends AbstractDropboxTest {
public void testDisallowedName() throws Exception { public void testDisallowedName() throws Exception {
final DropboxTouchFeature touch = new DropboxTouchFeature(session); final DropboxTouchFeature touch = new DropboxTouchFeature(session);
final Path file = new Path(new DefaultHomeFinderService(session).find(), String.format("~%s.tmp", new AlphanumericRandomStringService().random()), EnumSet.of(Path.Type.file)); final Path file = new Path(new DefaultHomeFinderService(session).find(), String.format("~%s.tmp", new AlphanumericRandomStringService().random()), EnumSet.of(Path.Type.file));
assertFalse(touch.isSupported(new DefaultHomeFinderService(session).find(), file.getName())); assertFalse(touch.isSupported(new DefaultHomeFinderService(session).find(), Optional.of(file.getName())));
touch.touch(new DropboxWriteFeature(session), file, new TransferStatus()); touch.touch(new DropboxWriteFeature(session), file, new TransferStatus());
} }
@@ -38,6 +38,7 @@ import org.apache.logging.log4j.Logger;
import java.text.MessageFormat; import java.text.MessageFormat;
import java.util.Collections; import java.util.Collections;
import java.util.Optional;
public class EueDirectoryFeature implements Directory<EueWriteFeature.Chunk> { public class EueDirectoryFeature implements Directory<EueWriteFeature.Chunk> {
private static final Logger log = LogManager.getLogger(EueDirectoryFeature.class); private static final Logger log = LogManager.getLogger(EueDirectoryFeature.class);
@@ -89,9 +90,11 @@ public class EueDirectoryFeature implements Directory<EueWriteFeature.Chunk> {
} }
@Override @Override
public void preflight(final Path workdir, final String filename) throws BackgroundException { public void preflight(final Path workdir, final Optional<String> filename) throws BackgroundException {
if(!EueTouchFeature.validate(filename)) { if(filename.isPresent()) {
if(!EueTouchFeature.validate(filename.get())) {
throw new InvalidFilenameException(MessageFormat.format(LocaleFactory.localizedString("Cannot create folder {0}", "Error"), filename)); throw new InvalidFilenameException(MessageFormat.format(LocaleFactory.localizedString("Cannot create folder {0}", "Error"), filename));
} }
} }
} }
}
@@ -24,6 +24,7 @@ import ch.cyberduck.core.shared.DefaultTouchFeature;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import java.text.MessageFormat; import java.text.MessageFormat;
import java.util.Optional;
public class EueTouchFeature extends DefaultTouchFeature<EueWriteFeature.Chunk> { public class EueTouchFeature extends DefaultTouchFeature<EueWriteFeature.Chunk> {
@@ -32,11 +33,13 @@ public class EueTouchFeature extends DefaultTouchFeature<EueWriteFeature.Chunk>
} }
@Override @Override
public void preflight(final Path workdir, final String filename) throws BackgroundException { public void preflight(final Path workdir, final Optional<String> filename) throws BackgroundException {
if(!validate(filename)) { if(filename.isPresent()) {
if(!validate(filename.get())) {
throw new InvalidFilenameException(MessageFormat.format(LocaleFactory.localizedString("Cannot create {0}", "Error"), filename)); throw new InvalidFilenameException(MessageFormat.format(LocaleFactory.localizedString("Cannot create {0}", "Error"), filename));
} }
} }
}
public static boolean validate(final String filename) { public static boolean validate(final String filename) {
// The path may contain all characters except the following: /, ", >, <, ?, *, :, \, |. // The path may contain all characters except the following: /, ", >, <, ?, *, :, \, |.
@@ -30,6 +30,7 @@ import org.junit.experimental.categories.Category;
import java.util.Collections; import java.util.Collections;
import java.util.EnumSet; import java.util.EnumSet;
import java.util.Optional;
import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertThrows; import static org.junit.Assert.assertThrows;
@@ -40,12 +41,12 @@ public class EueTouchFeatureTest extends AbstractEueSessionTest {
@Test @Test
public void testSupported() { public void testSupported() {
final EueResourceIdProvider fileid = new EueResourceIdProvider(session); final EueResourceIdProvider fileid = new EueResourceIdProvider(session);
assertFalse(new EueTouchFeature(session, fileid).isSupported(new Path("/", EnumSet.of(Path.Type.directory)), "f >f")); assertFalse(new EueTouchFeature(session, fileid).isSupported(new Path("/", EnumSet.of(Path.Type.directory)), Optional.of("f >f")));
assertFalse(new EueTouchFeature(session, fileid).isSupported(new Path("/", EnumSet.of(Path.Type.directory)), "f ")); assertFalse(new EueTouchFeature(session, fileid).isSupported(new Path("/", EnumSet.of(Path.Type.directory)), Optional.of("f ")));
assertFalse(new EueTouchFeature(session, fileid).isSupported(new Path("/", EnumSet.of(Path.Type.directory)), "f.")); assertFalse(new EueTouchFeature(session, fileid).isSupported(new Path("/", EnumSet.of(Path.Type.directory)), Optional.of("f.")));
// max path length exceeded. Allowed are 250, but the length was 255 // max path length exceeded. Allowed are 250, but the length was 255
assertFalse(new EueTouchFeature(session, fileid).isSupported(new Path("/", EnumSet.of(Path.Type.directory)), assertFalse(new EueTouchFeature(session, fileid).isSupported(new Path("/", EnumSet.of(Path.Type.directory)),
new AsciiRandomStringService(255).random())); Optional.of(new AsciiRandomStringService(255).random())));
} }
@Test @Test
@@ -27,6 +27,7 @@ import ch.cyberduck.core.transfer.TransferStatus;
import org.apache.commons.net.ftp.FTPReply; import org.apache.commons.net.ftp.FTPReply;
import java.io.IOException; import java.io.IOException;
import java.util.Optional;
public class FTPDirectoryFeature implements Directory<Void> { public class FTPDirectoryFeature implements Directory<Void> {
@@ -57,7 +58,7 @@ public class FTPDirectoryFeature implements Directory<Void> {
} }
@Override @Override
public void preflight(final Path workdir, final String filename) { public void preflight(final Path workdir, final Optional<String> filename) {
// Skip checking permission mask // Skip checking permission mask
} }
} }
@@ -18,6 +18,8 @@ package ch.cyberduck.core.ftp;
import ch.cyberduck.core.Path; import ch.cyberduck.core.Path;
import ch.cyberduck.core.shared.DefaultTouchFeature; import ch.cyberduck.core.shared.DefaultTouchFeature;
import java.util.Optional;
public class FTPTouchFeature extends DefaultTouchFeature<Void> { public class FTPTouchFeature extends DefaultTouchFeature<Void> {
public FTPTouchFeature(final FTPSession session) { public FTPTouchFeature(final FTPSession session) {
@@ -25,7 +27,7 @@ public class FTPTouchFeature extends DefaultTouchFeature<Void> {
} }
@Override @Override
public void preflight(final Path workdir, final String filename) { public void preflight(final Path workdir, final Optional<String> filename) {
// Skip checking permission mask // Skip checking permission mask
} }
} }
@@ -17,7 +17,6 @@ package ch.cyberduck.core.googledrive;
import ch.cyberduck.core.DefaultPathAttributes; import ch.cyberduck.core.DefaultPathAttributes;
import ch.cyberduck.core.Path; import ch.cyberduck.core.Path;
import ch.cyberduck.core.PathAttributes;
import ch.cyberduck.core.SimplePathPredicate; import ch.cyberduck.core.SimplePathPredicate;
import ch.cyberduck.core.UUIDRandomStringService; import ch.cyberduck.core.UUIDRandomStringService;
import ch.cyberduck.core.exception.BackgroundException; import ch.cyberduck.core.exception.BackgroundException;
@@ -30,6 +29,7 @@ import ch.cyberduck.core.transfer.TransferStatus;
import java.io.IOException; import java.io.IOException;
import java.util.Collections; import java.util.Collections;
import java.util.Optional;
import com.google.api.services.drive.Drive; import com.google.api.services.drive.Drive;
import com.google.api.services.drive.model.File; import com.google.api.services.drive.model.File;
@@ -81,7 +81,7 @@ public class DriveDirectoryFeature implements Directory<File> {
} }
@Override @Override
public void preflight(final Path workdir, final String filename) throws BackgroundException { public void preflight(final Path workdir, final Optional<String> filename) throws BackgroundException {
new DriveTouchFeature(session, fileid).preflight(workdir, filename); new DriveTouchFeature(session, fileid).preflight(workdir, filename);
} }
} }
@@ -30,6 +30,7 @@ import ch.cyberduck.core.transfer.TransferStatus;
import java.io.IOException; import java.io.IOException;
import java.text.MessageFormat; import java.text.MessageFormat;
import java.util.Collections; import java.util.Collections;
import java.util.Optional;
import com.google.api.services.drive.Drive; import com.google.api.services.drive.Drive;
import com.google.api.services.drive.model.File; import com.google.api.services.drive.model.File;
@@ -71,7 +72,7 @@ public class DriveTouchFeature implements Touch<File> {
} }
@Override @Override
public void preflight(final Path workdir, final String filename) throws BackgroundException { public void preflight(final Path workdir, final Optional<String> filename) throws BackgroundException {
if(workdir.isRoot()) { if(workdir.isRoot()) {
throw new AccessDeniedException(MessageFormat.format(LocaleFactory.localizedString("Cannot create {0}", "Error"), filename)).withFile(workdir); throw new AccessDeniedException(MessageFormat.format(LocaleFactory.localizedString("Cannot create {0}", "Error"), filename)).withFile(workdir);
} }
@@ -32,6 +32,7 @@ import org.jets3t.service.utils.ServiceUtils;
import java.io.IOException; import java.io.IOException;
import java.text.MessageFormat; import java.text.MessageFormat;
import java.util.EnumSet; import java.util.EnumSet;
import java.util.Optional;
import com.google.api.services.storage.Storage; import com.google.api.services.storage.Storage;
import com.google.api.services.storage.model.Bucket; import com.google.api.services.storage.model.Bucket;
@@ -77,20 +78,19 @@ public class GoogleStorageDirectoryFeature implements Directory<StorageObject> {
} }
@Override @Override
public void preflight(final Path workdir, final String filename) throws BackgroundException { public void preflight(final Path workdir, final Optional<String> filename) throws BackgroundException {
if(workdir.isRoot()) { if(workdir.isRoot()) {
if(StringUtils.isNotBlank(filename)) { if(filename.isPresent()) {
if(StringUtils.startsWith(filename, "goog")) { if(StringUtils.startsWith(filename.get(), "goog")) {
throw new InvalidFilenameException(MessageFormat.format(LocaleFactory.localizedString("Cannot create folder {0}", "Error"), filename)); throw new InvalidFilenameException(MessageFormat.format(LocaleFactory.localizedString("Cannot create folder {0}", "Error"), filename));
} }
if(StringUtils.contains(filename, "google")) { if(StringUtils.contains(filename.get(), "google")) {
throw new InvalidFilenameException(MessageFormat.format(LocaleFactory.localizedString("Cannot create folder {0}", "Error"), filename)); throw new InvalidFilenameException(MessageFormat.format(LocaleFactory.localizedString("Cannot create folder {0}", "Error"), filename));
} }
if(!ServiceUtils.isBucketNameValidDNSName(filename)) { if(!ServiceUtils.isBucketNameValidDNSName(filename.get())) {
throw new InvalidFilenameException(MessageFormat.format(LocaleFactory.localizedString("Cannot create folder {0}", "Error"), filename)); throw new InvalidFilenameException(MessageFormat.format(LocaleFactory.localizedString("Cannot create folder {0}", "Error"), filename));
} }
} }
} }
} }
} }
@@ -22,6 +22,7 @@ import ch.cyberduck.core.exception.BackgroundException;
import ch.cyberduck.core.shared.DefaultTouchFeature; import ch.cyberduck.core.shared.DefaultTouchFeature;
import java.text.MessageFormat; import java.text.MessageFormat;
import java.util.Optional;
import com.google.api.services.storage.model.StorageObject; import com.google.api.services.storage.model.StorageObject;
@@ -32,7 +33,7 @@ public class GoogleStorageTouchFeature extends DefaultTouchFeature<StorageObject
} }
@Override @Override
public void preflight(final Path workdir, final String filename) throws BackgroundException { public void preflight(final Path workdir, final Optional<String> filename) throws BackgroundException {
// Creating files is only possible inside a bucket. // Creating files is only possible inside a bucket.
if(workdir.isRoot()) { if(workdir.isRoot()) {
throw new AccessDeniedException(MessageFormat.format(LocaleFactory.localizedString("Cannot create {0}", "Error"), filename)).withFile(workdir); throw new AccessDeniedException(MessageFormat.format(LocaleFactory.localizedString("Cannot create {0}", "Error"), filename)).withFile(workdir);
@@ -22,8 +22,6 @@ import ch.cyberduck.core.features.Touch;
import ch.cyberduck.core.features.Write; import ch.cyberduck.core.features.Write;
import ch.cyberduck.core.transfer.TransferStatus; import ch.cyberduck.core.transfer.TransferStatus;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.irods.irods4j.high_level.connection.IRODSConnection; import org.irods.irods4j.high_level.connection.IRODSConnection;
import org.irods.irods4j.low_level.api.IRODSApi; import org.irods.irods4j.low_level.api.IRODSApi;
import org.irods.irods4j.low_level.api.IRODSException; import org.irods.irods4j.low_level.api.IRODSException;
@@ -32,6 +30,8 @@ import java.io.IOException;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import com.fasterxml.jackson.databind.ObjectMapper;
public class IRODSTouchFeature implements Touch { public class IRODSTouchFeature implements Touch {
private static final ObjectMapper mapper = new ObjectMapper(); private static final ObjectMapper mapper = new ObjectMapper();
@@ -66,9 +66,4 @@ public class IRODSTouchFeature implements Touch {
throw new DefaultIOExceptionMappingService().map("Cannot create {0}", e, file); throw new DefaultIOExceptionMappingService().map("Cannot create {0}", e, file);
} }
} }
@Override
public boolean isSupported(final Path workdir, final String filename) {
return true;
}
} }
@@ -26,11 +26,12 @@ import ch.cyberduck.core.transfer.TransferStatus;
import java.io.IOException; import java.io.IOException;
import java.text.MessageFormat; import java.text.MessageFormat;
import java.util.Optional;
import com.joyent.manta.exception.MantaClientHttpResponseException; import com.joyent.manta.exception.MantaClientHttpResponseException;
import com.joyent.manta.exception.MantaException; import com.joyent.manta.exception.MantaException;
public class MantaDirectoryFeature implements Directory { public class MantaDirectoryFeature implements Directory<Void> {
private final MantaSession session; private final MantaSession session;
@@ -39,7 +40,7 @@ public class MantaDirectoryFeature implements Directory {
} }
@Override @Override
public Path mkdir(final Write writer, final Path folder, final TransferStatus status) throws BackgroundException { public Path mkdir(final Write<Void> writer, final Path folder, final TransferStatus status) throws BackgroundException {
try { try {
session.getClient().putDirectory(folder.getAbsolute()); session.getClient().putDirectory(folder.getAbsolute());
return folder; return folder;
@@ -56,7 +57,7 @@ public class MantaDirectoryFeature implements Directory {
} }
@Override @Override
public void preflight(final Path workdir, final String filename) throws BackgroundException { public void preflight(final Path workdir, final Optional<String> filename) throws BackgroundException {
if(!session.isUserWritable(workdir)) { if(!session.isUserWritable(workdir)) {
throw new AccessDeniedException(MessageFormat.format(LocaleFactory.localizedString("Cannot create folder {0}", "Error"), filename)).withFile(workdir); throw new AccessDeniedException(MessageFormat.format(LocaleFactory.localizedString("Cannot create folder {0}", "Error"), filename)).withFile(workdir);
} }
@@ -26,6 +26,7 @@ import ch.cyberduck.core.transfer.TransferStatus;
import java.io.IOException; import java.io.IOException;
import java.text.MessageFormat; import java.text.MessageFormat;
import java.util.Optional;
import com.joyent.manta.client.MantaObjectResponse; import com.joyent.manta.client.MantaObjectResponse;
import com.joyent.manta.exception.MantaClientHttpResponseException; import com.joyent.manta.exception.MantaClientHttpResponseException;
@@ -60,7 +61,7 @@ public class MantaTouchFeature implements Touch<Void> {
} }
@Override @Override
public void preflight(final Path workdir, final String filename) throws BackgroundException { public void preflight(final Path workdir, final Optional<String> filename) throws BackgroundException {
if(!session.isUserWritable(workdir)) { if(!session.isUserWritable(workdir)) {
throw new AccessDeniedException(MessageFormat.format(LocaleFactory.localizedString("Cannot create {0}", "Error"), filename)).withFile(workdir); throw new AccessDeniedException(MessageFormat.format(LocaleFactory.localizedString("Cannot create {0}", "Error"), filename)).withFile(workdir);
} }
@@ -34,6 +34,7 @@ import org.nuxeo.onedrive.client.types.DriveItem;
import java.io.IOException; import java.io.IOException;
import java.text.MessageFormat; import java.text.MessageFormat;
import java.util.Optional;
public class GraphDirectoryFeature implements Directory<DriveItem.Metadata> { public class GraphDirectoryFeature implements Directory<DriveItem.Metadata> {
@@ -68,7 +69,7 @@ public class GraphDirectoryFeature implements Directory<DriveItem.Metadata> {
} }
@Override @Override
public void preflight(final Path workdir, final String filename) throws BackgroundException { public void preflight(final Path workdir, final Optional<String> filename) throws BackgroundException {
if(!session.isAccessible(workdir)) { if(!session.isAccessible(workdir)) {
throw new AccessDeniedException(MessageFormat.format(LocaleFactory.localizedString("Cannot create folder {0}", "Error"), filename)).withFile(workdir); throw new AccessDeniedException(MessageFormat.format(LocaleFactory.localizedString("Cannot create folder {0}", "Error"), filename)).withFile(workdir);
} }
@@ -37,6 +37,7 @@ import org.nuxeo.onedrive.client.types.DriveItem;
import java.io.IOException; import java.io.IOException;
import java.text.MessageFormat; import java.text.MessageFormat;
import java.util.Optional;
public class GraphTouchFeature implements Touch<DriveItem.Metadata> { public class GraphTouchFeature implements Touch<DriveItem.Metadata> {
@@ -70,7 +71,7 @@ public class GraphTouchFeature implements Touch<DriveItem.Metadata> {
} }
@Override @Override
public void preflight(final Path workdir, final String filename) throws BackgroundException { public void preflight(final Path workdir, final Optional<String> filename) throws BackgroundException {
if(!session.isAccessible(workdir)) { if(!session.isAccessible(workdir)) {
throw new AccessDeniedException(MessageFormat.format(LocaleFactory.localizedString("Cannot create {0}", "Error"), filename)).withFile(workdir); throw new AccessDeniedException(MessageFormat.format(LocaleFactory.localizedString("Cannot create {0}", "Error"), filename)).withFile(workdir);
} }
@@ -32,6 +32,7 @@ import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
import java.util.EnumSet; import java.util.EnumSet;
import java.util.List; import java.util.List;
import java.util.Optional;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail; import static org.junit.Assert.fail;
@@ -107,11 +108,11 @@ public class OfflineGraphDirectoryTouchFeatureTest {
if(feature instanceof Touch) { if(feature instanceof Touch) {
final Touch touch = (Touch) feature; final Touch touch = (Touch) feature;
assertEquals(String.format("Create \"%s\" in \"%s\".", name, parent.getAbsolute()), testCase.isValid, touch.isSupported(parent, name)); assertEquals(String.format("Create \"%s\" in \"%s\".", name, parent.getAbsolute()), testCase.isValid, touch.isSupported(parent, Optional.of(name)));
} }
else if(feature instanceof Directory) { else if(feature instanceof Directory) {
final Directory directory = (Directory) feature; final Directory directory = (Directory) feature;
assertEquals(String.format("Create \"%s\" in \"%s\".", name, parent.getAbsolute()), testCase.isValid, directory.isSupported(parent, name)); assertEquals(String.format("Create \"%s\" in \"%s\".", name, parent.getAbsolute()), testCase.isValid, directory.isSupported(parent, Optional.of(name)));
} }
else { else {
fail(); fail();
@@ -25,6 +25,7 @@ import ch.cyberduck.core.exception.BackgroundException;
import ch.cyberduck.core.shared.DefaultTouchFeature; import ch.cyberduck.core.shared.DefaultTouchFeature;
import java.text.MessageFormat; import java.text.MessageFormat;
import java.util.Optional;
import ch.iterate.openstack.swift.model.StorageObject; import ch.iterate.openstack.swift.model.StorageObject;
@@ -35,7 +36,7 @@ public class SwiftTouchFeature extends DefaultTouchFeature<StorageObject> {
} }
@Override @Override
public void preflight(final Path workdir, final String filename) throws BackgroundException { public void preflight(final Path workdir, final Optional<String> filename) throws BackgroundException {
// Creating files is only possible inside a container. // Creating files is only possible inside a container.
if(workdir.isRoot()) { if(workdir.isRoot()) {
throw new AccessDeniedException(MessageFormat.format(LocaleFactory.localizedString("Cannot create {0}", "Error"), filename)).withFile(workdir); throw new AccessDeniedException(MessageFormat.format(LocaleFactory.localizedString("Cannot create {0}", "Error"), filename)).withFile(workdir);
@@ -8,11 +8,11 @@ import ch.cyberduck.core.SimplePathPredicate;
import ch.cyberduck.core.transfer.TransferStatus; import ch.cyberduck.core.transfer.TransferStatus;
import ch.cyberduck.test.IntegrationTest; import ch.cyberduck.test.IntegrationTest;
import org.apache.commons.lang3.StringUtils;
import org.junit.Test; import org.junit.Test;
import org.junit.experimental.categories.Category; import org.junit.experimental.categories.Category;
import java.util.EnumSet; import java.util.EnumSet;
import java.util.Optional;
import static org.junit.Assert.*; import static org.junit.Assert.*;
@@ -21,8 +21,8 @@ public class SwiftTouchFeatureTest extends AbstractSwiftTest {
@Test @Test
public void testSupported() { public void testSupported() {
assertFalse(new SwiftTouchFeature(session, new SwiftRegionService(session)).isSupported(new Path("/", EnumSet.of(Path.Type.directory, Path.Type.volume)), StringUtils.EMPTY)); assertFalse(new SwiftTouchFeature(session, new SwiftRegionService(session)).isSupported(new Path("/", EnumSet.of(Path.Type.directory, Path.Type.volume)), Optional.empty()));
assertTrue(new SwiftTouchFeature(session, new SwiftRegionService(session)).isSupported(new Path("/container", EnumSet.of(Path.Type.directory, Path.Type.volume)), StringUtils.EMPTY)); assertTrue(new SwiftTouchFeature(session, new SwiftRegionService(session)).isSupported(new Path("/container", EnumSet.of(Path.Type.directory, Path.Type.volume)), Optional.empty()));
} }
@Test @Test
@@ -2727,8 +2727,7 @@ public class BrowserController extends WindowController implements NSToolbar.Del
uploadPanel = NSOpenPanel.openPanel(); uploadPanel = NSOpenPanel.openPanel();
uploadPanel.setCanChooseDirectories(true); uploadPanel.setCanChooseDirectories(true);
uploadPanel.setCanChooseFiles(pool.getFeature(Touch.class).isSupported( uploadPanel.setCanChooseFiles(pool.getFeature(Touch.class).isSupported(
new UploadTargetFinder(workdir).find(this.getSelectedPath()), new UploadTargetFinder(workdir).find(this.getSelectedPath()), Optional.empty()));
StringUtils.EMPTY));
uploadPanel.setCanCreateDirectories(false); uploadPanel.setCanCreateDirectories(false);
uploadPanel.setTreatsFilePackagesAsDirectories(true); uploadPanel.setTreatsFilePackagesAsDirectories(true);
uploadPanel.setAllowsMultipleSelection(true); uploadPanel.setAllowsMultipleSelection(true);
@@ -470,7 +470,7 @@ public abstract class BrowserTableDataSource extends ProxyController implements
return NSDraggingInfo.NSDragOperationNone; return NSDraggingInfo.NSDragOperationNone;
} }
final Touch feature = controller.getSession().getFeature(Touch.class); final Touch feature = controller.getSession().getFeature(Touch.class);
if(!feature.isSupported(destination, StringUtils.EMPTY)) { if(!feature.isSupported(destination, Optional.empty())) {
// Target file system does not support creating files. Creating files is not supported // Target file system does not support creating files. Creating files is not supported
// for example in root of cloud storage accounts. // for example in root of cloud storage accounts.
return NSDraggingInfo.NSDragOperationNone; return NSDraggingInfo.NSDragOperationNone;
@@ -45,7 +45,6 @@ import ch.cyberduck.core.vault.VaultRegistry;
import ch.cyberduck.ui.browser.UploadTargetFinder; import ch.cyberduck.ui.browser.UploadTargetFinder;
import ch.cyberduck.ui.cocoa.controller.BrowserController; import ch.cyberduck.ui.cocoa.controller.BrowserController;
import org.apache.commons.lang3.StringUtils;
import org.rococoa.Foundation; import org.rococoa.Foundation;
import org.rococoa.Rococoa; import org.rococoa.Rococoa;
import org.rococoa.Selector; import org.rococoa.Selector;
@@ -236,25 +235,25 @@ public class BrowserToolbarValidator implements ToolbarValidator {
else if(action.equals(newfolder.action())) { else if(action.equals(newfolder.action())) {
return this.isBrowser() && controller.isMounted() && return this.isBrowser() && controller.isMounted() &&
controller.getSession().getFeature(Directory.class).isSupported( controller.getSession().getFeature(Directory.class).isSupported(
new UploadTargetFinder(controller.workdir()).find(controller.getSelectedPath()), StringUtils.EMPTY new UploadTargetFinder(controller.workdir()).find(controller.getSelectedPath()), Optional.empty()
); );
} }
else if(action.equals(Foundation.selector("createEncryptedVaultButtonClicked:"))) { else if(action.equals(Foundation.selector("createEncryptedVaultButtonClicked:"))) {
return this.isBrowser() && controller.isMounted() && controller.getSession().getVaultRegistry() != VaultRegistry.DISABLED && return this.isBrowser() && controller.isMounted() && controller.getSession().getVaultRegistry() != VaultRegistry.DISABLED &&
!controller.getSession().getVaultRegistry().contains(controller.workdir()) && !controller.getSession().getVaultRegistry().contains(controller.workdir()) &&
controller.getSession().getFeature(Directory.class).isSupported( controller.getSession().getFeature(Directory.class).isSupported(
new UploadTargetFinder(controller.workdir()).find(controller.getSelectedPath()), StringUtils.EMPTY new UploadTargetFinder(controller.workdir()).find(controller.getSelectedPath()), Optional.empty()
); );
} }
else if(action.equals(Foundation.selector("createFileButtonClicked:"))) { else if(action.equals(Foundation.selector("createFileButtonClicked:"))) {
return this.isBrowser() && controller.isMounted() && controller.getSession().getFeature(Touch.class).isSupported( return this.isBrowser() && controller.isMounted() && controller.getSession().getFeature(Touch.class).isSupported(
new UploadTargetFinder(controller.workdir()).find(controller.getSelectedPath()), StringUtils.EMPTY new UploadTargetFinder(controller.workdir()).find(controller.getSelectedPath()), Optional.empty()
); );
} }
else if(action.equals(upload.action())) { else if(action.equals(upload.action())) {
return this.isBrowser() && controller.isMounted() && controller.getSession().getFeature(Touch.class).isSupported( return this.isBrowser() && controller.isMounted() && controller.getSession().getFeature(Touch.class).isSupported(
new UploadTargetFinder(controller.workdir()).find(controller.getSelectedPath()), new UploadTargetFinder(controller.workdir()).find(controller.getSelectedPath()),
StringUtils.EMPTY); Optional.empty());
} }
else if(action.equals(Foundation.selector("createSymlinkButtonClicked:"))) { else if(action.equals(Foundation.selector("createSymlinkButtonClicked:"))) {
return this.isBrowser() && controller.isMounted() && controller.getSession().getFeature(Symlink.class) != null return this.isBrowser() && controller.isMounted() && controller.getSession().getFeature(Symlink.class) != null
@@ -33,6 +33,7 @@ import org.jets3t.service.utils.ServiceUtils;
import java.text.MessageFormat; import java.text.MessageFormat;
import java.util.EnumSet; import java.util.EnumSet;
import java.util.Optional;
public class S3DirectoryFeature implements Directory<StorageObject> { public class S3DirectoryFeature implements Directory<StorageObject> {
@@ -69,11 +70,11 @@ public class S3DirectoryFeature implements Directory<StorageObject> {
@Override @Override
public void preflight(final Path workdir, final String filename) throws BackgroundException { public void preflight(final Path workdir, final Optional<String> filename) throws BackgroundException {
if(StringUtils.isEmpty(RequestEntityRestStorageService.findBucketInHostname(session.getHost()))) { if(StringUtils.isEmpty(RequestEntityRestStorageService.findBucketInHostname(session.getHost()))) {
if(workdir.isRoot()) { if(workdir.isRoot()) {
if(StringUtils.isNotBlank(filename)) { if(filename.isPresent()) {
if(!ServiceUtils.isBucketNameValidDNSName(filename)) { if(!ServiceUtils.isBucketNameValidDNSName(filename.get())) {
throw new InvalidFilenameException(MessageFormat.format(LocaleFactory.localizedString("Cannot create folder {0}", "Error"), filename)); throw new InvalidFilenameException(MessageFormat.format(LocaleFactory.localizedString("Cannot create folder {0}", "Error"), filename));
} }
} }
@@ -31,6 +31,7 @@ import org.apache.commons.lang3.StringUtils;
import org.jets3t.service.model.StorageObject; import org.jets3t.service.model.StorageObject;
import java.text.MessageFormat; import java.text.MessageFormat;
import java.util.Optional;
public class S3TouchFeature extends DefaultTouchFeature<StorageObject> { public class S3TouchFeature extends DefaultTouchFeature<StorageObject> {
@@ -47,7 +48,7 @@ public class S3TouchFeature extends DefaultTouchFeature<StorageObject> {
} }
@Override @Override
public void preflight(final Path workdir, final String filename) throws BackgroundException { public void preflight(final Path workdir, final Optional<String> filename) throws BackgroundException {
if(StringUtils.isEmpty(RequestEntityRestStorageService.findBucketInHostname(session.getHost()))) { if(StringUtils.isEmpty(RequestEntityRestStorageService.findBucketInHostname(session.getHost()))) {
// Creating files is only possible inside a bucket. // Creating files is only possible inside a bucket.
if(workdir.isRoot()) { if(workdir.isRoot()) {
@@ -39,6 +39,7 @@ import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.EnumSet; import java.util.EnumSet;
import java.util.HashSet; import java.util.HashSet;
import java.util.Optional;
import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicBoolean;
import static org.junit.Assert.*; import static org.junit.Assert.*;
@@ -59,7 +60,7 @@ public class S3DirectoryFeatureTest extends AbstractS3Test {
break; break;
default: default:
final Path test = new Path(new DefaultHomeFinderService(session).find(), new AsciiRandomStringService(30).random(), EnumSet.of(Path.Type.directory, Path.Type.volume)); final Path test = new Path(new DefaultHomeFinderService(session).find(), new AsciiRandomStringService(30).random(), EnumSet.of(Path.Type.directory, Path.Type.volume));
assertTrue(feature.isSupported(test.getParent(), test.getName())); assertTrue(feature.isSupported(test.getParent(), Optional.of(test.getName())));
test.attributes().setRegion(region.getIdentifier()); test.attributes().setRegion(region.getIdentifier());
feature.mkdir(new S3WriteFeature(session, new S3AccessControlListFeature(session)), test, new TransferStatus().setRegion(region.getIdentifier())); feature.mkdir(new S3WriteFeature(session, new S3AccessControlListFeature(session)), test, new TransferStatus().setRegion(region.getIdentifier()));
assertTrue(new S3FindFeature(session, acl).find(test)); assertTrue(new S3FindFeature(session, acl).find(test));
@@ -92,7 +93,7 @@ public class S3DirectoryFeatureTest extends AbstractS3Test {
final S3DirectoryFeature feature = new S3DirectoryFeature(session, acl); final S3DirectoryFeature feature = new S3DirectoryFeature(session, acl);
for(Location.Name region : Collections.singletonList(new S3LocationFeature.S3Region("us-east-1"))) { for(Location.Name region : Collections.singletonList(new S3LocationFeature.S3Region("us-east-1"))) {
final Path test = new Path(new DefaultHomeFinderService(session).find(), new AsciiRandomStringService(30).random(), EnumSet.of(Path.Type.directory, Path.Type.volume)); final Path test = new Path(new DefaultHomeFinderService(session).find(), new AsciiRandomStringService(30).random(), EnumSet.of(Path.Type.directory, Path.Type.volume));
assertTrue(feature.isSupported(test.getParent(), test.getName())); assertTrue(feature.isSupported(test.getParent(), Optional.of(test.getName())));
test.attributes().setRegion(region.getIdentifier()); test.attributes().setRegion(region.getIdentifier());
feature.mkdir(new S3WriteFeature(session, new S3AccessControlListFeature(session)), test, new TransferStatus().setRegion(region.getIdentifier())); feature.mkdir(new S3WriteFeature(session, new S3AccessControlListFeature(session)), test, new TransferStatus().setRegion(region.getIdentifier()));
assertTrue(new S3FindFeature(session, acl).find(test)); assertTrue(new S3FindFeature(session, acl).find(test));
@@ -125,7 +126,7 @@ public class S3DirectoryFeatureTest extends AbstractS3Test {
final S3DirectoryFeature feature = new S3DirectoryFeature(session, acl); final S3DirectoryFeature feature = new S3DirectoryFeature(session, acl);
for(Location.Name region : Collections.singletonList(new S3LocationFeature.S3Region("us-east-1"))) { for(Location.Name region : Collections.singletonList(new S3LocationFeature.S3Region("us-east-1"))) {
final Path test = new Path(new DefaultHomeFinderService(session).find(), new AsciiRandomStringService(30).random(), EnumSet.of(Path.Type.directory, Path.Type.volume)); final Path test = new Path(new DefaultHomeFinderService(session).find(), new AsciiRandomStringService(30).random(), EnumSet.of(Path.Type.directory, Path.Type.volume));
assertTrue(feature.isSupported(test.getParent(), test.getName())); assertTrue(feature.isSupported(test.getParent(), Optional.of(test.getName())));
test.attributes().setRegion(region.getIdentifier()); test.attributes().setRegion(region.getIdentifier());
feature.mkdir(new S3WriteFeature(session, new S3AccessControlListFeature(session)), test, new TransferStatus().setRegion(region.getIdentifier())); feature.mkdir(new S3WriteFeature(session, new S3AccessControlListFeature(session)), test, new TransferStatus().setRegion(region.getIdentifier()));
assertTrue(new S3FindFeature(session, acl).find(test)); assertTrue(new S3FindFeature(session, acl).find(test));
@@ -139,8 +140,8 @@ public class S3DirectoryFeatureTest extends AbstractS3Test {
public void testCreateBucketInvalidName() throws Exception { public void testCreateBucketInvalidName() throws Exception {
final S3AccessControlListFeature acl = new S3AccessControlListFeature(session); final S3AccessControlListFeature acl = new S3AccessControlListFeature(session);
final Path test = new Path(new DefaultHomeFinderService(session).find(), "untitled folder", EnumSet.of(Path.Type.directory, Path.Type.volume)); final Path test = new Path(new DefaultHomeFinderService(session).find(), "untitled folder", EnumSet.of(Path.Type.directory, Path.Type.volume));
assertFalse(new S3DirectoryFeature(session, acl).isSupported(test.getParent(), test.getName())); assertFalse(new S3DirectoryFeature(session, acl).isSupported(test.getParent(), Optional.of(test.getName())));
assertTrue(new S3DirectoryFeature(virtualhost, acl).isSupported(test.getParent(), test.getName())); assertTrue(new S3DirectoryFeature(virtualhost, acl).isSupported(test.getParent(), Optional.of(test.getName())));
final S3LocationFeature.S3Region region = new S3LocationFeature.S3Region("eu-west-2"); final S3LocationFeature.S3Region region = new S3LocationFeature.S3Region("eu-west-2");
test.attributes().setRegion(region.getIdentifier()); test.attributes().setRegion(region.getIdentifier());
new S3DirectoryFeature(session, acl).mkdir(new S3WriteFeature(session, new S3AccessControlListFeature(session)), test, new TransferStatus().setRegion(region.getIdentifier())); new S3DirectoryFeature(session, acl).mkdir(new S3WriteFeature(session, new S3AccessControlListFeature(session)), test, new TransferStatus().setRegion(region.getIdentifier()));
@@ -14,12 +14,12 @@ import ch.cyberduck.core.shared.DefaultFindFeature;
import ch.cyberduck.core.transfer.TransferStatus; import ch.cyberduck.core.transfer.TransferStatus;
import ch.cyberduck.test.IntegrationTest; import ch.cyberduck.test.IntegrationTest;
import org.apache.commons.lang3.StringUtils;
import org.junit.Test; import org.junit.Test;
import org.junit.experimental.categories.Category; import org.junit.experimental.categories.Category;
import java.util.Collections; import java.util.Collections;
import java.util.EnumSet; import java.util.EnumSet;
import java.util.Optional;
import static org.junit.Assert.*; import static org.junit.Assert.*;
@@ -29,10 +29,10 @@ public class S3TouchFeatureTest extends AbstractS3Test {
@Test @Test
public void testFile() { public void testFile() {
final S3AccessControlListFeature acl = new S3AccessControlListFeature(session); final S3AccessControlListFeature acl = new S3AccessControlListFeature(session);
assertFalse(new S3TouchFeature(session, acl).isSupported(Home.root(), StringUtils.EMPTY)); assertFalse(new S3TouchFeature(session, acl).isSupported(Home.root(), Optional.empty()));
assertTrue(new S3TouchFeature(session, acl).isSupported(new Path(Home.root(), "/container", EnumSet.of(Path.Type.volume, Path.Type.directory)), StringUtils.EMPTY)); assertTrue(new S3TouchFeature(session, acl).isSupported(new Path(Home.root(), "/container", EnumSet.of(Path.Type.volume, Path.Type.directory)), Optional.empty()));
assertTrue(new S3TouchFeature(virtualhost, acl).isSupported(Home.root(), StringUtils.EMPTY)); assertTrue(new S3TouchFeature(virtualhost, acl).isSupported(Home.root(), Optional.empty()));
assertTrue(new S3TouchFeature(virtualhost, acl).isSupported(new Path(Home.root(), "/container", EnumSet.of(Path.Type.volume, Path.Type.directory)), StringUtils.EMPTY)); assertTrue(new S3TouchFeature(virtualhost, acl).isSupported(new Path(Home.root(), "/container", EnumSet.of(Path.Type.volume, Path.Type.directory)), Optional.empty()));
} }
@Test @Test
@@ -41,8 +41,8 @@ public class S3TouchFeatureTest extends AbstractS3Test {
final S3AccessControlListFeature acl = new S3AccessControlListFeature(session); final S3AccessControlListFeature acl = new S3AccessControlListFeature(session);
final S3TouchFeature feature = new S3TouchFeature(session, acl); final S3TouchFeature feature = new S3TouchFeature(session, acl);
final String filename = new AsciiRandomStringService().random(); final String filename = new AsciiRandomStringService().random();
assertFalse(feature.isSupported(Home.root(), filename)); assertFalse(feature.isSupported(Home.root(), Optional.of(filename)));
assertTrue(feature.isSupported(container, filename)); assertTrue(feature.isSupported(container, Optional.of(filename)));
final Path test = feature.touch(new S3WriteFeature(session, new S3AccessControlListFeature(session)), new Path(container, filename, EnumSet.of(Path.Type.file)), new TransferStatus()); final Path test = feature.touch(new S3WriteFeature(session, new S3AccessControlListFeature(session)), new Path(container, filename, EnumSet.of(Path.Type.file)), new TransferStatus());
assertNull(test.attributes().getVersionId()); assertNull(test.attributes().getVersionId());
assertTrue(new S3FindFeature(session, acl).find(test)); assertTrue(new S3FindFeature(session, acl).find(test));
@@ -57,7 +57,7 @@ public class S3TouchFeatureTest extends AbstractS3Test {
final S3AccessControlListFeature acl = new S3AccessControlListFeature(virtualhost); final S3AccessControlListFeature acl = new S3AccessControlListFeature(virtualhost);
final S3TouchFeature feature = new S3TouchFeature(virtualhost, acl); final S3TouchFeature feature = new S3TouchFeature(virtualhost, acl);
final String filename = new AsciiRandomStringService().random(); final String filename = new AsciiRandomStringService().random();
assertTrue(feature.isSupported(Home.root(), filename)); assertTrue(feature.isSupported(Home.root(), Optional.of(filename)));
final Path test = feature.touch(new S3WriteFeature(virtualhost, new S3AccessControlListFeature(virtualhost)), new Path(filename, EnumSet.of(Path.Type.file)), new TransferStatus()); final Path test = feature.touch(new S3WriteFeature(virtualhost, new S3AccessControlListFeature(virtualhost)), new Path(filename, EnumSet.of(Path.Type.file)), new TransferStatus());
assertNull(test.attributes().getVersionId()); assertNull(test.attributes().getVersionId());
assertTrue(new S3FindFeature(virtualhost, acl).find(test)); assertTrue(new S3FindFeature(virtualhost, acl).find(test));
@@ -29,6 +29,7 @@ import org.jets3t.service.model.StorageObject;
import java.text.MessageFormat; import java.text.MessageFormat;
import java.util.Collections; import java.util.Collections;
import java.util.Optional;
public class SpectraTouchFeature extends DefaultTouchFeature<StorageObject> { public class SpectraTouchFeature extends DefaultTouchFeature<StorageObject> {
@@ -47,7 +48,7 @@ public class SpectraTouchFeature extends DefaultTouchFeature<StorageObject> {
} }
@Override @Override
public void preflight(final Path workdir, final String filename) throws BackgroundException { public void preflight(final Path workdir, final Optional<String> filename) throws BackgroundException {
// Creating files is only possible inside a bucket. // Creating files is only possible inside a bucket.
if(workdir.isRoot()) { if(workdir.isRoot()) {
throw new AccessDeniedException(MessageFormat.format(LocaleFactory.localizedString("Cannot create {0}", "Error"), filename)).withFile(workdir); throw new AccessDeniedException(MessageFormat.format(LocaleFactory.localizedString("Cannot create {0}", "Error"), filename)).withFile(workdir);
@@ -22,12 +22,12 @@ import ch.cyberduck.core.features.Home;
import ch.cyberduck.core.transfer.TransferStatus; import ch.cyberduck.core.transfer.TransferStatus;
import ch.cyberduck.test.IntegrationTest; import ch.cyberduck.test.IntegrationTest;
import org.apache.commons.lang3.StringUtils;
import org.junit.Test; import org.junit.Test;
import org.junit.experimental.categories.Category; import org.junit.experimental.categories.Category;
import java.util.Collections; import java.util.Collections;
import java.util.EnumSet; import java.util.EnumSet;
import java.util.Optional;
import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
@@ -37,8 +37,8 @@ public class SpectraTouchFeatureTest extends AbstractSpectraTest {
@Test @Test
public void testFile() { public void testFile() {
assertFalse(new SpectraTouchFeature(session).isSupported(Home.root(), StringUtils.EMPTY)); assertFalse(new SpectraTouchFeature(session).isSupported(Home.root(), Optional.empty()));
assertTrue(new SpectraTouchFeature(session).isSupported(new Path(Home.root(), "/container", EnumSet.of(Path.Type.directory, Path.Type.volume)), StringUtils.EMPTY)); assertTrue(new SpectraTouchFeature(session).isSupported(new Path(Home.root(), "/container", EnumSet.of(Path.Type.directory, Path.Type.volume)), Optional.empty()));
} }
@Test @Test
@@ -28,6 +28,7 @@ import ch.cyberduck.core.storegate.io.swagger.client.model.File;
import ch.cyberduck.core.transfer.TransferStatus; import ch.cyberduck.core.transfer.TransferStatus;
import java.text.MessageFormat; import java.text.MessageFormat;
import java.util.Optional;
public class StoregateDirectoryFeature implements Directory<File> { public class StoregateDirectoryFeature implements Directory<File> {
@@ -56,7 +57,7 @@ public class StoregateDirectoryFeature implements Directory<File> {
} }
@Override @Override
public void preflight(final Path workdir, final String filename) throws BackgroundException { public void preflight(final Path workdir, final Optional<String> filename) throws BackgroundException {
if(workdir.isRoot()) { if(workdir.isRoot()) {
throw new AccessDeniedException(MessageFormat.format(LocaleFactory.localizedString("Cannot create folder {0}", "Error"), filename)).withFile(workdir); throw new AccessDeniedException(MessageFormat.format(LocaleFactory.localizedString("Cannot create folder {0}", "Error"), filename)).withFile(workdir);
} }
@@ -23,6 +23,7 @@ import ch.cyberduck.core.shared.DefaultTouchFeature;
import ch.cyberduck.core.storegate.io.swagger.client.model.File; import ch.cyberduck.core.storegate.io.swagger.client.model.File;
import java.text.MessageFormat; import java.text.MessageFormat;
import java.util.Optional;
public class StoregateTouchFeature extends DefaultTouchFeature<File> { public class StoregateTouchFeature extends DefaultTouchFeature<File> {
@@ -31,7 +32,7 @@ public class StoregateTouchFeature extends DefaultTouchFeature<File> {
} }
@Override @Override
public void preflight(final Path workdir, final String filename) throws BackgroundException { public void preflight(final Path workdir, final Optional<String> filename) throws BackgroundException {
if(workdir.isRoot()) { if(workdir.isRoot()) {
throw new AccessDeniedException(MessageFormat.format(LocaleFactory.localizedString("Cannot create {0}", "Error"), filename)).withFile(workdir); throw new AccessDeniedException(MessageFormat.format(LocaleFactory.localizedString("Cannot create {0}", "Error"), filename)).withFile(workdir);
} }
@@ -1014,7 +1014,7 @@ namespace Ch.Cyberduck.Ui.Controller
return; return;
} }
Touch feature = (Touch)Pool.getFeature(typeof(Touch)); Touch feature = (Touch)Pool.getFeature(typeof(Touch));
if (!feature.isSupported(destination, String.Empty)) if (!feature.isSupported(destination, Optional.empty()))
{ {
args.Effect = DragDropEffects.None; args.Effect = DragDropEffects.None;
args.DropTargetLocation = DropTargetLocation.None; args.DropTargetLocation = DropTargetLocation.None;
@@ -1885,14 +1885,14 @@ namespace Ch.Cyberduck.Ui.Controller
{ {
return IsMounted() && return IsMounted() &&
((Touch)Pool.getFeature(typeof(Touch))).isSupported( ((Touch)Pool.getFeature(typeof(Touch))).isSupported(
new UploadTargetFinder(Workdir).find(SelectedPath), String.Empty); new UploadTargetFinder(Workdir).find(SelectedPath), Optional.empty());
} }
private bool View_ValidateUpload() private bool View_ValidateUpload()
{ {
return IsMounted() && return IsMounted() &&
((Touch)Pool.getFeature(typeof(Touch))).isSupported( ((Touch)Pool.getFeature(typeof(Touch))).isSupported(
new UploadTargetFinder(Workdir).find(SelectedPath), String.Empty); new UploadTargetFinder(Workdir).find(SelectedPath), Optional.empty());
} }
private void View_Upload() private void View_Upload()
@@ -2061,7 +2061,7 @@ namespace Ch.Cyberduck.Ui.Controller
{ {
return IsMounted() && return IsMounted() &&
((Directory)Pool.getFeature(typeof(Directory))).isSupported( ((Directory)Pool.getFeature(typeof(Directory))).isSupported(
new UploadTargetFinder(Workdir).find(SelectedPath), String.Empty); new UploadTargetFinder(Workdir).find(SelectedPath), Optional.empty());
} }
private bool View_ValidateNewVault() private bool View_ValidateNewVault()
@@ -2069,7 +2069,7 @@ namespace Ch.Cyberduck.Ui.Controller
return IsMounted() && Pool.getVaultRegistry() != VaultRegistry.DISABLED && return IsMounted() && Pool.getVaultRegistry() != VaultRegistry.DISABLED &&
!Pool.getVaultRegistry().contains(Workdir) && !Pool.getVaultRegistry().contains(Workdir) &&
((Directory)Pool.getFeature(typeof(Directory))).isSupported( ((Directory)Pool.getFeature(typeof(Directory))).isSupported(
new UploadTargetFinder(Workdir).find(SelectedPath), String.Empty); new UploadTargetFinder(Workdir).find(SelectedPath), Optional.empty());
} }
private void View_DuplicateFile() private void View_DuplicateFile()
@@ -2263,7 +2263,7 @@ namespace Ch.Cyberduck.Ui.Controller
return; return;
} }
Touch feature = (Touch)Pool.getFeature(typeof(Touch)); Touch feature = (Touch)Pool.getFeature(typeof(Touch));
if (!feature.isSupported(destination, String.Empty)) if (!feature.isSupported(destination, Optional.empty()))
{ {
Log.trace("Pool does not allow file creation"); Log.trace("Pool does not allow file creation");
args.Effect = DragDropEffects.None; args.Effect = DragDropEffects.None;