diff --git a/cmd/lyra/decrypt.go b/cmd/lyra/decrypt.go index 577736f..04ddf36 100644 --- a/cmd/lyra/decrypt.go +++ b/cmd/lyra/decrypt.go @@ -4,8 +4,7 @@ import ( "errors" "flag" - "github.com/azohra/lyra/pkg/lcrypt" - "github.com/azohra/lyra/pkg/lfile" + "github.com/azohra/lyra/internal/pkg/encryption" ) const ( @@ -93,7 +92,7 @@ func (cmd *decryptcmd) Run(opt []string) error { cmd.passphrase = string(getPassphrase()) } - err = decrypt(opt[0], cmd.path, cmd.printOnly, []byte(cmd.passphrase)) + err = encryption.Decrypt(opt[0], cmd.path, cmd.printOnly, []byte(cmd.passphrase)) cmd.passphrase = "" return err @@ -106,43 +105,3 @@ func (cmd *decryptcmd) validateInputs() error { return nil } - -//decrypt encrypts file file and overides the content of file with the ciphertext -//of the specified plaintext file. -func decrypt(file, saveTo string, print bool, passphrase []byte) error { - ctFile, err := lfile.NewParsedSLFile(file) - if err != nil { - return err - } - - key, err := lcrypt.NewLKey(passphrase, ctFile.RetrieveSalt()) - if err != nil { - return err - } - - ptFile, err := ctFile.DecipherFile(key) - if err != nil { - return err - } - - if saveTo == "" && !print { - err = ptFile.Write(file) - } else if saveTo != "" && !print { - err = ptFile.Write(saveTo) - } - - if err != nil { - return err - } - - if print { - ptFile.PrintLyraFile() - } - - err = key.DestroyKey() - if err != nil { - handleErr(err) - } - - return nil -} diff --git a/cmd/lyra/decrypt_test.go b/cmd/lyra/decrypt_test.go deleted file mode 100644 index 36265c2..0000000 --- a/cmd/lyra/decrypt_test.go +++ /dev/null @@ -1,9 +0,0 @@ -package main - -import "testing" - -func TestDecrypt(t *testing.T) { - file := "../../test/fixture.32.go.txt" - save := "../../test/fixture.322.go.txt" - decrypt(file, save, false, []byte("THIS IS A TEST PASSPHRASE YOU SHOULD NOT USE THIS")) -} diff --git a/cmd/lyra/encrypt.go b/cmd/lyra/encrypt.go index afd950d..af80f04 100644 --- a/cmd/lyra/encrypt.go +++ b/cmd/lyra/encrypt.go @@ -6,8 +6,7 @@ import ( "fmt" "os" - "github.com/azohra/lyra/pkg/lcrypt" - "github.com/azohra/lyra/pkg/lfile" + "github.com/azohra/lyra/internal/pkg/encryption" "github.com/brsmsn/gware/pkg/diceware" ) @@ -38,7 +37,7 @@ lyra encrypt --gen-str file Encrypts and overides file (user specified file) with an auto generated passphrase and outputs the auto generated passphrase to stdout. - Auto generaates a 7 word passphrase in kebab case (no spaces). + Auto generates a 7 word passphrase in kebab case (no spaces). lyra encrypt -p "mypassphrase" file @@ -138,7 +137,7 @@ func (cmd *encryptcmd) Run(opt []string) error { cmd.passphrase = string(input) } - err = encrypt(opt[0], cmd.path, []byte(cmd.passphrase)) + err = encryption.Encrypt(opt[0], cmd.path, []byte(cmd.passphrase)) if err != nil { return err } @@ -159,41 +158,6 @@ func (cmd *encryptcmd) validateInputs() error { return nil } -//encrypt encrypts file file and overides the content of file with the ciphertext -//of the specified plaintext file. -func encrypt(file, saveTo string, passphrase []byte) error { - ptFile, err := lfile.NewParsedLyraFile(file) - if err != nil { - return err - } - - key, err := lcrypt.NewLKey(passphrase, nil) - if err != nil { - return err - } - - ctFile, err := ptFile.EncipherFile(key) - if err != nil { - return err - } - - switch saveTo { - case "": - err = ctFile.Write(file) - default: - err = ctFile.Write(saveTo) - } - if err != nil { - return err - } - err = key.DestroyKey() - if err != nil { - return err - } - - return nil -} - //gen a diceware passphrase using eff long wordlist func (cmd *encryptcmd) genPass() error { diff --git a/cmd/lyra/encrypt_test.go b/cmd/lyra/encrypt_test.go deleted file mode 100644 index 3ce8514..0000000 --- a/cmd/lyra/encrypt_test.go +++ /dev/null @@ -1,10 +0,0 @@ -package main - -import "testing" - -func TestEncrypt(t *testing.T) { - file := "../../test/fixture.31.go.txt" - save := "../../test/fixture.311.go.txt" - encrypt(file, save, []byte("THIS IS A TEST PASSPHRASE YOU SHOULD NOT USE THIS")) - -} diff --git a/cmd/lyra/locker.go b/cmd/lyra/locker.go new file mode 100644 index 0000000..3da66e8 --- /dev/null +++ b/cmd/lyra/locker.go @@ -0,0 +1,336 @@ +package main + +import ( + "flag" + "fmt" + "io/ioutil" + "os" + "strings" + + "github.com/azohra/lyra/internal/pkg/locker" + "github.com/brsmsn/gware/pkg/diceware" +) + +const ( + lockerUsage = ` + +Sub commands: + + lock Lock all assets listed in lyralocker file + unlock Unlock all assets listed in lyralocker file + check Checks the locker to test for any unencrypted files + +` + + // Used to make cool reports + checkmark = "✓" + cross = "✕" + + // LockerConfigFilename defines the filename of the projects lyra locker config file + LockerConfigFilename = "lyralocker" + + // LockerPassphraseFilename defines the filename of the file that stores the projects passphrase + LockerPassphraseFilename = ".lockerpass" + + // Might need to add flags to configure these in the future + lockerPassGenNumWords = 7 + lockerPassGenNumPhrases = 1 + lockerPassGenRemoveSpaces = false + + lockerFileTemplate = `# This file is for listing assets to be encrypted + +# Uncomment the following line to lock the file +# super-secret-key.txt +` +) + +type lockercmd struct { + fileRecursionDepth int + passphrase string + quiet bool +} + +func (cmd *lockercmd) CName() string { + return "locker" +} + +func (cmd *lockercmd) Help() string { + return lockerUsage +} + +func (cmd *lockercmd) RegCFlags(fs *flag.FlagSet) { + fs.BoolVar(&cmd.quiet, "q", false, "Run command in quiet mode") + fs.StringVar(&cmd.passphrase, "p", "", "Use provided passphrase") +} + +func (cmd *lockercmd) Run(opt []string) error { + + if len(opt) < 1 { + fmt.Println(lockerUsage) + os.Exit(0) + } + + response := "" + code := 0 + + // Init is a special command that does not error + // when the lyrafile does not exist + if opt[0] == "init" { + response, code = initializeLocker() + } else { + + // If no passphrase provided to command, pull + // from project password file + if cmd.passphrase == "" { + pass, err := readPassFile() + if err != nil { + return err + } + cmd.passphrase = pass + } + + files, err := locker.ParseLockerFile(LockerConfigFilename) + if err != nil { + return err + } + + switch opt[0] { + case "lock": + response, code = lock(files, cmd) + break + case "unlock": + response, code = unlock(files, cmd) + break + case "check": + response, code = check(files, cmd) + break + default: + fmt.Println(lockerUsage) + os.Exit(1) + } + + } + + outputTo := os.Stdout + if code > 0 { + outputTo = os.Stderr + } + if !cmd.quiet { + fmt.Fprintf(outputTo, response) + } + os.Exit(code) + return nil // will never be reached since we handle things locally +} + +// Initializes the cwd with a password file and a config file +func initializeLocker() (string, int) { + createdPassFile := false + passFileExists, err := isFileExists(LockerPassphraseFilename) + if err != nil { + return err.Error(), BadExit + } + + if !passFileExists { + + passFile, err := os.Create(LockerPassphraseFilename) + defer passFile.Close() + if err != nil { + return err.Error(), BadExit + } else { + words, err := diceware.GeneratePassphrases(lockerPassGenNumPhrases, lockerPassGenNumWords, diceware.EffWorldList) + if err != nil { + return "Could not generate password", BadExit + } + + passphrase := strings.Join(words, " ") + if lockerPassGenRemoveSpaces { + passphrase = strings.Join(words, "") + } + + // Keep the formatting clean. Will be stripped out when read + passphrase += "\n" + + _, err = fmt.Fprint(passFile, passphrase) + if err != nil { + return "Could not write password to " + LockerPassphraseFilename, BadExit + } + createdPassFile = true + } + + } + + configFileCreated := false + + configFileExists, err := isFileExists(LockerConfigFilename) + if err != nil { + return err.Error(), BadExit + } + + if !configFileExists { + + configFile, err := os.Create(LockerConfigFilename) + defer configFile.Close() + if err != nil { + if !os.IsExist(err) { + configFileCreated = false + } + } else { + + _, err := fmt.Fprintln(configFile, lockerFileTemplate) + if err != nil { + configFileCreated = false + } else { + configFileCreated = true + } + + } + } + + reply := "" + + if createdPassFile { + reply += fmt.Sprintf("Generated passphrase file at %s\n", LockerPassphraseFilename) + } else { + reply += fmt.Sprintf("Passphrase file already exists\n") + } + + if configFileCreated { + reply += fmt.Sprintf("Generated %s file\n", LockerConfigFilename) + } else { + reply += fmt.Sprintf("%s file already exists\n", LockerConfigFilename) + } + + return reply, GoodExit +} + +// Locks all provided assets +func lock(assets []locker.Asset, cmd *lockercmd) (string, int) { + successCount := 0 + failCount := 0 + for _, asset := range assets { + if asset.Err != nil { + if os.IsNotExist(asset.Err) { + fmt.Fprint(os.Stderr, fmt.Sprintf("File %s does not exist\n", asset.Filename)) + } + failCount++ + } else { + err := asset.Lock([]byte(cmd.passphrase)) + if err != nil { + fmt.Fprint(os.Stderr, err.Error()+"\n") + failCount++ + } else { + if !cmd.quiet { + fmt.Printf("Locked %s\n", asset.Filename) + } + successCount++ + } + } + } + + reply := fmt.Sprintf("%d assets encrypted\n", successCount) + replyCode := GoodExit + + if failCount > 0 { + replyCode = BadExit + reply = fmt.Sprintf("%d could not be encrypted\n", failCount) + } + + return reply, replyCode +} + +// Unlocks locked assets provided +func unlock(assets []locker.Asset, cmd *lockercmd) (string, int) { + successCount := 0 + failCount := 0 + for _, asset := range assets { + if asset.Err != nil { + if os.IsNotExist(asset.Err) { + fmt.Fprint(os.Stderr, fmt.Sprintf("File %s does not exist\n", asset.Filename)) + } + failCount++ + } else { + err := asset.Unlock([]byte(cmd.passphrase)) + + if err != nil { + fmt.Fprint(os.Stderr, err.Error()) + failCount++ + } else { + if !cmd.quiet { + fmt.Printf("Unlocked %s\n", asset.Filename) + } + successCount++ + } + } + } + + reply := fmt.Sprintf("%d assets decrypted\n", successCount) + replyCode := GoodExit + + if failCount > 0 { + replyCode = BadExit + reply = fmt.Sprintf("%d could not be decrypted\n", failCount) + } + + return reply, replyCode +} + +// Checks the current project for any assets that are in an +// unencrypted state +func check(files []locker.Asset, cmd *lockercmd) (string, int) { + successCount := 0 + failCount := 0 + for _, f := range files { + if f.Err != nil { + if os.IsNotExist(f.Err) { + fmt.Fprint(os.Stderr, fmt.Sprintf("File %s does not exist\n", f.Filename)) + } + failCount++ + } else { + validEncryption, err := f.ValidateLocked() + + if err != nil { + fmt.Fprint(os.Stderr, err.Error()) + failCount++ + } else if validEncryption { + if !cmd.quiet { + fmt.Printf("%s %s\n", checkmark, f.Filename) + } + successCount++ + } else { + fmt.Fprintf(os.Stderr, "%s %s\n", cross, f.Filename) + failCount++ + } + } + } + + reply := fmt.Sprintf("%d/%d assets secured.\n", successCount, len(files)) + replyCode := GoodExit + + if failCount > 0 { + replyCode = BadExit + reply = fmt.Sprintf("%d/%d assets secured. %d files have not be encrypted.\n", successCount, len(files), failCount) + } + + return reply, replyCode +} + +// Reads a password file +func readPassFile() (string, error) { + contents, err := ioutil.ReadFile(LockerPassphraseFilename) + if err != nil { + return "", err + } + return strings.TrimSpace(string(contents)), nil +} + +// Checks if a file exists and not a directory +func isFileExists(filename string) (bool, error) { + fileInfo, err := os.Stat(filename) + if err != nil { + if os.IsNotExist(err) { + return false, nil + } + return false, err + } + return !fileInfo.IsDir(), nil +} diff --git a/cmd/lyra/lyra.go b/cmd/lyra/lyra.go index b166cf7..4f0a2de 100644 --- a/cmd/lyra/lyra.go +++ b/cmd/lyra/lyra.go @@ -29,6 +29,7 @@ Commands: encrypt Encipher a specified file with inputed passphrase decrypt Decipher a specified file with inputed passphrase generate Generate passphrase(s) + locker A tool for locking project secrets To get more info on commands do: lyra [Command] --help ` @@ -62,6 +63,7 @@ func main() { &encryptcmd{}, &decryptcmd{}, &gencmd{}, + &lockercmd{}, } versionSet := flag.Bool("version", false, "") diff --git a/internal/pkg/encryption/encryption.go b/internal/pkg/encryption/encryption.go new file mode 100644 index 0000000..72329c9 --- /dev/null +++ b/internal/pkg/encryption/encryption.go @@ -0,0 +1,81 @@ +package encryption + +import ( + "github.com/azohra/lyra/pkg/lcrypt" + "github.com/azohra/lyra/pkg/lfile" +) + +// Encrypt encrypts file file and overides the content of file with the ciphertext +// of the specified plaintext file. +func Encrypt(file, saveTo string, passphrase []byte) error { + ptFile, err := lfile.NewParsedLyraFile(file) + if err != nil { + return err + } + + key, err := lcrypt.NewLKey(passphrase, nil) + if err != nil { + return err + } + + ctFile, err := ptFile.EncipherFile(key) + if err != nil { + return err + } + + switch saveTo { + case "": + err = ctFile.Write(file) + default: + err = ctFile.Write(saveTo) + } + if err != nil { + return err + } + err = key.DestroyKey() + if err != nil { + return err + } + + return nil +} + +// Decrypt encrypts file file and overides the content of file with the ciphertext +// of the specified plaintext file. +func Decrypt(file, saveTo string, print bool, passphrase []byte) error { + ctFile, err := lfile.NewParsedSLFile(file) + if err != nil { + return err + } + + key, err := lcrypt.NewLKey(passphrase, ctFile.RetrieveSalt()) + if err != nil { + return err + } + + ptFile, err := ctFile.DecipherFile(key) + if err != nil { + return err + } + + if saveTo == "" && !print { + err = ptFile.Write(file) + } else if saveTo != "" && !print { + err = ptFile.Write(saveTo) + } + + if err != nil { + return err + } + + if print { + ptFile.PrintLyraFile() + } + + err = key.DestroyKey() + if err != nil { + return err + } + + return nil +} diff --git a/internal/pkg/encryption/encryption_test.go b/internal/pkg/encryption/encryption_test.go new file mode 100644 index 0000000..6d046e1 --- /dev/null +++ b/internal/pkg/encryption/encryption_test.go @@ -0,0 +1,17 @@ +package encryption + +import ( + "testing" +) + +func TestEncrypt(t *testing.T) { + file := "../../test/fixture.31.go.txt" + save := "../../test/fixture.311.go.txt" + Encrypt(file, save, []byte("THIS IS A TEST PASSPHRASE YOU SHOULD NOT USE THIS")) +} + +func TestDecrypt(t *testing.T) { + file := "../../test/fixture.32.go.txt" + save := "../../test/fixture.322.go.txt" + Decrypt(file, save, false, []byte("THIS IS A TEST PASSPHRASE YOU SHOULD NOT USE THIS")) +} diff --git a/internal/pkg/locker/locker.go b/internal/pkg/locker/locker.go new file mode 100644 index 0000000..1ee17db --- /dev/null +++ b/internal/pkg/locker/locker.go @@ -0,0 +1,172 @@ +package locker + +import ( + "bufio" + "os" + "path/filepath" + "regexp" + "strings" + + "github.com/azohra/lyra/internal/pkg/encryption" +) + +const ( + lockedFileExtension = ".locked" // What the extension is for locked files + commentSequence = "#" // What signals a comment in a locker file + encryptionValidatorRegex = `^\@\![a-f0-9]{32}\@\![a-f0-9]{24}$` +) + +// Asset represents a Locker file asset. +type Asset struct { + Filename string + LockedFilename string + IsLocked bool + Err error +} + +// ParseLockerFile parses a locker file and returns a list of locker assets +func ParseLockerFile(filename string) ([]Asset, error) { + jobs := []Asset{} + + lockerFile, err := os.Open(filename) + defer lockerFile.Close() + if err != nil { + return nil, err + } + scanner := bufio.NewScanner(lockerFile) + for scanner.Scan() { + entry := strings.TrimSpace(scanner.Text()) + + // ignore empty lines and comments from locker file + if entry == "" || strings.HasPrefix(entry, commentSequence) { + continue + } + + fileInfo, err := os.Stat(entry) + // cant be a dir if it is not found but maybe .locked? + if err == nil && fileInfo.IsDir() { + + filepath.Walk(entry, func(path string, info os.FileInfo, err error) error { + if info != nil && !info.IsDir() { + // newLockerAsset will propagate errors to the top cmd level so we dont need to + // handle them here + jobs = append(jobs, NewLockerAsset(path)) + } + return nil + }) + + } else { + // Creating a locker asset from a missing file is ok. Error will + // propagate to the cmd level for reporting + jobs = append(jobs, NewLockerAsset(entry)) + } + + } + return jobs, nil +} + +// NewLockerAsset creates a new asset record from a filename. +// This includes determining if the file is locked and/or +// even exists +func NewLockerAsset(filename string) (l Asset) { + l.Filename = filename + l.LockedFilename = filename + l.IsLocked = true + l.Err = nil + + if isFilenameLocked(filename) { + l.Filename = createLockedFilename(filename, false) + } else { + l.LockedFilename = createLockedFilename(filename, true) + } + + _, baseErr := os.Stat(l.Filename) + _, lockedErr := os.Stat(l.LockedFilename) + + if baseErr == nil && lockedErr != nil && os.IsNotExist(lockedErr) { + l.IsLocked = false + } else if baseErr != nil && os.IsNotExist(baseErr) && lockedErr == nil { + l.IsLocked = true + } else { + l.Err = baseErr + } + + return +} + +// Lock encrypts a locker Asset. +func (a *Asset) Lock(passphrase []byte) error { + if !a.IsLocked { + err := encryption.Encrypt(a.Filename, a.LockedFilename, passphrase) + if err != nil { + return err + } + err = os.Remove(a.Filename) + if err == nil { + a.IsLocked = true + } + return err + } + return nil +} + +// Unlock decrypts a locker Asset. +func (a *Asset) Unlock(passphrase []byte) error { + if a.IsLocked { + err := encryption.Decrypt(a.LockedFilename, a.Filename, false, passphrase) + if err != nil { + return err + } + err = os.Remove(a.LockedFilename) + if err == nil { + a.IsLocked = false + } + return err + } + return nil +} + +// ValidateLocked validates an asset is locked +// and the file is encrypted - not just +// the extension changed. +func (a *Asset) ValidateLocked() (bool, error) { + validationRegex := regexp.MustCompile(encryptionValidatorRegex) + if !a.IsLocked { + return false, nil + } else { + + // Make sure the file does not exist in plain text first + _, err := os.Stat(a.Filename) + if err == nil || os.IsExist(err) { + return false, nil + } + + // Check the headder of the locked file + file, err := os.Open(a.LockedFilename) + defer file.Close() + if err != nil { + return false, err + } + + scanner := bufio.NewScanner(file) + if scanner.Scan() { + firstLine := scanner.Text() + return validationRegex.MatchString(firstLine), nil + } + } + return false, nil +} + +func createLockedFilename(filename string, lock bool) string { + if lock && !isFilenameLocked(filename) { + return filename + lockedFileExtension + } else if !lock && isFilenameLocked(filename) { + return strings.TrimSuffix(filename, lockedFileExtension) + } else { + return filename + } +} + +func isFilenameLocked(filename string) bool { + return strings.HasSuffix(filename, lockedFileExtension) +} diff --git a/internal/pkg/locker/locker_test.go b/internal/pkg/locker/locker_test.go new file mode 100644 index 0000000..46bd267 --- /dev/null +++ b/internal/pkg/locker/locker_test.go @@ -0,0 +1,127 @@ +package locker + +import ( + "io/ioutil" + "os" + "testing" +) + +func TestParseLockerFile(t *testing.T) { + assets, err := ParseLockerFile("../../../test/locker/lyralocker") + if err != nil { + t.Error(err) + return + } + if len(assets) != 2 { + t.Errorf("Expecting 1 entry in test lyralocker file") + return + } +} + +func TestValidateLockAndUnlock(t *testing.T) { + testFile := "../../../test/locker/lockme.txt" + fileText := "This data is to be locked and unlocked by tests\n" + passphrase := "forthegoodoftesting" + + // clean anything that may be remaining from previous tests + os.Remove(testFile) + os.Remove(testFile + ".locked") + + // overwrite the file if already exists, and schedule it to be cleaned up + ioutil.WriteFile(testFile, []byte(fileText), 0666) + defer os.Remove(testFile) + defer os.Remove(testFile + ".locked") // just incase a premature exit + + asset := NewLockerAsset(testFile) + asset.Lock([]byte(passphrase)) + + isLocked, err := asset.ValidateLocked() + if err != nil || !isLocked { + t.Errorf("Failed to lock file. Got: (%v, %v)", isLocked, err) + } + + contents, err := ioutil.ReadFile(testFile + ".locked") + if err != nil { + t.Error(err) + } + if string(contents) == fileText { + t.Errorf("File was not encrypted.") + return + } + + asset.Unlock([]byte(passphrase)) + + contents, err = ioutil.ReadFile(testFile) + if err != nil { + t.Error(err) + } + if string(contents) != fileText { + t.Errorf("File was not decrypted properly.") + } + +} + +func TestValidateLocked(t *testing.T) { + asset1 := NewLockerAsset("../../../test/locker/test-file1.txt") // just the txt + asset2 := NewLockerAsset("../../../test/locker/test-file2.txt") // normal txt and locked files + asset3 := NewLockerAsset("../../../test/locker/test-file3.txt") // plain txt marked as locked but not encrypted + asset4 := NewLockerAsset("../../../test/locker/test-file4.txt") // properly locked + asset5 := NewLockerAsset("../../../test/locker/test-file-404.txt") // does not exist + + isLocked, err := asset1.ValidateLocked() + if err != nil || isLocked { + t.Errorf("%s is plan text and should not be validated as locked. Got: (%v, %v)", asset1.Filename, isLocked, err) + } + + isLocked, err = asset2.ValidateLocked() + if err != nil || isLocked { + t.Errorf("%s is in both plain text and encrypted. It should not be validated as locked. Got: (%v, %v)", asset2.Filename, isLocked, err) + } + + isLocked, err = asset3.ValidateLocked() + if err != nil || isLocked { + t.Errorf("%s has the extension .locked but is still in plan text. It should not be validated as locked. Got: (%v, %v)", asset3.Filename, isLocked, err) + } + + isLocked, err = asset4.ValidateLocked() + if err != nil || !isLocked { + t.Errorf("%s should be validated as locked. Got: (%v, %v)", asset4.Filename, isLocked, err) + } + + isLocked, err = asset5.ValidateLocked() + if err == nil { + t.Errorf("%s does not exist and should error out. Got: (%v, %v)", asset5.Filename, isLocked, err) + } +} + +func TestIsFilenameLocked(t *testing.T) { + if isFilenameLocked("somefile.txt") { + t.Errorf("'somefile.txt' is not a locked name") + } + + if !isFilenameLocked("someOtherFile.exs.locked") { + t.Errorf("'someOtherFile.exs.locked' is a locked name") + } +} + +func TestCreateLockedFilename(t *testing.T) { + test1 := [...]string{"someFile.txt", "someFile.txt.locked"} + if createLockedFilename(test1[0], true) != test1[1] { + t.Errorf("'%s' locked filename not correct! Got: %s", test1[0], test1[1]) + } + + test2 := [...]string{"someFile.txt.locked", "someFile.txt"} + if createLockedFilename(test2[0], false) != test2[1] { + t.Errorf("'%s' unlocked filename not correct! Got: %s", test2[0], test2[1]) + } + + test3 := [...]string{"someFile.txt", "someFile.txt"} + if createLockedFilename(test3[0], false) != test3[1] { + t.Errorf("'%s' unlocked filename not correct! Got: %s", test3[0], test3[1]) + } + + test4 := [...]string{"someFile.txt.locked", "someFile.txt.locked"} + if createLockedFilename(test4[0], true) != test4[1] { + t.Errorf("'%s' locked filename not correct! Got: %s", test4[0], test4[1]) + } +} diff --git a/test/locker/.lockerpass b/test/locker/.lockerpass new file mode 100644 index 0000000..f29df65 --- /dev/null +++ b/test/locker/.lockerpass @@ -0,0 +1 @@ +polyester speech luxurious rocklike untidy reproduce daytime diff --git a/test/locker/lyralocker b/test/locker/lyralocker new file mode 100644 index 0000000..637c085 --- /dev/null +++ b/test/locker/lyralocker @@ -0,0 +1,9 @@ +# This file is for listing assets to be encrypted + +# Uncomment the following line to lock the file +# super-secret-key.txt + +test-item1 +test-item2 +# test-item3 +# test-item4 diff --git a/test/locker/test-file1.txt b/test/locker/test-file1.txt new file mode 100644 index 0000000..ba7c6c7 --- /dev/null +++ b/test/locker/test-file1.txt @@ -0,0 +1 @@ +I the first test file. diff --git a/test/locker/test-file2.txt b/test/locker/test-file2.txt new file mode 100644 index 0000000..ba7c6c7 --- /dev/null +++ b/test/locker/test-file2.txt @@ -0,0 +1 @@ +I the first test file. diff --git a/test/locker/test-file2.txt.locked b/test/locker/test-file2.txt.locked new file mode 100644 index 0000000..116b45c --- /dev/null +++ b/test/locker/test-file2.txt.locked @@ -0,0 +1,2 @@ +@!350af03a671a0145058b362abf0701d5@!2dd1f2e3cab997ab940c15ae +3 dDhصbF6xk0sUqަv \ No newline at end of file diff --git a/test/locker/test-file3.txt.locked b/test/locker/test-file3.txt.locked new file mode 100644 index 0000000..2be6b4e --- /dev/null +++ b/test/locker/test-file3.txt.locked @@ -0,0 +1 @@ +I am an invalid locked file diff --git a/test/locker/test-file4.txt.locked b/test/locker/test-file4.txt.locked new file mode 100644 index 0000000..0adccd1 Binary files /dev/null and b/test/locker/test-file4.txt.locked differ