xmnt/util/util.go

127 lines
2.9 KiB
Go

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)
}