Add cli_utils.d
This commit is contained in:
parent
f2df5a48d2
commit
6fd042f594
106
source/app.d
106
source/app.d
|
@ -11,6 +11,7 @@ import botan.hash.hash : HashFunction;
|
||||||
import botan.hash.sha2_32 : SHA256;
|
import botan.hash.sha2_32 : SHA256;
|
||||||
|
|
||||||
import cipher_utils;
|
import cipher_utils;
|
||||||
|
import cli_utils;
|
||||||
|
|
||||||
int main(string[] args) {
|
int main(string[] args) {
|
||||||
Params params;
|
Params params;
|
||||||
|
@ -20,10 +21,9 @@ int main(string[] args) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
BlockCipher cipher = null;
|
BlockCipher cipher = null;
|
||||||
// TODO: Use args to determine block cipher.
|
// TODO: Use args to determine block cipher.
|
||||||
writeln("Enter a password:");
|
writeln("Enter a passphrase:");
|
||||||
string password = readPassphrase();
|
string password = readPassphrase();
|
||||||
if (password is null) {
|
if (password is null) {
|
||||||
return 2;
|
return 2;
|
||||||
|
@ -54,108 +54,6 @@ int main(string[] args) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
enum Action {
|
|
||||||
ENCRYPT,
|
|
||||||
DECRYPT
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Params {
|
|
||||||
Action action = Action.ENCRYPT;
|
|
||||||
string target = ".";
|
|
||||||
bool recursive = false;
|
|
||||||
bool verbose = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
int parseParams(string[] args, ref Params params) {
|
|
||||||
getopt(
|
|
||||||
args,
|
|
||||||
"recursive|r", ¶ms.recursive,
|
|
||||||
"verbose|v", ¶ms.verbose
|
|
||||||
);
|
|
||||||
if (args.length < 2) {
|
|
||||||
stderr.writeln("Missing required action.");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
string action = args[1].strip();
|
|
||||||
if (action != "encrypt" && action != "decrypt") {
|
|
||||||
stderr.writeln("Invalid action.");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
if (action == "encrypt") {
|
|
||||||
params.action = Action.ENCRYPT;
|
|
||||||
} else if (action == "decrypt") {
|
|
||||||
params.action = Action.DECRYPT;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (args.length >= 3) {
|
|
||||||
params.target = args[2];
|
|
||||||
if (!exists(params.target)) {
|
|
||||||
stderr.writefln!"Target \"%s\" doesn't exist."(params.target);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
string readPassphrase() {
|
|
||||||
version(Posix) {
|
|
||||||
import core.sys.posix.termios : termios, tcgetattr, tcsetattr, ECHO;
|
|
||||||
import core.sys.posix.stdio;
|
|
||||||
termios term;
|
|
||||||
tcgetattr(0, &term);
|
|
||||||
term.c_lflag &= ~ECHO;
|
|
||||||
tcsetattr(0, 0, &term);
|
|
||||||
|
|
||||||
string passphrase = readln().strip();
|
|
||||||
|
|
||||||
term.c_lflag |= ECHO;
|
|
||||||
tcsetattr(0, 0, &term);
|
|
||||||
|
|
||||||
return passphrase;
|
|
||||||
} else version(Windows) {
|
|
||||||
import core.sys.windows.windows;
|
|
||||||
DWORD con_mode;
|
|
||||||
DWORD dwRead;
|
|
||||||
HANDLE hIn = GetStdHandle(STD_INPUT_HANDLE);
|
|
||||||
GetConsoleMode(hIn, &con_mode);
|
|
||||||
SetConsoleMode(hIn, con_mode & ~(ENABLE_ECHO_INPUT | ENABLE_LINE_INPUT));
|
|
||||||
|
|
||||||
string password = "";
|
|
||||||
char BACKSPACE = 8;
|
|
||||||
char RETURN = 13;
|
|
||||||
char ch = 0;
|
|
||||||
while (ReadConsoleA(hIn, &ch, 1, &dwRead, NULL) && ch != RETURN) {
|
|
||||||
if (ch == BACKSPACE) {
|
|
||||||
if (password.length > 0) {
|
|
||||||
password = password[0 .. $ - 1];
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
password ~= ch;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return password;
|
|
||||||
} else {
|
|
||||||
stderr.writeln("Unsupported password reading.");
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void printUsage() {
|
|
||||||
writeln(q"HELP
|
|
||||||
Usage: scrambler <encrypt|decrypt> [target] [options]
|
|
||||||
Scramber is a command-line tool for "scrambling", or encrypting files with a
|
|
||||||
passphrase so they can only be read after they're decrypted using the same
|
|
||||||
passphrase.
|
|
||||||
|
|
||||||
Provide either the "encrypt" or "decrypt" command, followed by a target that's
|
|
||||||
either a directory, or an individual file. By default, the target is the
|
|
||||||
directory that Scrambler was invoked from.
|
|
||||||
|
|
||||||
The following options are available:
|
|
||||||
-r | --recursive Recursively encrypt/decrypt nested directories.
|
|
||||||
-v | --verbose Show verbose output during runtime.
|
|
||||||
HELP");
|
|
||||||
}
|
|
||||||
|
|
||||||
void encryptAndRemoveFile(string filename, BlockCipher cipher, ref ubyte[] buffer) {
|
void encryptAndRemoveFile(string filename, BlockCipher cipher, ref ubyte[] buffer) {
|
||||||
string encryptedFilename = filename ~ ".enc";
|
string encryptedFilename = filename ~ ".enc";
|
||||||
|
|
|
@ -0,0 +1,121 @@
|
||||||
|
module cli_utils;
|
||||||
|
|
||||||
|
enum Action {
|
||||||
|
ENCRYPT,
|
||||||
|
DECRYPT
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Params {
|
||||||
|
Action action = Action.ENCRYPT;
|
||||||
|
string target = ".";
|
||||||
|
bool recursive = false;
|
||||||
|
bool verbose = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int parseParams(string[] args, ref Params params) {
|
||||||
|
import std.getopt;
|
||||||
|
import std.stdio;
|
||||||
|
import std.file : exists;
|
||||||
|
import std.string : strip;
|
||||||
|
bool isEncrypting;
|
||||||
|
bool isDecrypting;
|
||||||
|
getopt(
|
||||||
|
args,
|
||||||
|
"recursive|r", ¶ms.recursive,
|
||||||
|
"verbose|v", ¶ms.verbose,
|
||||||
|
"encrypt|e", &isEncrypting,
|
||||||
|
"decrypt|d", &isDecrypting
|
||||||
|
);
|
||||||
|
if (isEncrypting && isDecrypting) {
|
||||||
|
stderr.writeln("Invalid arguments: Cannot specify both the --encrypt and --decrypt flags.");
|
||||||
|
}
|
||||||
|
if (isEncrypting) {
|
||||||
|
params.action = Action.ENCRYPT;
|
||||||
|
} else if (isDecrypting) {
|
||||||
|
params.action = Action.DECRYPT;
|
||||||
|
} else {
|
||||||
|
writeln("Determining if we should encrypt or decrypt");
|
||||||
|
params.action = Action.ENCRYPT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (args.length > 1) {
|
||||||
|
params.target = args[1];
|
||||||
|
if (!exists(params.target)) {
|
||||||
|
stderr.writefln!"Target \"%s\" doesn't exist."(params.target);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void printUsage() {
|
||||||
|
import std.stdio : writeln;
|
||||||
|
writeln(q"HELP
|
||||||
|
Usage: scrambler [target] [options]
|
||||||
|
Scramber is a command-line tool for encrypting and decrypting files or entire
|
||||||
|
directories using a passphrase.
|
||||||
|
|
||||||
|
The following options are available:
|
||||||
|
-e | --encrypt Do an encryption operation on the target file or
|
||||||
|
directory.
|
||||||
|
-d | --decrypt Do a decryption operation on the target file or
|
||||||
|
directory.
|
||||||
|
-r | --recursive Recursively encrypt/decrypt nested directories.
|
||||||
|
-v | --verbose Show verbose output during runtime.
|
||||||
|
-s | --no-suffix Do not add the ".enc" suffix to files.
|
||||||
|
|
||||||
|
Encrypted files are suffixed with ".enc" to indicate that they're encrypted and
|
||||||
|
cannot be read as usual. If neither --encrypt nor --decrypt flags are provided,
|
||||||
|
Scrambler will try to determine which operation to do based on the presence of
|
||||||
|
".enc" file(s) at the target location. It's recommended that you always do
|
||||||
|
provide an explicit --encrypt or --decrypt flag.
|
||||||
|
HELP");
|
||||||
|
}
|
||||||
|
|
||||||
|
string readPassphrase() {
|
||||||
|
import std.stdio;
|
||||||
|
import std.string : strip;
|
||||||
|
version(Posix) {
|
||||||
|
import core.sys.posix.termios : termios, tcgetattr, tcsetattr, ECHO;
|
||||||
|
import core.sys.posix.stdio;
|
||||||
|
termios term;
|
||||||
|
tcgetattr(0, &term);
|
||||||
|
term.c_lflag &= ~ECHO;
|
||||||
|
tcsetattr(0, 0, &term);
|
||||||
|
|
||||||
|
string passphrase = readln().strip();
|
||||||
|
|
||||||
|
term.c_lflag |= ECHO;
|
||||||
|
tcsetattr(0, 0, &term);
|
||||||
|
|
||||||
|
return passphrase;
|
||||||
|
} else version(Windows) {
|
||||||
|
import core.sys.windows.windows;
|
||||||
|
DWORD prev_con_mode;
|
||||||
|
DWORD con_mode;
|
||||||
|
DWORD dwRead;
|
||||||
|
HANDLE hIn = GetStdHandle(STD_INPUT_HANDLE);
|
||||||
|
GetConsoleMode(hIn, &con_mode);
|
||||||
|
GetConsoleMode(hIn, &prev_con_mode);
|
||||||
|
SetConsoleMode(hIn, con_mode & ~(ENABLE_ECHO_INPUT | ENABLE_LINE_INPUT));
|
||||||
|
|
||||||
|
string password = "";
|
||||||
|
char BACKSPACE = 8;
|
||||||
|
char RETURN = 13;
|
||||||
|
char ch = 0;
|
||||||
|
while (ReadConsoleA(hIn, &ch, 1, &dwRead, NULL) && ch != RETURN) {
|
||||||
|
if (ch == BACKSPACE) {
|
||||||
|
if (password.length > 0) {
|
||||||
|
password = password[0 .. $ - 1];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
password ~= ch;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SetConsoleMode(hIn, prev_con_mode);
|
||||||
|
return password;
|
||||||
|
} else {
|
||||||
|
stderr.writeln("Cannot securely read password from terminal.");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue