diff options
author | Jakob Unterwurzacher | 2020-05-17 19:31:04 +0200 |
---|---|---|
committer | Jakob Unterwurzacher | 2020-05-17 19:31:04 +0200 |
commit | 416080203b4dd79de857eaf7c7cc97d050e00a9f (patch) | |
tree | ed729c4cd365acc803a3d1e339eae8f1e8112f4c /internal | |
parent | ded4bbe6456dcfaa770f2c06df46d578fcbaa97e (diff) |
main: accept multiple -passfile options
Each file will be read and then concatenated
for the effictive password. This can be used as a
kind of multi-factor authenticiton.
Fixes https://github.com/rfjakob/gocryptfs/issues/288
Diffstat (limited to 'internal')
-rw-r--r-- | internal/readpassword/extpass_test.go | 10 | ||||
-rw-r--r-- | internal/readpassword/passfile.go | 12 | ||||
-rw-r--r-- | internal/readpassword/passfile_test.go | 27 | ||||
-rw-r--r-- | internal/readpassword/read.go | 14 |
4 files changed, 47 insertions, 16 deletions
diff --git a/internal/readpassword/extpass_test.go b/internal/readpassword/extpass_test.go index b4ca8fa..9a643a5 100644 --- a/internal/readpassword/extpass_test.go +++ b/internal/readpassword/extpass_test.go @@ -26,7 +26,7 @@ func TestExtpass(t *testing.T) { func TestOnceExtpass(t *testing.T) { p1 := "lkadsf0923rdfi48rqwhdsf" - p2 := string(Once([]string{"echo " + p1}, "", "")) + p2 := string(Once([]string{"echo " + p1}, nil, "")) if p1 != p2 { t.Errorf("p1=%q != p2=%q", p1, p2) } @@ -35,7 +35,7 @@ func TestOnceExtpass(t *testing.T) { // extpass with two arguments func TestOnceExtpass2(t *testing.T) { p1 := "foo" - p2 := string(Once([]string{"echo", p1}, "", "")) + p2 := string(Once([]string{"echo", p1}, nil, "")) if p1 != p2 { t.Errorf("p1=%q != p2=%q", p1, p2) } @@ -44,7 +44,7 @@ func TestOnceExtpass2(t *testing.T) { // extpass with three arguments func TestOnceExtpass3(t *testing.T) { p1 := "foo bar baz" - p2 := string(Once([]string{"echo", "foo", "bar", "baz"}, "", "")) + p2 := string(Once([]string{"echo", "foo", "bar", "baz"}, nil, "")) if p1 != p2 { t.Errorf("p1=%q != p2=%q", p1, p2) } @@ -52,7 +52,7 @@ func TestOnceExtpass3(t *testing.T) { func TestOnceExtpassSpaces(t *testing.T) { p1 := "mypassword" - p2 := string(Once([]string{"cat", "passfile_test_files/file with spaces.txt"}, "", "")) + p2 := string(Once([]string{"cat", "passfile_test_files/file with spaces.txt"}, nil, "")) if p1 != p2 { t.Errorf("p1=%q != p2=%q", p1, p2) } @@ -60,7 +60,7 @@ func TestOnceExtpassSpaces(t *testing.T) { func TestTwiceExtpass(t *testing.T) { p1 := "w5w44t3wfe45srz434" - p2 := string(Once([]string{"echo " + p1}, "", "")) + p2 := string(Once([]string{"echo " + p1}, nil, "")) if p1 != p2 { t.Errorf("p1=%q != p2=%q", p1, p2) } diff --git a/internal/readpassword/passfile.go b/internal/readpassword/passfile.go index 73af279..df6cd4d 100644 --- a/internal/readpassword/passfile.go +++ b/internal/readpassword/passfile.go @@ -8,6 +8,16 @@ import ( "github.com/rfjakob/gocryptfs/internal/tlog" ) +// readPassFileConcatenate reads the first line from each file name and +// concatenates the results. The result does not contain any newlines. +func readPassFileConcatenate(passfileSlice []string) (result []byte) { + for _, e := range passfileSlice { + result = append(result, readPassFile(e)...) + } + return result +} + +// readPassFile reads the first line from the passed file name. func readPassFile(passfile string) []byte { tlog.Info.Printf("passfile: reading from file %q", passfile) f, err := os.Open(passfile) @@ -36,7 +46,7 @@ func readPassFile(passfile string) []byte { os.Exit(exitcodes.ReadPassword) } if len(lines) > 1 && len(lines[1]) > 0 { - tlog.Warn.Printf("passfile: ignoring trailing garbage (%d bytes) after first line", + tlog.Warn.Printf("warning: passfile: ignoring trailing garbage (%d bytes) after first line", len(lines[1])) } return lines[0] diff --git a/internal/readpassword/passfile_test.go b/internal/readpassword/passfile_test.go index cb7fa44..dbfe159 100644 --- a/internal/readpassword/passfile_test.go +++ b/internal/readpassword/passfile_test.go @@ -21,13 +21,20 @@ func TestPassfile(t *testing.T) { if string(pw) != tc.want { t.Errorf("Wrong result: want=%q have=%q", tc.want, pw) } + // Calling readPassFileConcatenate with only one element should give the + // same result + pw = readPassFileConcatenate([]string{"passfile_test_files/" + tc.file}) + if string(pw) != tc.want { + t.Errorf("Wrong result: want=%q have=%q", tc.want, pw) + } } } // readPassFile() should exit instead of returning an empty string. // // The TEST_SLAVE magic is explained at -// https://talks.golang.org/2014/testing.slide#23 . +// https://talks.golang.org/2014/testing.slide#23 , mirror: +// http://web.archive.org/web/20200426174352/https://talks.golang.org/2014/testing.slide#23 func TestPassfileEmpty(t *testing.T) { if os.Getenv("TEST_SLAVE") == "1" { readPassFile("passfile_test_files/empty.txt") @@ -46,7 +53,8 @@ func TestPassfileEmpty(t *testing.T) { // readPassFile() should exit instead of returning an empty string. // // The TEST_SLAVE magic is explained at -// https://talks.golang.org/2014/testing.slide#23 . +// https://talks.golang.org/2014/testing.slide#23 , mirror: +// http://web.archive.org/web/20200426174352/https://talks.golang.org/2014/testing.slide#23 func TestPassfileNewline(t *testing.T) { if os.Getenv("TEST_SLAVE") == "1" { readPassFile("passfile_test_files/newline.txt") @@ -65,7 +73,8 @@ func TestPassfileNewline(t *testing.T) { // readPassFile() should exit instead of returning an empty string. // // The TEST_SLAVE magic is explained at -// https://talks.golang.org/2014/testing.slide#23 . +// https://talks.golang.org/2014/testing.slide#23 , mirror: +// http://web.archive.org/web/20200426174352/https://talks.golang.org/2014/testing.slide#23 func TestPassfileEmptyFirstLine(t *testing.T) { if os.Getenv("TEST_SLAVE") == "1" { readPassFile("passfile_test_files/empty_first_line.txt") @@ -79,3 +88,15 @@ func TestPassfileEmptyFirstLine(t *testing.T) { } t.Fatal("should have exited") } + +// TestPassFileConcatenate tests readPassFileConcatenate +func TestPassFileConcatenate(t *testing.T) { + files := []string{ + "passfile_test_files/file with spaces.txt", + "passfile_test_files/mypassword_garbage.txt", + } + res := string(readPassFileConcatenate(files)) + if res != "mypasswordmypassword" { + t.Errorf("wrong result: %q", res) + } +} diff --git a/internal/readpassword/read.go b/internal/readpassword/read.go index 92a0886..e116f0b 100644 --- a/internal/readpassword/read.go +++ b/internal/readpassword/read.go @@ -20,11 +20,11 @@ const ( maxPasswordLen = 2048 ) -// Once tries to get a password from the user, either from the terminal, extpass +// Once tries to get a password from the user, either from the terminal, extpass, passfile // or stdin. Leave "prompt" empty to use the default "Password: " prompt. -func Once(extpass []string, passfile string, prompt string) []byte { - if passfile != "" { - return readPassFile(passfile) +func Once(extpass []string, passfile []string, prompt string) []byte { + if len(passfile) != 0 { + return readPassFileConcatenate(passfile) } if len(extpass) != 0 { return readPasswordExtpass(extpass) @@ -40,9 +40,9 @@ func Once(extpass []string, passfile string, prompt string) []byte { // Twice is the same as Once but will prompt twice if we get the password from // the terminal. -func Twice(extpass []string, passfile string) []byte { - if passfile != "" { - return readPassFile(passfile) +func Twice(extpass []string, passfile []string) []byte { + if len(passfile) != 0 { + return readPassFileConcatenate(passfile) } if len(extpass) != 0 { return readPasswordExtpass(extpass) |