package util import ( "fmt" "os" "path/filepath" "github.com/bitfield/script" "github.com/go-errors/errors" "golang.org/x/text/cases" "golang.org/x/text/language" "gensokyo.cafe/xmnt/msg" ) // FileExists checks if a given path exists. It returns error when the target // exists but is not a regular file. func FileExists(path string) (bool, error) { fi, err := os.Stat(path) if os.IsNotExist(err) { return false, nil } if err != nil { return false, err } if !fi.Mode().IsRegular() { err = errors.Errorf("%q is not a regular file", path) } return true, err } // DirExists checks if a given path exists. It returns error when the target // exists but is not a directory. func DirExists(path string) (bool, error) { fi, err := os.Stat(path) if os.IsNotExist(err) { return false, nil } if err != nil { return false, err } if !fi.Mode().IsDir() { err = errors.Errorf("%q is not a directory", path) } return true, err } func findCredentialFileFrom(dir, uuid string) (string, error) { keyName := uuid + ".key" keyPath := "" if err := filepath.WalkDir(dir, func(path string, d os.DirEntry, err error) error { if err != nil { return err } if keyPath != "" { return filepath.SkipDir } if d.Type().IsRegular() && d.Name() == keyName { keyPath = path } return nil }); err != nil { return "", errors.Wrap(err, 0) } return keyPath, nil } func ReadCredentialFile(uuid string, dirs []string) (string, error) { var ( keyPath string err error keyText []byte ) for _, dir := range dirs { if keyPath != "" { break } keyPath, err = findCredentialFileFrom(dir, uuid) if err != nil { return "", errors.WrapPrefix(err, "cannot read credential file", 0) } } if keyPath == "" { return "", errors.Errorf("cannot find credential file for uuid %q", uuid) } isPgp, err := isPgpEncrypted(keyPath) if err != nil { msg.Errorf("Cannot determine type of credential file %q: %v", keyPath, err) isPgp = false } if isPgp { msg.Infof("Reading PGP encrypted credential from %q", keyPath) keyText, err = readPgpEncryptedFile(keyPath) } else { msg.Infof("Reading credential from %q", keyPath) keyText, err = os.ReadFile(keyPath) } if err != nil { return "", errors.WrapPrefix(err, "cannot read credential file", 0) } return string(keyText), nil } func isPgpEncrypted(path string) (bool, error) { output, err := RunCommand("file", nil, path) if err != nil { return false, errors.Wrap(err, 0) } l, err := script.Echo(string(output)).Match("PGP").Match("encrypted").CountLines() return l > 0, nil } func readPgpEncryptedFile(path string) ([]byte, error) { output, err := RunCommand("gpg", nil, "--decrypt", path) if err != nil { return nil, errors.WrapPrefix(err, fmt.Sprintf("failed to read pgp encrypted file %q", path), 0) } return output, nil } func Title(s string) string { return cases.Title(language.Und).String(s) }