Cyberduck Mountain Duck CLI

Changeset 43179


Ignore:
Timestamp:
Nov 3, 2017 1:01:53 PM (4 years ago)
Author:
Tomas Celaya
Message:

Merge branch 'feature/TRAC-9711' of github.com:iterate-ch/cyberduck into feature/TRAC-9711

Location:
shelves/Tomas_Celaya
Files:
5 added
45 edited
1 moved

Legend:

Unmodified
Added
Removed
  • shelves/Tomas_Celaya

  • shelves/Tomas_Celaya/Changelog.txt

    r43167 r43179  
    11Cyberduck
    22https://cyberduck.io/
     3
     46.2.11
     5- [Bugfix] Application crash restoring workspace (Windows)
     6
     76.2.10
     8- [Feature] Option to disable auto-detect of vaults (Cryptomator)
     9- [Bugfix] Login where authentication is required with both password and public key method (SFTP)
    310
    4116.2.9
  • shelves/Tomas_Celaya/Cyberduck CLI-WiX.wxs

    r43139 r43179  
    162162        </File>
    163163      </Component>
     164      <Component Id="ikvm.misc" Guid="1F57FEE7-5278-44C8-9C30-CBDAC2019304">
     165        <File Source="$(var.CLI.TargetDir)/IKVM.OpenJDK.Misc.dll" KeyPath="yes" Checksum="yes">
     166          <netfx:NativeImage Id="ngen_ikvm.misc" Platform="32bit" Priority="3" />
     167        </File>
     168      </Component>
    164169      <Component Id="jnidispatch" Guid="B6621775-1A9A-461E-83B8-BB1EE34B5965">
    165170        <File Source="$(var.CLI.TargetDir)/jnidispatch.dll" KeyPath="yes" Checksum="yes" />
  • shelves/Tomas_Celaya/README.md

    r41249 r43179  
    66[![Twitter](https://img.shields.io/badge/twitter-@cyberduckapp-blue.svg?style=flat)](http://twitter.com/cyberduckapp)
    77
    8 Libre FTP, SFTP, WebDAV, S3, Azure and OpenStack Swift browser for Mac and Windows. Command line interface (CLI) for Linux, OS X and Windows.
     8Libre file transfer client for macOS and Windows. Command line interface (CLI) for Linux, macOS and Windows.
    99
    1010## Prerequisites
     
    1313- Apache Ant 1.10.1 or later
    1414- Apache Maven 3.5 or later
    15 - [Xcode 8](https://developer.apple.com/xcode/download/) or later
    16 - Microsoft Visual Studio 2012 or later
    17 - [Microsoft Windows SDK for Windows 7 and .NET Framework 4](http://www.microsoft.com/downloads/details.aspx?FamilyID=6b6c21d2-2006-4afa-9702-529fa782d63b&displaylang=en)
    18 - [MSBuild Community Tasks](https://github.com/loresoft/msbuildtasks)
     15
     16### macOS
     17- [Xcode 9](https://developer.apple.com/xcode/download/) or later
     18
     19### Windows
     20
     21- Visual Studio 2017 or later
     22  - `.NET Desktop development`-Workload
     23  - Windows SDK (10.0.14393.0)
     24  - [MSBuild Community Tasks](https://github.com/loresoft/msbuildtasks)
    1925- [Bonjour SDK for Windows](https://developer.apple.com/downloads/index.action?q=Bonjour%20SDK%20for%20Windows)
    2026
     
    2329Run `mvn verify -DskipTests` to build without running any tests.
    2430
     31### Windows
     32
     33You will run into errors by MSBuild/Wix that are unrelated to how Cyberduck is built. You may safely ignore them.
     34
    2535## Running Tests
    2636
    2737After packaging, run `mvn test -DskipITs` to run unit tests but skip integration tests.
    28 
    29 ## Releases
    30 
    31 Releases are tagged in GIT/SVN such as `release-2-6`. Checkout using `svn co https://svn.cyberduck.io/tags/release-2-6`.
    3238
    3339### Maven Artifacts
  • shelves/Tomas_Celaya/cli/src/main/java/ch/cyberduck/cli/Terminal.java

    r41786 r43179  
    3939import ch.cyberduck.core.local.ApplicationFinderFactory;
    4040import ch.cyberduck.core.local.ApplicationQuitCallback;
     41import ch.cyberduck.core.manta.MantaProtocol;
    4142import ch.cyberduck.core.nio.LocalProtocol;
    4243import ch.cyberduck.core.onedrive.OneDriveProtocol;
     
    109110        this.preferences = defaults.withDefaults(input);
    110111        ProtocolFactory.get().register(
    111                 new FTPProtocol(),
    112                 new FTPTLSProtocol(),
    113                 new SFTPProtocol(),
    114                 new DAVProtocol(),
    115                 new DAVSSLProtocol(),
    116                 new SwiftProtocol(),
    117                 new S3Protocol(),
    118                 new GoogleStorageProtocol(),
    119                 new AzureProtocol(),
    120                 new IRODSProtocol(),
    121                 new SpectraProtocol(),
    122                 new B2Protocol(),
    123                 new DriveProtocol(),
    124                 new HubicProtocol(),
    125                 new DropboxProtocol(),
    126                 new DropboxProtocol(),
    127                 new OneDriveProtocol(),
    128                 new LocalProtocol(),
    129                 new SDSProtocol()
     112            new FTPProtocol(),
     113            new FTPTLSProtocol(),
     114            new SFTPProtocol(),
     115            new DAVProtocol(),
     116            new DAVSSLProtocol(),
     117            new SwiftProtocol(),
     118            new S3Protocol(),
     119            new GoogleStorageProtocol(),
     120            new AzureProtocol(),
     121            new IRODSProtocol(),
     122            new SpectraProtocol(),
     123            new B2Protocol(),
     124            new DriveProtocol(),
     125            new HubicProtocol(),
     126            new DropboxProtocol(),
     127            new DropboxProtocol(),
     128            new OneDriveProtocol(),
     129            new LocalProtocol(),
     130            new SDSProtocol(),
     131            new MantaProtocol()
    130132        );
    131133        this.options = options;
     
    136138        this.cache = new PathCache(preferences.getInteger("browser.cache.size"));
    137139        this.progress = input.hasOption(TerminalOptionsBuilder.Params.quiet.name())
    138                 ? new DisabledListProgressListener() : new TerminalProgressListener();
     140            ? new DisabledListProgressListener() : new TerminalProgressListener();
    139141        this.transcript = input.hasOption(TerminalOptionsBuilder.Params.verbose.name())
    140                 ? new TerminalTranscriptListener() : new DisabledTranscriptListener();
     142            ? new TerminalTranscriptListener() : new DisabledTranscriptListener();
    141143        this.reader = input.hasOption(TerminalOptionsBuilder.Params.assumeyes.name())
    142                 ? new DisabledTerminalPromptReader() : new InteractiveTerminalPromptReader();
     144            ? new DisabledTerminalPromptReader() : new InteractiveTerminalPromptReader();
    143145        this.controller = new TerminalController(progress, transcript);
    144146    }
     
    218220            final Host host = new CommandLineUriParser(input).parse(uri);
    219221            final LoginConnectionService connect = new LoginConnectionService(new TerminalLoginService(input,
    220                     new TerminalLoginCallback(reader)), new TerminalHostKeyVerifier(reader), progress);
     222                new TerminalLoginCallback(reader)), new TerminalHostKeyVerifier(reader), progress);
    221223            source = SessionPoolFactory.create(connect, transcript, cache, host,
    222                     new CertificateStoreX509TrustManager(new DefaultTrustManagerHostnameCallback(host), new TerminalCertificateStore(reader)),
    223                     new PreferencesX509KeyManager(host, new TerminalCertificateStore(reader)),
    224                     VaultRegistryFactory.create(new TerminalPasswordCallback()));
     224                new CertificateStoreX509TrustManager(new DefaultTrustManagerHostnameCallback(host), new TerminalCertificateStore(reader)),
     225                new PreferencesX509KeyManager(host, new TerminalCertificateStore(reader)),
     226                VaultRegistryFactory.create(new TerminalPasswordCallback()));
    225227            final Path remote;
    226228            if(new CommandLinePathParser(input).parse(uri).getAbsolute().startsWith(TildePathExpander.PREFIX)) {
     
    247249                case synchronize:
    248250                    return this.transfer(new TerminalTransferFactory().create(input, host, remote,
    249                             new ArrayList<TransferItem>(new SingleTransferItemFinder().find(input, action, remote))),
    250                             source, SessionPool.DISCONNECTED);
     251                        new ArrayList<TransferItem>(new SingleTransferItemFinder().find(input, action, remote))),
     252                        source, SessionPool.DISCONNECTED);
    251253                case copy:
    252254                    final Host target = new CommandLineUriParser(input).parse(input.getOptionValues(action.name())[1]);
    253255                    destination = SessionPoolFactory.create(connect, transcript, cache, target,
    254                             new CertificateStoreX509TrustManager(new DefaultTrustManagerHostnameCallback(target), new TerminalCertificateStore(reader)),
    255                             new PreferencesX509KeyManager(target, new TerminalCertificateStore(reader)),
    256                             VaultRegistryFactory.create(new TerminalPasswordCallback()));
     256                        new CertificateStoreX509TrustManager(new DefaultTrustManagerHostnameCallback(target), new TerminalCertificateStore(reader)),
     257                        new PreferencesX509KeyManager(target, new TerminalCertificateStore(reader)),
     258                        VaultRegistryFactory.create(new TerminalPasswordCallback()));
    257259                    return this.transfer(new CopyTransfer(
    258                                     host, target, Collections.singletonMap(remote, new CommandLinePathParser(input).parse(input.getOptionValues(action.name())[1]))),
    259                             source, destination);
     260                            host, target, Collections.singletonMap(remote, new CommandLinePathParser(input).parse(input.getOptionValues(action.name())[1]))),
     261                        source, destination);
    260262                default:
    261263                    throw new BackgroundException(LocaleFactory.localizedString("Unknown"),
    262                             String.format("Unknown transfer type %s", action.name()));
     264                        String.format("Unknown transfer type %s", action.name()));
    263265            }
    264266        }
     
    291293            if(StringUtils.isNotBlank(input.getOptionValue(TerminalOptionsBuilder.Params.retry.name()))) {
    292294                preferences.setProperty("connection.retry",
    293                         NumberUtils.toInt(input.getOptionValue(TerminalOptionsBuilder.Params.retry.name()), 1));
     295                    NumberUtils.toInt(input.getOptionValue(TerminalOptionsBuilder.Params.retry.name()), 1));
    294296            }
    295297            else {
     
    307309        if(input.hasOption(TerminalOptionsBuilder.Params.parallel.name())) {
    308310            preferences.setProperty("queue.connections.limit",
    309                     NumberUtils.toInt(input.getOptionValue(TerminalOptionsBuilder.Params.parallel.name()), 2));
     311                NumberUtils.toInt(input.getOptionValue(TerminalOptionsBuilder.Params.parallel.name()), 2));
    310312        }
    311313    }
     
    342344        }
    343345        final TerminalTransferBackgroundAction action = new TerminalTransferBackgroundAction(controller, reader,
    344                 source, destination,
    345                 transfer, new TransferOptions().reload(true), prompt, meter,
    346                 input.hasOption(TerminalOptionsBuilder.Params.quiet.name())
    347                         ? new DisabledStreamListener() : new TerminalStreamListener(meter)
     346            source, destination,
     347            transfer, new TransferOptions().reload(true), prompt, meter,
     348            input.hasOption(TerminalOptionsBuilder.Params.quiet.name())
     349                ? new DisabledStreamListener() : new TerminalStreamListener(meter)
    348350        );
    349351        if(!this.execute(action)) {
     
    355357    protected Exit mount(final SessionPool session) {
    356358        final SessionBackgroundAction<Path> action = new WorkerBackgroundAction<Path>(
    357                 controller, session, new FilesystemWorker(FilesystemFactory.get(controller, session.getHost(), cache)));
     359            controller, session, new FilesystemWorker(FilesystemFactory.get(controller, session.getHost(), cache)));
    358360        if(!this.execute(action)) {
    359361            return Exit.failure;
     
    364366    protected Exit list(final SessionPool session, final Path remote, final boolean verbose) {
    365367        final SessionListWorker worker = new SessionListWorker(cache, remote,
    366                 new TerminalListProgressListener(reader, verbose));
     368            new TerminalListProgressListener(reader, verbose));
    367369        final SessionBackgroundAction<AttributedList<Path>> action = new TerminalBackgroundAction<AttributedList<Path>>(
    368                 controller,
    369                 session, worker);
     370            controller,
     371            session, worker);
    370372        if(!this.execute(action)) {
    371373            return Exit.failure;
     
    401403            if(!finder.isInstalled(application)) {
    402404                throw new BackgroundException(LocaleFactory.localizedString("Unknown"),
    403                         String.format("Application %s not found", input.getOptionValue(TerminalOptionsBuilder.Params.application.name())));
     405                    String.format("Application %s not found", input.getOptionValue(TerminalOptionsBuilder.Params.application.name())));
    404406            }
    405407        }
     
    409411        if(!finder.isInstalled(application)) {
    410412            throw new BackgroundException(LocaleFactory.localizedString("Unknown"),
    411                     String.format("No application found to edit %s", remote.getName()));
     413                String.format("No application found to edit %s", remote.getName()));
    412414        }
    413415        final Editor editor = factory.create(controller, session, application, remote);
  • shelves/Tomas_Celaya/core/src/main/java/ch/cyberduck/core/AbstractProtocol.java

    r43139 r43179  
    9696    }
    9797
    98 
    9998    @Override
    10099    public boolean isPortConfigurable() {
     
    124123    @Override
    125124    public boolean isPasswordConfigurable() {
    126         return true;
     125        return StringUtils.isBlank(this.getOAuthClientId());
    127126    }
    128127
  • shelves/Tomas_Celaya/core/src/main/java/ch/cyberduck/core/AuthenticationProvider.java

    r43173 r43179  
    1 package ch.cyberduck.core.sftp;
     1package ch.cyberduck.core;
    22
    33/*
     
    1616 */
    1717
    18 import ch.cyberduck.core.Host;
    19 import ch.cyberduck.core.LoginCallback;
    2018import ch.cyberduck.core.exception.BackgroundException;
    2119import ch.cyberduck.core.threading.CancelCallback;
    2220
    23 public interface SFTPAuthentication {
     21public interface AuthenticationProvider {
    2422
    2523    /**
    2624     * @return True if authentication is complete
    2725     */
    28     boolean authenticate(Host bookmark, LoginCallback prompt, CancelCallback cancel)
    29             throws BackgroundException;
     26    boolean authenticate(Host bookmark, HostPasswordStore keychain, LoginCallback prompt, CancelCallback cancel)
     27        throws BackgroundException;
    3028}
  • shelves/Tomas_Celaya/core/src/main/java/ch/cyberduck/core/HostParser.java

    r41376 r43179  
    110110                    begin += username.length() + 1;
    111111                    cut = input.indexOf('@', begin);
     112                    try {
     113                        username = URLDecoder.decode(username, "UTF-8");
     114                    }
     115                    catch(UnsupportedEncodingException e) {
     116                        log.error(e.getMessage(), e);
     117                    }
    112118                    password = input.substring(begin, cut);
    113119                    begin += password.length() + 1;
     
    117123                    username = input.substring(begin, cut);
    118124                    begin += username.length() + 1;
     125                    try {
     126                        username = URLDecoder.decode(username, "UTF-8");
     127                    }
     128                    catch(UnsupportedEncodingException e) {
     129                        log.error(e.getMessage(), e);
     130                    }
    119131                }
    120132            }
  • shelves/Tomas_Celaya/core/src/main/java/ch/cyberduck/core/Profile.java

    r43167 r43179  
    4444
    4545    private final Deserializer<String> dict;
    46 
    4746    /**
    4847     * The actual protocol implementation registered
    4948     */
    5049    private final Protocol parent;
    51 
    5250    private final Local image;
    5351
     
    336334    public boolean isPasswordConfigurable() {
    337335        if(StringUtils.isBlank(this.value("Password Configurable"))) {
    338             return parent.isPasswordConfigurable();
     336            return StringUtils.isBlank(this.getOAuthClientId());
    339337        }
    340338        return this.bool("Password Configurable");
     
    352350    public boolean isHostnameConfigurable() {
    353351        if(StringUtils.isBlank(this.value("Hostname Configurable"))) {
    354             return parent.isHostnameConfigurable();
     352            return StringUtils.isBlank(this.getDefaultHostname());
    355353        }
    356354        return this.bool("Hostname Configurable");
     
    360358    public boolean isPortConfigurable() {
    361359        if(StringUtils.isBlank(this.value("Port Configurable"))) {
    362             return parent.isPortConfigurable();
     360            return StringUtils.isBlank(this.getDefaultHostname());
    363361        }
    364362        return this.bool("Port Configurable");
  • shelves/Tomas_Celaya/core/src/main/java/ch/cyberduck/core/Protocol.java

    r43162 r43179  
    5252            }
    5353        },
    54         sftp {
    55             @Override
    56             public boolean validate(final Credentials credentials, final LoginOptions options) {
    57                 if(options.user) {
    58                     return StringUtils.isNotBlank(credentials.getUsername());
    59                 }
    60                 return true;
    61             }
    62         },
     54        sftp,
    6355        s3,
    6456        googlestorage {
     
    7365            @Override
    7466            public boolean validate(final Credentials credentials, final LoginOptions options) {
    75                 // OAuth only requires the project token
     67                // OAuth only
    7668                return true;
    7769            }
     
    9486            @Override
    9587            public boolean validate(final Credentials credentials, final LoginOptions options) {
    96                 // OAuth only requires the project token
     88                // OAuth only
    9789                return true;
    9890            }
     
    129121                }
    130122            }
     123            if(options.publickey) {
     124                // No password may be required to decrypt private key
     125                if(credentials.isPublicKeyAuthentication()) {
     126                    return true;
     127                }
     128            }
    131129            if(options.password) {
    132130                if(StringUtils.isEmpty(credentials.getPassword())) {
  • shelves/Tomas_Celaya/dracoon/src/main/java/ch/cyberduck/core/sds/SDSAttributesFinderFeature.java

    r43171 r43179  
    3737
    3838    private final SDSSession session;
    39 
    40     public static final Acl.Role MANAGE_ROLE = new Acl.Role("MANAGE_ROLE");
    41 
    42     public static final Acl.Role READ_ROLE = new Acl.Role(Acl.Role.READ);
    43     public static final Acl.Role CREATE_ROLE = new Acl.Role("CREATE");
    44     public static final Acl.Role CHANGE_ROLE = new Acl.Role("CHANGE");
    45     public static final Acl.Role DELETE_ROLE = new Acl.Role("DELETE");
    46 
    47     public static final Acl.Role DOWNLOAD_SHARE_ROLE = new Acl.Role("DOWNLOAD_SHARE");
    48     public static final Acl.Role UPLOAD_SHARE_ROLE = new Acl.Role("UPLOAD_SHARE");
    4939
    5040    public SDSAttributesFinderFeature(final SDSSession session) {
     
    9383        final Acl.User user = new Acl.CanonicalUser(String.valueOf(session.userAccount().getId()));
    9484        if(node.getPermissions().getManage()) {
    95             acl.addAll(user, MANAGE_ROLE);
     85            acl.addAll(user, SDSPermissionsFeature.MANAGE_ROLE);
    9686        }
    9787        if(node.getPermissions().getRead()) {
    98             acl.addAll(user, READ_ROLE);
     88            acl.addAll(user, SDSPermissionsFeature.READ_ROLE);
    9989        }
    10090        if(node.getPermissions().getCreate()) {
    101             acl.addAll(user, CREATE_ROLE);
     91            acl.addAll(user, SDSPermissionsFeature.CREATE_ROLE);
    10292        }
    10393        if(node.getPermissions().getChange()) {
    104             acl.addAll(user, CHANGE_ROLE);
     94            acl.addAll(user, SDSPermissionsFeature.CHANGE_ROLE);
    10595        }
    10696        if(node.getPermissions().getDelete()) {
    107             acl.addAll(user, DELETE_ROLE);
     97            acl.addAll(user, SDSPermissionsFeature.DELETE_ROLE);
    10898        }
    10999        if(node.getPermissions().getManageDownloadShare()) {
    110             acl.addAll(user, DOWNLOAD_SHARE_ROLE);
     100            acl.addAll(user, SDSPermissionsFeature.DOWNLOAD_SHARE_ROLE);
    111101        }
    112102        if(node.getPermissions().getManageUploadShare()) {
    113             acl.addAll(user, UPLOAD_SHARE_ROLE);
     103            acl.addAll(user, SDSPermissionsFeature.UPLOAD_SHARE_ROLE);
    114104        }
    115105        return acl;
  • shelves/Tomas_Celaya/dracoon/src/main/java/ch/cyberduck/core/sds/SDSDeleteFeature.java

    r43171 r43179  
    6666                if(parent.equals(node)) {
    6767                    // top-level data room
    68                     return this.getRoles(node).contains(SDSAttributesFinderFeature.MANAGE_ROLE);
     68                    return this.getRoles(node).contains(SDSPermissionsFeature.MANAGE_ROLE);
    6969                }
    7070                // sub data room
    71                 return this.getRoles(parent).contains(SDSAttributesFinderFeature.MANAGE_ROLE);
     71                return this.getRoles(parent).contains(SDSPermissionsFeature.MANAGE_ROLE);
    7272            }
    73             return this.getRoles(node).contains(SDSAttributesFinderFeature.DELETE_ROLE);
     73            return this.getRoles(node).contains(SDSPermissionsFeature.DELETE_ROLE);
    7474        }
    7575        catch(BackgroundException e) {
     
    7979    }
    8080
    81     private Set<Acl.Role> getRoles(final Path node) throws BackgroundException {
    82         final Set<Acl.Role> roles = containerService.getContainer(node).attributes().getAcl().get(new Acl.CanonicalUser(String.valueOf(session.userAccount().getId())));
     81    private Set<Acl.Role> getRoles(final Path file) throws BackgroundException {
     82        final Acl acl = new SDSPermissionsFeature(session).getPermission(containerService.getContainer(file));
     83        final Set<Acl.Role> roles = acl.get(new Acl.CanonicalUser(String.valueOf(session.userAccount().getId())));
    8384        return roles != null ? roles : Collections.emptySet();
    8485    }
  • shelves/Tomas_Celaya/dracoon/src/main/java/ch/cyberduck/core/sds/SDSListService.java

    r43167 r43179  
    5959                nodes = new NodesApi(session.getClient()).getFsNodes(StringUtils.EMPTY, null, 0,
    6060                    Long.parseLong(new SDSNodeIdProvider(session).getFileid(directory, new DisabledListProgressListener())),
    61                     null, null, null, offset, chunksize);
     61                    null, null, "name:asc", offset, chunksize);
    6262                for(Node node : nodes.getItems()) {
    6363                    final PathAttributes attributes = feature.toAttributes(node);
  • shelves/Tomas_Celaya/dracoon/src/main/java/ch/cyberduck/core/sds/SDSSession.java

    r43171 r43179  
    285285            return (T) new SDSQuotaFeature(this);
    286286        }
     287        if(type == Search.class) {
     288            return (T) new SDSSearchFeature(this);
     289        }
    287290        return super._getFeature(type);
    288291    }
  • shelves/Tomas_Celaya/dracoon/src/main/java/ch/cyberduck/core/sds/SDSSharesUrlProvider.java

    r43167 r43179  
    7070                                        final PasswordCallback callback) throws BackgroundException {
    7171        try {
    72             final Set<Acl.Role> roles = containerService.getContainer(file).attributes().getAcl().get(new Acl.CanonicalUser(String.valueOf(session.userAccount().getId())));
    73             if(roles != null && !roles.contains(SDSAttributesFinderFeature.DOWNLOAD_SHARE_ROLE)) {
     72            final Set<Acl.Role> roles = new SDSPermissionsFeature(session).getPermission(containerService.getContainer(file)).get(new Acl.CanonicalUser(String.valueOf(session.userAccount().getId())));
     73            if(roles != null && !roles.contains(SDSPermissionsFeature.DOWNLOAD_SHARE_ROLE)) {
    7474                return DescriptiveUrl.EMPTY;
    7575            }
     
    124124    public DescriptiveUrl toUploadUrl(final Path file, final CreateUploadShareRequest options, final PasswordCallback callback) throws BackgroundException {
    125125        try {
    126             final Set<Acl.Role> roles = containerService.getContainer(file).attributes().getAcl().get(new Acl.CanonicalUser(String.valueOf(session.userAccount().getId())));
    127             if(roles != null && !roles.contains(SDSAttributesFinderFeature.UPLOAD_SHARE_ROLE)) {
     126            final Set<Acl.Role> roles = new SDSPermissionsFeature(session).getPermission(containerService.getContainer(file)).get(new Acl.CanonicalUser(String.valueOf(session.userAccount().getId())));
     127            if(roles != null && !roles.contains(SDSPermissionsFeature.UPLOAD_SHARE_ROLE)) {
    128128                return DescriptiveUrl.EMPTY;
    129129            }
  • shelves/Tomas_Celaya/dracoon/src/main/java/ch/cyberduck/core/sds/triplecrypt/TripleCryptKeyPair.java

    r43171 r43179  
    4545        final String passphrase = keychain.getPassword(String.format("Triple-Crypt Encryption Password (%s)", bookmark.getCredentials().getUsername()),
    4646                new DefaultUrlProvider(bookmark).toUrl(new Path(String.valueOf(Path.DELIMITER), EnumSet.of(Path.Type.volume, Path.Type.directory))).find(DescriptiveUrl.Type.provider).getUrl());
    47         return this.unlock(callback, bookmark, keypair, passphrase, LocaleFactory.localizedString("Enter the passphrase for the private key file", "Credentials"));
     47        return this.unlock(callback, bookmark, keypair, passphrase, LocaleFactory.localizedString("Enter your decryption password to access encrypted data rooms.", "SDS"));
    4848    }
    4949
     
    5151        final Credentials credentials;
    5252        if(null == passphrase) {
    53             credentials = callback.prompt(bookmark, LocaleFactory.localizedString("Private key password protected", "Credentials"), message,
     53            credentials = callback.prompt(bookmark, LocaleFactory.localizedString("Decryption password required", "SDS"), message,
    5454                    new LoginOptions(bookmark.getProtocol())
    55                             .user(false).passwordPlaceholder(LocaleFactory.localizedString("Private Key Passphrase", "Credentials"))
     55                        .user(false).passwordPlaceholder(LocaleFactory.localizedString("Private Key Passphrase", "SDS"))
    5656                            .anonymous(false)
    5757                            .icon(bookmark.getProtocol().disk())
     
    6666        }
    6767        if(!Crypto.checkUserKeyPair(keypair, credentials.getPassword())) {
    68             return this.unlock(callback, bookmark, keypair, null, String.format("%s. %s", LocaleFactory.localizedString("Invalid passphrase", "Credentials"), LocaleFactory.localizedString("Enter the passphrase for the private key file", "Credentials")));
     68            return this.unlock(callback, bookmark, keypair, null, String.format("%s. %s", LocaleFactory.localizedString("Invalid passphrase", "Credentials"), LocaleFactory.localizedString("Enter your decryption password to access encrypted data rooms.", "SDS")));
    6969        }
    7070        else {
  • shelves/Tomas_Celaya/dracoon/src/test/java/ch/cyberduck/core/sds/SDSDelegatingCopyFeatureTest.java

    r43171 r43179  
    5050
    5151    @Test
    52     public void testCopyFile() throws Exception {
     52    public void testCopyFileServerSide() throws Exception {
    5353        final Host host = new Host(new SDSProtocol(), "duck.ssp-europe.eu", new Credentials(
    5454            System.getProperties().getProperty("sds.user"), System.getProperties().getProperty("sds.key")
     
    6161        final Path test = new SDSTouchFeature(session).touch(new Path(room, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)), new TransferStatus());
    6262        final Path copy = new Path(new SDSDirectoryFeature(session).mkdir(new Path(room, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)), null, new TransferStatus()), test.getName(), EnumSet.of(Path.Type.file));
     63        new SDSTouchFeature(session).touch(copy, new TransferStatus());
    6364        final SDSCopyFeature feature = new SDSCopyFeature(session);
    6465        assertTrue(feature.isSupported(test, copy));
     
    226227        session.login(new DisabledPasswordStore(), new DisabledLoginCallback(), new DisabledCancelCallback());
    227228        final Path room1 = new Path("CD-TEST-ENCRYPTED", EnumSet.of(Path.Type.directory, Path.Type.volume, Path.Type.vault));
    228         room1.attributes().getAcl().addAll(new Acl.EmailUser(System.getProperties().getProperty("sds.user")), SDSAttributesFinderFeature.DELETE_ROLE);
     229        room1.attributes().getAcl().addAll(new Acl.EmailUser(System.getProperties().getProperty("sds.user")), SDSPermissionsFeature.DELETE_ROLE);
    229230        final Path room2 = new SDSDirectoryFeature(session).mkdir(new Path(
    230231            new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory, Path.Type.volume)), null, new TransferStatus());
     
    284285        session.login(new DisabledPasswordStore(), new DisabledLoginCallback(), new DisabledCancelCallback());
    285286        final Path room1 = new Path("CD-TEST-ENCRYPTED", EnumSet.of(Path.Type.directory, Path.Type.volume, Path.Type.vault));
    286         room1.attributes().getAcl().addAll(new Acl.EmailUser(System.getProperties().getProperty("sds.user")), SDSAttributesFinderFeature.DELETE_ROLE);
     287        room1.attributes().getAcl().addAll(new Acl.EmailUser(System.getProperties().getProperty("sds.user")), SDSPermissionsFeature.DELETE_ROLE);
    287288        final Path room2 = new SDSDirectoryFeature(session).mkdir(new Path(
    288289            new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory, Path.Type.volume)), null, new TransferStatus());
     
    330331        session.login(new DisabledPasswordStore(), new DisabledLoginCallback(), new DisabledCancelCallback());
    331332        final Path room1 = new Path("CD-TEST-ENCRYPTED", EnumSet.of(Path.Type.directory, Path.Type.volume, Path.Type.vault));
    332         room1.attributes().getAcl().addAll(new Acl.EmailUser(System.getProperties().getProperty("sds.user")), SDSAttributesFinderFeature.DELETE_ROLE);
     333        room1.attributes().getAcl().addAll(new Acl.EmailUser(System.getProperties().getProperty("sds.user")), SDSPermissionsFeature.DELETE_ROLE);
    333334        final Path room2 = new Path("CD-TEST-ENCRYPTED-TOO", EnumSet.of(Path.Type.directory, Path.Type.volume, Path.Type.vault));
    334335        final byte[] content = RandomUtils.nextBytes(32769);
     
    387388        session.login(new DisabledPasswordStore(), new DisabledLoginCallback(), new DisabledCancelCallback());
    388389        final Path room1 = new Path("CD-TEST-ENCRYPTED", EnumSet.of(Path.Type.directory, Path.Type.volume, Path.Type.vault));
    389         room1.attributes().getAcl().addAll(new Acl.EmailUser(System.getProperties().getProperty("sds.user")), SDSAttributesFinderFeature.DELETE_ROLE);
     390        room1.attributes().getAcl().addAll(new Acl.EmailUser(System.getProperties().getProperty("sds.user")), SDSPermissionsFeature.DELETE_ROLE);
    390391        final Path room2 = new Path("CD-TEST-ENCRYPTED-TOO", EnumSet.of(Path.Type.directory, Path.Type.volume, Path.Type.vault));
    391392        final byte[] content = RandomUtils.nextBytes(32769);
  • shelves/Tomas_Celaya/dracoon/src/test/java/ch/cyberduck/core/sds/SDSDelegatingMoveFeatureTest.java

    r43171 r43179  
    109109        session.login(new DisabledPasswordStore(), new DisabledLoginCallback(), new DisabledCancelCallback());
    110110        final Path room1 = new Path("CD-TEST-ENCRYPTED", EnumSet.of(Path.Type.directory, Path.Type.volume, Path.Type.vault));
    111         room1.attributes().getAcl().addAll(new Acl.EmailUser(System.getProperties().getProperty("sds.user")), SDSAttributesFinderFeature.DELETE_ROLE);
     111        room1.attributes().getAcl().addAll(new Acl.EmailUser(System.getProperties().getProperty("sds.user")), SDSPermissionsFeature.DELETE_ROLE);
    112112        final Path room2 = new SDSDirectoryFeature(session).mkdir(new Path(
    113113            new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory, Path.Type.volume)), null, new TransferStatus());
     
    166166        session.login(new DisabledPasswordStore(), new DisabledLoginCallback(), new DisabledCancelCallback());
    167167        final Path room1 = new Path("CD-TEST-ENCRYPTED", EnumSet.of(Path.Type.directory, Path.Type.volume, Path.Type.vault));
    168         room1.attributes().getAcl().addAll(new Acl.EmailUser(System.getProperties().getProperty("sds.user")), SDSAttributesFinderFeature.DELETE_ROLE);
     168        room1.attributes().getAcl().addAll(new Acl.EmailUser(System.getProperties().getProperty("sds.user")), SDSPermissionsFeature.DELETE_ROLE);
    169169        final Path room2 = new SDSDirectoryFeature(session).mkdir(new Path(
    170170            new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory, Path.Type.volume)), null, new TransferStatus());
     
    211211        session.login(new DisabledPasswordStore(), new DisabledLoginCallback(), new DisabledCancelCallback());
    212212        final Path room1 = new Path("CD-TEST-ENCRYPTED", EnumSet.of(Path.Type.directory, Path.Type.volume, Path.Type.vault));
    213         room1.attributes().getAcl().addAll(new Acl.EmailUser(System.getProperties().getProperty("sds.user")), SDSAttributesFinderFeature.DELETE_ROLE);
     213        room1.attributes().getAcl().addAll(new Acl.EmailUser(System.getProperties().getProperty("sds.user")), SDSPermissionsFeature.DELETE_ROLE);
    214214        final Path room2 = new Path("CD-TEST-ENCRYPTED-TOO", EnumSet.of(Path.Type.directory, Path.Type.volume, Path.Type.vault));
    215215        final byte[] content = RandomUtils.nextBytes(32769);
  • shelves/Tomas_Celaya/oauth/src/main/java/ch/cyberduck/core/oauth/OAuth2AuthorizationService.java

    r43139 r43179  
    4343import java.util.List;
    4444import java.util.Map;
    45 import java.util.concurrent.atomic.AtomicReference;
    4645
    4746import com.google.api.client.auth.oauth2.AuthorizationCodeFlow;
     
    6766
    6867    private final Preferences preferences
    69             = PreferencesFactory.get();
     68        = PreferencesFactory.get();
    7069
    7170    private final JsonFactory json
    72             = new GsonFactory();
     71        = new GsonFactory();
    7372
    7473    private final String tokenServerUrl;
     
    7978
    8079    public final BrowserLauncher browser
    81             = BrowserLauncherFactory.get();
     80        = BrowserLauncherFactory.get();
    8281
    8382    private final List<String> scopes;
    8483
    8584    private final Map<String, String> additionalParameters
    86             = new HashMap<>();
     85        = new HashMap<>();
    8786
    8887    private Credential.AccessMethod method
    89             = BearerToken.authorizationHeaderAccessMethod();
     88        = BearerToken.authorizationHeaderAccessMethod();
    9089
    9190    private String redirectUri = OOB_REDIRECT_URI;
     
    9796                                      final String clientid, final String clientsecret, final List<String> scopes) {
    9897        this(new ApacheHttpTransport(client),
    99                 tokenServerUrl, authorizationServerUrl, clientid, clientsecret, scopes);
     98            tokenServerUrl, authorizationServerUrl, clientid, clientsecret, scopes);
    10099    }
    101100
     
    131130        // Start OAuth2 flow within browser
    132131        final AuthorizationCodeFlow flow = new AuthorizationCodeFlow.Builder(
    133                 method,
    134                 transport, json,
    135                 new GenericUrl(tokenServerUrl),
    136                 new ClientParametersAuthentication(clientid, clientsecret),
    137                 clientid,
    138                 authorizationServerUrl)
    139                 .setScopes(scopes)
    140                 .build();
     132            method,
     133            transport, json,
     134            new GenericUrl(tokenServerUrl),
     135            new ClientParametersAuthentication(clientid, clientsecret),
     136            clientid,
     137            authorizationServerUrl)
     138            .setScopes(scopes)
     139            .build();
    141140        final AuthorizationCodeRequestUrl authorizationCodeRequestUrl = flow.newAuthorizationUrl();
    142141        authorizationCodeRequestUrl.setRedirectUri(redirectUri);
     
    151150            log.warn(String.format("Failed to launch web browser for %s", url));
    152151        }
    153         final AtomicReference<String> authenticationCode = new AtomicReference<>();
    154         boolean savePassword = false;
    155152        if(StringUtils.equals(CYBERDUCK_REDIRECT_URI, redirectUri)) {
    156153            final OAuth2TokenListenerRegistry registry = OAuth2TokenListenerRegistry.get();
     
    158155                @Override
    159156                public void callback(final String param) {
    160                     authenticationCode.set(param);
     157                    log.warn(String.format("Callback with code %s from redirect uri not currently handled.", param));
    161158                }
    162159            }, cancel);
    163160        }
    164         else {
    165             final Credentials credentials = prompt.prompt(bookmark, bookmark.getCredentials().getUsername(),
    166                     LocaleFactory.localizedString("OAuth2 Authentication", "Credentials"),
    167                     LocaleFactory.localizedString("Paste the authentication code from your web browser", "Credentials"),
    168                     new LoginOptions(bookmark.getProtocol()).keychain(true).user(false).password(true)
    169                             .passwordPlaceholder(LocaleFactory.localizedString("Authentication Code", "Credentials"))
    170             );
    171             authenticationCode.set(credentials.getPassword());
    172             savePassword = credentials.isSaved();
    173         }
     161        final Credentials credentials = prompt.prompt(bookmark, bookmark.getCredentials().getUsername(),
     162            LocaleFactory.localizedString("OAuth2 Authentication", "Credentials"),
     163            LocaleFactory.localizedString("Paste the authentication code from your web browser", "Credentials"),
     164            new LoginOptions(bookmark.getProtocol()).keychain(true).user(false).password(true)
     165                .passwordPlaceholder(LocaleFactory.localizedString("Authentication Code", "Credentials"))
     166        );
    174167        try {
    175             if(StringUtils.isBlank(authenticationCode.get())) {
     168            if(StringUtils.isBlank(credentials.getPassword())) {
    176169                throw new LoginCanceledException();
    177170            }
    178171            // Swap the given authorization token for access/refresh tokens
    179             final TokenResponse response = flow.newTokenRequest(authenticationCode.get())
    180                     .setRedirectUri(redirectUri).setScopes(scopes.isEmpty() ? null : scopes).execute();
     172            final TokenResponse response = flow.newTokenRequest(credentials.getPassword())
     173                .setRedirectUri(redirectUri).setScopes(scopes.isEmpty() ? null : scopes).execute();
    181174            // Save access key and refresh key
    182175            final Tokens tokens = new Tokens(
    183                     response.getAccessToken(), response.getRefreshToken(),
    184                     null == response.getExpiresInSeconds() ? System.currentTimeMillis() :
    185                             System.currentTimeMillis() + response.getExpiresInSeconds() * 1000);
    186             if(savePassword) {
     176                response.getAccessToken(), response.getRefreshToken(),
     177                null == response.getExpiresInSeconds() ? System.currentTimeMillis() :
     178                    System.currentTimeMillis() + response.getExpiresInSeconds() * 1000);
     179            if(credentials.isSaved()) {
    187180                this.save(keychain, bookmark, tokens);
    188181            }
     
    194187        catch(HttpResponseException e) {
    195188            throw new HttpResponseExceptionMappingService().map(new org.apache.http.client
    196                     .HttpResponseException(e.getStatusCode(), e.getStatusMessage()));
     189                .HttpResponseException(e.getStatusCode(), e.getStatusMessage()));
    197190        }
    198191        catch(IOException e) {
     
    211204        try {
    212205            final TokenResponse response = new RefreshTokenRequest(transport, json, new GenericUrl(tokenServerUrl),
    213                     tokens.getRefreshToken())
    214                     .setClientAuthentication(new ClientParametersAuthentication(clientid, clientsecret)).execute();
     206                tokens.getRefreshToken())
     207                .setClientAuthentication(new ClientParametersAuthentication(clientid, clientsecret)).execute();
    215208            final long expiryInMilliseconds = System.currentTimeMillis() + response.getExpiresInSeconds() * 1000;
    216209            if(StringUtils.isBlank(response.getRefreshToken())) {
     
    224217        catch(HttpResponseException e) {
    225218            throw new HttpResponseExceptionMappingService().map(new org.apache.http.client
    226                     .HttpResponseException(e.getStatusCode(), e.getStatusMessage()));
     219                .HttpResponseException(e.getStatusCode(), e.getStatusMessage()));
    227220        }
    228221        catch(IOException e) {
     
    235228        final String prefix = this.getPrefix(bookmark);
    236229        return new Tokens(keychain.getPassword(bookmark.getProtocol().getScheme(),
     230            bookmark.getPort(), URI.create(tokenServerUrl).getHost(),
     231            String.format("%s OAuth2 Access Token", prefix)),
     232            keychain.getPassword(bookmark.getProtocol().getScheme(),
    237233                bookmark.getPort(), URI.create(tokenServerUrl).getHost(),
    238                 String.format("%s OAuth2 Access Token", prefix)),
    239                 keychain.getPassword(bookmark.getProtocol().getScheme(),
    240                         bookmark.getPort(), URI.create(tokenServerUrl).getHost(),
    241                         String.format("%s OAuth2 Refresh Token", prefix)),
    242                 expiry);
     234                String.format("%s OAuth2 Refresh Token", prefix)),
     235            expiry);
    243236    }
    244237
     
    247240        if(StringUtils.isNotBlank(tokens.getAccessToken())) {
    248241            keychain.addPassword(bookmark.getProtocol().getScheme(),
    249                     bookmark.getPort(), URI.create(tokenServerUrl).getHost(),
    250                     String.format("%s OAuth2 Access Token", prefix), tokens.getAccessToken());
     242                bookmark.getPort(), URI.create(tokenServerUrl).getHost(),
     243                String.format("%s OAuth2 Access Token", prefix), tokens.getAccessToken());
    251244        }
    252245        if(StringUtils.isNotBlank(tokens.refreshToken)) {
    253246            keychain.addPassword(bookmark.getProtocol().getScheme(),
    254                     bookmark.getPort(), URI.create(tokenServerUrl).getHost(),
    255                     String.format("%s OAuth2 Refresh Token", prefix), tokens.getRefreshToken());
     247                bookmark.getPort(), URI.create(tokenServerUrl).getHost(),
     248                String.format("%s OAuth2 Refresh Token", prefix), tokens.getRefreshToken());
    256249        }
    257250        // Save expiry
  • shelves/Tomas_Celaya/osx/src/main/java/ch/cyberduck/ui/cocoa/controller/ConnectionController.java

    r43139 r43179  
    110110            @Override
    111111            public void change(final Host bookmark) {
    112                 passwordField.cell().setPlaceholderString(bookmark.getProtocol().getPasswordPlaceholder());
     112                passwordField.cell().setPlaceholderString(options.getPasswordPlaceholder());
    113113                passwordField.setEnabled(options.password && !credentials.isAnonymousLogin());
    114114                if(preferences.getBoolean("connection.login.keychain")) {
     
    143143            public void change(final Host bookmark) {
    144144                passwordLabel.setAttributedStringValue(NSAttributedString.attributedStringWithAttributes(
    145                         StringUtils.isNotBlank(bookmark.getProtocol().getPasswordPlaceholder()) ? String.format("%s:",
    146                                 bookmark.getProtocol().getPasswordPlaceholder()) : StringUtils.EMPTY, LABEL_ATTRIBUTES
     145                        StringUtils.isNotBlank(options.getPasswordPlaceholder()) ? String.format("%s:",
     146                                options.getPasswordPlaceholder()) : StringUtils.EMPTY, LABEL_ATTRIBUTES
    147147                ));
    148148            }
  • shelves/Tomas_Celaya/pom.xml

    r43167 r43179  
    112112                <groupId>org.bouncycastle</groupId>
    113113                <artifactId>bcprov-jdk15on</artifactId>
    114                 <version>1.58</version>
     114                <version>1.52</version>
    115115            </dependency>
    116116            <dependency>
    117117                <groupId>org.bouncycastle</groupId>
    118118                <artifactId>bcpkix-jdk15on</artifactId>
    119                 <version>1.58</version>
     119                <version>1.52</version>
    120120            </dependency>
    121121            <dependency>
    122122                <groupId>commons-codec</groupId>
    123123                <artifactId>commons-codec</artifactId>
    124                 <version>1.10</version>
     124                <version>1.11</version>
    125125            </dependency>
    126126            <dependency>
     
    279279                        <encoding>UTF-8</encoding>
    280280                        <compilerArgument>-Xlint:unchecked</compilerArgument>
    281                         <compilerArguments>
    282                             <profile>compact3</profile>
    283                         </compilerArguments>
    284281                        <source>${maven.compiler.source}</source>
    285282                        <target>${maven.compiler.target}</target>
  • shelves/Tomas_Celaya/profiles/default/Dropbox.cyberduckprofile

    r42043 r43179  
    3434        <key>OAuth Redirect Url</key>
    3535        <string>https://cyberduck.io/oauth</string>
     36        <key>Password Configurable</key>
     37        <false/>
    3638    </dict>
    3739</plist>
  • shelves/Tomas_Celaya/profiles/default/Google Cloud Storage.cyberduckprofile

    r42039 r43179  
    3838        <key>OAuth Redirect Url</key>
    3939        <string>urn:ietf:wg:oauth:2.0:oob</string>
     40        <key>Password Configurable</key>
     41        <false/>
    4042    </dict>
    4143</plist>
  • shelves/Tomas_Celaya/profiles/default/Google Drive.cyberduckprofile

    r42039 r43179  
    3838        <key>OAuth Redirect Url</key>
    3939        <string>urn:ietf:wg:oauth:2.0:oob</string>
     40        <key>Password Configurable</key>
     41        <false/>
    4042    </dict>
    4143</plist>
  • shelves/Tomas_Celaya/protocols/pom.xml

    r43169 r43179  
    3636            <type>pom</type>
    3737            <scope>test</scope>
     38            <version>${project.version}</version>
     39        </dependency>
     40        <dependency>
     41            <groupId>ch.cyberduck</groupId>
     42            <artifactId>profiles</artifactId>
    3843            <version>${project.version}</version>
    3944        </dependency>
  • shelves/Tomas_Celaya/s3/src/main/java/ch/cyberduck/core/s3/S3ObjectListService.java

    r43139 r43179  
    8585                for(StorageObject object : objects) {
    8686                    final String key = PathNormalizer.normalize(object.getKey());
     87                    if(String.valueOf(Path.DELIMITER).equals(key)) {
     88                        log.warn(String.format("Skipping prefix %s", key));
     89                        continue;
     90                    }
    8791                    if(new Path(bucket, key, EnumSet.of(Path.Type.directory)).equals(directory)) {
    8892                        continue;
     
    104108                final String[] prefixes = chunk.getCommonPrefixes();
    105109                for(String common : prefixes) {
    106                     if(common.equals(String.valueOf(Path.DELIMITER))) {
     110                    if(String.valueOf(Path.DELIMITER).equals(common)) {
    107111                        log.warn(String.format("Skipping prefix %s", common));
    108112                        continue;
  • shelves/Tomas_Celaya/s3/src/main/java/ch/cyberduck/core/s3/S3VersionedObjectListService.java

    r43139 r43179  
    4242
    4343    private final Preferences preferences
    44             = PreferencesFactory.get();
     44        = PreferencesFactory.get();
    4545
    4646    private final PathContainerService containerService
    47             = new S3PathContainerService();
     47        = new S3PathContainerService();
    4848
    4949    private final S3Session session;
     
    6363            do {
    6464                final VersionOrDeleteMarkersChunk chunk = session.getClient().listVersionedObjectsChunked(
    65                         bucket.getName(), prefix, String.valueOf(Path.DELIMITER),
    66                         preferences.getInteger("s3.listing.chunksize"),
    67                         priorLastKey, priorLastVersionId, true);
     65                    bucket.getName(), prefix, String.valueOf(Path.DELIMITER),
     66                    preferences.getInteger("s3.listing.chunksize"),
     67                    priorLastKey, priorLastVersionId, true);
    6868                // Amazon S3 returns object versions in the order in which they were
    6969                // stored, with the most recently stored returned first.
     
    7272                for(BaseVersionOrDeleteMarker marker : items) {
    7373                    final String key = PathNormalizer.normalize(marker.getKey());
     74                    if(String.valueOf(Path.DELIMITER).equals(key)) {
     75                        log.warn(String.format("Skipping prefix %s", key));
     76                        continue;
     77                    }
    7478                    if(new Path(bucket, key, EnumSet.of(Path.Type.directory)).equals(directory)) {
    7579                        continue;
     
    9397                final String[] prefixes = chunk.getCommonPrefixes();
    9498                for(String common : prefixes) {
    95                     if(common.equals(String.valueOf(Path.DELIMITER))) {
     99                    if(String.valueOf(Path.DELIMITER).equals(common)) {
    96100                        log.warn(String.format("Skipping prefix %s", common));
    97101                        continue;
  • shelves/Tomas_Celaya/setup/app/Info.plist

    r41180 r43179  
    284284                <dict>
    285285                    <key>default</key>
    286                     <string>Cyberduck/Upload</string>
     286                    <string>Cyberduck/Upload with Cyberduck</string>
    287287                </dict>
    288288                <key>NSMessage</key>
  • shelves/Tomas_Celaya/ssh/src/main/java/ch/cyberduck/core/sftp/SFTPAgentAuthentication.java

    r43171 r43179  
    1616 */
    1717
     18import ch.cyberduck.core.AuthenticationProvider;
    1819import ch.cyberduck.core.DefaultIOExceptionMappingService;
    1920import ch.cyberduck.core.Host;
     21import ch.cyberduck.core.HostPasswordStore;
    2022import ch.cyberduck.core.LoginCallback;
    2123import ch.cyberduck.core.exception.BackgroundException;
     
    3032import net.schmizz.sshj.userauth.UserAuthException;
    3133
    32 public class SFTPAgentAuthentication implements SFTPAuthentication {
     34public class SFTPAgentAuthentication implements AuthenticationProvider {
    3335    private static final Logger log = Logger.getLogger(SFTPAgentAuthentication.class);
    3436
    3537    private final SFTPSession session;
    36 
    3738    private final AgentAuthenticator agent;
    3839
     
    4344
    4445    @Override
    45     public boolean authenticate(final Host bookmark, final LoginCallback prompt, final CancelCallback cancel)
    46             throws BackgroundException {
     46    public boolean authenticate(final Host bookmark, final HostPasswordStore keychain, final LoginCallback prompt, final CancelCallback cancel)
     47        throws BackgroundException {
    4748        if(log.isDebugEnabled()) {
    48             log.debug(String.format("Login using agent %s with credentials %s", agent, bookmark.getCredentials()));
     49            log.debug(String.format("Login using agent %s for %s", agent, bookmark));
    4950        }
    5051        for(Identity identity : agent.getIdentities()) {
     
    5657            catch(UserAuthException e) {
    5758                cancel.verify();
    58                 // continue;
     59                // Continue;
    5960            }
    6061            catch(Buffer.BufferException e) {
  • shelves/Tomas_Celaya/ssh/src/main/java/ch/cyberduck/core/sftp/SFTPChallengeResponseAuthentication.java

    r43171 r43179  
    1616 */
    1717
     18import ch.cyberduck.core.AuthenticationProvider;
    1819import ch.cyberduck.core.Credentials;
    1920import ch.cyberduck.core.Host;
     21import ch.cyberduck.core.HostPasswordStore;
    2022import ch.cyberduck.core.LocaleFactory;
    2123import ch.cyberduck.core.LoginCallback;
     
    3234import java.util.Collections;
    3335import java.util.List;
    34 import java.util.concurrent.atomic.AtomicBoolean;
    3536
    3637import net.schmizz.sshj.userauth.method.AuthKeyboardInteractive;
     
    3839import net.schmizz.sshj.userauth.password.Resource;
    3940
    40 public class SFTPChallengeResponseAuthentication implements SFTPAuthentication {
     41public class SFTPChallengeResponseAuthentication implements AuthenticationProvider {
    4142    private static final Logger log = Logger.getLogger(SFTPChallengeResponseAuthentication.class);
    4243
     
    5051
    5152    @Override
    52     public boolean authenticate(final Host bookmark, final LoginCallback prompt, CancelCallback cancel) throws BackgroundException {
    53         if(StringUtils.isBlank(bookmark.getCredentials().getPassword())) {
    54             final Credentials additional = prompt.prompt(bookmark, bookmark.getCredentials().getUsername(),
    55                 LocaleFactory.localizedString("Partial authentication success", "Credentials"),
    56                 LocaleFactory.localizedString("Provide additional login credentials", "Credentials"),
    57                 new LoginOptions(bookmark.getProtocol()).user(false).keychain(false).publickey(false)
    58                     .usernamePlaceholder(bookmark.getCredentials().getUsername()));
    59             return this.authenticate(bookmark, additional, prompt);
    60         }
    61         else {
    62             return this.authenticate(bookmark, bookmark.getCredentials(), prompt);
    63         }
    64     }
    65 
    66     private boolean authenticate(final Host host, final Credentials credentials, final LoginCallback controller) throws BackgroundException {
     53    public boolean authenticate(final Host bookmark, final HostPasswordStore keychain, final LoginCallback callback, final CancelCallback cancel) throws BackgroundException {
    6754        if(log.isDebugEnabled()) {
    68             log.debug(String.format("Login using challenge response authentication with credentials %s", credentials));
     55            log.debug(String.format("Login using challenge response authentication for %s", bookmark));
    6956        }
    7057        try {
    71             session.getClient().auth(credentials.getUsername(), new AuthKeyboardInteractive(new ChallengeResponseProvider() {
    72                 /**
    73                  * Password sent flag
    74                  */
    75                 private final AtomicBoolean password = new AtomicBoolean();
    76 
     58            session.getClient().auth(bookmark.getCredentials().getUsername(), new AuthKeyboardInteractive(new ChallengeResponseProvider() {
    7759                private String name = StringUtils.EMPTY;
    78 
    7960                private String instruction = StringUtils.EMPTY;
    8061
     
    9677                @Override
    9778                public char[] getResponse(final String prompt, final boolean echo) {
     79                    // For each prompt, the corresponding echo field indicates whether the user input should be echoed as characters are typed
    9880                    if(log.isDebugEnabled()) {
    9981                        log.debug(String.format("Reply to challenge name %s with instruction %s", name, instruction));
    10082                    }
    101                     final String response;
    102                     // For each prompt, the corresponding echo field indicates whether the user input should
    103                     // be echoed as characters are typed
    104                     if(!password.get()
    105                         // Some servers ask for one-time passcode first
    106                         && !StringUtils.contains(prompt, "Verification code")) {
    107                         // In its first callback the server prompts for the password
    108                         if(log.isDebugEnabled()) {
    109                             log.debug("First callback returning provided credentials");
    110                         }
    111                         response = credentials.getPassword();
    112                         password.set(true);
     83                    final StringAppender message = new StringAppender().append(instruction).append(prompt);
     84                    // Properly handle an instruction field with embedded newlines.  They should also
     85                    // be able to display at least 30 characters for the name and prompts.
     86                    final Credentials additional;
     87                    try {
     88                        final StringAppender title = new StringAppender().append(name).append(
     89                            LocaleFactory.localizedString("Provide additional login credentials", "Credentials")
     90                        );
     91                        additional = callback.prompt(bookmark, bookmark.getCredentials().getUsername(), title.toString(),
     92                            message.toString(), new LoginOptions(bookmark.getProtocol()).user(false).publickey(false).keychain(false)
     93                                .usernamePlaceholder(bookmark.getCredentials().getUsername())
     94                        );
    11395                    }
    114                     else {
    115                         final StringAppender message = new StringAppender().append(instruction).append(prompt);
    116                         // Properly handle an instruction field with embedded newlines.  They should also
    117                         // be able to display at least 30 characters for the name and prompts.
    118                         final Credentials additional;
    119                         try {
    120                             final StringAppender title = new StringAppender().append(name).append(
    121                                 LocaleFactory.localizedString("Provide additional login credentials", "Credentials")
    122                             );
    123                             additional = controller.prompt(host, credentials.getUsername(), title.toString(),
    124                                 message.toString(), new LoginOptions(host.getProtocol()).user(false).publickey(false).keychain(false)
    125                                     .usernamePlaceholder(credentials.getUsername())
    126                             );
    127                         }
    128                         catch(LoginCanceledException e) {
    129                             return EMPTY_RESPONSE;
    130                         }
    131                         response = additional.getPassword();
     96                    catch(LoginCanceledException e) {
     97                        return EMPTY_RESPONSE;
    13298                    }
    13399                    // Responses are encoded in ISO-10646 UTF-8.
    134                     return response.toCharArray();
     100                    return additional.getPassword().toCharArray();
    135101                }
    136102
  • shelves/Tomas_Celaya/ssh/src/main/java/ch/cyberduck/core/sftp/SFTPNoneAuthentication.java

    r43171 r43179  
    1616 */
    1717
     18import ch.cyberduck.core.AuthenticationProvider;
    1819import ch.cyberduck.core.Host;
     20import ch.cyberduck.core.HostPasswordStore;
    1921import ch.cyberduck.core.LoginCallback;
    2022import ch.cyberduck.core.exception.BackgroundException;
     
    2729import net.schmizz.sshj.userauth.method.AuthNone;
    2830
    29 public class SFTPNoneAuthentication implements SFTPAuthentication {
     31public class SFTPNoneAuthentication implements AuthenticationProvider {
    3032    private static final Logger log = Logger.getLogger(SFTPNoneAuthentication.class);
    3133
     
    3739
    3840    @Override
    39     public boolean authenticate(final Host bookmark, final LoginCallback prompt, final CancelCallback cancel)
     41    public boolean authenticate(final Host bookmark, final HostPasswordStore keychain, final LoginCallback prompt, final CancelCallback cancel)
    4042            throws BackgroundException {
    4143        if(log.isDebugEnabled()) {
  • shelves/Tomas_Celaya/ssh/src/main/java/ch/cyberduck/core/sftp/SFTPPasswordAuthentication.java

    r43171 r43179  
    1616 */
    1717
     18import ch.cyberduck.core.AuthenticationProvider;
    1819import ch.cyberduck.core.BookmarkNameProvider;
    1920import ch.cyberduck.core.Credentials;
    2021import ch.cyberduck.core.Host;
     22import ch.cyberduck.core.HostPasswordStore;
    2123import ch.cyberduck.core.LocaleFactory;
    2224import ch.cyberduck.core.LoginCallback;
     
    3840import net.schmizz.sshj.userauth.password.Resource;
    3941
    40 public class SFTPPasswordAuthentication implements SFTPAuthentication {
     42public class SFTPPasswordAuthentication implements AuthenticationProvider {
    4143    private static final Logger log = Logger.getLogger(SFTPPasswordAuthentication.class);
    4244
     
    4850
    4951    @Override
    50     public boolean authenticate(final Host bookmark, final LoginCallback prompt, final CancelCallback cancel)
     52    public boolean authenticate(final Host bookmark, final HostPasswordStore keychain, final LoginCallback callback, final CancelCallback cancel)
    5153        throws BackgroundException {
    5254        if(StringUtils.isBlank(bookmark.getCredentials().getPassword())) {
    53             final Credentials additional = prompt.prompt(bookmark, bookmark.getCredentials().getUsername(),
    54                 LocaleFactory.localizedString("Partial authentication success", "Credentials"),
    55                 MessageFormat.format(LocaleFactory.localizedString(
    56                     "Login {0} with username and password", "Credentials"), BookmarkNameProvider.toString(bookmark)),
     55            final String message;
     56            if(session.getClient().getUserAuth().hadPartialSuccess()) {
     57                message = LocaleFactory.localizedString("Partial authentication success", "Credentials");
     58            }
     59            else {
     60                message = MessageFormat.format(LocaleFactory.localizedString(
     61                    "Login {0} with username and password", "Credentials"), BookmarkNameProvider.toString(bookmark));
     62            }
     63            final Credentials additional = callback.prompt(bookmark, bookmark.getCredentials().getUsername(),
     64                String.format("%s %s", LocaleFactory.localizedString("Login", "Login"), bookmark.getHostname()),
     65                message,
    5766                new LoginOptions(bookmark.getProtocol()).user(false).keychain(false).publickey(false)
    5867                    .usernamePlaceholder(bookmark.getCredentials().getUsername()));
    59             return this.authenticate(bookmark, additional, prompt);
     68            return this.authenticate(bookmark, additional, callback, cancel);
    6069        }
    6170        else {
    62             return this.authenticate(bookmark, bookmark.getCredentials(), prompt);
     71            return this.authenticate(bookmark, bookmark.getCredentials(), callback, cancel);
    6372        }
    6473    }
    6574
    66     public boolean authenticate(final Host host, final Credentials credentials, final LoginCallback callback) throws BackgroundException {
     75    public boolean authenticate(final Host host, final Credentials credentials, final LoginCallback callback, final CancelCallback cancel)
     76        throws BackgroundException {
    6777        if(log.isDebugEnabled()) {
    6878            log.debug(String.format("Login using password authentication with credentials %s", credentials));
  • shelves/Tomas_Celaya/ssh/src/main/java/ch/cyberduck/core/sftp/SFTPPublicKeyAuthentication.java

    r43171 r43179  
    1616 */
    1717
     18import ch.cyberduck.core.AuthenticationProvider;
    1819import ch.cyberduck.core.Credentials;
    1920import ch.cyberduck.core.Host;
     
    4647import net.schmizz.sshj.userauth.password.Resource;
    4748
    48 public class SFTPPublicKeyAuthentication implements SFTPAuthentication {
     49public class SFTPPublicKeyAuthentication implements AuthenticationProvider {
    4950    private static final Logger log = Logger.getLogger(SFTPPublicKeyAuthentication.class);
    5051
    5152    private final SFTPSession session;
    5253
    53     private final HostPasswordStore keychain;
    54 
    55     public SFTPPublicKeyAuthentication(final SFTPSession session, final HostPasswordStore keychain) {
     54    public SFTPPublicKeyAuthentication(final SFTPSession session) {
    5655        this.session = session;
    57         this.keychain = keychain;
    5856    }
    5957
    6058    @Override
    61     public boolean authenticate(final Host bookmark, final LoginCallback prompt, final CancelCallback cancel)
    62             throws BackgroundException {
     59    public boolean authenticate(final Host bookmark, final HostPasswordStore keychain, final LoginCallback prompt, final CancelCallback cancel)
     60        throws BackgroundException {
    6361        final Credentials credentials = bookmark.getCredentials();
    6462        if(log.isDebugEnabled()) {
     
    7068            try {
    7169                final KeyFormat format = KeyProviderUtil.detectKeyFileFormat(
    72                         new InputStreamReader(identity.getInputStream(), Charset.forName("UTF-8")), true);
     70                    new InputStreamReader(identity.getInputStream(), Charset.forName("UTF-8")), true);
    7371                if(log.isInfoEnabled()) {
    7472                    log.info(String.format("Reading private key %s with key format %s", identity, format));
     
    10098                            try {
    10199                                return prompt.prompt(bookmark, credentials.getUsername(),
    102                                         LocaleFactory.localizedString("Private key password protected", "Credentials"),
    103                                         String.format("%s (%s)",
    104                                                 LocaleFactory.localizedString("Enter the passphrase for the private key file", "Credentials"),
    105                                                 identity.getAbbreviatedPath()), new LoginOptions(bookmark.getProtocol())
    106                                                 .user(false).password(true)
    107                                                 .passwordPlaceholder(LocaleFactory.localizedString("Private Key Passphrase", "Credentials"))
     100                                    LocaleFactory.localizedString("Private key password protected", "Credentials"),
     101                                    String.format("%s (%s)",
     102                                        LocaleFactory.localizedString("Enter the passphrase for the private key file", "Credentials"),
     103                                        identity.getAbbreviatedPath()), new LoginOptions(bookmark.getProtocol())
     104                                        .user(false).password(true)
     105                                        .passwordPlaceholder(LocaleFactory.localizedString("Private Key Passphrase", "Credentials"))
    108106                                ).getPassword().toCharArray();
    109107                            }
  • shelves/Tomas_Celaya/ssh/src/main/java/ch/cyberduck/core/sftp/SFTPSession.java

    r43171 r43179  
    221221    @Override
    222222    public void login(final HostPasswordStore keychain, final LoginCallback prompt, final CancelCallback cancel) throws BackgroundException {
    223         final List<SFTPAuthentication> methods = new ArrayList<SFTPAuthentication>();
     223        final List<AuthenticationProvider> methods = new ArrayList<AuthenticationProvider>();
    224224        final Credentials credentials = host.getCredentials();
    225225        if(credentials.isAnonymousLogin()) {
     
    231231                methods.add(new SFTPAgentAuthentication(this, new PageantAuthenticator()));
    232232            }
    233             if(credentials.isPublicKeyAuthentication()) {
    234                 methods.add(new SFTPPublicKeyAuthentication(this, keychain));
    235             }
     233            methods.add(new SFTPPublicKeyAuthentication(this));
     234            methods.add(new SFTPPasswordAuthentication(this));
    236235            methods.add(new SFTPChallengeResponseAuthentication(this));
    237             methods.add(new SFTPPasswordAuthentication(this));
    238236        }
    239237        if(log.isDebugEnabled()) {
     
    241239        }
    242240        BackgroundException lastFailure = null;
    243         for(SFTPAuthentication auth : methods) {
     241        for(AuthenticationProvider auth : methods) {
    244242            if(log.isDebugEnabled()) {
    245243                log.debug(String.format("Attempt authentication with credentials %s and authentication method %s", credentials, auth));
     
    247245            cancel.verify();
    248246            try {
    249                 if(!auth.authenticate(host, prompt, cancel)) {
    250                     if(log.isDebugEnabled()) {
    251                         log.debug(String.format("Login refused with credentials %s and authentication method %s", credentials, auth));
     247                if(!auth.authenticate(host, keychain, prompt, cancel)) {
     248                    if(client.getUserAuth().hadPartialSuccess()) {
     249                        if(log.isDebugEnabled()) {
     250                            log.debug(String.format("Partial login success with credentials %s and authentication method %s", credentials, auth));
     251                        }
     252                    }
     253                    else {
     254                        if(log.isDebugEnabled()) {
     255                            log.debug(String.format("Login refused with credentials %s and authentication method %s", credentials, auth));
     256                        }
    252257                    }
    253258                    continue;
     
    281286                log.info(String.format("Login successful with authentication method %s", auth));
    282287            }
    283             if(client.getUserAuth().hadPartialSuccess()) {
    284                 continue;
    285             }
    286288            break;
    287289        }
  • shelves/Tomas_Celaya/ssh/src/test/java/ch/cyberduck/core/sftp/SFTPChallengeResponseAuthenticationTest.java

    r36762 r43179  
    2222import ch.cyberduck.core.DisabledHostKeyCallback;
    2323import ch.cyberduck.core.DisabledLoginCallback;
     24import ch.cyberduck.core.DisabledPasswordStore;
    2425import ch.cyberduck.core.Host;
    2526import ch.cyberduck.core.exception.LoginFailureException;
     
    4142        final SFTPSession session = new SFTPSession(host);
    4243        session.open(new DisabledHostKeyCallback());
    43         assertFalse(new SFTPChallengeResponseAuthentication(session).authenticate(host, new DisabledLoginCallback(), new DisabledCancelCallback()));
     44        assertFalse(new SFTPChallengeResponseAuthentication(session).authenticate(host, new DisabledPasswordStore(), new DisabledLoginCallback(), new DisabledCancelCallback()));
    4445        session.close();
    4546    }
  • shelves/Tomas_Celaya/ssh/src/test/java/ch/cyberduck/core/sftp/SFTPNoneAuthenticationTest.java

    r36762 r43179  
    2222import ch.cyberduck.core.DisabledHostKeyCallback;
    2323import ch.cyberduck.core.DisabledLoginCallback;
     24import ch.cyberduck.core.DisabledPasswordStore;
    2425import ch.cyberduck.core.Host;
    2526import ch.cyberduck.core.exception.LoginFailureException;
     
    4142        final SFTPSession session = new SFTPSession(host);
    4243        session.open(new DisabledHostKeyCallback());
    43         assertFalse(new SFTPNoneAuthentication(session).authenticate(host, new DisabledLoginCallback(), new DisabledCancelCallback()));
     44        assertFalse(new SFTPNoneAuthentication(session).authenticate(host, new DisabledPasswordStore(), new DisabledLoginCallback(), new DisabledCancelCallback()));
    4445        session.close();
    4546    }
  • shelves/Tomas_Celaya/ssh/src/test/java/ch/cyberduck/core/sftp/SFTPPasswordAuthenticationTest.java

    r36762 r43179  
    2222import ch.cyberduck.core.DisabledHostKeyCallback;
    2323import ch.cyberduck.core.DisabledLoginCallback;
     24import ch.cyberduck.core.DisabledPasswordStore;
    2425import ch.cyberduck.core.Host;
    2526import ch.cyberduck.core.exception.LoginFailureException;
     
    4243        final SFTPSession session = new SFTPSession(host);
    4344        session.open(new DisabledHostKeyCallback());
    44         assertTrue(new SFTPPasswordAuthentication(session).authenticate(host, new DisabledLoginCallback(), new DisabledCancelCallback()));
     45        assertTrue(new SFTPPasswordAuthentication(session).authenticate(host, new DisabledPasswordStore(), new DisabledLoginCallback(), new DisabledCancelCallback()));
    4546        session.close();
    4647    }
     
    5354        final SFTPSession session = new SFTPSession(host);
    5455        session.open(new DisabledHostKeyCallback());
    55         assertFalse(new SFTPPasswordAuthentication(session).authenticate(host, new DisabledLoginCallback(), new DisabledCancelCallback()));
     56        assertFalse(new SFTPPasswordAuthentication(session).authenticate(host, new DisabledPasswordStore(), new DisabledLoginCallback(), new DisabledCancelCallback()));
    5657        session.close();
    5758    }
  • shelves/Tomas_Celaya/ssh/src/test/java/ch/cyberduck/core/sftp/SFTPPublicKeyAuthenticationTest.java

    r43171 r43179  
    4242            final SFTPSession session = new SFTPSession(host);
    4343            session.open(new DisabledHostKeyCallback());
    44             assertTrue(new SFTPPublicKeyAuthentication(session, new DisabledPasswordStore()).authenticate(host, new DisabledLoginCallback() {
     44            assertTrue(new SFTPPublicKeyAuthentication(session).authenticate(host, new DisabledPasswordStore(), new DisabledLoginCallback() {
    4545                @Override
    4646                public Credentials prompt(final Host bookmark, String username, String title, String reason, LoginOptions options) throws LoginCanceledException {
     
    7070            session.open(new DisabledHostKeyCallback());
    7171            final AtomicBoolean p = new AtomicBoolean();
    72             assertFalse(new SFTPPublicKeyAuthentication(session, new DisabledPasswordStore()).authenticate(host, new DisabledLoginCallback() {
     72            assertFalse(new SFTPPublicKeyAuthentication(session).authenticate(host, new DisabledPasswordStore(), new DisabledLoginCallback() {
    7373                @Override
    7474                public Credentials prompt(final Host bookmark, String username, String title, String reason, LoginOptions options) throws LoginCanceledException {
     
    9999            session.open(new DisabledHostKeyCallback());
    100100            final AtomicBoolean b = new AtomicBoolean();
    101             assertTrue(new SFTPPublicKeyAuthentication(session, new DisabledPasswordStore()).authenticate(host, new DisabledLoginCallback() {
     101            assertTrue(new SFTPPublicKeyAuthentication(session).authenticate(host, new DisabledPasswordStore(), new DisabledLoginCallback() {
    102102                @Override
    103103                public Credentials prompt(final Host bookmark, String username, String title, String reason, LoginOptions options) throws LoginCanceledException {
     
    127127            final SFTPSession session = new SFTPSession(host);
    128128            session.open(new DisabledHostKeyCallback());
    129             assertTrue(new SFTPPublicKeyAuthentication(session, new DisabledPasswordStore()).authenticate(host, new DisabledLoginCallback() {
     129            assertTrue(new SFTPPublicKeyAuthentication(session).authenticate(host, new DisabledPasswordStore(), new DisabledLoginCallback() {
    130130                @Override
    131131                public Credentials prompt(final Host bookmark, String username, String title, String reason, LoginOptions options) throws LoginCanceledException {
  • shelves/Tomas_Celaya/triton/src/main/java/ch/cyberduck/core/manta/MantaProtocol.java

    r43166 r43179  
    5252
    5353    @Override
     54    public String disk() {
     55        return String.format("%s.tiff", "ftp");
     56    }
     57
     58    @Override
    5459    public boolean isAnonymousConfigurable() {
    5560        return false;
  • shelves/Tomas_Celaya/windows/src/main/csharp/ch/cyberduck/ui/controller/MainController.cs

    r43171 r43179  
    3232using ch.cyberduck.core.azure;
    3333using ch.cyberduck.core.b2;
     34using ch.cyberduck.core.manta;
    3435using ch.cyberduck.core.bonjour;
    3536using ch.cyberduck.core.dav;
     
    136137                new AzureProtocol(), new IRODSProtocol(), new SpectraProtocol(), new B2Protocol(), new DriveProtocol(),
    137138                new DropboxProtocol(), new HubicProtocol(), new LocalProtocol(), new OneDriveProtocol(),
     139                new MantaProtocol(),
    138140                new SDSProtocol());
    139141
     
    819821        private void OnStartup(object state)
    820822        {
    821             MainForm = NewBrowser(true, true).View as Form;
     823            _bc = NewBrowser(true, true);
     824            MainForm = _bc.View as Form;
    822825
    823826            /* UWP Registration, initialize as soon as possible */
  • shelves/Tomas_Celaya/www/update/changelog.html

    r43167 r43179  
    5555            list-style-type: disc;
    5656        }
    57 
    58 
    5957    </style>
    6058</head>
     
    7270    supports transparent <strong>client-side encryption</strong> using Cryptomator interoperable vaults.
    7371</p>
     72
     73<p>
     74    <a href="https://trac.cyberduck.io/milestone/6.2.11"><strong>Version 6.2.11</strong></a>
     75</p>
     76<ul>
     77    <li><span class="label label-warning">Bugfix</span> Application crash restoring workspace (Windows)</li>
     78</ul>
     79
     80<p>
     81    <a href="https://trac.cyberduck.io/milestone/6.2.10"><strong>Version 6.2.10</strong></a>
     82</p>
     83<ul>
     84    <li><span class="label label-success">Feature</span> Option to disable auto-detect of vaults (Cryptomator)</li>
     85    <li><span class="label label-warning">Bugfix</span> Login where authentication is required with both password and
     86        public key method (SFTP)
     87    </li>
     88</ul>
    7489
    7590<p>
Note: See TracChangeset for help on using the changeset viewer.