How to mask an input string in Spring-Shell

1.4k Views Asked by At

I am using Spring-Shell and I would like to mask the input when typing the password field for a particular method.

Looking on the internet and here in the forum, I found many people suggesting to use the console.readPassword() command but, creating the console from inside the IDE gives me a null result.

Scanner in= new Scanner(System.in)
-------------------------------OR------------------------------------
BufferedReader in = new BufferedReader(new InputStreamReader(System.in)

these are the code lines I tried to get the input from the user, but I can't find a way to mask the input, so when someone types the password it shows on the screen.

Looking around I found out that to make the console command work I could use an external terminal instead of the IDE but, when starting SpringBoot (a Spring-Shell project) I get the Jline Warning:

"Unable to create a system terminal, creating a dumb terminal (enable debug logging for more information)".

So is there an easy way to mask the password using the scanner/BufferedReader classes, or do I need to enable the system terminal to use the console?

Thank you

1

There are 1 best solutions below

0
On

You can use org.jline.reader.LineReader from JLine library which you get by default in a Spring Shell application.

Here's some example code:

import org.jline.reader.LineReader;

public class InputReader {

private static final Character DEFAULT_MASK = '*';

private Character mask;
private LineReader lineReader;

public InputReader(LineReader lineReader) {
    this(lineReader, null);
}

public InputReader(LineReader lineReader, Character mask) {
    this.lineReader = lineReader;
    this.mask = mask != null ? mask : DEFAULT_MASK;
}

public String prompt(String  prompt) {
    return prompt(prompt, true);
}

public String prompt(String  prompt, boolean echo) {
    String answer;
    if (echo) {
        answer = lineReader.readLine(prompt + ": ");
    } else {
        answer = lineReader.readLine(prompt + ": ", mask);
    }
    return answer;
}

}

Then, make it a bean:

@Bean
public InputReader inputReader(@Lazy LineReader lineReader) {
    return new InputReader(lineReader);
}

and finally use it in your app:

@ShellComponent
public class YourShellComponent {

private final InputReader inputReader;

@Autowired
public YourShellComponent(InputReader inputReader) {
    this.inputReader = inputReader;
}

@ShellMethod(value = "connect")
public void connect() throws Exception {
    String username = this.inputReader.prompt("Username");
    String password = this.inputReader.prompt("Password", false);

    // other code
}
}