Skip to content

Commit a996725

Browse files
Merge pull request #21 from didlich/pwd-prompt
implement showing password prompt if password not provided
2 parents 7bf9dc0 + 5dc2409 commit a996725

File tree

7 files changed

+170
-34
lines changed

7 files changed

+170
-34
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,5 @@ test-output/
1717
out/
1818
.idea_modules/
1919
*.iws
20+
21+
*.iml

src/main/java/org/cryptomator/cli/Args.java

Lines changed: 31 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -8,21 +8,23 @@
88
*******************************************************************************/
99
package org.cryptomator.cli;
1010

11-
import java.io.IOException;
12-
import java.nio.file.Files;
13-
import java.nio.file.Path;
1411
import java.nio.file.Paths;
12+
import java.util.HashMap;
13+
import java.util.Map;
1514
import java.util.Properties;
1615
import java.util.Set;
1716
import java.util.stream.Collectors;
18-
import java.util.stream.Stream;
1917

2018
import org.apache.commons.cli.CommandLine;
2119
import org.apache.commons.cli.DefaultParser;
2220
import org.apache.commons.cli.HelpFormatter;
2321
import org.apache.commons.cli.Option;
2422
import org.apache.commons.cli.Options;
2523
import org.apache.commons.cli.ParseException;
24+
import org.cryptomator.cli.pwd.PasswordFromFileStrategy;
25+
import org.cryptomator.cli.pwd.PasswordFromStdInputStrategy;
26+
import org.cryptomator.cli.pwd.PasswordStrategy;
27+
import org.cryptomator.cli.pwd.PasswordFromPropertyStrategy;
2628

2729
/**
2830
* Parses program arguments. Does not validate them.
@@ -76,17 +78,15 @@ public class Args {
7678
private final Properties vaultPaths;
7779
private final Properties vaultPasswords;
7880
private final Properties vaultPasswordFiles;
79-
80-
private boolean hasPasswordOrPasswordFile(Object vaultPath) {
81-
return vaultPasswords.containsKey(vaultPath) || vaultPasswordFiles.containsKey(vaultPath);
82-
}
81+
private final Map<String, PasswordStrategy> passwordStrategies;
8382

8483
public Args(CommandLine commandLine) throws ParseException {
8584
this.bindAddr = commandLine.getOptionValue("bind", "localhost");
8685
this.port = Integer.parseInt(commandLine.getOptionValue("port", "0"));
8786
this.vaultPaths = commandLine.getOptionProperties("vault");
8887
this.vaultPasswords = commandLine.getOptionProperties("password");
8988
this.vaultPasswordFiles = commandLine.getOptionProperties("passwordfile");
89+
this.passwordStrategies = new HashMap<>();
9090
}
9191

9292
public String getBindAddr() {
@@ -98,32 +98,13 @@ public int getPort() {
9898
}
9999

100100
public Set<String> getVaultNames() {
101-
return vaultPaths.keySet().stream().filter(this::hasPasswordOrPasswordFile).map(String.class::cast).collect(Collectors.toSet());
101+
return vaultPaths.keySet().stream().map(String.class::cast).collect(Collectors.toSet());
102102
}
103103

104104
public String getVaultPath(String vaultName) {
105105
return vaultPaths.getProperty(vaultName);
106106
}
107107

108-
public String getVaultPasswordPath(String vaultName) {
109-
return vaultPasswordFiles.getProperty(vaultName);
110-
}
111-
112-
public String getVaultPassword(String vaultName) {
113-
if (vaultPasswords.getProperty(vaultName) == null) {
114-
Path vaultPasswordPath = Paths.get(vaultPasswordFiles.getProperty(vaultName));
115-
if (Files.isReadable(vaultPasswordPath) && Files.isRegularFile(vaultPasswordPath)) {
116-
try (Stream<String> lines = Files.lines(vaultPasswordPath)) {
117-
return lines.findFirst().get().toString();
118-
} catch (IOException e) {
119-
return null;
120-
}
121-
}
122-
return null;
123-
}
124-
return vaultPasswords.getProperty(vaultName);
125-
}
126-
127108
public static Args parse(String[] arguments) throws ParseException {
128109
CommandLine commandLine = new DefaultParser().parse(OPTIONS, arguments);
129110
return new Args(commandLine);
@@ -133,4 +114,26 @@ public static void printUsage() {
133114
new HelpFormatter().printHelp(USAGE, OPTIONS);
134115
}
135116

117+
public PasswordStrategy addPasswortStrategy(final String vaultName) {
118+
PasswordStrategy passwordStrategy = new PasswordFromStdInputStrategy(vaultName);
119+
120+
if (vaultPasswords.getProperty(vaultName) != null) {
121+
passwordStrategy = new PasswordFromPropertyStrategy(
122+
vaultName,
123+
vaultPasswords.getProperty(vaultName)
124+
);
125+
} else if (vaultPasswordFiles.getProperty(vaultName) != null) {
126+
passwordStrategy = new PasswordFromFileStrategy(
127+
vaultName,
128+
Paths.get(vaultPasswordFiles.getProperty(vaultName))
129+
);
130+
}
131+
132+
this.passwordStrategies.put(vaultName, passwordStrategy);
133+
return passwordStrategy;
134+
}
135+
136+
public PasswordStrategy getPasswordStrategy(final String vaultName) {
137+
return passwordStrategies.get(vaultName);
138+
}
136139
}

src/main/java/org/cryptomator/cli/CryptomatorCli.java

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
import java.nio.file.Files;
1313
import java.nio.file.Path;
1414
import java.nio.file.Paths;
15+
import java.util.Set;
1516

1617
import org.apache.commons.cli.ParseException;
1718
import org.cryptomator.cryptofs.CryptoFileSystemProperties;
@@ -40,22 +41,21 @@ public static void main(String[] rawArgs) throws IOException {
4041
}
4142

4243
private static void validate(Args args) throws IllegalArgumentException {
44+
Set<String> vaultNames = args.getVaultNames();
4345
if (args.getPort() < 0 || args.getPort() > 65536) {
4446
throw new IllegalArgumentException("Invalid WebDAV Port.");
4547
}
4648

47-
if (args.getVaultNames().size() == 0) {
49+
if (vaultNames.size() == 0) {
4850
throw new IllegalArgumentException("No vault specified.");
4951
}
5052

51-
for (String vaultName : args.getVaultNames()) {
53+
for (String vaultName : vaultNames) {
5254
Path vaultPath = Paths.get(args.getVaultPath(vaultName));
53-
if ((args.getVaultPasswordPath(vaultName) != null) && args.getVaultPassword(vaultName) == null) {
54-
throw new IllegalArgumentException("Cannot read password from file: " + Paths.get(args.getVaultPasswordPath(vaultName)));
55-
}
5655
if (!Files.isDirectory(vaultPath)) {
5756
throw new IllegalArgumentException("Not a directory: " + vaultPath);
5857
}
58+
args.addPasswortStrategy(vaultName).validate();
5959
}
6060
}
6161

@@ -67,7 +67,7 @@ private static void startup(Args args) throws IOException {
6767
for (String vaultName : args.getVaultNames()) {
6868
Path vaultPath = Paths.get(args.getVaultPath(vaultName));
6969
LOG.info("Unlocking vault \"{}\" located at {}", vaultName, vaultPath);
70-
String vaultPassword = args.getVaultPassword(vaultName);
70+
String vaultPassword = args.getPasswordStrategy(vaultName).password();
7171
CryptoFileSystemProperties properties = CryptoFileSystemProperties.cryptoFileSystemProperties().withPassphrase(vaultPassword).build();
7272
Path vaultRoot = CryptoFileSystemProvider.newFileSystem(vaultPath, properties).getPath("/");
7373
WebDavServletController servlet = server.createWebDavServlet(vaultRoot, vaultName);
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
package org.cryptomator.cli.pwd;
2+
3+
import org.slf4j.Logger;
4+
import org.slf4j.LoggerFactory;
5+
6+
import java.io.IOException;
7+
import java.nio.file.Files;
8+
import java.nio.file.Path;
9+
import java.util.stream.Stream;
10+
11+
public class PasswordFromFileStrategy implements PasswordStrategy {
12+
private static final Logger LOG = LoggerFactory.getLogger(PasswordFromFileStrategy.class);
13+
14+
private final String vaultName;
15+
private final Path pathToFile;
16+
17+
public PasswordFromFileStrategy(final String vaultName, final Path pathToFile) {
18+
this.vaultName = vaultName;
19+
this.pathToFile = pathToFile;
20+
}
21+
22+
@Override
23+
public String password() {
24+
LOG.info("Vault " + "'" + vaultName + "'" + " password from file.");
25+
26+
if (Files.isReadable(pathToFile) && Files.isRegularFile(pathToFile)) {
27+
try (Stream<String> lines = Files.lines(pathToFile)) {
28+
return lines.findFirst().get().toString();
29+
} catch (IOException e) {
30+
return null;
31+
}
32+
}
33+
return null;
34+
}
35+
36+
@Override
37+
public void validate() throws IllegalArgumentException {
38+
if (!Files.isReadable(pathToFile)) {
39+
throw new IllegalArgumentException("Cannot read password from file: " + pathToFile);
40+
}
41+
}
42+
43+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package org.cryptomator.cli.pwd;
2+
3+
import org.slf4j.Logger;
4+
import org.slf4j.LoggerFactory;
5+
6+
public class PasswordFromPropertyStrategy implements PasswordStrategy {
7+
private static final Logger LOG = LoggerFactory.getLogger(PasswordFromPropertyStrategy.class);
8+
9+
private final String vaultName;
10+
private final String password;
11+
12+
public PasswordFromPropertyStrategy(final String vaultName, final String password) {
13+
this.vaultName = vaultName;
14+
this.password = password;
15+
}
16+
17+
@Override
18+
public String password() {
19+
LOG.info("Vault " + "'" + vaultName + "'" + " password from property.");
20+
return this.password;
21+
}
22+
23+
@Override
24+
public void validate() throws IllegalArgumentException {
25+
if (password.equals("")) {
26+
throw new IllegalArgumentException("Invalid password");
27+
}
28+
}
29+
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
package org.cryptomator.cli.pwd;
2+
3+
import org.slf4j.Logger;
4+
import org.slf4j.LoggerFactory;
5+
6+
import java.io.BufferedReader;
7+
import java.io.Console;
8+
import java.io.IOException;
9+
import java.io.InputStreamReader;
10+
11+
public class PasswordFromStdInputStrategy implements PasswordStrategy {
12+
private static final Logger LOG = LoggerFactory.getLogger(PasswordFromStdInputStrategy.class);
13+
14+
private final String vaultName;
15+
private final String inputMessage = "Enter password for vault '%s': ";
16+
17+
public PasswordFromStdInputStrategy(final String vaultName) {
18+
this.vaultName = vaultName;
19+
}
20+
21+
@Override
22+
public String password() {
23+
LOG.info("Vault " + "'" + vaultName + "'" + " password from standard input.");
24+
25+
String password = "";
26+
Console console = System.console();
27+
if (console == null) {
28+
LOG.warn("No console: non-interactive mode, instead use insecure replacement, PW is shown!");
29+
30+
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
31+
System.out.println(String.format(inputMessage, vaultName));
32+
33+
try {
34+
password = reader.readLine();
35+
} catch (IOException e) {
36+
LOG.error("There was an error reading line from console.");
37+
e.printStackTrace();
38+
}
39+
} else {
40+
System.out.println(String.format(inputMessage, vaultName));
41+
password = new String(console.readPassword());
42+
}
43+
44+
return password;
45+
}
46+
47+
@Override
48+
public void validate() throws IllegalArgumentException {
49+
if (vaultName.equals("")) {
50+
throw new IllegalArgumentException("Invalid vault name");
51+
}
52+
}
53+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
package org.cryptomator.cli.pwd;
2+
3+
public interface PasswordStrategy {
4+
String password();
5+
void validate() throws IllegalArgumentException;
6+
}

0 commit comments

Comments
 (0)