1 /**
2  * Consoleur: a package for interaction with character-oriented terminal emulators
3  *
4  * Copyright: Maxim Freck, 2017.
5  * Authors:   Maxim Freck <maxim@freck.pp.ru>
6  * License:   $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
7  */
8 module consoleur.cli.password;
9 
10 /**
11  * Reads password from the user with echo
12  *
13  * Params:
14  *  mask = Typed character mask
15  *
16  * Returns: Password
17  */
18 string getPassword(string prompt = "Password: ", int maxLength = 0, dchar mask = '•') @trusted
19 {
20 	import consoleur.cli.util: delchar, utf8length;
21 	import consoleur.core.termparam: setTermparam, Term;
22 	import consoleur.core: flushStdin;
23 	import consoleur.input.key: Command, getKeyPressed, KeyModifier, KeyType;
24 	import std.stdio: stdout, write;
25 
26 	string ret;
27 	immutable tparam = setTermparam(Term.quiet|Term.raw);
28 
29 	write(prompt);
30 	stdout.flush;
31 
32 	while (true) {
33 		auto code = getKeyPressed();
34 
35 		if (code.type == KeyType.COMMAND && code.content.code == Command.del && ret.length > 0) {
36 			ret = ret.delchar;
37 			write("\b \b");
38 			stdout.flush;
39 		}
40 		if ( ( (code.type == KeyType.COMMAND && code.content.code == Command.escape ) ||
41 			(code.type == KeyType.COMMAND && code.content.code == Command.del && (code.modifier & KeyModifier.alt) ) )
42 			&& ret.length > 0
43 		) {
44 			foreach (_; 0 .. ret.utf8length) write("\b \b");
45 			stdout.flush;
46 			ret.length = 0;
47 		}
48 
49 		if (code.type == KeyType.COMMAND && code.content.code == Command.lineFeed) break;
50 
51 		if (maxLength > 0 && ret.length == maxLength) continue;
52 
53 		if (code.type == KeyType.ASCII || code.type == KeyType.UTF8) {
54 			ret ~= cast(string)(code);
55 			write(mask);
56 			stdout.flush;
57 		}
58 	}
59 
60 	flushStdin();
61 	return ret;
62 }