Skip to content

Commit

Permalink
Fix #8541. Add option -y to dismiss all prompts by default.
Browse files Browse the repository at this point in the history
Former-commit-id: eefe77ce270ffe0919f2e18f1526e38544d8667d
  • Loading branch information
dkocher committed Feb 3, 2015
1 parent 0775e38 commit 9cca6d1
Show file tree
Hide file tree
Showing 13 changed files with 191 additions and 48 deletions.
28 changes: 28 additions & 0 deletions source/ch/cyberduck/cli/DisabledTerminalPromptReader.java
@@ -0,0 +1,28 @@
package ch.cyberduck.cli;

/*
* Copyright (c) 2002-2015 David Kocher. All rights reserved.
* http://cyberduck.ch/
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* Bug fixes, suggestions and comments should be sent to feedback@cyberduck.ch
*/

/**
* @version $Id$
*/
class DisabledTerminalPromptReader implements TerminalPromptReader {
@Override
public boolean prompt(final String message) {
return true;
}
}
49 changes: 49 additions & 0 deletions source/ch/cyberduck/cli/InteractiveTerminalPromptReader.java
@@ -0,0 +1,49 @@
package ch.cyberduck.cli;

/*
* Copyright (c) 2002-2015 David Kocher. All rights reserved.
* http://cyberduck.io/
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* Bug fixes, suggestions and comments should be sent to:
* feedback@cyberduck.io
*/

import ch.cyberduck.core.exception.ConnectionCanceledException;

/**
* @version $Id$
*/
public class InteractiveTerminalPromptReader implements TerminalPromptReader {

private final Console console = new Console();

@Override
public boolean prompt(final String message) {
final String input;
try {
input = console.readLine("%n%s (y/n): ", message);
}
catch(ConnectionCanceledException e) {
return false;
}
switch(input) {
case "y":
return true;
case "n":
return false;
default:
console.printf("Please type 'y' or 'n'.");
return this.prompt(message);
}
}
}
29 changes: 21 additions & 8 deletions source/ch/cyberduck/cli/Terminal.java
Expand Up @@ -31,6 +31,9 @@
import ch.cyberduck.core.local.ApplicationQuitCallback;
import ch.cyberduck.core.preferences.Preferences;
import ch.cyberduck.core.preferences.PreferencesFactory;
import ch.cyberduck.core.ssl.CertificateStoreX509TrustManager;
import ch.cyberduck.core.ssl.DefaultTrustManagerHostnameCallback;
import ch.cyberduck.core.ssl.PreferencesX509KeyManager;
import ch.cyberduck.core.threading.SessionBackgroundAction;
import ch.cyberduck.core.transfer.CopyTransfer;
import ch.cyberduck.core.transfer.DisabledTransferErrorCallback;
Expand Down Expand Up @@ -69,6 +72,8 @@ public class Terminal {

private final TerminalController controller;

private final TerminalPromptReader reader;

private PathCache cache;

private ProgressListener progress;
Expand Down Expand Up @@ -101,7 +106,9 @@ public Terminal(final Preferences defaults, final Options options, final Command
? new DisabledListProgressListener() : new TerminalProgressListener();
this.transcript = input.hasOption(TerminalOptionsBuilder.Params.verbose.name())
? new TerminalTranscriptListener() : new DisabledTranscriptListener();
this.controller = new TerminalController(progress, transcript);
this.reader = input.hasOption(TerminalOptionsBuilder.Params.assumeyes.name())
? new DisabledTerminalPromptReader() : new InteractiveTerminalPromptReader();
this.controller = new TerminalController(progress, transcript, reader);
}

/**
Expand Down Expand Up @@ -172,7 +179,12 @@ public void uncaughtException(final Thread t, final Throwable e) {
}
final String uri = input.getOptionValue(action.name());
final Host host = new UriParser(input).parse(uri);
session = SessionFactory.create(host);
session = SessionFactory.create(host,
new CertificateStoreX509TrustManager(
new DefaultTrustManagerHostnameCallback(host),
new TerminalCertificateStore(reader)
),
new PreferencesX509KeyManager(new TerminalCertificateStore(reader)));
this.connect(session);
final Path remote = new TildePathExpander(session).expand(new PathParser(input).parse(uri));
switch(action) {
Expand Down Expand Up @@ -220,7 +232,7 @@ remote, new PathParser(input).parse(target)

protected void connect(final Session session) throws BackgroundException {
final LoginConnectionService connect = new LoginConnectionService(new TerminalLoginService(input,
new TerminalLoginCallback()), new TerminalHostKeyVerifier(), progress, transcript);
new TerminalLoginCallback(reader)), new TerminalHostKeyVerifier(reader), progress, transcript);
connect.check(session, cache);
}

Expand Down Expand Up @@ -277,8 +289,8 @@ public TransferAction prompt(final TransferItem file) {
else {
prompt = new TerminalTransferPrompt(transfer.getType());
}
final TerminalTransferBackgroundAction action = new TerminalTransferBackgroundAction(controller,
new TerminalLoginService(input, new TerminalLoginCallback()), session, cache,
final TerminalTransferBackgroundAction action = new TerminalTransferBackgroundAction(controller, reader,
new TerminalLoginService(input, new TerminalLoginCallback(reader)), session, cache,
transfer, new TransferOptions().reload(true), prompt, meter,
input.hasOption(TerminalOptionsBuilder.Params.quiet.name())
? new DisabledStreamListener() : new TerminalStreamListener(meter));
Expand All @@ -291,9 +303,9 @@ transfer, new TransferOptions().reload(true), prompt, meter,

protected Exit list(final Session session, final Path remote, final boolean verbose) {
final SessionListWorker worker = new SessionListWorker(session, cache, remote,
new TerminalListProgressListener(verbose));
new TerminalListProgressListener(reader, verbose));
final TerminalBackgroundAction action = new TerminalBackgroundAction<AttributedList<Path>>(
new TerminalLoginService(input, new TerminalLoginCallback()), controller,
new TerminalLoginService(input, new TerminalLoginCallback(reader)), controller,
session, cache, worker);
this.execute(action);
if(action.hasFailed()) {
Expand Down Expand Up @@ -323,7 +335,7 @@ protected Exit edit(final Session session, final Path remote) throws BackgroundE
final Editor editor = factory.create(controller, session, application, remote);
final CountDownLatch lock = new CountDownLatch(1);
final TerminalBackgroundAction<Transfer> action = new TerminalBackgroundAction<Transfer>(
new TerminalLoginService(input, new TerminalLoginCallback()),
new TerminalLoginService(input, new TerminalLoginCallback(reader)),
controller, session, cache, editor.open(new ApplicationQuitCallback() {
@Override
public void callback() {
Expand Down Expand Up @@ -366,4 +378,5 @@ protected <T> boolean execute(SessionBackgroundAction<T> action) {
return false;
}
}

}
12 changes: 11 additions & 1 deletion source/ch/cyberduck/cli/TerminalAlertCallback.java
Expand Up @@ -31,12 +31,22 @@ public class TerminalAlertCallback implements AlertCallback {

private final Console console = new Console();

private TerminalPromptReader prompt;

public TerminalAlertCallback() {
this.prompt = new InteractiveTerminalPromptReader();
}

public TerminalAlertCallback(final TerminalPromptReader prompt) {
this.prompt = prompt;
}

@Override
public boolean alert(final Host host, final BackgroundException failure, final StringBuilder transcript) {
final StringAppender appender = new StringAppender();
appender.append(failure.getMessage());
appender.append(failure.getDetail());
console.printf("%n%s", appender.toString());
return new TerminalPromptReader().prompt(LocaleFactory.localizedString("Try Again", "Alert"));
return prompt.prompt(LocaleFactory.localizedString("Try Again", "Alert"));
}
}
16 changes: 13 additions & 3 deletions source/ch/cyberduck/cli/TerminalCertificateStore.java
Expand Up @@ -42,6 +42,16 @@ public class TerminalCertificateStore extends DefaultCertificateStore {
private final X509HostnameVerifier verifier
= new BrowserCompatHostnameVerifier();

private TerminalPromptReader prompt;

public TerminalCertificateStore() {
this.prompt = new InteractiveTerminalPromptReader();
}

public TerminalCertificateStore(final TerminalPromptReader prompt) {
this.prompt = prompt;
}

@Override
public boolean display(final List<X509Certificate> certificates) {
for(X509Certificate c : certificates) {
Expand All @@ -61,20 +71,20 @@ public boolean isTrusted(final String hostname, final List<X509Certificate> cert
c.checkValidity();
}
catch(CertificateExpiredException e) {
return new TerminalPromptReader().prompt(LocaleFactory.localizedString(StringUtils.replace("The certificate for this server has expired. You might be connecting to a server that " +
return prompt.prompt(LocaleFactory.localizedString(StringUtils.replace("The certificate for this server has expired. You might be connecting to a server that " +
"is pretending to be “%@” which could put your confidential information at risk. " +
"Would you like to connect to the server anyway?", "%@", hostname), "Keychain"));
}
catch(CertificateNotYetValidException e) {
return new TerminalPromptReader().prompt(LocaleFactory.localizedString(StringUtils.replace("The certificate for this server is not yet valid. You might be connecting to a server that " +
return prompt.prompt(LocaleFactory.localizedString(StringUtils.replace("The certificate for this server is not yet valid. You might be connecting to a server that " +
"is pretending to be “%@” which could put your confidential information at risk. Would you like to connect to the server anyway?", "%@", hostname), "Keychain"));
}
}
try {
verifier.verify(hostname, certificates.get(0));
}
catch(SSLException e) {
return new TerminalPromptReader().prompt(LocaleFactory.localizedString(StringUtils.replace("The certificate for this server is invalid. " +
return prompt.prompt(LocaleFactory.localizedString(StringUtils.replace("The certificate for this server is invalid. " +
"You might be connecting to a server that is pretending to be “%@” which could put " +
"your confidential information at risk. Would you like to connect to the server anyway?", "%@", hostname), "Keychain"));
}
Expand Down
8 changes: 6 additions & 2 deletions source/ch/cyberduck/cli/TerminalController.java
Expand Up @@ -34,10 +34,14 @@ public class TerminalController extends AbstractController {

private ProgressListener progress;

private TerminalPromptReader prompt;

public TerminalController(final ProgressListener progress,
final TranscriptListener transcript) {
final TranscriptListener transcript,
final TerminalPromptReader prompt) {
this.transcript = transcript;
this.progress = progress;
this.prompt = prompt;
}

@Override
Expand All @@ -47,7 +51,7 @@ public void invoke(final MainAction runnable, final boolean wait) {

@Override
public boolean alert(final Host host, final BackgroundException failure, final StringBuilder transcript) {
return new TerminalAlertCallback().alert(host, failure, transcript);
return new TerminalAlertCallback(prompt).alert(host, failure, transcript);
}

@Override
Expand Down
14 changes: 12 additions & 2 deletions source/ch/cyberduck/cli/TerminalHostKeyVerifier.java
Expand Up @@ -38,10 +38,20 @@ public class TerminalHostKeyVerifier extends OpenSSHHostKeyVerifier {

private final Console console = new Console();

private TerminalPromptReader prompt;

public TerminalHostKeyVerifier() {
super(LocalFactory.get(PreferencesFactory.get().getProperty("ssh.knownhosts")).withBookmark(
PreferencesFactory.get().getProperty("ssh.knownhosts.bookmark")
));
this.prompt = new InteractiveTerminalPromptReader();
}

public TerminalHostKeyVerifier(final TerminalPromptReader prompt) {
super(LocalFactory.get(PreferencesFactory.get().getProperty("ssh.knownhosts")).withBookmark(
PreferencesFactory.get().getProperty("ssh.knownhosts.bookmark")
));
this.prompt = prompt;
}

@Override
Expand All @@ -51,7 +61,7 @@ protected boolean isUnknownKeyAccepted(final String hostname, final PublicKey ke
new MD5ChecksumCompute().fingerprint(key),
KeyType.fromKey(key).name()),
LocaleFactory.localizedString("Continue", "Credentials"));
if(!new TerminalPromptReader().prompt(message)) {
if(!prompt.prompt(message)) {
throw new ConnectionCanceledException();
}
this.allow(hostname, key, true);
Expand All @@ -65,7 +75,7 @@ protected boolean isChangedKeyAccepted(final String hostname, final PublicKey ke
new MD5ChecksumCompute().fingerprint(key),
KeyType.fromKey(key).name()),
LocaleFactory.localizedString("Continue", "Credentials"));
if(!new TerminalPromptReader().prompt(message)) {
if(!prompt.prompt(message)) {
throw new ConnectionCanceledException();
}
this.allow(hostname, key, true);
Expand Down
16 changes: 15 additions & 1 deletion source/ch/cyberduck/cli/TerminalListProgressListener.java
Expand Up @@ -45,8 +45,11 @@ public class TerminalListProgressListener extends LimitedListProgressListener {

private boolean l;

private TerminalPromptReader prompt;

public TerminalListProgressListener() {
super(new TerminalProgressListener());
this.prompt = new InteractiveTerminalPromptReader();
}

/**
Expand All @@ -57,6 +60,17 @@ public TerminalListProgressListener(final boolean l) {
this.l = l;
}

public TerminalListProgressListener(final TerminalPromptReader prompt) {
super(new TerminalProgressListener());
this.prompt = prompt;
}

public TerminalListProgressListener(final TerminalPromptReader prompt, final boolean l) {
super(new TerminalProgressListener());
this.l = l;
this.prompt = prompt;
}

@Override
public void chunk(final Path folder, final AttributedList<Path> list) throws ListCanceledException {
for(int i = size; i < list.size(); i++) {
Expand Down Expand Up @@ -96,7 +110,7 @@ public void chunk(final Path folder, final AttributedList<Path> list) throws Lis
final String message = String.format("%s %s?: ",
MessageFormat.format(LocaleFactory.localizedString("Continue listing directory with more than {0} files.", "Alert"), e.getChunk().size()),
LocaleFactory.localizedString("Continue", "Credentials"));
if(!new TerminalPromptReader().prompt(message)) {
if(!prompt.prompt(message)) {
throw e;
}
}
Expand Down
12 changes: 11 additions & 1 deletion source/ch/cyberduck/cli/TerminalLoginCallback.java
Expand Up @@ -43,11 +43,21 @@ public class TerminalLoginCallback implements LoginCallback {
private final HostPasswordStore keychain
= PasswordStoreFactory.get();

private TerminalPromptReader prompt;

public TerminalLoginCallback() {
this.prompt = new InteractiveTerminalPromptReader();
}

public TerminalLoginCallback(final TerminalPromptReader prompt) {
this.prompt = prompt;
}

@Override
public void warn(final Protocol protocol, final String title, final String reason,
final String defaultButton, final String cancelButton, final String preference) throws ConnectionCanceledException {
console.printf("%n%s", reason);
if(!new TerminalPromptReader().prompt(String.format("%s (y) or %s (n): ", defaultButton, cancelButton))) {
if(!prompt.prompt(String.format("%s (y) or %s (n): ", defaultButton, cancelButton))) {
throw new ConnectionCanceledException();
}
}
Expand Down
7 changes: 7 additions & 0 deletions source/ch/cyberduck/cli/TerminalOptionsBuilder.java
Expand Up @@ -157,6 +157,12 @@ public static Options options() {
.hasArg(false)
.isRequired(false)
.create('q'));
options.addOption(OptionBuilder
.withDescription("Assume yes for all prompts")
.withLongOpt(Params.assumeyes.name())
.hasArg(false)
.isRequired(false)
.create('y'));
options.addOption(OptionBuilder
.withDescription("Show version number and quit")
.withLongOpt(TerminalAction.version.name())
Expand All @@ -182,6 +188,7 @@ public enum Params {
existing,
verbose,
quiet,
assumeyes,
username,
password,
identity,
Expand Down

0 comments on commit 9cca6d1

Please sign in to comment.