- AGE encryption with master password model - Core commands: init, show, insert, edit, generate, rm, mv, cp, find, grep, ls - Git integration for version control - Clipboard support (X11 and Wayland) - Secure password generation - Backup and restore functionality - Comprehensive security features - Complete documentation
79 lines
2.1 KiB
Go
79 lines
2.1 KiB
Go
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"os/exec"
|
|
"os/signal"
|
|
"strings"
|
|
"syscall"
|
|
"time"
|
|
)
|
|
|
|
// clearClipboardAfter clears the clipboard after a delay
|
|
// Runs in a goroutine so it doesn't block
|
|
func clearClipboardAfter(duration time.Duration) {
|
|
go func() {
|
|
time.Sleep(duration)
|
|
clearClipboard()
|
|
}()
|
|
}
|
|
|
|
// clearClipboard clears the clipboard
|
|
// Tries both Wayland and X11 - whichever is available
|
|
func clearClipboard() {
|
|
var cmd *exec.Cmd
|
|
if os.Getenv("WAYLAND_DISPLAY") != "" {
|
|
cmd = exec.Command("wl-copy", "--clear")
|
|
} else if os.Getenv("DISPLAY") != "" {
|
|
// X11 - clear by copying /dev/null (hacky but works)
|
|
cmd = exec.Command("xclip", "-selection", "clipboard", "/dev/null")
|
|
} else {
|
|
return // No clipboard available, nothing to clear
|
|
}
|
|
cmd.Run() // Best effort - if it fails, oh well
|
|
}
|
|
|
|
// clipToClipboard copies text to clipboard and sets up auto-clear
|
|
func clipToClipboard(text, path string) {
|
|
clipTime := 10
|
|
if env := os.Getenv("PASSAGE_CLIP_TIME"); env != "" {
|
|
if n, err := fmt.Sscanf(env, "%d", &clipTime); err != nil || n != 1 || clipTime < 0 || clipTime > 3600 {
|
|
clipTime = 10 // Reset to default on invalid input
|
|
}
|
|
}
|
|
|
|
// Try xclip (X11) or wl-copy (Wayland)
|
|
var cmd *exec.Cmd
|
|
if os.Getenv("WAYLAND_DISPLAY") != "" {
|
|
cmd = exec.Command("wl-copy")
|
|
} else if os.Getenv("DISPLAY") != "" {
|
|
cmd = exec.Command("xclip", "-selection", "clipboard")
|
|
} else {
|
|
fmt.Fprintf(os.Stderr, "Error: no clipboard available (needs X11 or Wayland)\n")
|
|
os.Exit(1)
|
|
}
|
|
|
|
cmd.Stdin = strings.NewReader(text)
|
|
if err := cmd.Run(); err != nil {
|
|
fmt.Fprintf(os.Stderr, "Error: failed to copy to clipboard: %v\n", err)
|
|
os.Exit(1)
|
|
}
|
|
|
|
fmt.Printf("Copied %s to clipboard. Will clear in %d seconds.\n", path, clipTime)
|
|
|
|
// Set up signal handler to clear clipboard if user hits Ctrl+C
|
|
sigChan := make(chan os.Signal, 1)
|
|
signal.Notify(sigChan, os.Interrupt, syscall.SIGTERM)
|
|
|
|
// Auto-clear after the timeout
|
|
clearClipboardAfter(time.Duration(clipTime) * time.Second)
|
|
|
|
// Also clear if interrupted - don't leave passwords lying around
|
|
go func() {
|
|
<-sigChan
|
|
clearClipboard()
|
|
os.Exit(0)
|
|
}()
|
|
}
|