Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 34 additions & 0 deletions pass/cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@
package cmd

import (
"fmt"
"os"
"path/filepath"
"strings"

"github.com/mandu/tools/pass/cmd/tui"
"github.com/spf13/cobra"
Expand Down Expand Up @@ -122,3 +125,34 @@ func GetPasswordStoreDir() string {
func IsClipboardFlagSet() bool {
return clipFlag
}

// getPasswordFullPath returns the full path to a password file, trying multiple
// strategies for cross-platform compatibility. It returns the first path that exists.
// The path should NOT include the .gpg extension (it will be added).
func getPasswordFullPath(path string) (string, error) {
storeDir := GetPasswordStoreDir()

// Normalize the input path: strip .gpg if present, ensure forward slashes
filePath := strings.ReplaceAll(path, "\\", "/")
if strings.HasSuffix(filePath, ".gpg") {
filePath = strings.TrimSuffix(filePath, ".gpg")
}
filePath += ".gpg"

// Normalize store directory to use forward slashes for consistency
storeDir = strings.ReplaceAll(storeDir, "\\", "/")

// Strategy 1: Use forward slashes (works on both Windows and Unix)
fullPath := storeDir + "/" + filePath
if _, err := os.Stat(fullPath); err == nil {
return fullPath, nil
}

// Strategy 2: Use filepath.Join for systems that need native separators
fullPath = filepath.Join(storeDir, filePath)
if _, err := os.Stat(fullPath); err == nil {
return fullPath, nil
}

return "", fmt.Errorf("pass: %s: No such file or directory", path)
}
41 changes: 8 additions & 33 deletions pass/cmd/show.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@ package cmd
import (
"fmt"
"os"
"path/filepath"
"strings"

"github.com/mandu/tools/pass/pkg/gpg"
"github.com/mandu/tools/pass/pkg/filesystem"
Expand All @@ -29,38 +27,11 @@ func addShowCmd() {

// showPassword retrieves and displays a password
func showPassword(path string) error {
storeDir := GetPasswordStoreDir()

// Normalize the input path: strip .gpg if present, ensure forward slashes
filePath := strings.ReplaceAll(path, "\\", "/")
if strings.HasSuffix(filePath, ".gpg") {
filePath = strings.TrimSuffix(filePath, ".gpg")
}
filePath += ".gpg"

// Construct full path - try multiple strategies for cross-platform compatibility
// Strategy 1: Use filepath.Join with FromSlash (handles path separator conversion)
fullPath := filepath.Join(storeDir, filepath.FromSlash(filePath))

// Check if file exists
if _, err := os.Stat(fullPath); err == nil {
return decryptAndDisplay(fullPath, path)
}

// Strategy 2: Try with forward slashes directly (for Unix-like environments on Windows)
fullPath = storeDir + "/" + filePath
if _, err := os.Stat(fullPath); err == nil {
return decryptAndDisplay(fullPath, path)
}

// Strategy 3: Try storeDir with forward slashes + path
storeDirForward := strings.ReplaceAll(storeDir, "\\", "/")
fullPath = storeDirForward + "/" + filePath
if _, err := os.Stat(fullPath); err == nil {
return decryptAndDisplay(fullPath, path)
fullPath, err := getPasswordFullPath(path)
if err != nil {
return err
}

return fmt.Errorf("pass: %s: No such file or directory", path)
return decryptAndDisplay(fullPath, path)
}

// decryptAndDisplay handles the decryption and output
Expand All @@ -83,6 +54,10 @@ func decryptAndDisplay(fullPath, displayPath string) error {
} else {
// Print to stdout
fmt.Print(password)
// Explicitly flush stdout to avoid buffering delay
// This is especially important for passwords without trailing newlines
// that are piped to other commands
_ = os.Stdout.Sync()
}

return nil
Expand Down
Loading