127 lines
2.9 KiB
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)
|
|
}
|