package main import ( "flag" "fmt" "os" "os/exec" "path/filepath" "testing" "github.com/StackExchange/blackbox/v2/pkg/bblog" _ "github.com/StackExchange/blackbox/v2/pkg/bblog" _ "github.com/StackExchange/blackbox/v2/pkg/vcs/_all" ) var vcsToTest = flag.String("testvcs", "GIT", "VCS to test") var longTests = flag.Bool("long", false, "Run long version of tests") //var crypterToTest = flag.String("crypter", "GnuPG", "crypter to test") func init() { testing.Init() flag.Parse() op, err := os.Getwd() if err != nil { panic(err) } originPath = op } func compile(t *testing.T) { if PathToBlackBox() != "" { // It's been compiled already. return } // Make sure we have the latest binary fmt.Println("========== Compiling") cmd := exec.Command("go", "build", "-o", "../bbintegration", "../cmd/blackbox") cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr err := cmd.Run() if err != nil { t.Fatalf("setup_compile: %v", err) } cwd, err := os.Getwd() if err != nil { t.Fatal(err) } SetPathToBlackBox(filepath.Join(cwd, "../bbintegration")) } func setup(t *testing.T) { logDebug := bblog.GetDebug(*verbose) logDebug.Printf("flag.testvcs is %v", *vcsToTest) vh := getVcs(t, *vcsToTest) logDebug.Printf("Using BLACKBOX_VCS=%v", vh.Name()) os.Setenv("BLACKBOX_VCS", vh.Name()) } func TestInit(t *testing.T) { if !*longTests { return } compile(t) makeHomeDir(t, "init") // Only zero or one args are permitted. invalidArgs(t, "init", "one", "two") invalidArgs(t, "init", "one", "two", "three") runBB(t, "init", "yes") assertFileEmpty(t, ".blackbox/blackbox-admins.txt") assertFileEmpty(t, ".blackbox/blackbox-files.txt") assertFilePerms(t, ".blackbox/blackbox-admins.txt", 0o640) assertFilePerms(t, ".blackbox/blackbox-files.txt", 0o640) } func TestList(t *testing.T) { if !*longTests { return } compile(t) makeHomeDir(t, "init") runBB(t, "init", "yes") createDummyFilesAdmin(t) checkOutput("000-admin-list.txt", t, "admin", "list") checkOutput("000-file-list.txt", t, "file", "list") invalidArgs(t, "file", "list", "extra") invalidArgs(t, "admin", "list", "extra") } func TestStatus(t *testing.T) { if !*longTests { return } compile(t) makeHomeDir(t, "init") runBB(t, "init", "yes") createFilesStatus(t) checkOutput("000-status.txt", t, "status") } func TestShred(t *testing.T) { if !*longTests { return } compile(t) makeHomeDir(t, "shred") runBB(t, "init", "yes") makeFile(t, "shredme.txt", "File with SHREDME in it.\n") assertFileExists(t, "shredme.txt") runBB(t, "shred", "shredme.txt") assertFileMissing(t, "shredme.txt") } func TestStatus_notreg(t *testing.T) { if !*longTests { return } compile(t) makeHomeDir(t, "init") runBB(t, "init", "yes") createFilesStatus(t) checkOutput("status-noreg.txt", t, "status", "status-ENCRYPTED.txt", "blah.txt") } // TestHard tests the functions using a fake homedir and repo. func TestHard(t *testing.T) { if !*longTests { return } // These are basic tests that work on a fake repo. // The repo has mostly real data, except any .gpg file // is just garbage. compile(t) setup(t) for _, cx := range []struct{ subname, prefix string }{ //{subname: ".", prefix: "."}, {subname: "mysub", prefix: ".."}, } { subname := cx.subname prefix := cx.prefix _ = prefix phase("========== SUBDIR = " + subname + " ==========") makeHomeDir(t, "BasicAlice") plaintextFoo := "I am the foo.txt file!\n" plainAltered := "I am the altered file!\n" runBB(t, "testing_init") // Runs "git init" or equiv assertFileExists(t, ".git") runBB(t, "init", "yes") // Creates .blackbox or equiv if subname != "." { err := os.Mkdir(subname, 0770) if err != nil { t.Fatal(fmt.Errorf("hard-mk-home %q: %v", subname, err)) } } olddir, err := os.Getwd() if err != nil { t.Fatal(err) } os.Chdir(subname) os.Chdir(olddir) phase("Alice creates a GPG key") gpgdir := makeAdmin(t, "alice", "Alice Example", "alice@example.com") become(t, "alice") phase("Alice enrolls as an admin") //os.Chdir(subname) runBB(t, "admin", "add", "alice@example.com", gpgdir) //os.Chdir(olddir) // encrypt phase("Alice registers foo.txt") makeFile(t, "foo.txt", plaintextFoo) //os.Chdir(subname) //runBB(t, "file", "add", "--shred", filepath.Join(prefix, "foo.txt")) runBB(t, "file", "add", "--shred", "foo.txt") //os.Chdir(olddir) // "file add" encrypts the file. // We shred the plaintext so that we are sure that when Decrypt runs, // we can verify the contents wasn't just sitting there all the time. assertFileMissing(t, "foo.txt") assertFileExists(t, "foo.txt.gpg") phase("Alice decrypts foo.txt") // decrypt //os.Chdir(subname) runBB(t, "decrypt", "foo.txt") //runBB(t, "decrypt", filepath.Join(prefix, "foo.txt")) //os.Chdir(olddir) assertFileExists(t, "foo.txt") assertFileExists(t, "foo.txt.gpg") assertFileContents(t, "foo.txt", plaintextFoo) // encrypts (without shredding) phase("Alice encrypts foo.txt (again)") runBB(t, "encrypt", "foo.txt") assertFileExists(t, "foo.txt") assertFileExists(t, "foo.txt.gpg") assertFileContents(t, "foo.txt", plaintextFoo) // reencrypt phase("Alice reencrypts") checkOutput("basic-status.txt", t, "status") runBB(t, "reencrypt", "--overwrite", "foo.txt") // Test variations of cat // foo.txt=plain result=plain phase("Alice cats plain:plain") makeFile(t, "foo.txt", plaintextFoo) assertFileExists(t, "foo.txt") runBB(t, "encrypt", "foo.txt") assertFileExists(t, "foo.txt") assertFileExists(t, "foo.txt.gpg") checkOutput("alice-cat-plain.txt", t, "cat", "foo.txt") assertFileExists(t, "foo.txt") assertFileExists(t, "foo.txt.gpg") // foo.txt=altered result=plain phase("Alice cats altered:plain") makeFile(t, "foo.txt", plainAltered) assertFileExists(t, "foo.txt") assertFileExists(t, "foo.txt.gpg") checkOutput("alice-cat-plain.txt", t, "cat", "foo.txt") assertFileExists(t, "foo.txt") assertFileExists(t, "foo.txt.gpg") // foo.txt=missing result=plain phase("Alice cats missing:plain") removeFile(t, "foo.txt") assertFileMissing(t, "foo.txt") assertFileMissing(t, "foo.txt") assertFileExists(t, "foo.txt.gpg") checkOutput("alice-cat-plain.txt", t, "cat", "foo.txt") assertFileMissing(t, "foo.txt") assertFileExists(t, "foo.txt.gpg") // Chapter 2: Bob // Alice adds Bob. // Bob encrypts a file. // Bob makes sure he can decrypt alice's file. // Bob removes Alice. // Alice verifies she CAN'T decrypt files. // Bob adds Alice back. // Alice verifies she CAN decrypt files. // Bob adds an encrypted file by mistake, "bb add" and fixes it. // Bob corrupts the blackbox-admins.txt file, verifies that commands fail. } } // TestEvilFilenames verifies commands work with "difficult" file names func TestEvilFilenames(t *testing.T) { if !*longTests { return } compile(t) setup(t) makeHomeDir(t, "Mallory") runBB(t, "testing_init") // Runs "git init" or equiv assertFileExists(t, ".git") runBB(t, "init", "yes") // Creates .blackbox or equiv phase("Malory creates a GPG key") gpgdir := makeAdmin(t, "mallory", "Mallory Evil", "mallory@example.com") become(t, "mallory") phase("Mallory enrolls as an admin") runBB(t, "admin", "add", "mallory@example.com", gpgdir) _ = os.MkdirAll("my/path/to", 0o770) _ = os.Mkdir("other", 0o770) for i, name := range []string{ "!important!.txt", "#andpounds.txt", "stars*bars?.txt", "space space.txt", "tab\ttab.txt", "ret\rret.txt", "smile😁eyes", "¡que!", "thé", "pound£", "*.go", "rm -f erase ; echo done", `smile☺`, `dub𝓦`, "my/path/to/relsecrets.txt", //"my/../my/path/../path/to/myother.txt", // Not permitted yet //"other/../my//path/../path/to/otherother.txt", // Not permitted yet //"new\nnew.txt", // \n not permitted //"two\n", // \n not permitted (yet) //"four\U0010FFFF", // Illegal byte sequence. git won't accept. } { phase(fmt.Sprintf("Mallory tries %02d: %q", i, name)) contents := "the name of this file is the talking heads... i mean, " + name makeFile(t, name, contents) assertFileExists(t, name) assertFileMissing(t, name+".gpg") assertFileContents(t, name, contents) runBB(t, "file", "add", name) assertFileMissing(t, name) assertFileExists(t, name+".gpg") runBB(t, "decrypt", name) assertFileExists(t, name) assertFileExists(t, name+".gpg") assertFileContents(t, name, contents) runBB(t, "encrypt", name) assertFileExists(t, name) assertFileExists(t, name+".gpg") assertFileContents(t, name, contents) runBB(t, "shred", name) assertFileMissing(t, name) assertFileExists(t, name+".gpg") } } // More tests to implement. // 1. Verify that the --gid works (blackbox decrypt --gid)