Skip to content

Commit d0dcdbd

Browse files
committed
JCRVLT-819: Upgrade to JLine 3
Fixes CVE-2023-50572
1 parent 4e48737 commit d0dcdbd

5 files changed

Lines changed: 99 additions & 54 deletions

File tree

vault-cli/pom.xml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -239,9 +239,9 @@
239239
<scope>compile</scope>
240240
</dependency>
241241
<dependency>
242-
<groupId>jline</groupId>
242+
<groupId>org.jline</groupId>
243243
<artifactId>jline</artifactId>
244-
<version>1.0</version>
244+
<version>3.30.6</version>
245245
<scope>compile</scope>
246246
</dependency>
247247

vault-cli/src/main/java/org/apache/jackrabbit/vault/cli/VaultFsApp.java

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@
6363
import org.apache.jackrabbit.vault.vlt.VltContext;
6464
import org.apache.jackrabbit.vault.vlt.VltDirectory;
6565
import org.apache.jackrabbit.vault.vlt.meta.MetaDirectory;
66+
import org.jline.reader.LineReaderBuilder;
6667
import org.slf4j.Logger;
6768
import org.slf4j.LoggerFactory;
6869

@@ -792,16 +793,13 @@ private PasswordPromptingCredentialsStore(CredentialsStore base) {
792793
public Credentials getCredentials(RepositoryAddress mountpoint) {
793794
Credentials creds = base.getCredentials(mountpoint);
794795
if (creds instanceof SimpleCredentials) {
795-
try {
796-
SimpleCredentials simpleCredentials = (SimpleCredentials) creds;
797-
if (simpleCredentials.getPassword().length == 0) {
798-
System.out.printf(Locale.ENGLISH, "Please enter password for user %s connecting to %s: ",
799-
simpleCredentials.getUserID(), mountpoint);
800-
String password = new jline.ConsoleReader().readLine('*');
801-
creds = new SimpleCredentials(simpleCredentials.getUserID(), password.toCharArray());
802-
}
803-
} catch (IOException e) {
804-
log.error("Error while opening console for reading password" + e);
796+
SimpleCredentials simpleCredentials = (SimpleCredentials) creds;
797+
if (simpleCredentials.getPassword().length == 0) {
798+
System.out.printf(Locale.ENGLISH, "Please enter password for user %s connecting to %s: ",
799+
simpleCredentials.getUserID(), mountpoint);
800+
// ensure JLine is initialized
801+
String password = LineReaderBuilder.builder().build().readLine('*');
802+
creds = new SimpleCredentials(simpleCredentials.getUserID(), password.toCharArray());
805803
}
806804
}
807805
return creds;

vault-cli/src/main/java/org/apache/jackrabbit/vault/util/console/Console.java

Lines changed: 28 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -20,34 +20,35 @@
2020
import java.util.HashMap;
2121
import java.util.Iterator;
2222
import java.util.Map;
23-
import java.util.Set;
2423

2524
import org.apache.jackrabbit.vault.util.console.util.Table;
25+
import org.jline.reader.History;
26+
import org.jline.reader.LineReader;
27+
import org.jline.reader.LineReaderBuilder;
28+
import org.jline.reader.impl.history.DefaultHistory;
2629
import org.slf4j.Logger;
2730
import org.slf4j.LoggerFactory;
2831

29-
import jline.Completor;
30-
import jline.ConsoleReader;
31-
import jline.History;
32-
import jline.SimpleCompletor;
3332

3433
/**
3534
* {@code Console}...
3635
*/
3736
public class Console {
3837

38+
static final String VARIABLE_CONTEXT_NAME = "CONTEXT";
39+
3940
/**
4041
* the default logger
4142
*/
4243
static final Logger log = LoggerFactory.getLogger(Console.class);
4344

4445
private ConsoleExecutionContext currentCtx;
4546

46-
private final Map contexts = new HashMap();
47+
private final Map<String, ConsoleExecutionContext> contexts = new HashMap<>();
4748

4849
private final AbstractApplication app;
4950

50-
private ConsoleReader reader;
51+
private LineReader reader;
5152

5253
/**
5354
* indicates console is running
@@ -65,7 +66,7 @@ public void addContext(ConsoleExecutionContext ctx) {
6566
}
6667
contexts.put(ctx.getName(), ctx);
6768
ctx.attach(this);
68-
currentCtx = ctx;
69+
switchContext(ctx.getName());
6970
}
7071

7172
public void removeContext(ConsoleExecutionContext ctx) {
@@ -79,19 +80,9 @@ public void switchContext(ConsoleExecutionContext ctx) {
7980
switchContext(ctx.getName());
8081
}
8182

82-
private void setCompletor() {
83-
// always remove existing
84-
Iterator iter = reader.getCompletors().iterator();
85-
while (iter.hasNext()) {
86-
reader.removeCompletor((Completor) iter.next());
87-
iter = reader.getCompletors().iterator();
88-
}
89-
Set triggers = currentCtx.getCommandsGroup().getTriggers();
90-
reader.addCompletor(new SimpleCompletor((String[]) triggers.toArray(new String[triggers.size()])));
91-
}
92-
9383
public void switchContext(String name) {
94-
if (name == null) {
84+
if (name == null) {
85+
// lists all contexts
9586
Iterator iter = contexts.keySet().iterator();
9687
Table t = new Table(2);
9788
while (iter.hasNext()) {
@@ -111,8 +102,10 @@ public void switchContext(String name) {
111102
if (!contexts.containsKey(name)) {
112103
throw new ExecutionException("No such context: " + name);
113104
}
114-
currentCtx = (ConsoleExecutionContext) contexts.get(name);
115-
setCompletor();
105+
currentCtx = contexts.get(name);
106+
if (reader != null) {
107+
reader.setVariable(VARIABLE_CONTEXT_NAME, name);
108+
}
116109
log.info("Switched to context '{}'", name);
117110
}
118111
}
@@ -124,25 +117,19 @@ protected AbstractApplication getApplication() {
124117
return app;
125118
}
126119

127-
protected void initJLine() {
128-
History history = new History();
129-
/*
130-
try {
131-
history = new History(new File(".consolehistory"));
132-
} catch (IOException e) {
133-
log.warn("Cannot read or write file for storing command line history: " + e.getMessage() + "");
134-
history = new History();
135-
}
136-
*/
137-
reader.setHistory(history);
138-
reader.setUseHistory(true);
139-
setCompletor();
120+
protected LineReader createJLineReader() {
121+
History history = new DefaultHistory();
122+
return LineReaderBuilder.builder()
123+
.history(history)
124+
.completer(new ContextAwareCompleter(contexts))
125+
// set current context
126+
.variable(VARIABLE_CONTEXT_NAME, currentCtx.getName())
127+
.build();
140128
}
141129

142130
public void run() throws IOException {
143131

144-
reader = new ConsoleReader();
145-
initJLine();
132+
reader = createJLineReader();
146133
// setup and start
147134
setup();
148135

@@ -159,13 +146,13 @@ public void run() throws IOException {
159146
// re-execute event from history
160147
String oldLine;
161148
try {
162-
int historyIndex = Integer.valueOf(line.substring(1).trim()).intValue();
163-
oldLine = (String) reader.getHistory().getHistoryList().get(historyIndex - 1);
149+
int historyIndex = Integer.parseInt(line.substring(1).trim());
150+
oldLine = reader.getHistory().get(historyIndex - 1);
164151
} catch (Exception e) {
165152
System.out.println(" " + line + ": event not found");
166153
continue;
167154
}
168-
reader.getHistory().addToHistory(oldLine);
155+
reader.getHistory().add(oldLine);
169156
System.out.println("Executing '" + oldLine + "'");
170157
line = oldLine;
171158
}
@@ -182,7 +169,7 @@ public void run() throws IOException {
182169
close();
183170
}
184171

185-
public ConsoleReader getReader() {
172+
public LineReader getReader() {
186173
return reader;
187174
}
188175

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one or more
3+
* contributor license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright ownership.
5+
* The ASF licenses this file to You under the Apache License, Version 2.0
6+
* (the "License"); you may not use this file except in compliance with
7+
* the License. You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
package org.apache.jackrabbit.vault.util.console;
18+
19+
import java.util.List;
20+
import java.util.Map;
21+
22+
import org.jline.reader.Candidate;
23+
import org.jline.reader.Completer;
24+
import org.jline.reader.LineReader;
25+
import org.jline.reader.ParsedLine;
26+
import org.jline.reader.impl.completer.StringsCompleter;
27+
28+
public class ContextAwareCompleter implements Completer {
29+
30+
private final Map<String, Completer> contextCompleters;
31+
32+
public ContextAwareCompleter(Map<String, ConsoleExecutionContext> contexts) {
33+
if (contexts == null || contexts.isEmpty()) {
34+
throw new IllegalArgumentException("No contexts provided for ContextAwareCompleter");
35+
}
36+
contextCompleters = new java.util.HashMap<>();
37+
for (Map.Entry<String, ConsoleExecutionContext> entry : contexts.entrySet()) {
38+
Iterable<String> commands = entry.getValue().getCommandsGroup().getTriggers();
39+
contextCompleters.put(entry.getKey(), new StringsCompleter(commands));
40+
}
41+
}
42+
43+
@Override
44+
public void complete(LineReader reader, ParsedLine line, List<Candidate> candidates) {
45+
// Get current context from reader variables
46+
String context = (String) reader.getVariable(Console.VARIABLE_CONTEXT_NAME);
47+
if (context == null) {
48+
throw new IllegalStateException("No context set in reader variables");
49+
}
50+
// Use the appropriate completer for this context
51+
Completer contextCompleter = contextCompleters.get(context);
52+
// If no completer found for context, fallback to a default behavior
53+
if (contextCompleter == null) {
54+
throw new IllegalStateException("No completer found for context: " + context);
55+
}
56+
contextCompleter.complete(reader, line, candidates);
57+
}
58+
59+
}

vault-cli/src/main/java/org/apache/jackrabbit/vault/util/console/commands/CmdHistory.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import org.apache.commons.cli2.builder.CommandBuilder;
2323
import org.apache.commons.cli2.option.Command;
2424
import org.apache.jackrabbit.vault.util.console.ConsoleExecutionContext;
25+
import org.jline.reader.History;
2526

2627
/**
2728
*/
@@ -31,7 +32,7 @@ protected void doExecute(ConsoleExecutionContext ctx, CommandLine cl)
3132
throws Exception {
3233

3334
// print the history
34-
Iterator iter = ctx.getConsole().getReader().getHistory().getHistoryList().iterator();
35+
Iterator<History.Entry> iter = ctx.getConsole().getReader().getHistory().iterator();
3536
int i=1;
3637
while (iter.hasNext()) {
3738
System.out.println(" " + i + " " + iter.next());

0 commit comments

Comments
 (0)